1*85d5e707SKishon Vijay Abraham I /** 2*85d5e707SKishon Vijay Abraham I * core.c - DesignWare USB3 DRD Controller Core file 3*85d5e707SKishon Vijay Abraham I * 4*85d5e707SKishon Vijay Abraham I * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com 5*85d5e707SKishon Vijay Abraham I * 6*85d5e707SKishon Vijay Abraham I * Authors: Felipe Balbi <balbi@ti.com>, 7*85d5e707SKishon Vijay Abraham I * Sebastian Andrzej Siewior <bigeasy@linutronix.de> 8*85d5e707SKishon Vijay Abraham I * 9*85d5e707SKishon Vijay Abraham I * This program is free software: you can redistribute it and/or modify 10*85d5e707SKishon Vijay Abraham I * it under the terms of the GNU General Public License version 2 of 11*85d5e707SKishon Vijay Abraham I * the License as published by the Free Software Foundation. 12*85d5e707SKishon Vijay Abraham I * 13*85d5e707SKishon Vijay Abraham I * This program is distributed in the hope that it will be useful, 14*85d5e707SKishon Vijay Abraham I * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*85d5e707SKishon Vijay Abraham I * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*85d5e707SKishon Vijay Abraham I * GNU General Public License for more details. 17*85d5e707SKishon Vijay Abraham I * 18*85d5e707SKishon Vijay Abraham I * You should have received a copy of the GNU General Public License 19*85d5e707SKishon Vijay Abraham I * along with this program. If not, see <http://www.gnu.org/licenses/>. 20*85d5e707SKishon Vijay Abraham I */ 21*85d5e707SKishon Vijay Abraham I 22*85d5e707SKishon Vijay Abraham I #include <linux/version.h> 23*85d5e707SKishon Vijay Abraham I #include <linux/module.h> 24*85d5e707SKishon Vijay Abraham I #include <linux/kernel.h> 25*85d5e707SKishon Vijay Abraham I #include <linux/slab.h> 26*85d5e707SKishon Vijay Abraham I #include <linux/spinlock.h> 27*85d5e707SKishon Vijay Abraham I #include <linux/platform_device.h> 28*85d5e707SKishon Vijay Abraham I #include <linux/pm_runtime.h> 29*85d5e707SKishon Vijay Abraham I #include <linux/interrupt.h> 30*85d5e707SKishon Vijay Abraham I #include <linux/ioport.h> 31*85d5e707SKishon Vijay Abraham I #include <linux/io.h> 32*85d5e707SKishon Vijay Abraham I #include <linux/list.h> 33*85d5e707SKishon Vijay Abraham I #include <linux/delay.h> 34*85d5e707SKishon Vijay Abraham I #include <linux/dma-mapping.h> 35*85d5e707SKishon Vijay Abraham I #include <linux/of.h> 36*85d5e707SKishon Vijay Abraham I #include <linux/acpi.h> 37*85d5e707SKishon Vijay Abraham I 38*85d5e707SKishon Vijay Abraham I #include <linux/usb/ch9.h> 39*85d5e707SKishon Vijay Abraham I #include <linux/usb/gadget.h> 40*85d5e707SKishon Vijay Abraham I #include <linux/usb/of.h> 41*85d5e707SKishon Vijay Abraham I #include <linux/usb/otg.h> 42*85d5e707SKishon Vijay Abraham I 43*85d5e707SKishon Vijay Abraham I #include "platform_data.h" 44*85d5e707SKishon Vijay Abraham I #include "core.h" 45*85d5e707SKishon Vijay Abraham I #include "gadget.h" 46*85d5e707SKishon Vijay Abraham I #include "io.h" 47*85d5e707SKishon Vijay Abraham I 48*85d5e707SKishon Vijay Abraham I #include "debug.h" 49*85d5e707SKishon Vijay Abraham I 50*85d5e707SKishon Vijay Abraham I /* -------------------------------------------------------------------------- */ 51*85d5e707SKishon Vijay Abraham I 52*85d5e707SKishon Vijay Abraham I void dwc3_set_mode(struct dwc3 *dwc, u32 mode) 53*85d5e707SKishon Vijay Abraham I { 54*85d5e707SKishon Vijay Abraham I u32 reg; 55*85d5e707SKishon Vijay Abraham I 56*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 57*85d5e707SKishon Vijay Abraham I reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); 58*85d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_PRTCAPDIR(mode); 59*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 60*85d5e707SKishon Vijay Abraham I } 61*85d5e707SKishon Vijay Abraham I 62*85d5e707SKishon Vijay Abraham I /** 63*85d5e707SKishon Vijay Abraham I * dwc3_core_soft_reset - Issues core soft reset and PHY reset 64*85d5e707SKishon Vijay Abraham I * @dwc: pointer to our context structure 65*85d5e707SKishon Vijay Abraham I */ 66*85d5e707SKishon Vijay Abraham I static int dwc3_core_soft_reset(struct dwc3 *dwc) 67*85d5e707SKishon Vijay Abraham I { 68*85d5e707SKishon Vijay Abraham I u32 reg; 69*85d5e707SKishon Vijay Abraham I int ret; 70*85d5e707SKishon Vijay Abraham I 71*85d5e707SKishon Vijay Abraham I /* Before Resetting PHY, put Core in Reset */ 72*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 73*85d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_CORESOFTRESET; 74*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 75*85d5e707SKishon Vijay Abraham I 76*85d5e707SKishon Vijay Abraham I /* Assert USB3 PHY reset */ 77*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 78*85d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; 79*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 80*85d5e707SKishon Vijay Abraham I 81*85d5e707SKishon Vijay Abraham I /* Assert USB2 PHY reset */ 82*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 83*85d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; 84*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 85*85d5e707SKishon Vijay Abraham I 86*85d5e707SKishon Vijay Abraham I usb_phy_init(dwc->usb2_phy); 87*85d5e707SKishon Vijay Abraham I usb_phy_init(dwc->usb3_phy); 88*85d5e707SKishon Vijay Abraham I ret = phy_init(dwc->usb2_generic_phy); 89*85d5e707SKishon Vijay Abraham I if (ret < 0) 90*85d5e707SKishon Vijay Abraham I return ret; 91*85d5e707SKishon Vijay Abraham I 92*85d5e707SKishon Vijay Abraham I ret = phy_init(dwc->usb3_generic_phy); 93*85d5e707SKishon Vijay Abraham I if (ret < 0) { 94*85d5e707SKishon Vijay Abraham I phy_exit(dwc->usb2_generic_phy); 95*85d5e707SKishon Vijay Abraham I return ret; 96*85d5e707SKishon Vijay Abraham I } 97*85d5e707SKishon Vijay Abraham I mdelay(100); 98*85d5e707SKishon Vijay Abraham I 99*85d5e707SKishon Vijay Abraham I /* Clear USB3 PHY reset */ 100*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 101*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; 102*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 103*85d5e707SKishon Vijay Abraham I 104*85d5e707SKishon Vijay Abraham I /* Clear USB2 PHY reset */ 105*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 106*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; 107*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 108*85d5e707SKishon Vijay Abraham I 109*85d5e707SKishon Vijay Abraham I mdelay(100); 110*85d5e707SKishon Vijay Abraham I 111*85d5e707SKishon Vijay Abraham I /* After PHYs are stable we can take Core out of reset state */ 112*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 113*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_CORESOFTRESET; 114*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 115*85d5e707SKishon Vijay Abraham I 116*85d5e707SKishon Vijay Abraham I return 0; 117*85d5e707SKishon Vijay Abraham I } 118*85d5e707SKishon Vijay Abraham I 119*85d5e707SKishon Vijay Abraham I /** 120*85d5e707SKishon Vijay Abraham I * dwc3_free_one_event_buffer - Frees one event buffer 121*85d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 122*85d5e707SKishon Vijay Abraham I * @evt: Pointer to event buffer to be freed 123*85d5e707SKishon Vijay Abraham I */ 124*85d5e707SKishon Vijay Abraham I static void dwc3_free_one_event_buffer(struct dwc3 *dwc, 125*85d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt) 126*85d5e707SKishon Vijay Abraham I { 127*85d5e707SKishon Vijay Abraham I dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma); 128*85d5e707SKishon Vijay Abraham I } 129*85d5e707SKishon Vijay Abraham I 130*85d5e707SKishon Vijay Abraham I /** 131*85d5e707SKishon Vijay Abraham I * dwc3_alloc_one_event_buffer - Allocates one event buffer structure 132*85d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 133*85d5e707SKishon Vijay Abraham I * @length: size of the event buffer 134*85d5e707SKishon Vijay Abraham I * 135*85d5e707SKishon Vijay Abraham I * Returns a pointer to the allocated event buffer structure on success 136*85d5e707SKishon Vijay Abraham I * otherwise ERR_PTR(errno). 137*85d5e707SKishon Vijay Abraham I */ 138*85d5e707SKishon Vijay Abraham I static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, 139*85d5e707SKishon Vijay Abraham I unsigned length) 140*85d5e707SKishon Vijay Abraham I { 141*85d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 142*85d5e707SKishon Vijay Abraham I 143*85d5e707SKishon Vijay Abraham I evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL); 144*85d5e707SKishon Vijay Abraham I if (!evt) 145*85d5e707SKishon Vijay Abraham I return ERR_PTR(-ENOMEM); 146*85d5e707SKishon Vijay Abraham I 147*85d5e707SKishon Vijay Abraham I evt->dwc = dwc; 148*85d5e707SKishon Vijay Abraham I evt->length = length; 149*85d5e707SKishon Vijay Abraham I evt->buf = dma_alloc_coherent(dwc->dev, length, 150*85d5e707SKishon Vijay Abraham I &evt->dma, GFP_KERNEL); 151*85d5e707SKishon Vijay Abraham I if (!evt->buf) 152*85d5e707SKishon Vijay Abraham I return ERR_PTR(-ENOMEM); 153*85d5e707SKishon Vijay Abraham I 154*85d5e707SKishon Vijay Abraham I return evt; 155*85d5e707SKishon Vijay Abraham I } 156*85d5e707SKishon Vijay Abraham I 157*85d5e707SKishon Vijay Abraham I /** 158*85d5e707SKishon Vijay Abraham I * dwc3_free_event_buffers - frees all allocated event buffers 159*85d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 160*85d5e707SKishon Vijay Abraham I */ 161*85d5e707SKishon Vijay Abraham I static void dwc3_free_event_buffers(struct dwc3 *dwc) 162*85d5e707SKishon Vijay Abraham I { 163*85d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 164*85d5e707SKishon Vijay Abraham I int i; 165*85d5e707SKishon Vijay Abraham I 166*85d5e707SKishon Vijay Abraham I for (i = 0; i < dwc->num_event_buffers; i++) { 167*85d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[i]; 168*85d5e707SKishon Vijay Abraham I if (evt) 169*85d5e707SKishon Vijay Abraham I dwc3_free_one_event_buffer(dwc, evt); 170*85d5e707SKishon Vijay Abraham I } 171*85d5e707SKishon Vijay Abraham I } 172*85d5e707SKishon Vijay Abraham I 173*85d5e707SKishon Vijay Abraham I /** 174*85d5e707SKishon Vijay Abraham I * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length 175*85d5e707SKishon Vijay Abraham I * @dwc: pointer to our controller context structure 176*85d5e707SKishon Vijay Abraham I * @length: size of event buffer 177*85d5e707SKishon Vijay Abraham I * 178*85d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. In the error case, dwc 179*85d5e707SKishon Vijay Abraham I * may contain some buffers allocated but not all which were requested. 180*85d5e707SKishon Vijay Abraham I */ 181*85d5e707SKishon Vijay Abraham I static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) 182*85d5e707SKishon Vijay Abraham I { 183*85d5e707SKishon Vijay Abraham I int num; 184*85d5e707SKishon Vijay Abraham I int i; 185*85d5e707SKishon Vijay Abraham I 186*85d5e707SKishon Vijay Abraham I num = DWC3_NUM_INT(dwc->hwparams.hwparams1); 187*85d5e707SKishon Vijay Abraham I dwc->num_event_buffers = num; 188*85d5e707SKishon Vijay Abraham I 189*85d5e707SKishon Vijay Abraham I dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num, 190*85d5e707SKishon Vijay Abraham I GFP_KERNEL); 191*85d5e707SKishon Vijay Abraham I if (!dwc->ev_buffs) 192*85d5e707SKishon Vijay Abraham I return -ENOMEM; 193*85d5e707SKishon Vijay Abraham I 194*85d5e707SKishon Vijay Abraham I for (i = 0; i < num; i++) { 195*85d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 196*85d5e707SKishon Vijay Abraham I 197*85d5e707SKishon Vijay Abraham I evt = dwc3_alloc_one_event_buffer(dwc, length); 198*85d5e707SKishon Vijay Abraham I if (IS_ERR(evt)) { 199*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "can't allocate event buffer\n"); 200*85d5e707SKishon Vijay Abraham I return PTR_ERR(evt); 201*85d5e707SKishon Vijay Abraham I } 202*85d5e707SKishon Vijay Abraham I dwc->ev_buffs[i] = evt; 203*85d5e707SKishon Vijay Abraham I } 204*85d5e707SKishon Vijay Abraham I 205*85d5e707SKishon Vijay Abraham I return 0; 206*85d5e707SKishon Vijay Abraham I } 207*85d5e707SKishon Vijay Abraham I 208*85d5e707SKishon Vijay Abraham I /** 209*85d5e707SKishon Vijay Abraham I * dwc3_event_buffers_setup - setup our allocated event buffers 210*85d5e707SKishon Vijay Abraham I * @dwc: pointer to our controller context structure 211*85d5e707SKishon Vijay Abraham I * 212*85d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. 213*85d5e707SKishon Vijay Abraham I */ 214*85d5e707SKishon Vijay Abraham I static int dwc3_event_buffers_setup(struct dwc3 *dwc) 215*85d5e707SKishon Vijay Abraham I { 216*85d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 217*85d5e707SKishon Vijay Abraham I int n; 218*85d5e707SKishon Vijay Abraham I 219*85d5e707SKishon Vijay Abraham I for (n = 0; n < dwc->num_event_buffers; n++) { 220*85d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[n]; 221*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n", 222*85d5e707SKishon Vijay Abraham I evt->buf, (unsigned long long) evt->dma, 223*85d5e707SKishon Vijay Abraham I evt->length); 224*85d5e707SKishon Vijay Abraham I 225*85d5e707SKishon Vijay Abraham I evt->lpos = 0; 226*85d5e707SKishon Vijay Abraham I 227*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 228*85d5e707SKishon Vijay Abraham I lower_32_bits(evt->dma)); 229*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 230*85d5e707SKishon Vijay Abraham I upper_32_bits(evt->dma)); 231*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 232*85d5e707SKishon Vijay Abraham I DWC3_GEVNTSIZ_SIZE(evt->length)); 233*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); 234*85d5e707SKishon Vijay Abraham I } 235*85d5e707SKishon Vijay Abraham I 236*85d5e707SKishon Vijay Abraham I return 0; 237*85d5e707SKishon Vijay Abraham I } 238*85d5e707SKishon Vijay Abraham I 239*85d5e707SKishon Vijay Abraham I static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) 240*85d5e707SKishon Vijay Abraham I { 241*85d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 242*85d5e707SKishon Vijay Abraham I int n; 243*85d5e707SKishon Vijay Abraham I 244*85d5e707SKishon Vijay Abraham I for (n = 0; n < dwc->num_event_buffers; n++) { 245*85d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[n]; 246*85d5e707SKishon Vijay Abraham I 247*85d5e707SKishon Vijay Abraham I evt->lpos = 0; 248*85d5e707SKishon Vijay Abraham I 249*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); 250*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); 251*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK 252*85d5e707SKishon Vijay Abraham I | DWC3_GEVNTSIZ_SIZE(0)); 253*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); 254*85d5e707SKishon Vijay Abraham I } 255*85d5e707SKishon Vijay Abraham I } 256*85d5e707SKishon Vijay Abraham I 257*85d5e707SKishon Vijay Abraham I static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) 258*85d5e707SKishon Vijay Abraham I { 259*85d5e707SKishon Vijay Abraham I if (!dwc->has_hibernation) 260*85d5e707SKishon Vijay Abraham I return 0; 261*85d5e707SKishon Vijay Abraham I 262*85d5e707SKishon Vijay Abraham I if (!dwc->nr_scratch) 263*85d5e707SKishon Vijay Abraham I return 0; 264*85d5e707SKishon Vijay Abraham I 265*85d5e707SKishon Vijay Abraham I dwc->scratchbuf = kmalloc_array(dwc->nr_scratch, 266*85d5e707SKishon Vijay Abraham I DWC3_SCRATCHBUF_SIZE, GFP_KERNEL); 267*85d5e707SKishon Vijay Abraham I if (!dwc->scratchbuf) 268*85d5e707SKishon Vijay Abraham I return -ENOMEM; 269*85d5e707SKishon Vijay Abraham I 270*85d5e707SKishon Vijay Abraham I return 0; 271*85d5e707SKishon Vijay Abraham I } 272*85d5e707SKishon Vijay Abraham I 273*85d5e707SKishon Vijay Abraham I static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) 274*85d5e707SKishon Vijay Abraham I { 275*85d5e707SKishon Vijay Abraham I dma_addr_t scratch_addr; 276*85d5e707SKishon Vijay Abraham I u32 param; 277*85d5e707SKishon Vijay Abraham I int ret; 278*85d5e707SKishon Vijay Abraham I 279*85d5e707SKishon Vijay Abraham I if (!dwc->has_hibernation) 280*85d5e707SKishon Vijay Abraham I return 0; 281*85d5e707SKishon Vijay Abraham I 282*85d5e707SKishon Vijay Abraham I if (!dwc->nr_scratch) 283*85d5e707SKishon Vijay Abraham I return 0; 284*85d5e707SKishon Vijay Abraham I 285*85d5e707SKishon Vijay Abraham I /* should never fall here */ 286*85d5e707SKishon Vijay Abraham I if (!WARN_ON(dwc->scratchbuf)) 287*85d5e707SKishon Vijay Abraham I return 0; 288*85d5e707SKishon Vijay Abraham I 289*85d5e707SKishon Vijay Abraham I scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf, 290*85d5e707SKishon Vijay Abraham I dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, 291*85d5e707SKishon Vijay Abraham I DMA_BIDIRECTIONAL); 292*85d5e707SKishon Vijay Abraham I if (dma_mapping_error(dwc->dev, scratch_addr)) { 293*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to map scratch buffer\n"); 294*85d5e707SKishon Vijay Abraham I ret = -EFAULT; 295*85d5e707SKishon Vijay Abraham I goto err0; 296*85d5e707SKishon Vijay Abraham I } 297*85d5e707SKishon Vijay Abraham I 298*85d5e707SKishon Vijay Abraham I dwc->scratch_addr = scratch_addr; 299*85d5e707SKishon Vijay Abraham I 300*85d5e707SKishon Vijay Abraham I param = lower_32_bits(scratch_addr); 301*85d5e707SKishon Vijay Abraham I 302*85d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_generic_command(dwc, 303*85d5e707SKishon Vijay Abraham I DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param); 304*85d5e707SKishon Vijay Abraham I if (ret < 0) 305*85d5e707SKishon Vijay Abraham I goto err1; 306*85d5e707SKishon Vijay Abraham I 307*85d5e707SKishon Vijay Abraham I param = upper_32_bits(scratch_addr); 308*85d5e707SKishon Vijay Abraham I 309*85d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_generic_command(dwc, 310*85d5e707SKishon Vijay Abraham I DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param); 311*85d5e707SKishon Vijay Abraham I if (ret < 0) 312*85d5e707SKishon Vijay Abraham I goto err1; 313*85d5e707SKishon Vijay Abraham I 314*85d5e707SKishon Vijay Abraham I return 0; 315*85d5e707SKishon Vijay Abraham I 316*85d5e707SKishon Vijay Abraham I err1: 317*85d5e707SKishon Vijay Abraham I dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch * 318*85d5e707SKishon Vijay Abraham I DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); 319*85d5e707SKishon Vijay Abraham I 320*85d5e707SKishon Vijay Abraham I err0: 321*85d5e707SKishon Vijay Abraham I return ret; 322*85d5e707SKishon Vijay Abraham I } 323*85d5e707SKishon Vijay Abraham I 324*85d5e707SKishon Vijay Abraham I static void dwc3_free_scratch_buffers(struct dwc3 *dwc) 325*85d5e707SKishon Vijay Abraham I { 326*85d5e707SKishon Vijay Abraham I if (!dwc->has_hibernation) 327*85d5e707SKishon Vijay Abraham I return; 328*85d5e707SKishon Vijay Abraham I 329*85d5e707SKishon Vijay Abraham I if (!dwc->nr_scratch) 330*85d5e707SKishon Vijay Abraham I return; 331*85d5e707SKishon Vijay Abraham I 332*85d5e707SKishon Vijay Abraham I /* should never fall here */ 333*85d5e707SKishon Vijay Abraham I if (!WARN_ON(dwc->scratchbuf)) 334*85d5e707SKishon Vijay Abraham I return; 335*85d5e707SKishon Vijay Abraham I 336*85d5e707SKishon Vijay Abraham I dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch * 337*85d5e707SKishon Vijay Abraham I DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); 338*85d5e707SKishon Vijay Abraham I kfree(dwc->scratchbuf); 339*85d5e707SKishon Vijay Abraham I } 340*85d5e707SKishon Vijay Abraham I 341*85d5e707SKishon Vijay Abraham I static void dwc3_core_num_eps(struct dwc3 *dwc) 342*85d5e707SKishon Vijay Abraham I { 343*85d5e707SKishon Vijay Abraham I struct dwc3_hwparams *parms = &dwc->hwparams; 344*85d5e707SKishon Vijay Abraham I 345*85d5e707SKishon Vijay Abraham I dwc->num_in_eps = DWC3_NUM_IN_EPS(parms); 346*85d5e707SKishon Vijay Abraham I dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps; 347*85d5e707SKishon Vijay Abraham I 348*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n", 349*85d5e707SKishon Vijay Abraham I dwc->num_in_eps, dwc->num_out_eps); 350*85d5e707SKishon Vijay Abraham I } 351*85d5e707SKishon Vijay Abraham I 352*85d5e707SKishon Vijay Abraham I static void dwc3_cache_hwparams(struct dwc3 *dwc) 353*85d5e707SKishon Vijay Abraham I { 354*85d5e707SKishon Vijay Abraham I struct dwc3_hwparams *parms = &dwc->hwparams; 355*85d5e707SKishon Vijay Abraham I 356*85d5e707SKishon Vijay Abraham I parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0); 357*85d5e707SKishon Vijay Abraham I parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1); 358*85d5e707SKishon Vijay Abraham I parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2); 359*85d5e707SKishon Vijay Abraham I parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3); 360*85d5e707SKishon Vijay Abraham I parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4); 361*85d5e707SKishon Vijay Abraham I parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5); 362*85d5e707SKishon Vijay Abraham I parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6); 363*85d5e707SKishon Vijay Abraham I parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7); 364*85d5e707SKishon Vijay Abraham I parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); 365*85d5e707SKishon Vijay Abraham I } 366*85d5e707SKishon Vijay Abraham I 367*85d5e707SKishon Vijay Abraham I /** 368*85d5e707SKishon Vijay Abraham I * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core 369*85d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 370*85d5e707SKishon Vijay Abraham I */ 371*85d5e707SKishon Vijay Abraham I static void dwc3_phy_setup(struct dwc3 *dwc) 372*85d5e707SKishon Vijay Abraham I { 373*85d5e707SKishon Vijay Abraham I u32 reg; 374*85d5e707SKishon Vijay Abraham I 375*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 376*85d5e707SKishon Vijay Abraham I 377*85d5e707SKishon Vijay Abraham I /* 378*85d5e707SKishon Vijay Abraham I * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY 379*85d5e707SKishon Vijay Abraham I * to '0' during coreConsultant configuration. So default value 380*85d5e707SKishon Vijay Abraham I * will be '0' when the core is reset. Application needs to set it 381*85d5e707SKishon Vijay Abraham I * to '1' after the core initialization is completed. 382*85d5e707SKishon Vijay Abraham I */ 383*85d5e707SKishon Vijay Abraham I if (dwc->revision > DWC3_REVISION_194A) 384*85d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_SUSPHY; 385*85d5e707SKishon Vijay Abraham I 386*85d5e707SKishon Vijay Abraham I if (dwc->u2ss_inp3_quirk) 387*85d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; 388*85d5e707SKishon Vijay Abraham I 389*85d5e707SKishon Vijay Abraham I if (dwc->req_p1p2p3_quirk) 390*85d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_REQP1P2P3; 391*85d5e707SKishon Vijay Abraham I 392*85d5e707SKishon Vijay Abraham I if (dwc->del_p1p2p3_quirk) 393*85d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN; 394*85d5e707SKishon Vijay Abraham I 395*85d5e707SKishon Vijay Abraham I if (dwc->del_phy_power_chg_quirk) 396*85d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE; 397*85d5e707SKishon Vijay Abraham I 398*85d5e707SKishon Vijay Abraham I if (dwc->lfps_filter_quirk) 399*85d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_LFPSFILT; 400*85d5e707SKishon Vijay Abraham I 401*85d5e707SKishon Vijay Abraham I if (dwc->rx_detect_poll_quirk) 402*85d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL; 403*85d5e707SKishon Vijay Abraham I 404*85d5e707SKishon Vijay Abraham I if (dwc->tx_de_emphasis_quirk) 405*85d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis); 406*85d5e707SKishon Vijay Abraham I 407*85d5e707SKishon Vijay Abraham I if (dwc->dis_u3_susphy_quirk) 408*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; 409*85d5e707SKishon Vijay Abraham I 410*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 411*85d5e707SKishon Vijay Abraham I 412*85d5e707SKishon Vijay Abraham I mdelay(100); 413*85d5e707SKishon Vijay Abraham I 414*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 415*85d5e707SKishon Vijay Abraham I 416*85d5e707SKishon Vijay Abraham I /* 417*85d5e707SKishon Vijay Abraham I * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to 418*85d5e707SKishon Vijay Abraham I * '0' during coreConsultant configuration. So default value will 419*85d5e707SKishon Vijay Abraham I * be '0' when the core is reset. Application needs to set it to 420*85d5e707SKishon Vijay Abraham I * '1' after the core initialization is completed. 421*85d5e707SKishon Vijay Abraham I */ 422*85d5e707SKishon Vijay Abraham I if (dwc->revision > DWC3_REVISION_194A) 423*85d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB2PHYCFG_SUSPHY; 424*85d5e707SKishon Vijay Abraham I 425*85d5e707SKishon Vijay Abraham I if (dwc->dis_u2_susphy_quirk) 426*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; 427*85d5e707SKishon Vijay Abraham I 428*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 429*85d5e707SKishon Vijay Abraham I 430*85d5e707SKishon Vijay Abraham I mdelay(100); 431*85d5e707SKishon Vijay Abraham I } 432*85d5e707SKishon Vijay Abraham I 433*85d5e707SKishon Vijay Abraham I /** 434*85d5e707SKishon Vijay Abraham I * dwc3_core_init - Low-level initialization of DWC3 Core 435*85d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 436*85d5e707SKishon Vijay Abraham I * 437*85d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. 438*85d5e707SKishon Vijay Abraham I */ 439*85d5e707SKishon Vijay Abraham I static int dwc3_core_init(struct dwc3 *dwc) 440*85d5e707SKishon Vijay Abraham I { 441*85d5e707SKishon Vijay Abraham I unsigned long timeout; 442*85d5e707SKishon Vijay Abraham I u32 hwparams4 = dwc->hwparams.hwparams4; 443*85d5e707SKishon Vijay Abraham I u32 reg; 444*85d5e707SKishon Vijay Abraham I int ret; 445*85d5e707SKishon Vijay Abraham I 446*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); 447*85d5e707SKishon Vijay Abraham I /* This should read as U3 followed by revision number */ 448*85d5e707SKishon Vijay Abraham I if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) { 449*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); 450*85d5e707SKishon Vijay Abraham I ret = -ENODEV; 451*85d5e707SKishon Vijay Abraham I goto err0; 452*85d5e707SKishon Vijay Abraham I } 453*85d5e707SKishon Vijay Abraham I dwc->revision = reg; 454*85d5e707SKishon Vijay Abraham I 455*85d5e707SKishon Vijay Abraham I /* 456*85d5e707SKishon Vijay Abraham I * Write Linux Version Code to our GUID register so it's easy to figure 457*85d5e707SKishon Vijay Abraham I * out which kernel version a bug was found. 458*85d5e707SKishon Vijay Abraham I */ 459*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE); 460*85d5e707SKishon Vijay Abraham I 461*85d5e707SKishon Vijay Abraham I /* Handle USB2.0-only core configuration */ 462*85d5e707SKishon Vijay Abraham I if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == 463*85d5e707SKishon Vijay Abraham I DWC3_GHWPARAMS3_SSPHY_IFC_DIS) { 464*85d5e707SKishon Vijay Abraham I if (dwc->maximum_speed == USB_SPEED_SUPER) 465*85d5e707SKishon Vijay Abraham I dwc->maximum_speed = USB_SPEED_HIGH; 466*85d5e707SKishon Vijay Abraham I } 467*85d5e707SKishon Vijay Abraham I 468*85d5e707SKishon Vijay Abraham I /* issue device SoftReset too */ 469*85d5e707SKishon Vijay Abraham I timeout = jiffies + msecs_to_jiffies(500); 470*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST); 471*85d5e707SKishon Vijay Abraham I do { 472*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 473*85d5e707SKishon Vijay Abraham I if (!(reg & DWC3_DCTL_CSFTRST)) 474*85d5e707SKishon Vijay Abraham I break; 475*85d5e707SKishon Vijay Abraham I 476*85d5e707SKishon Vijay Abraham I if (time_after(jiffies, timeout)) { 477*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "Reset Timed Out\n"); 478*85d5e707SKishon Vijay Abraham I ret = -ETIMEDOUT; 479*85d5e707SKishon Vijay Abraham I goto err0; 480*85d5e707SKishon Vijay Abraham I } 481*85d5e707SKishon Vijay Abraham I 482*85d5e707SKishon Vijay Abraham I cpu_relax(); 483*85d5e707SKishon Vijay Abraham I } while (true); 484*85d5e707SKishon Vijay Abraham I 485*85d5e707SKishon Vijay Abraham I ret = dwc3_core_soft_reset(dwc); 486*85d5e707SKishon Vijay Abraham I if (ret) 487*85d5e707SKishon Vijay Abraham I goto err0; 488*85d5e707SKishon Vijay Abraham I 489*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 490*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_SCALEDOWN_MASK; 491*85d5e707SKishon Vijay Abraham I 492*85d5e707SKishon Vijay Abraham I switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { 493*85d5e707SKishon Vijay Abraham I case DWC3_GHWPARAMS1_EN_PWROPT_CLK: 494*85d5e707SKishon Vijay Abraham I /** 495*85d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an 496*85d5e707SKishon Vijay Abraham I * issue which would cause xHCI compliance tests to fail. 497*85d5e707SKishon Vijay Abraham I * 498*85d5e707SKishon Vijay Abraham I * Because of that we cannot enable clock gating on such 499*85d5e707SKishon Vijay Abraham I * configurations. 500*85d5e707SKishon Vijay Abraham I * 501*85d5e707SKishon Vijay Abraham I * Refers to: 502*85d5e707SKishon Vijay Abraham I * 503*85d5e707SKishon Vijay Abraham I * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based 504*85d5e707SKishon Vijay Abraham I * SOF/ITP Mode Used 505*85d5e707SKishon Vijay Abraham I */ 506*85d5e707SKishon Vijay Abraham I if ((dwc->dr_mode == USB_DR_MODE_HOST || 507*85d5e707SKishon Vijay Abraham I dwc->dr_mode == USB_DR_MODE_OTG) && 508*85d5e707SKishon Vijay Abraham I (dwc->revision >= DWC3_REVISION_210A && 509*85d5e707SKishon Vijay Abraham I dwc->revision <= DWC3_REVISION_250A)) 510*85d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC; 511*85d5e707SKishon Vijay Abraham I else 512*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_DSBLCLKGTNG; 513*85d5e707SKishon Vijay Abraham I break; 514*85d5e707SKishon Vijay Abraham I case DWC3_GHWPARAMS1_EN_PWROPT_HIB: 515*85d5e707SKishon Vijay Abraham I /* enable hibernation here */ 516*85d5e707SKishon Vijay Abraham I dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4); 517*85d5e707SKishon Vijay Abraham I 518*85d5e707SKishon Vijay Abraham I /* 519*85d5e707SKishon Vijay Abraham I * REVISIT Enabling this bit so that host-mode hibernation 520*85d5e707SKishon Vijay Abraham I * will work. Device-mode hibernation is not yet implemented. 521*85d5e707SKishon Vijay Abraham I */ 522*85d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_GBLHIBERNATIONEN; 523*85d5e707SKishon Vijay Abraham I break; 524*85d5e707SKishon Vijay Abraham I default: 525*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "No power optimization available\n"); 526*85d5e707SKishon Vijay Abraham I } 527*85d5e707SKishon Vijay Abraham I 528*85d5e707SKishon Vijay Abraham I /* check if current dwc3 is on simulation board */ 529*85d5e707SKishon Vijay Abraham I if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) { 530*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "it is on FPGA board\n"); 531*85d5e707SKishon Vijay Abraham I dwc->is_fpga = true; 532*85d5e707SKishon Vijay Abraham I } 533*85d5e707SKishon Vijay Abraham I 534*85d5e707SKishon Vijay Abraham I WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga, 535*85d5e707SKishon Vijay Abraham I "disable_scramble cannot be used on non-FPGA builds\n"); 536*85d5e707SKishon Vijay Abraham I 537*85d5e707SKishon Vijay Abraham I if (dwc->disable_scramble_quirk && dwc->is_fpga) 538*85d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_DISSCRAMBLE; 539*85d5e707SKishon Vijay Abraham I else 540*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_DISSCRAMBLE; 541*85d5e707SKishon Vijay Abraham I 542*85d5e707SKishon Vijay Abraham I if (dwc->u2exit_lfps_quirk) 543*85d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_U2EXIT_LFPS; 544*85d5e707SKishon Vijay Abraham I 545*85d5e707SKishon Vijay Abraham I /* 546*85d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 revisions <1.90a have a bug 547*85d5e707SKishon Vijay Abraham I * where the device can fail to connect at SuperSpeed 548*85d5e707SKishon Vijay Abraham I * and falls back to high-speed mode which causes 549*85d5e707SKishon Vijay Abraham I * the device to enter a Connect/Disconnect loop 550*85d5e707SKishon Vijay Abraham I */ 551*85d5e707SKishon Vijay Abraham I if (dwc->revision < DWC3_REVISION_190A) 552*85d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_U2RSTECN; 553*85d5e707SKishon Vijay Abraham I 554*85d5e707SKishon Vijay Abraham I dwc3_core_num_eps(dwc); 555*85d5e707SKishon Vijay Abraham I 556*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 557*85d5e707SKishon Vijay Abraham I 558*85d5e707SKishon Vijay Abraham I dwc3_phy_setup(dwc); 559*85d5e707SKishon Vijay Abraham I 560*85d5e707SKishon Vijay Abraham I ret = dwc3_alloc_scratch_buffers(dwc); 561*85d5e707SKishon Vijay Abraham I if (ret) 562*85d5e707SKishon Vijay Abraham I goto err1; 563*85d5e707SKishon Vijay Abraham I 564*85d5e707SKishon Vijay Abraham I ret = dwc3_setup_scratch_buffers(dwc); 565*85d5e707SKishon Vijay Abraham I if (ret) 566*85d5e707SKishon Vijay Abraham I goto err2; 567*85d5e707SKishon Vijay Abraham I 568*85d5e707SKishon Vijay Abraham I return 0; 569*85d5e707SKishon Vijay Abraham I 570*85d5e707SKishon Vijay Abraham I err2: 571*85d5e707SKishon Vijay Abraham I dwc3_free_scratch_buffers(dwc); 572*85d5e707SKishon Vijay Abraham I 573*85d5e707SKishon Vijay Abraham I err1: 574*85d5e707SKishon Vijay Abraham I usb_phy_shutdown(dwc->usb2_phy); 575*85d5e707SKishon Vijay Abraham I usb_phy_shutdown(dwc->usb3_phy); 576*85d5e707SKishon Vijay Abraham I phy_exit(dwc->usb2_generic_phy); 577*85d5e707SKishon Vijay Abraham I phy_exit(dwc->usb3_generic_phy); 578*85d5e707SKishon Vijay Abraham I 579*85d5e707SKishon Vijay Abraham I err0: 580*85d5e707SKishon Vijay Abraham I return ret; 581*85d5e707SKishon Vijay Abraham I } 582*85d5e707SKishon Vijay Abraham I 583*85d5e707SKishon Vijay Abraham I static void dwc3_core_exit(struct dwc3 *dwc) 584*85d5e707SKishon Vijay Abraham I { 585*85d5e707SKishon Vijay Abraham I dwc3_free_scratch_buffers(dwc); 586*85d5e707SKishon Vijay Abraham I usb_phy_shutdown(dwc->usb2_phy); 587*85d5e707SKishon Vijay Abraham I usb_phy_shutdown(dwc->usb3_phy); 588*85d5e707SKishon Vijay Abraham I phy_exit(dwc->usb2_generic_phy); 589*85d5e707SKishon Vijay Abraham I phy_exit(dwc->usb3_generic_phy); 590*85d5e707SKishon Vijay Abraham I } 591*85d5e707SKishon Vijay Abraham I 592*85d5e707SKishon Vijay Abraham I static int dwc3_core_get_phy(struct dwc3 *dwc) 593*85d5e707SKishon Vijay Abraham I { 594*85d5e707SKishon Vijay Abraham I struct device *dev = dwc->dev; 595*85d5e707SKishon Vijay Abraham I struct device_node *node = dev->of_node; 596*85d5e707SKishon Vijay Abraham I int ret; 597*85d5e707SKishon Vijay Abraham I 598*85d5e707SKishon Vijay Abraham I if (node) { 599*85d5e707SKishon Vijay Abraham I dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); 600*85d5e707SKishon Vijay Abraham I dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); 601*85d5e707SKishon Vijay Abraham I } else { 602*85d5e707SKishon Vijay Abraham I dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); 603*85d5e707SKishon Vijay Abraham I dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); 604*85d5e707SKishon Vijay Abraham I } 605*85d5e707SKishon Vijay Abraham I 606*85d5e707SKishon Vijay Abraham I if (IS_ERR(dwc->usb2_phy)) { 607*85d5e707SKishon Vijay Abraham I ret = PTR_ERR(dwc->usb2_phy); 608*85d5e707SKishon Vijay Abraham I if (ret == -ENXIO || ret == -ENODEV) { 609*85d5e707SKishon Vijay Abraham I dwc->usb2_phy = NULL; 610*85d5e707SKishon Vijay Abraham I } else if (ret == -EPROBE_DEFER) { 611*85d5e707SKishon Vijay Abraham I return ret; 612*85d5e707SKishon Vijay Abraham I } else { 613*85d5e707SKishon Vijay Abraham I dev_err(dev, "no usb2 phy configured\n"); 614*85d5e707SKishon Vijay Abraham I return ret; 615*85d5e707SKishon Vijay Abraham I } 616*85d5e707SKishon Vijay Abraham I } 617*85d5e707SKishon Vijay Abraham I 618*85d5e707SKishon Vijay Abraham I if (IS_ERR(dwc->usb3_phy)) { 619*85d5e707SKishon Vijay Abraham I ret = PTR_ERR(dwc->usb3_phy); 620*85d5e707SKishon Vijay Abraham I if (ret == -ENXIO || ret == -ENODEV) { 621*85d5e707SKishon Vijay Abraham I dwc->usb3_phy = NULL; 622*85d5e707SKishon Vijay Abraham I } else if (ret == -EPROBE_DEFER) { 623*85d5e707SKishon Vijay Abraham I return ret; 624*85d5e707SKishon Vijay Abraham I } else { 625*85d5e707SKishon Vijay Abraham I dev_err(dev, "no usb3 phy configured\n"); 626*85d5e707SKishon Vijay Abraham I return ret; 627*85d5e707SKishon Vijay Abraham I } 628*85d5e707SKishon Vijay Abraham I } 629*85d5e707SKishon Vijay Abraham I 630*85d5e707SKishon Vijay Abraham I dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); 631*85d5e707SKishon Vijay Abraham I if (IS_ERR(dwc->usb2_generic_phy)) { 632*85d5e707SKishon Vijay Abraham I ret = PTR_ERR(dwc->usb2_generic_phy); 633*85d5e707SKishon Vijay Abraham I if (ret == -ENOSYS || ret == -ENODEV) { 634*85d5e707SKishon Vijay Abraham I dwc->usb2_generic_phy = NULL; 635*85d5e707SKishon Vijay Abraham I } else if (ret == -EPROBE_DEFER) { 636*85d5e707SKishon Vijay Abraham I return ret; 637*85d5e707SKishon Vijay Abraham I } else { 638*85d5e707SKishon Vijay Abraham I dev_err(dev, "no usb2 phy configured\n"); 639*85d5e707SKishon Vijay Abraham I return ret; 640*85d5e707SKishon Vijay Abraham I } 641*85d5e707SKishon Vijay Abraham I } 642*85d5e707SKishon Vijay Abraham I 643*85d5e707SKishon Vijay Abraham I dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy"); 644*85d5e707SKishon Vijay Abraham I if (IS_ERR(dwc->usb3_generic_phy)) { 645*85d5e707SKishon Vijay Abraham I ret = PTR_ERR(dwc->usb3_generic_phy); 646*85d5e707SKishon Vijay Abraham I if (ret == -ENOSYS || ret == -ENODEV) { 647*85d5e707SKishon Vijay Abraham I dwc->usb3_generic_phy = NULL; 648*85d5e707SKishon Vijay Abraham I } else if (ret == -EPROBE_DEFER) { 649*85d5e707SKishon Vijay Abraham I return ret; 650*85d5e707SKishon Vijay Abraham I } else { 651*85d5e707SKishon Vijay Abraham I dev_err(dev, "no usb3 phy configured\n"); 652*85d5e707SKishon Vijay Abraham I return ret; 653*85d5e707SKishon Vijay Abraham I } 654*85d5e707SKishon Vijay Abraham I } 655*85d5e707SKishon Vijay Abraham I 656*85d5e707SKishon Vijay Abraham I return 0; 657*85d5e707SKishon Vijay Abraham I } 658*85d5e707SKishon Vijay Abraham I 659*85d5e707SKishon Vijay Abraham I static int dwc3_core_init_mode(struct dwc3 *dwc) 660*85d5e707SKishon Vijay Abraham I { 661*85d5e707SKishon Vijay Abraham I struct device *dev = dwc->dev; 662*85d5e707SKishon Vijay Abraham I int ret; 663*85d5e707SKishon Vijay Abraham I 664*85d5e707SKishon Vijay Abraham I switch (dwc->dr_mode) { 665*85d5e707SKishon Vijay Abraham I case USB_DR_MODE_PERIPHERAL: 666*85d5e707SKishon Vijay Abraham I dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); 667*85d5e707SKishon Vijay Abraham I ret = dwc3_gadget_init(dwc); 668*85d5e707SKishon Vijay Abraham I if (ret) { 669*85d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize gadget\n"); 670*85d5e707SKishon Vijay Abraham I return ret; 671*85d5e707SKishon Vijay Abraham I } 672*85d5e707SKishon Vijay Abraham I break; 673*85d5e707SKishon Vijay Abraham I case USB_DR_MODE_HOST: 674*85d5e707SKishon Vijay Abraham I dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); 675*85d5e707SKishon Vijay Abraham I ret = dwc3_host_init(dwc); 676*85d5e707SKishon Vijay Abraham I if (ret) { 677*85d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize host\n"); 678*85d5e707SKishon Vijay Abraham I return ret; 679*85d5e707SKishon Vijay Abraham I } 680*85d5e707SKishon Vijay Abraham I break; 681*85d5e707SKishon Vijay Abraham I case USB_DR_MODE_OTG: 682*85d5e707SKishon Vijay Abraham I dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); 683*85d5e707SKishon Vijay Abraham I ret = dwc3_host_init(dwc); 684*85d5e707SKishon Vijay Abraham I if (ret) { 685*85d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize host\n"); 686*85d5e707SKishon Vijay Abraham I return ret; 687*85d5e707SKishon Vijay Abraham I } 688*85d5e707SKishon Vijay Abraham I 689*85d5e707SKishon Vijay Abraham I ret = dwc3_gadget_init(dwc); 690*85d5e707SKishon Vijay Abraham I if (ret) { 691*85d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize gadget\n"); 692*85d5e707SKishon Vijay Abraham I return ret; 693*85d5e707SKishon Vijay Abraham I } 694*85d5e707SKishon Vijay Abraham I break; 695*85d5e707SKishon Vijay Abraham I default: 696*85d5e707SKishon Vijay Abraham I dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); 697*85d5e707SKishon Vijay Abraham I return -EINVAL; 698*85d5e707SKishon Vijay Abraham I } 699*85d5e707SKishon Vijay Abraham I 700*85d5e707SKishon Vijay Abraham I return 0; 701*85d5e707SKishon Vijay Abraham I } 702*85d5e707SKishon Vijay Abraham I 703*85d5e707SKishon Vijay Abraham I static void dwc3_core_exit_mode(struct dwc3 *dwc) 704*85d5e707SKishon Vijay Abraham I { 705*85d5e707SKishon Vijay Abraham I switch (dwc->dr_mode) { 706*85d5e707SKishon Vijay Abraham I case USB_DR_MODE_PERIPHERAL: 707*85d5e707SKishon Vijay Abraham I dwc3_gadget_exit(dwc); 708*85d5e707SKishon Vijay Abraham I break; 709*85d5e707SKishon Vijay Abraham I case USB_DR_MODE_HOST: 710*85d5e707SKishon Vijay Abraham I dwc3_host_exit(dwc); 711*85d5e707SKishon Vijay Abraham I break; 712*85d5e707SKishon Vijay Abraham I case USB_DR_MODE_OTG: 713*85d5e707SKishon Vijay Abraham I dwc3_host_exit(dwc); 714*85d5e707SKishon Vijay Abraham I dwc3_gadget_exit(dwc); 715*85d5e707SKishon Vijay Abraham I break; 716*85d5e707SKishon Vijay Abraham I default: 717*85d5e707SKishon Vijay Abraham I /* do nothing */ 718*85d5e707SKishon Vijay Abraham I break; 719*85d5e707SKishon Vijay Abraham I } 720*85d5e707SKishon Vijay Abraham I } 721*85d5e707SKishon Vijay Abraham I 722*85d5e707SKishon Vijay Abraham I #define DWC3_ALIGN_MASK (16 - 1) 723*85d5e707SKishon Vijay Abraham I 724*85d5e707SKishon Vijay Abraham I static int dwc3_probe(struct platform_device *pdev) 725*85d5e707SKishon Vijay Abraham I { 726*85d5e707SKishon Vijay Abraham I struct device *dev = &pdev->dev; 727*85d5e707SKishon Vijay Abraham I struct dwc3_platform_data *pdata = dev_get_platdata(dev); 728*85d5e707SKishon Vijay Abraham I struct device_node *node = dev->of_node; 729*85d5e707SKishon Vijay Abraham I struct resource *res; 730*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc; 731*85d5e707SKishon Vijay Abraham I u8 lpm_nyet_threshold; 732*85d5e707SKishon Vijay Abraham I u8 tx_de_emphasis; 733*85d5e707SKishon Vijay Abraham I u8 hird_threshold; 734*85d5e707SKishon Vijay Abraham I 735*85d5e707SKishon Vijay Abraham I int ret; 736*85d5e707SKishon Vijay Abraham I 737*85d5e707SKishon Vijay Abraham I void __iomem *regs; 738*85d5e707SKishon Vijay Abraham I void *mem; 739*85d5e707SKishon Vijay Abraham I 740*85d5e707SKishon Vijay Abraham I mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); 741*85d5e707SKishon Vijay Abraham I if (!mem) 742*85d5e707SKishon Vijay Abraham I return -ENOMEM; 743*85d5e707SKishon Vijay Abraham I 744*85d5e707SKishon Vijay Abraham I dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); 745*85d5e707SKishon Vijay Abraham I dwc->mem = mem; 746*85d5e707SKishon Vijay Abraham I dwc->dev = dev; 747*85d5e707SKishon Vijay Abraham I 748*85d5e707SKishon Vijay Abraham I res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 749*85d5e707SKishon Vijay Abraham I if (!res) { 750*85d5e707SKishon Vijay Abraham I dev_err(dev, "missing IRQ\n"); 751*85d5e707SKishon Vijay Abraham I return -ENODEV; 752*85d5e707SKishon Vijay Abraham I } 753*85d5e707SKishon Vijay Abraham I dwc->xhci_resources[1].start = res->start; 754*85d5e707SKishon Vijay Abraham I dwc->xhci_resources[1].end = res->end; 755*85d5e707SKishon Vijay Abraham I dwc->xhci_resources[1].flags = res->flags; 756*85d5e707SKishon Vijay Abraham I dwc->xhci_resources[1].name = res->name; 757*85d5e707SKishon Vijay Abraham I 758*85d5e707SKishon Vijay Abraham I res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 759*85d5e707SKishon Vijay Abraham I if (!res) { 760*85d5e707SKishon Vijay Abraham I dev_err(dev, "missing memory resource\n"); 761*85d5e707SKishon Vijay Abraham I return -ENODEV; 762*85d5e707SKishon Vijay Abraham I } 763*85d5e707SKishon Vijay Abraham I 764*85d5e707SKishon Vijay Abraham I dwc->xhci_resources[0].start = res->start; 765*85d5e707SKishon Vijay Abraham I dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + 766*85d5e707SKishon Vijay Abraham I DWC3_XHCI_REGS_END; 767*85d5e707SKishon Vijay Abraham I dwc->xhci_resources[0].flags = res->flags; 768*85d5e707SKishon Vijay Abraham I dwc->xhci_resources[0].name = res->name; 769*85d5e707SKishon Vijay Abraham I 770*85d5e707SKishon Vijay Abraham I res->start += DWC3_GLOBALS_REGS_START; 771*85d5e707SKishon Vijay Abraham I 772*85d5e707SKishon Vijay Abraham I /* 773*85d5e707SKishon Vijay Abraham I * Request memory region but exclude xHCI regs, 774*85d5e707SKishon Vijay Abraham I * since it will be requested by the xhci-plat driver. 775*85d5e707SKishon Vijay Abraham I */ 776*85d5e707SKishon Vijay Abraham I regs = devm_ioremap_resource(dev, res); 777*85d5e707SKishon Vijay Abraham I if (IS_ERR(regs)) 778*85d5e707SKishon Vijay Abraham I return PTR_ERR(regs); 779*85d5e707SKishon Vijay Abraham I 780*85d5e707SKishon Vijay Abraham I dwc->regs = regs; 781*85d5e707SKishon Vijay Abraham I dwc->regs_size = resource_size(res); 782*85d5e707SKishon Vijay Abraham I /* 783*85d5e707SKishon Vijay Abraham I * restore res->start back to its original value so that, 784*85d5e707SKishon Vijay Abraham I * in case the probe is deferred, we don't end up getting error in 785*85d5e707SKishon Vijay Abraham I * request the memory region the next time probe is called. 786*85d5e707SKishon Vijay Abraham I */ 787*85d5e707SKishon Vijay Abraham I res->start -= DWC3_GLOBALS_REGS_START; 788*85d5e707SKishon Vijay Abraham I 789*85d5e707SKishon Vijay Abraham I /* default to highest possible threshold */ 790*85d5e707SKishon Vijay Abraham I lpm_nyet_threshold = 0xff; 791*85d5e707SKishon Vijay Abraham I 792*85d5e707SKishon Vijay Abraham I /* default to -3.5dB de-emphasis */ 793*85d5e707SKishon Vijay Abraham I tx_de_emphasis = 1; 794*85d5e707SKishon Vijay Abraham I 795*85d5e707SKishon Vijay Abraham I /* 796*85d5e707SKishon Vijay Abraham I * default to assert utmi_sleep_n and use maximum allowed HIRD 797*85d5e707SKishon Vijay Abraham I * threshold value of 0b1100 798*85d5e707SKishon Vijay Abraham I */ 799*85d5e707SKishon Vijay Abraham I hird_threshold = 12; 800*85d5e707SKishon Vijay Abraham I 801*85d5e707SKishon Vijay Abraham I if (node) { 802*85d5e707SKishon Vijay Abraham I dwc->maximum_speed = of_usb_get_maximum_speed(node); 803*85d5e707SKishon Vijay Abraham I dwc->has_lpm_erratum = of_property_read_bool(node, 804*85d5e707SKishon Vijay Abraham I "snps,has-lpm-erratum"); 805*85d5e707SKishon Vijay Abraham I of_property_read_u8(node, "snps,lpm-nyet-threshold", 806*85d5e707SKishon Vijay Abraham I &lpm_nyet_threshold); 807*85d5e707SKishon Vijay Abraham I dwc->is_utmi_l1_suspend = of_property_read_bool(node, 808*85d5e707SKishon Vijay Abraham I "snps,is-utmi-l1-suspend"); 809*85d5e707SKishon Vijay Abraham I of_property_read_u8(node, "snps,hird-threshold", 810*85d5e707SKishon Vijay Abraham I &hird_threshold); 811*85d5e707SKishon Vijay Abraham I 812*85d5e707SKishon Vijay Abraham I dwc->needs_fifo_resize = of_property_read_bool(node, 813*85d5e707SKishon Vijay Abraham I "tx-fifo-resize"); 814*85d5e707SKishon Vijay Abraham I dwc->dr_mode = of_usb_get_dr_mode(node); 815*85d5e707SKishon Vijay Abraham I 816*85d5e707SKishon Vijay Abraham I dwc->disable_scramble_quirk = of_property_read_bool(node, 817*85d5e707SKishon Vijay Abraham I "snps,disable_scramble_quirk"); 818*85d5e707SKishon Vijay Abraham I dwc->u2exit_lfps_quirk = of_property_read_bool(node, 819*85d5e707SKishon Vijay Abraham I "snps,u2exit_lfps_quirk"); 820*85d5e707SKishon Vijay Abraham I dwc->u2ss_inp3_quirk = of_property_read_bool(node, 821*85d5e707SKishon Vijay Abraham I "snps,u2ss_inp3_quirk"); 822*85d5e707SKishon Vijay Abraham I dwc->req_p1p2p3_quirk = of_property_read_bool(node, 823*85d5e707SKishon Vijay Abraham I "snps,req_p1p2p3_quirk"); 824*85d5e707SKishon Vijay Abraham I dwc->del_p1p2p3_quirk = of_property_read_bool(node, 825*85d5e707SKishon Vijay Abraham I "snps,del_p1p2p3_quirk"); 826*85d5e707SKishon Vijay Abraham I dwc->del_phy_power_chg_quirk = of_property_read_bool(node, 827*85d5e707SKishon Vijay Abraham I "snps,del_phy_power_chg_quirk"); 828*85d5e707SKishon Vijay Abraham I dwc->lfps_filter_quirk = of_property_read_bool(node, 829*85d5e707SKishon Vijay Abraham I "snps,lfps_filter_quirk"); 830*85d5e707SKishon Vijay Abraham I dwc->rx_detect_poll_quirk = of_property_read_bool(node, 831*85d5e707SKishon Vijay Abraham I "snps,rx_detect_poll_quirk"); 832*85d5e707SKishon Vijay Abraham I dwc->dis_u3_susphy_quirk = of_property_read_bool(node, 833*85d5e707SKishon Vijay Abraham I "snps,dis_u3_susphy_quirk"); 834*85d5e707SKishon Vijay Abraham I dwc->dis_u2_susphy_quirk = of_property_read_bool(node, 835*85d5e707SKishon Vijay Abraham I "snps,dis_u2_susphy_quirk"); 836*85d5e707SKishon Vijay Abraham I 837*85d5e707SKishon Vijay Abraham I dwc->tx_de_emphasis_quirk = of_property_read_bool(node, 838*85d5e707SKishon Vijay Abraham I "snps,tx_de_emphasis_quirk"); 839*85d5e707SKishon Vijay Abraham I of_property_read_u8(node, "snps,tx_de_emphasis", 840*85d5e707SKishon Vijay Abraham I &tx_de_emphasis); 841*85d5e707SKishon Vijay Abraham I } else if (pdata) { 842*85d5e707SKishon Vijay Abraham I dwc->maximum_speed = pdata->maximum_speed; 843*85d5e707SKishon Vijay Abraham I dwc->has_lpm_erratum = pdata->has_lpm_erratum; 844*85d5e707SKishon Vijay Abraham I if (pdata->lpm_nyet_threshold) 845*85d5e707SKishon Vijay Abraham I lpm_nyet_threshold = pdata->lpm_nyet_threshold; 846*85d5e707SKishon Vijay Abraham I dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend; 847*85d5e707SKishon Vijay Abraham I if (pdata->hird_threshold) 848*85d5e707SKishon Vijay Abraham I hird_threshold = pdata->hird_threshold; 849*85d5e707SKishon Vijay Abraham I 850*85d5e707SKishon Vijay Abraham I dwc->needs_fifo_resize = pdata->tx_fifo_resize; 851*85d5e707SKishon Vijay Abraham I dwc->dr_mode = pdata->dr_mode; 852*85d5e707SKishon Vijay Abraham I 853*85d5e707SKishon Vijay Abraham I dwc->disable_scramble_quirk = pdata->disable_scramble_quirk; 854*85d5e707SKishon Vijay Abraham I dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk; 855*85d5e707SKishon Vijay Abraham I dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk; 856*85d5e707SKishon Vijay Abraham I dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk; 857*85d5e707SKishon Vijay Abraham I dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk; 858*85d5e707SKishon Vijay Abraham I dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; 859*85d5e707SKishon Vijay Abraham I dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; 860*85d5e707SKishon Vijay Abraham I dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk; 861*85d5e707SKishon Vijay Abraham I dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk; 862*85d5e707SKishon Vijay Abraham I dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk; 863*85d5e707SKishon Vijay Abraham I 864*85d5e707SKishon Vijay Abraham I dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk; 865*85d5e707SKishon Vijay Abraham I if (pdata->tx_de_emphasis) 866*85d5e707SKishon Vijay Abraham I tx_de_emphasis = pdata->tx_de_emphasis; 867*85d5e707SKishon Vijay Abraham I } 868*85d5e707SKishon Vijay Abraham I 869*85d5e707SKishon Vijay Abraham I /* default to superspeed if no maximum_speed passed */ 870*85d5e707SKishon Vijay Abraham I if (dwc->maximum_speed == USB_SPEED_UNKNOWN) 871*85d5e707SKishon Vijay Abraham I dwc->maximum_speed = USB_SPEED_SUPER; 872*85d5e707SKishon Vijay Abraham I 873*85d5e707SKishon Vijay Abraham I dwc->lpm_nyet_threshold = lpm_nyet_threshold; 874*85d5e707SKishon Vijay Abraham I dwc->tx_de_emphasis = tx_de_emphasis; 875*85d5e707SKishon Vijay Abraham I 876*85d5e707SKishon Vijay Abraham I dwc->hird_threshold = hird_threshold 877*85d5e707SKishon Vijay Abraham I | (dwc->is_utmi_l1_suspend << 4); 878*85d5e707SKishon Vijay Abraham I 879*85d5e707SKishon Vijay Abraham I ret = dwc3_core_get_phy(dwc); 880*85d5e707SKishon Vijay Abraham I if (ret) 881*85d5e707SKishon Vijay Abraham I return ret; 882*85d5e707SKishon Vijay Abraham I 883*85d5e707SKishon Vijay Abraham I spin_lock_init(&dwc->lock); 884*85d5e707SKishon Vijay Abraham I platform_set_drvdata(pdev, dwc); 885*85d5e707SKishon Vijay Abraham I 886*85d5e707SKishon Vijay Abraham I if (!dev->dma_mask) { 887*85d5e707SKishon Vijay Abraham I dev->dma_mask = dev->parent->dma_mask; 888*85d5e707SKishon Vijay Abraham I dev->dma_parms = dev->parent->dma_parms; 889*85d5e707SKishon Vijay Abraham I dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); 890*85d5e707SKishon Vijay Abraham I } 891*85d5e707SKishon Vijay Abraham I 892*85d5e707SKishon Vijay Abraham I pm_runtime_enable(dev); 893*85d5e707SKishon Vijay Abraham I pm_runtime_get_sync(dev); 894*85d5e707SKishon Vijay Abraham I pm_runtime_forbid(dev); 895*85d5e707SKishon Vijay Abraham I 896*85d5e707SKishon Vijay Abraham I dwc3_cache_hwparams(dwc); 897*85d5e707SKishon Vijay Abraham I 898*85d5e707SKishon Vijay Abraham I ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); 899*85d5e707SKishon Vijay Abraham I if (ret) { 900*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to allocate event buffers\n"); 901*85d5e707SKishon Vijay Abraham I ret = -ENOMEM; 902*85d5e707SKishon Vijay Abraham I goto err0; 903*85d5e707SKishon Vijay Abraham I } 904*85d5e707SKishon Vijay Abraham I 905*85d5e707SKishon Vijay Abraham I if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) 906*85d5e707SKishon Vijay Abraham I dwc->dr_mode = USB_DR_MODE_HOST; 907*85d5e707SKishon Vijay Abraham I else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) 908*85d5e707SKishon Vijay Abraham I dwc->dr_mode = USB_DR_MODE_PERIPHERAL; 909*85d5e707SKishon Vijay Abraham I 910*85d5e707SKishon Vijay Abraham I if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) 911*85d5e707SKishon Vijay Abraham I dwc->dr_mode = USB_DR_MODE_OTG; 912*85d5e707SKishon Vijay Abraham I 913*85d5e707SKishon Vijay Abraham I ret = dwc3_core_init(dwc); 914*85d5e707SKishon Vijay Abraham I if (ret) { 915*85d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize core\n"); 916*85d5e707SKishon Vijay Abraham I goto err0; 917*85d5e707SKishon Vijay Abraham I } 918*85d5e707SKishon Vijay Abraham I 919*85d5e707SKishon Vijay Abraham I usb_phy_set_suspend(dwc->usb2_phy, 0); 920*85d5e707SKishon Vijay Abraham I usb_phy_set_suspend(dwc->usb3_phy, 0); 921*85d5e707SKishon Vijay Abraham I ret = phy_power_on(dwc->usb2_generic_phy); 922*85d5e707SKishon Vijay Abraham I if (ret < 0) 923*85d5e707SKishon Vijay Abraham I goto err1; 924*85d5e707SKishon Vijay Abraham I 925*85d5e707SKishon Vijay Abraham I ret = phy_power_on(dwc->usb3_generic_phy); 926*85d5e707SKishon Vijay Abraham I if (ret < 0) 927*85d5e707SKishon Vijay Abraham I goto err_usb2phy_power; 928*85d5e707SKishon Vijay Abraham I 929*85d5e707SKishon Vijay Abraham I ret = dwc3_event_buffers_setup(dwc); 930*85d5e707SKishon Vijay Abraham I if (ret) { 931*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to setup event buffers\n"); 932*85d5e707SKishon Vijay Abraham I goto err_usb3phy_power; 933*85d5e707SKishon Vijay Abraham I } 934*85d5e707SKishon Vijay Abraham I 935*85d5e707SKishon Vijay Abraham I ret = dwc3_core_init_mode(dwc); 936*85d5e707SKishon Vijay Abraham I if (ret) 937*85d5e707SKishon Vijay Abraham I goto err2; 938*85d5e707SKishon Vijay Abraham I 939*85d5e707SKishon Vijay Abraham I ret = dwc3_debugfs_init(dwc); 940*85d5e707SKishon Vijay Abraham I if (ret) { 941*85d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize debugfs\n"); 942*85d5e707SKishon Vijay Abraham I goto err3; 943*85d5e707SKishon Vijay Abraham I } 944*85d5e707SKishon Vijay Abraham I 945*85d5e707SKishon Vijay Abraham I pm_runtime_allow(dev); 946*85d5e707SKishon Vijay Abraham I 947*85d5e707SKishon Vijay Abraham I return 0; 948*85d5e707SKishon Vijay Abraham I 949*85d5e707SKishon Vijay Abraham I err3: 950*85d5e707SKishon Vijay Abraham I dwc3_core_exit_mode(dwc); 951*85d5e707SKishon Vijay Abraham I 952*85d5e707SKishon Vijay Abraham I err2: 953*85d5e707SKishon Vijay Abraham I dwc3_event_buffers_cleanup(dwc); 954*85d5e707SKishon Vijay Abraham I 955*85d5e707SKishon Vijay Abraham I err_usb3phy_power: 956*85d5e707SKishon Vijay Abraham I phy_power_off(dwc->usb3_generic_phy); 957*85d5e707SKishon Vijay Abraham I 958*85d5e707SKishon Vijay Abraham I err_usb2phy_power: 959*85d5e707SKishon Vijay Abraham I phy_power_off(dwc->usb2_generic_phy); 960*85d5e707SKishon Vijay Abraham I 961*85d5e707SKishon Vijay Abraham I err1: 962*85d5e707SKishon Vijay Abraham I usb_phy_set_suspend(dwc->usb2_phy, 1); 963*85d5e707SKishon Vijay Abraham I usb_phy_set_suspend(dwc->usb3_phy, 1); 964*85d5e707SKishon Vijay Abraham I dwc3_core_exit(dwc); 965*85d5e707SKishon Vijay Abraham I 966*85d5e707SKishon Vijay Abraham I err0: 967*85d5e707SKishon Vijay Abraham I dwc3_free_event_buffers(dwc); 968*85d5e707SKishon Vijay Abraham I 969*85d5e707SKishon Vijay Abraham I return ret; 970*85d5e707SKishon Vijay Abraham I } 971*85d5e707SKishon Vijay Abraham I 972*85d5e707SKishon Vijay Abraham I static int dwc3_remove(struct platform_device *pdev) 973*85d5e707SKishon Vijay Abraham I { 974*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = platform_get_drvdata(pdev); 975*85d5e707SKishon Vijay Abraham I 976*85d5e707SKishon Vijay Abraham I dwc3_debugfs_exit(dwc); 977*85d5e707SKishon Vijay Abraham I dwc3_core_exit_mode(dwc); 978*85d5e707SKishon Vijay Abraham I dwc3_event_buffers_cleanup(dwc); 979*85d5e707SKishon Vijay Abraham I dwc3_free_event_buffers(dwc); 980*85d5e707SKishon Vijay Abraham I 981*85d5e707SKishon Vijay Abraham I usb_phy_set_suspend(dwc->usb2_phy, 1); 982*85d5e707SKishon Vijay Abraham I usb_phy_set_suspend(dwc->usb3_phy, 1); 983*85d5e707SKishon Vijay Abraham I phy_power_off(dwc->usb2_generic_phy); 984*85d5e707SKishon Vijay Abraham I phy_power_off(dwc->usb3_generic_phy); 985*85d5e707SKishon Vijay Abraham I 986*85d5e707SKishon Vijay Abraham I dwc3_core_exit(dwc); 987*85d5e707SKishon Vijay Abraham I 988*85d5e707SKishon Vijay Abraham I pm_runtime_put_sync(&pdev->dev); 989*85d5e707SKishon Vijay Abraham I pm_runtime_disable(&pdev->dev); 990*85d5e707SKishon Vijay Abraham I 991*85d5e707SKishon Vijay Abraham I return 0; 992*85d5e707SKishon Vijay Abraham I } 993*85d5e707SKishon Vijay Abraham I 994*85d5e707SKishon Vijay Abraham I #ifdef CONFIG_PM_SLEEP 995*85d5e707SKishon Vijay Abraham I static int dwc3_suspend(struct device *dev) 996*85d5e707SKishon Vijay Abraham I { 997*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dev_get_drvdata(dev); 998*85d5e707SKishon Vijay Abraham I unsigned long flags; 999*85d5e707SKishon Vijay Abraham I 1000*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 1001*85d5e707SKishon Vijay Abraham I 1002*85d5e707SKishon Vijay Abraham I switch (dwc->dr_mode) { 1003*85d5e707SKishon Vijay Abraham I case USB_DR_MODE_PERIPHERAL: 1004*85d5e707SKishon Vijay Abraham I case USB_DR_MODE_OTG: 1005*85d5e707SKishon Vijay Abraham I dwc3_gadget_suspend(dwc); 1006*85d5e707SKishon Vijay Abraham I /* FALLTHROUGH */ 1007*85d5e707SKishon Vijay Abraham I case USB_DR_MODE_HOST: 1008*85d5e707SKishon Vijay Abraham I default: 1009*85d5e707SKishon Vijay Abraham I dwc3_event_buffers_cleanup(dwc); 1010*85d5e707SKishon Vijay Abraham I break; 1011*85d5e707SKishon Vijay Abraham I } 1012*85d5e707SKishon Vijay Abraham I 1013*85d5e707SKishon Vijay Abraham I dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL); 1014*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 1015*85d5e707SKishon Vijay Abraham I 1016*85d5e707SKishon Vijay Abraham I usb_phy_shutdown(dwc->usb3_phy); 1017*85d5e707SKishon Vijay Abraham I usb_phy_shutdown(dwc->usb2_phy); 1018*85d5e707SKishon Vijay Abraham I phy_exit(dwc->usb2_generic_phy); 1019*85d5e707SKishon Vijay Abraham I phy_exit(dwc->usb3_generic_phy); 1020*85d5e707SKishon Vijay Abraham I 1021*85d5e707SKishon Vijay Abraham I return 0; 1022*85d5e707SKishon Vijay Abraham I } 1023*85d5e707SKishon Vijay Abraham I 1024*85d5e707SKishon Vijay Abraham I static int dwc3_resume(struct device *dev) 1025*85d5e707SKishon Vijay Abraham I { 1026*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dev_get_drvdata(dev); 1027*85d5e707SKishon Vijay Abraham I unsigned long flags; 1028*85d5e707SKishon Vijay Abraham I int ret; 1029*85d5e707SKishon Vijay Abraham I 1030*85d5e707SKishon Vijay Abraham I usb_phy_init(dwc->usb3_phy); 1031*85d5e707SKishon Vijay Abraham I usb_phy_init(dwc->usb2_phy); 1032*85d5e707SKishon Vijay Abraham I ret = phy_init(dwc->usb2_generic_phy); 1033*85d5e707SKishon Vijay Abraham I if (ret < 0) 1034*85d5e707SKishon Vijay Abraham I return ret; 1035*85d5e707SKishon Vijay Abraham I 1036*85d5e707SKishon Vijay Abraham I ret = phy_init(dwc->usb3_generic_phy); 1037*85d5e707SKishon Vijay Abraham I if (ret < 0) 1038*85d5e707SKishon Vijay Abraham I goto err_usb2phy_init; 1039*85d5e707SKishon Vijay Abraham I 1040*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 1041*85d5e707SKishon Vijay Abraham I 1042*85d5e707SKishon Vijay Abraham I dwc3_event_buffers_setup(dwc); 1043*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl); 1044*85d5e707SKishon Vijay Abraham I 1045*85d5e707SKishon Vijay Abraham I switch (dwc->dr_mode) { 1046*85d5e707SKishon Vijay Abraham I case USB_DR_MODE_PERIPHERAL: 1047*85d5e707SKishon Vijay Abraham I case USB_DR_MODE_OTG: 1048*85d5e707SKishon Vijay Abraham I dwc3_gadget_resume(dwc); 1049*85d5e707SKishon Vijay Abraham I /* FALLTHROUGH */ 1050*85d5e707SKishon Vijay Abraham I case USB_DR_MODE_HOST: 1051*85d5e707SKishon Vijay Abraham I default: 1052*85d5e707SKishon Vijay Abraham I /* do nothing */ 1053*85d5e707SKishon Vijay Abraham I break; 1054*85d5e707SKishon Vijay Abraham I } 1055*85d5e707SKishon Vijay Abraham I 1056*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 1057*85d5e707SKishon Vijay Abraham I 1058*85d5e707SKishon Vijay Abraham I pm_runtime_disable(dev); 1059*85d5e707SKishon Vijay Abraham I pm_runtime_set_active(dev); 1060*85d5e707SKishon Vijay Abraham I pm_runtime_enable(dev); 1061*85d5e707SKishon Vijay Abraham I 1062*85d5e707SKishon Vijay Abraham I return 0; 1063*85d5e707SKishon Vijay Abraham I 1064*85d5e707SKishon Vijay Abraham I err_usb2phy_init: 1065*85d5e707SKishon Vijay Abraham I phy_exit(dwc->usb2_generic_phy); 1066*85d5e707SKishon Vijay Abraham I 1067*85d5e707SKishon Vijay Abraham I return ret; 1068*85d5e707SKishon Vijay Abraham I } 1069*85d5e707SKishon Vijay Abraham I 1070*85d5e707SKishon Vijay Abraham I static const struct dev_pm_ops dwc3_dev_pm_ops = { 1071*85d5e707SKishon Vijay Abraham I SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume) 1072*85d5e707SKishon Vijay Abraham I }; 1073*85d5e707SKishon Vijay Abraham I 1074*85d5e707SKishon Vijay Abraham I #define DWC3_PM_OPS &(dwc3_dev_pm_ops) 1075*85d5e707SKishon Vijay Abraham I #else 1076*85d5e707SKishon Vijay Abraham I #define DWC3_PM_OPS NULL 1077*85d5e707SKishon Vijay Abraham I #endif 1078*85d5e707SKishon Vijay Abraham I 1079*85d5e707SKishon Vijay Abraham I #ifdef CONFIG_OF 1080*85d5e707SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = { 1081*85d5e707SKishon Vijay Abraham I { 1082*85d5e707SKishon Vijay Abraham I .compatible = "snps,dwc3" 1083*85d5e707SKishon Vijay Abraham I }, 1084*85d5e707SKishon Vijay Abraham I { 1085*85d5e707SKishon Vijay Abraham I .compatible = "synopsys,dwc3" 1086*85d5e707SKishon Vijay Abraham I }, 1087*85d5e707SKishon Vijay Abraham I { }, 1088*85d5e707SKishon Vijay Abraham I }; 1089*85d5e707SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, of_dwc3_match); 1090*85d5e707SKishon Vijay Abraham I #endif 1091*85d5e707SKishon Vijay Abraham I 1092*85d5e707SKishon Vijay Abraham I #ifdef CONFIG_ACPI 1093*85d5e707SKishon Vijay Abraham I 1094*85d5e707SKishon Vijay Abraham I #define ACPI_ID_INTEL_BSW "808622B7" 1095*85d5e707SKishon Vijay Abraham I 1096*85d5e707SKishon Vijay Abraham I static const struct acpi_device_id dwc3_acpi_match[] = { 1097*85d5e707SKishon Vijay Abraham I { ACPI_ID_INTEL_BSW, 0 }, 1098*85d5e707SKishon Vijay Abraham I { }, 1099*85d5e707SKishon Vijay Abraham I }; 1100*85d5e707SKishon Vijay Abraham I MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match); 1101*85d5e707SKishon Vijay Abraham I #endif 1102*85d5e707SKishon Vijay Abraham I 1103*85d5e707SKishon Vijay Abraham I static struct platform_driver dwc3_driver = { 1104*85d5e707SKishon Vijay Abraham I .probe = dwc3_probe, 1105*85d5e707SKishon Vijay Abraham I .remove = dwc3_remove, 1106*85d5e707SKishon Vijay Abraham I .driver = { 1107*85d5e707SKishon Vijay Abraham I .name = "dwc3", 1108*85d5e707SKishon Vijay Abraham I .of_match_table = of_match_ptr(of_dwc3_match), 1109*85d5e707SKishon Vijay Abraham I .acpi_match_table = ACPI_PTR(dwc3_acpi_match), 1110*85d5e707SKishon Vijay Abraham I .pm = DWC3_PM_OPS, 1111*85d5e707SKishon Vijay Abraham I }, 1112*85d5e707SKishon Vijay Abraham I }; 1113*85d5e707SKishon Vijay Abraham I 1114*85d5e707SKishon Vijay Abraham I module_platform_driver(dwc3_driver); 1115*85d5e707SKishon Vijay Abraham I 1116*85d5e707SKishon Vijay Abraham I MODULE_ALIAS("platform:dwc3"); 1117*85d5e707SKishon Vijay Abraham I MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 1118*85d5e707SKishon Vijay Abraham I MODULE_LICENSE("GPL v2"); 1119*85d5e707SKishon Vijay Abraham I MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); 1120