1*85d5e707SKishon Vijay Abraham I /** 2*85d5e707SKishon Vijay Abraham I * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link 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 19*85d5e707SKishon Vijay Abraham I #include <linux/kernel.h> 20*85d5e707SKishon Vijay Abraham I #include <linux/delay.h> 21*85d5e707SKishon Vijay Abraham I #include <linux/slab.h> 22*85d5e707SKishon Vijay Abraham I #include <linux/spinlock.h> 23*85d5e707SKishon Vijay Abraham I #include <linux/platform_device.h> 24*85d5e707SKishon Vijay Abraham I #include <linux/pm_runtime.h> 25*85d5e707SKishon Vijay Abraham I #include <linux/interrupt.h> 26*85d5e707SKishon Vijay Abraham I #include <linux/io.h> 27*85d5e707SKishon Vijay Abraham I #include <linux/list.h> 28*85d5e707SKishon Vijay Abraham I #include <linux/dma-mapping.h> 29*85d5e707SKishon Vijay Abraham I 30*85d5e707SKishon Vijay Abraham I #include <linux/usb/ch9.h> 31*85d5e707SKishon Vijay Abraham I #include <linux/usb/gadget.h> 32*85d5e707SKishon Vijay Abraham I 33*85d5e707SKishon Vijay Abraham I #include "debug.h" 34*85d5e707SKishon Vijay Abraham I #include "core.h" 35*85d5e707SKishon Vijay Abraham I #include "gadget.h" 36*85d5e707SKishon Vijay Abraham I #include "io.h" 37*85d5e707SKishon Vijay Abraham I 38*85d5e707SKishon Vijay Abraham I /** 39*85d5e707SKishon Vijay Abraham I * dwc3_gadget_set_test_mode - Enables USB2 Test Modes 40*85d5e707SKishon Vijay Abraham I * @dwc: pointer to our context structure 41*85d5e707SKishon Vijay Abraham I * @mode: the mode to set (J, K SE0 NAK, Force Enable) 42*85d5e707SKishon Vijay Abraham I * 43*85d5e707SKishon Vijay Abraham I * Caller should take care of locking. This function will 44*85d5e707SKishon Vijay Abraham I * return 0 on success or -EINVAL if wrong Test Selector 45*85d5e707SKishon Vijay Abraham I * is passed 46*85d5e707SKishon Vijay Abraham I */ 47*85d5e707SKishon Vijay Abraham I int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) 48*85d5e707SKishon Vijay Abraham I { 49*85d5e707SKishon Vijay Abraham I u32 reg; 50*85d5e707SKishon Vijay Abraham I 51*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 52*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_TSTCTRL_MASK; 53*85d5e707SKishon Vijay Abraham I 54*85d5e707SKishon Vijay Abraham I switch (mode) { 55*85d5e707SKishon Vijay Abraham I case TEST_J: 56*85d5e707SKishon Vijay Abraham I case TEST_K: 57*85d5e707SKishon Vijay Abraham I case TEST_SE0_NAK: 58*85d5e707SKishon Vijay Abraham I case TEST_PACKET: 59*85d5e707SKishon Vijay Abraham I case TEST_FORCE_EN: 60*85d5e707SKishon Vijay Abraham I reg |= mode << 1; 61*85d5e707SKishon Vijay Abraham I break; 62*85d5e707SKishon Vijay Abraham I default: 63*85d5e707SKishon Vijay Abraham I return -EINVAL; 64*85d5e707SKishon Vijay Abraham I } 65*85d5e707SKishon Vijay Abraham I 66*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 67*85d5e707SKishon Vijay Abraham I 68*85d5e707SKishon Vijay Abraham I return 0; 69*85d5e707SKishon Vijay Abraham I } 70*85d5e707SKishon Vijay Abraham I 71*85d5e707SKishon Vijay Abraham I /** 72*85d5e707SKishon Vijay Abraham I * dwc3_gadget_get_link_state - Gets current state of USB Link 73*85d5e707SKishon Vijay Abraham I * @dwc: pointer to our context structure 74*85d5e707SKishon Vijay Abraham I * 75*85d5e707SKishon Vijay Abraham I * Caller should take care of locking. This function will 76*85d5e707SKishon Vijay Abraham I * return the link state on success (>= 0) or -ETIMEDOUT. 77*85d5e707SKishon Vijay Abraham I */ 78*85d5e707SKishon Vijay Abraham I int dwc3_gadget_get_link_state(struct dwc3 *dwc) 79*85d5e707SKishon Vijay Abraham I { 80*85d5e707SKishon Vijay Abraham I u32 reg; 81*85d5e707SKishon Vijay Abraham I 82*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DSTS); 83*85d5e707SKishon Vijay Abraham I 84*85d5e707SKishon Vijay Abraham I return DWC3_DSTS_USBLNKST(reg); 85*85d5e707SKishon Vijay Abraham I } 86*85d5e707SKishon Vijay Abraham I 87*85d5e707SKishon Vijay Abraham I /** 88*85d5e707SKishon Vijay Abraham I * dwc3_gadget_set_link_state - Sets USB Link to a particular State 89*85d5e707SKishon Vijay Abraham I * @dwc: pointer to our context structure 90*85d5e707SKishon Vijay Abraham I * @state: the state to put link into 91*85d5e707SKishon Vijay Abraham I * 92*85d5e707SKishon Vijay Abraham I * Caller should take care of locking. This function will 93*85d5e707SKishon Vijay Abraham I * return 0 on success or -ETIMEDOUT. 94*85d5e707SKishon Vijay Abraham I */ 95*85d5e707SKishon Vijay Abraham I int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) 96*85d5e707SKishon Vijay Abraham I { 97*85d5e707SKishon Vijay Abraham I int retries = 10000; 98*85d5e707SKishon Vijay Abraham I u32 reg; 99*85d5e707SKishon Vijay Abraham I 100*85d5e707SKishon Vijay Abraham I /* 101*85d5e707SKishon Vijay Abraham I * Wait until device controller is ready. Only applies to 1.94a and 102*85d5e707SKishon Vijay Abraham I * later RTL. 103*85d5e707SKishon Vijay Abraham I */ 104*85d5e707SKishon Vijay Abraham I if (dwc->revision >= DWC3_REVISION_194A) { 105*85d5e707SKishon Vijay Abraham I while (--retries) { 106*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DSTS); 107*85d5e707SKishon Vijay Abraham I if (reg & DWC3_DSTS_DCNRD) 108*85d5e707SKishon Vijay Abraham I udelay(5); 109*85d5e707SKishon Vijay Abraham I else 110*85d5e707SKishon Vijay Abraham I break; 111*85d5e707SKishon Vijay Abraham I } 112*85d5e707SKishon Vijay Abraham I 113*85d5e707SKishon Vijay Abraham I if (retries <= 0) 114*85d5e707SKishon Vijay Abraham I return -ETIMEDOUT; 115*85d5e707SKishon Vijay Abraham I } 116*85d5e707SKishon Vijay Abraham I 117*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 118*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; 119*85d5e707SKishon Vijay Abraham I 120*85d5e707SKishon Vijay Abraham I /* set requested state */ 121*85d5e707SKishon Vijay Abraham I reg |= DWC3_DCTL_ULSTCHNGREQ(state); 122*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 123*85d5e707SKishon Vijay Abraham I 124*85d5e707SKishon Vijay Abraham I /* 125*85d5e707SKishon Vijay Abraham I * The following code is racy when called from dwc3_gadget_wakeup, 126*85d5e707SKishon Vijay Abraham I * and is not needed, at least on newer versions 127*85d5e707SKishon Vijay Abraham I */ 128*85d5e707SKishon Vijay Abraham I if (dwc->revision >= DWC3_REVISION_194A) 129*85d5e707SKishon Vijay Abraham I return 0; 130*85d5e707SKishon Vijay Abraham I 131*85d5e707SKishon Vijay Abraham I /* wait for a change in DSTS */ 132*85d5e707SKishon Vijay Abraham I retries = 10000; 133*85d5e707SKishon Vijay Abraham I while (--retries) { 134*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DSTS); 135*85d5e707SKishon Vijay Abraham I 136*85d5e707SKishon Vijay Abraham I if (DWC3_DSTS_USBLNKST(reg) == state) 137*85d5e707SKishon Vijay Abraham I return 0; 138*85d5e707SKishon Vijay Abraham I 139*85d5e707SKishon Vijay Abraham I udelay(5); 140*85d5e707SKishon Vijay Abraham I } 141*85d5e707SKishon Vijay Abraham I 142*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "link state change request timed out\n"); 143*85d5e707SKishon Vijay Abraham I 144*85d5e707SKishon Vijay Abraham I return -ETIMEDOUT; 145*85d5e707SKishon Vijay Abraham I } 146*85d5e707SKishon Vijay Abraham I 147*85d5e707SKishon Vijay Abraham I /** 148*85d5e707SKishon Vijay Abraham I * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case 149*85d5e707SKishon Vijay Abraham I * @dwc: pointer to our context structure 150*85d5e707SKishon Vijay Abraham I * 151*85d5e707SKishon Vijay Abraham I * This function will a best effort FIFO allocation in order 152*85d5e707SKishon Vijay Abraham I * to improve FIFO usage and throughput, while still allowing 153*85d5e707SKishon Vijay Abraham I * us to enable as many endpoints as possible. 154*85d5e707SKishon Vijay Abraham I * 155*85d5e707SKishon Vijay Abraham I * Keep in mind that this operation will be highly dependent 156*85d5e707SKishon Vijay Abraham I * on the configured size for RAM1 - which contains TxFifo -, 157*85d5e707SKishon Vijay Abraham I * the amount of endpoints enabled on coreConsultant tool, and 158*85d5e707SKishon Vijay Abraham I * the width of the Master Bus. 159*85d5e707SKishon Vijay Abraham I * 160*85d5e707SKishon Vijay Abraham I * In the ideal world, we would always be able to satisfy the 161*85d5e707SKishon Vijay Abraham I * following equation: 162*85d5e707SKishon Vijay Abraham I * 163*85d5e707SKishon Vijay Abraham I * ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \ 164*85d5e707SKishon Vijay Abraham I * (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes 165*85d5e707SKishon Vijay Abraham I * 166*85d5e707SKishon Vijay Abraham I * Unfortunately, due to many variables that's not always the case. 167*85d5e707SKishon Vijay Abraham I */ 168*85d5e707SKishon Vijay Abraham I int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc) 169*85d5e707SKishon Vijay Abraham I { 170*85d5e707SKishon Vijay Abraham I int last_fifo_depth = 0; 171*85d5e707SKishon Vijay Abraham I int ram1_depth; 172*85d5e707SKishon Vijay Abraham I int fifo_size; 173*85d5e707SKishon Vijay Abraham I int mdwidth; 174*85d5e707SKishon Vijay Abraham I int num; 175*85d5e707SKishon Vijay Abraham I 176*85d5e707SKishon Vijay Abraham I if (!dwc->needs_fifo_resize) 177*85d5e707SKishon Vijay Abraham I return 0; 178*85d5e707SKishon Vijay Abraham I 179*85d5e707SKishon Vijay Abraham I ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7); 180*85d5e707SKishon Vijay Abraham I mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); 181*85d5e707SKishon Vijay Abraham I 182*85d5e707SKishon Vijay Abraham I /* MDWIDTH is represented in bits, we need it in bytes */ 183*85d5e707SKishon Vijay Abraham I mdwidth >>= 3; 184*85d5e707SKishon Vijay Abraham I 185*85d5e707SKishon Vijay Abraham I /* 186*85d5e707SKishon Vijay Abraham I * FIXME For now we will only allocate 1 wMaxPacketSize space 187*85d5e707SKishon Vijay Abraham I * for each enabled endpoint, later patches will come to 188*85d5e707SKishon Vijay Abraham I * improve this algorithm so that we better use the internal 189*85d5e707SKishon Vijay Abraham I * FIFO space 190*85d5e707SKishon Vijay Abraham I */ 191*85d5e707SKishon Vijay Abraham I for (num = 0; num < dwc->num_in_eps; num++) { 192*85d5e707SKishon Vijay Abraham I /* bit0 indicates direction; 1 means IN ep */ 193*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = dwc->eps[(num << 1) | 1]; 194*85d5e707SKishon Vijay Abraham I int mult = 1; 195*85d5e707SKishon Vijay Abraham I int tmp; 196*85d5e707SKishon Vijay Abraham I 197*85d5e707SKishon Vijay Abraham I if (!(dep->flags & DWC3_EP_ENABLED)) 198*85d5e707SKishon Vijay Abraham I continue; 199*85d5e707SKishon Vijay Abraham I 200*85d5e707SKishon Vijay Abraham I if (usb_endpoint_xfer_bulk(dep->endpoint.desc) 201*85d5e707SKishon Vijay Abraham I || usb_endpoint_xfer_isoc(dep->endpoint.desc)) 202*85d5e707SKishon Vijay Abraham I mult = 3; 203*85d5e707SKishon Vijay Abraham I 204*85d5e707SKishon Vijay Abraham I /* 205*85d5e707SKishon Vijay Abraham I * REVISIT: the following assumes we will always have enough 206*85d5e707SKishon Vijay Abraham I * space available on the FIFO RAM for all possible use cases. 207*85d5e707SKishon Vijay Abraham I * Make sure that's true somehow and change FIFO allocation 208*85d5e707SKishon Vijay Abraham I * accordingly. 209*85d5e707SKishon Vijay Abraham I * 210*85d5e707SKishon Vijay Abraham I * If we have Bulk or Isochronous endpoints, we want 211*85d5e707SKishon Vijay Abraham I * them to be able to be very, very fast. So we're giving 212*85d5e707SKishon Vijay Abraham I * those endpoints a fifo_size which is enough for 3 full 213*85d5e707SKishon Vijay Abraham I * packets 214*85d5e707SKishon Vijay Abraham I */ 215*85d5e707SKishon Vijay Abraham I tmp = mult * (dep->endpoint.maxpacket + mdwidth); 216*85d5e707SKishon Vijay Abraham I tmp += mdwidth; 217*85d5e707SKishon Vijay Abraham I 218*85d5e707SKishon Vijay Abraham I fifo_size = DIV_ROUND_UP(tmp, mdwidth); 219*85d5e707SKishon Vijay Abraham I 220*85d5e707SKishon Vijay Abraham I fifo_size |= (last_fifo_depth << 16); 221*85d5e707SKishon Vijay Abraham I 222*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n", 223*85d5e707SKishon Vijay Abraham I dep->name, last_fifo_depth, fifo_size & 0xffff); 224*85d5e707SKishon Vijay Abraham I 225*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size); 226*85d5e707SKishon Vijay Abraham I 227*85d5e707SKishon Vijay Abraham I last_fifo_depth += (fifo_size & 0xffff); 228*85d5e707SKishon Vijay Abraham I } 229*85d5e707SKishon Vijay Abraham I 230*85d5e707SKishon Vijay Abraham I return 0; 231*85d5e707SKishon Vijay Abraham I } 232*85d5e707SKishon Vijay Abraham I 233*85d5e707SKishon Vijay Abraham I void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, 234*85d5e707SKishon Vijay Abraham I int status) 235*85d5e707SKishon Vijay Abraham I { 236*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 237*85d5e707SKishon Vijay Abraham I int i; 238*85d5e707SKishon Vijay Abraham I 239*85d5e707SKishon Vijay Abraham I if (req->queued) { 240*85d5e707SKishon Vijay Abraham I i = 0; 241*85d5e707SKishon Vijay Abraham I do { 242*85d5e707SKishon Vijay Abraham I dep->busy_slot++; 243*85d5e707SKishon Vijay Abraham I /* 244*85d5e707SKishon Vijay Abraham I * Skip LINK TRB. We can't use req->trb and check for 245*85d5e707SKishon Vijay Abraham I * DWC3_TRBCTL_LINK_TRB because it points the TRB we 246*85d5e707SKishon Vijay Abraham I * just completed (not the LINK TRB). 247*85d5e707SKishon Vijay Abraham I */ 248*85d5e707SKishon Vijay Abraham I if (((dep->busy_slot & DWC3_TRB_MASK) == 249*85d5e707SKishon Vijay Abraham I DWC3_TRB_NUM- 1) && 250*85d5e707SKishon Vijay Abraham I usb_endpoint_xfer_isoc(dep->endpoint.desc)) 251*85d5e707SKishon Vijay Abraham I dep->busy_slot++; 252*85d5e707SKishon Vijay Abraham I } while(++i < req->request.num_mapped_sgs); 253*85d5e707SKishon Vijay Abraham I req->queued = false; 254*85d5e707SKishon Vijay Abraham I } 255*85d5e707SKishon Vijay Abraham I list_del(&req->list); 256*85d5e707SKishon Vijay Abraham I req->trb = NULL; 257*85d5e707SKishon Vijay Abraham I 258*85d5e707SKishon Vijay Abraham I if (req->request.status == -EINPROGRESS) 259*85d5e707SKishon Vijay Abraham I req->request.status = status; 260*85d5e707SKishon Vijay Abraham I 261*85d5e707SKishon Vijay Abraham I if (dwc->ep0_bounced && dep->number == 0) 262*85d5e707SKishon Vijay Abraham I dwc->ep0_bounced = false; 263*85d5e707SKishon Vijay Abraham I else 264*85d5e707SKishon Vijay Abraham I usb_gadget_unmap_request(&dwc->gadget, &req->request, 265*85d5e707SKishon Vijay Abraham I req->direction); 266*85d5e707SKishon Vijay Abraham I 267*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n", 268*85d5e707SKishon Vijay Abraham I req, dep->name, req->request.actual, 269*85d5e707SKishon Vijay Abraham I req->request.length, status); 270*85d5e707SKishon Vijay Abraham I trace_dwc3_gadget_giveback(req); 271*85d5e707SKishon Vijay Abraham I 272*85d5e707SKishon Vijay Abraham I spin_unlock(&dwc->lock); 273*85d5e707SKishon Vijay Abraham I usb_gadget_giveback_request(&dep->endpoint, &req->request); 274*85d5e707SKishon Vijay Abraham I spin_lock(&dwc->lock); 275*85d5e707SKishon Vijay Abraham I } 276*85d5e707SKishon Vijay Abraham I 277*85d5e707SKishon Vijay Abraham I int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) 278*85d5e707SKishon Vijay Abraham I { 279*85d5e707SKishon Vijay Abraham I u32 timeout = 500; 280*85d5e707SKishon Vijay Abraham I u32 reg; 281*85d5e707SKishon Vijay Abraham I 282*85d5e707SKishon Vijay Abraham I trace_dwc3_gadget_generic_cmd(cmd, param); 283*85d5e707SKishon Vijay Abraham I 284*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param); 285*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); 286*85d5e707SKishon Vijay Abraham I 287*85d5e707SKishon Vijay Abraham I do { 288*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DGCMD); 289*85d5e707SKishon Vijay Abraham I if (!(reg & DWC3_DGCMD_CMDACT)) { 290*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "Command Complete --> %d\n", 291*85d5e707SKishon Vijay Abraham I DWC3_DGCMD_STATUS(reg)); 292*85d5e707SKishon Vijay Abraham I return 0; 293*85d5e707SKishon Vijay Abraham I } 294*85d5e707SKishon Vijay Abraham I 295*85d5e707SKishon Vijay Abraham I /* 296*85d5e707SKishon Vijay Abraham I * We can't sleep here, because it's also called from 297*85d5e707SKishon Vijay Abraham I * interrupt context. 298*85d5e707SKishon Vijay Abraham I */ 299*85d5e707SKishon Vijay Abraham I timeout--; 300*85d5e707SKishon Vijay Abraham I if (!timeout) 301*85d5e707SKishon Vijay Abraham I return -ETIMEDOUT; 302*85d5e707SKishon Vijay Abraham I udelay(1); 303*85d5e707SKishon Vijay Abraham I } while (1); 304*85d5e707SKishon Vijay Abraham I } 305*85d5e707SKishon Vijay Abraham I 306*85d5e707SKishon Vijay Abraham I int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, 307*85d5e707SKishon Vijay Abraham I unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) 308*85d5e707SKishon Vijay Abraham I { 309*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = dwc->eps[ep]; 310*85d5e707SKishon Vijay Abraham I u32 timeout = 500; 311*85d5e707SKishon Vijay Abraham I u32 reg; 312*85d5e707SKishon Vijay Abraham I 313*85d5e707SKishon Vijay Abraham I trace_dwc3_gadget_ep_cmd(dep, cmd, params); 314*85d5e707SKishon Vijay Abraham I 315*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); 316*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1); 317*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2); 318*85d5e707SKishon Vijay Abraham I 319*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DEPCMD(ep), cmd | DWC3_DEPCMD_CMDACT); 320*85d5e707SKishon Vijay Abraham I do { 321*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep)); 322*85d5e707SKishon Vijay Abraham I if (!(reg & DWC3_DEPCMD_CMDACT)) { 323*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "Command Complete --> %d\n", 324*85d5e707SKishon Vijay Abraham I DWC3_DEPCMD_STATUS(reg)); 325*85d5e707SKishon Vijay Abraham I return 0; 326*85d5e707SKishon Vijay Abraham I } 327*85d5e707SKishon Vijay Abraham I 328*85d5e707SKishon Vijay Abraham I /* 329*85d5e707SKishon Vijay Abraham I * We can't sleep here, because it is also called from 330*85d5e707SKishon Vijay Abraham I * interrupt context. 331*85d5e707SKishon Vijay Abraham I */ 332*85d5e707SKishon Vijay Abraham I timeout--; 333*85d5e707SKishon Vijay Abraham I if (!timeout) 334*85d5e707SKishon Vijay Abraham I return -ETIMEDOUT; 335*85d5e707SKishon Vijay Abraham I 336*85d5e707SKishon Vijay Abraham I udelay(1); 337*85d5e707SKishon Vijay Abraham I } while (1); 338*85d5e707SKishon Vijay Abraham I } 339*85d5e707SKishon Vijay Abraham I 340*85d5e707SKishon Vijay Abraham I static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, 341*85d5e707SKishon Vijay Abraham I struct dwc3_trb *trb) 342*85d5e707SKishon Vijay Abraham I { 343*85d5e707SKishon Vijay Abraham I u32 offset = (char *) trb - (char *) dep->trb_pool; 344*85d5e707SKishon Vijay Abraham I 345*85d5e707SKishon Vijay Abraham I return dep->trb_pool_dma + offset; 346*85d5e707SKishon Vijay Abraham I } 347*85d5e707SKishon Vijay Abraham I 348*85d5e707SKishon Vijay Abraham I static int dwc3_alloc_trb_pool(struct dwc3_ep *dep) 349*85d5e707SKishon Vijay Abraham I { 350*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 351*85d5e707SKishon Vijay Abraham I 352*85d5e707SKishon Vijay Abraham I if (dep->trb_pool) 353*85d5e707SKishon Vijay Abraham I return 0; 354*85d5e707SKishon Vijay Abraham I 355*85d5e707SKishon Vijay Abraham I if (dep->number == 0 || dep->number == 1) 356*85d5e707SKishon Vijay Abraham I return 0; 357*85d5e707SKishon Vijay Abraham I 358*85d5e707SKishon Vijay Abraham I dep->trb_pool = dma_alloc_coherent(dwc->dev, 359*85d5e707SKishon Vijay Abraham I sizeof(struct dwc3_trb) * DWC3_TRB_NUM, 360*85d5e707SKishon Vijay Abraham I &dep->trb_pool_dma, GFP_KERNEL); 361*85d5e707SKishon Vijay Abraham I if (!dep->trb_pool) { 362*85d5e707SKishon Vijay Abraham I dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n", 363*85d5e707SKishon Vijay Abraham I dep->name); 364*85d5e707SKishon Vijay Abraham I return -ENOMEM; 365*85d5e707SKishon Vijay Abraham I } 366*85d5e707SKishon Vijay Abraham I 367*85d5e707SKishon Vijay Abraham I return 0; 368*85d5e707SKishon Vijay Abraham I } 369*85d5e707SKishon Vijay Abraham I 370*85d5e707SKishon Vijay Abraham I static void dwc3_free_trb_pool(struct dwc3_ep *dep) 371*85d5e707SKishon Vijay Abraham I { 372*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 373*85d5e707SKishon Vijay Abraham I 374*85d5e707SKishon Vijay Abraham I dma_free_coherent(dwc->dev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM, 375*85d5e707SKishon Vijay Abraham I dep->trb_pool, dep->trb_pool_dma); 376*85d5e707SKishon Vijay Abraham I 377*85d5e707SKishon Vijay Abraham I dep->trb_pool = NULL; 378*85d5e707SKishon Vijay Abraham I dep->trb_pool_dma = 0; 379*85d5e707SKishon Vijay Abraham I } 380*85d5e707SKishon Vijay Abraham I 381*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep) 382*85d5e707SKishon Vijay Abraham I { 383*85d5e707SKishon Vijay Abraham I struct dwc3_gadget_ep_cmd_params params; 384*85d5e707SKishon Vijay Abraham I u32 cmd; 385*85d5e707SKishon Vijay Abraham I 386*85d5e707SKishon Vijay Abraham I memset(¶ms, 0x00, sizeof(params)); 387*85d5e707SKishon Vijay Abraham I 388*85d5e707SKishon Vijay Abraham I if (dep->number != 1) { 389*85d5e707SKishon Vijay Abraham I cmd = DWC3_DEPCMD_DEPSTARTCFG; 390*85d5e707SKishon Vijay Abraham I /* XferRscIdx == 0 for ep0 and 2 for the remaining */ 391*85d5e707SKishon Vijay Abraham I if (dep->number > 1) { 392*85d5e707SKishon Vijay Abraham I if (dwc->start_config_issued) 393*85d5e707SKishon Vijay Abraham I return 0; 394*85d5e707SKishon Vijay Abraham I dwc->start_config_issued = true; 395*85d5e707SKishon Vijay Abraham I cmd |= DWC3_DEPCMD_PARAM(2); 396*85d5e707SKishon Vijay Abraham I } 397*85d5e707SKishon Vijay Abraham I 398*85d5e707SKishon Vijay Abraham I return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, ¶ms); 399*85d5e707SKishon Vijay Abraham I } 400*85d5e707SKishon Vijay Abraham I 401*85d5e707SKishon Vijay Abraham I return 0; 402*85d5e707SKishon Vijay Abraham I } 403*85d5e707SKishon Vijay Abraham I 404*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, 405*85d5e707SKishon Vijay Abraham I const struct usb_endpoint_descriptor *desc, 406*85d5e707SKishon Vijay Abraham I const struct usb_ss_ep_comp_descriptor *comp_desc, 407*85d5e707SKishon Vijay Abraham I bool ignore, bool restore) 408*85d5e707SKishon Vijay Abraham I { 409*85d5e707SKishon Vijay Abraham I struct dwc3_gadget_ep_cmd_params params; 410*85d5e707SKishon Vijay Abraham I 411*85d5e707SKishon Vijay Abraham I memset(¶ms, 0x00, sizeof(params)); 412*85d5e707SKishon Vijay Abraham I 413*85d5e707SKishon Vijay Abraham I params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc)) 414*85d5e707SKishon Vijay Abraham I | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc)); 415*85d5e707SKishon Vijay Abraham I 416*85d5e707SKishon Vijay Abraham I /* Burst size is only needed in SuperSpeed mode */ 417*85d5e707SKishon Vijay Abraham I if (dwc->gadget.speed == USB_SPEED_SUPER) { 418*85d5e707SKishon Vijay Abraham I u32 burst = dep->endpoint.maxburst - 1; 419*85d5e707SKishon Vijay Abraham I 420*85d5e707SKishon Vijay Abraham I params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst); 421*85d5e707SKishon Vijay Abraham I } 422*85d5e707SKishon Vijay Abraham I 423*85d5e707SKishon Vijay Abraham I if (ignore) 424*85d5e707SKishon Vijay Abraham I params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM; 425*85d5e707SKishon Vijay Abraham I 426*85d5e707SKishon Vijay Abraham I if (restore) { 427*85d5e707SKishon Vijay Abraham I params.param0 |= DWC3_DEPCFG_ACTION_RESTORE; 428*85d5e707SKishon Vijay Abraham I params.param2 |= dep->saved_state; 429*85d5e707SKishon Vijay Abraham I } 430*85d5e707SKishon Vijay Abraham I 431*85d5e707SKishon Vijay Abraham I params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN 432*85d5e707SKishon Vijay Abraham I | DWC3_DEPCFG_XFER_NOT_READY_EN; 433*85d5e707SKishon Vijay Abraham I 434*85d5e707SKishon Vijay Abraham I if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) { 435*85d5e707SKishon Vijay Abraham I params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE 436*85d5e707SKishon Vijay Abraham I | DWC3_DEPCFG_STREAM_EVENT_EN; 437*85d5e707SKishon Vijay Abraham I dep->stream_capable = true; 438*85d5e707SKishon Vijay Abraham I } 439*85d5e707SKishon Vijay Abraham I 440*85d5e707SKishon Vijay Abraham I if (!usb_endpoint_xfer_control(desc)) 441*85d5e707SKishon Vijay Abraham I params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN; 442*85d5e707SKishon Vijay Abraham I 443*85d5e707SKishon Vijay Abraham I /* 444*85d5e707SKishon Vijay Abraham I * We are doing 1:1 mapping for endpoints, meaning 445*85d5e707SKishon Vijay Abraham I * Physical Endpoints 2 maps to Logical Endpoint 2 and 446*85d5e707SKishon Vijay Abraham I * so on. We consider the direction bit as part of the physical 447*85d5e707SKishon Vijay Abraham I * endpoint number. So USB endpoint 0x81 is 0x03. 448*85d5e707SKishon Vijay Abraham I */ 449*85d5e707SKishon Vijay Abraham I params.param1 |= DWC3_DEPCFG_EP_NUMBER(dep->number); 450*85d5e707SKishon Vijay Abraham I 451*85d5e707SKishon Vijay Abraham I /* 452*85d5e707SKishon Vijay Abraham I * We must use the lower 16 TX FIFOs even though 453*85d5e707SKishon Vijay Abraham I * HW might have more 454*85d5e707SKishon Vijay Abraham I */ 455*85d5e707SKishon Vijay Abraham I if (dep->direction) 456*85d5e707SKishon Vijay Abraham I params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1); 457*85d5e707SKishon Vijay Abraham I 458*85d5e707SKishon Vijay Abraham I if (desc->bInterval) { 459*85d5e707SKishon Vijay Abraham I params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1); 460*85d5e707SKishon Vijay Abraham I dep->interval = 1 << (desc->bInterval - 1); 461*85d5e707SKishon Vijay Abraham I } 462*85d5e707SKishon Vijay Abraham I 463*85d5e707SKishon Vijay Abraham I return dwc3_send_gadget_ep_cmd(dwc, dep->number, 464*85d5e707SKishon Vijay Abraham I DWC3_DEPCMD_SETEPCONFIG, ¶ms); 465*85d5e707SKishon Vijay Abraham I } 466*85d5e707SKishon Vijay Abraham I 467*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep) 468*85d5e707SKishon Vijay Abraham I { 469*85d5e707SKishon Vijay Abraham I struct dwc3_gadget_ep_cmd_params params; 470*85d5e707SKishon Vijay Abraham I 471*85d5e707SKishon Vijay Abraham I memset(¶ms, 0x00, sizeof(params)); 472*85d5e707SKishon Vijay Abraham I 473*85d5e707SKishon Vijay Abraham I params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1); 474*85d5e707SKishon Vijay Abraham I 475*85d5e707SKishon Vijay Abraham I return dwc3_send_gadget_ep_cmd(dwc, dep->number, 476*85d5e707SKishon Vijay Abraham I DWC3_DEPCMD_SETTRANSFRESOURCE, ¶ms); 477*85d5e707SKishon Vijay Abraham I } 478*85d5e707SKishon Vijay Abraham I 479*85d5e707SKishon Vijay Abraham I /** 480*85d5e707SKishon Vijay Abraham I * __dwc3_gadget_ep_enable - Initializes a HW endpoint 481*85d5e707SKishon Vijay Abraham I * @dep: endpoint to be initialized 482*85d5e707SKishon Vijay Abraham I * @desc: USB Endpoint Descriptor 483*85d5e707SKishon Vijay Abraham I * 484*85d5e707SKishon Vijay Abraham I * Caller should take care of locking 485*85d5e707SKishon Vijay Abraham I */ 486*85d5e707SKishon Vijay Abraham I static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, 487*85d5e707SKishon Vijay Abraham I const struct usb_endpoint_descriptor *desc, 488*85d5e707SKishon Vijay Abraham I const struct usb_ss_ep_comp_descriptor *comp_desc, 489*85d5e707SKishon Vijay Abraham I bool ignore, bool restore) 490*85d5e707SKishon Vijay Abraham I { 491*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 492*85d5e707SKishon Vijay Abraham I u32 reg; 493*85d5e707SKishon Vijay Abraham I int ret; 494*85d5e707SKishon Vijay Abraham I 495*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); 496*85d5e707SKishon Vijay Abraham I 497*85d5e707SKishon Vijay Abraham I if (!(dep->flags & DWC3_EP_ENABLED)) { 498*85d5e707SKishon Vijay Abraham I ret = dwc3_gadget_start_config(dwc, dep); 499*85d5e707SKishon Vijay Abraham I if (ret) 500*85d5e707SKishon Vijay Abraham I return ret; 501*85d5e707SKishon Vijay Abraham I } 502*85d5e707SKishon Vijay Abraham I 503*85d5e707SKishon Vijay Abraham I ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore, 504*85d5e707SKishon Vijay Abraham I restore); 505*85d5e707SKishon Vijay Abraham I if (ret) 506*85d5e707SKishon Vijay Abraham I return ret; 507*85d5e707SKishon Vijay Abraham I 508*85d5e707SKishon Vijay Abraham I if (!(dep->flags & DWC3_EP_ENABLED)) { 509*85d5e707SKishon Vijay Abraham I struct dwc3_trb *trb_st_hw; 510*85d5e707SKishon Vijay Abraham I struct dwc3_trb *trb_link; 511*85d5e707SKishon Vijay Abraham I 512*85d5e707SKishon Vijay Abraham I ret = dwc3_gadget_set_xfer_resource(dwc, dep); 513*85d5e707SKishon Vijay Abraham I if (ret) 514*85d5e707SKishon Vijay Abraham I return ret; 515*85d5e707SKishon Vijay Abraham I 516*85d5e707SKishon Vijay Abraham I dep->endpoint.desc = desc; 517*85d5e707SKishon Vijay Abraham I dep->comp_desc = comp_desc; 518*85d5e707SKishon Vijay Abraham I dep->type = usb_endpoint_type(desc); 519*85d5e707SKishon Vijay Abraham I dep->flags |= DWC3_EP_ENABLED; 520*85d5e707SKishon Vijay Abraham I 521*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); 522*85d5e707SKishon Vijay Abraham I reg |= DWC3_DALEPENA_EP(dep->number); 523*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); 524*85d5e707SKishon Vijay Abraham I 525*85d5e707SKishon Vijay Abraham I if (!usb_endpoint_xfer_isoc(desc)) 526*85d5e707SKishon Vijay Abraham I return 0; 527*85d5e707SKishon Vijay Abraham I 528*85d5e707SKishon Vijay Abraham I /* Link TRB for ISOC. The HWO bit is never reset */ 529*85d5e707SKishon Vijay Abraham I trb_st_hw = &dep->trb_pool[0]; 530*85d5e707SKishon Vijay Abraham I 531*85d5e707SKishon Vijay Abraham I trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1]; 532*85d5e707SKishon Vijay Abraham I memset(trb_link, 0, sizeof(*trb_link)); 533*85d5e707SKishon Vijay Abraham I 534*85d5e707SKishon Vijay Abraham I trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw)); 535*85d5e707SKishon Vijay Abraham I trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw)); 536*85d5e707SKishon Vijay Abraham I trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB; 537*85d5e707SKishon Vijay Abraham I trb_link->ctrl |= DWC3_TRB_CTRL_HWO; 538*85d5e707SKishon Vijay Abraham I } 539*85d5e707SKishon Vijay Abraham I 540*85d5e707SKishon Vijay Abraham I return 0; 541*85d5e707SKishon Vijay Abraham I } 542*85d5e707SKishon Vijay Abraham I 543*85d5e707SKishon Vijay Abraham I static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force); 544*85d5e707SKishon Vijay Abraham I static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) 545*85d5e707SKishon Vijay Abraham I { 546*85d5e707SKishon Vijay Abraham I struct dwc3_request *req; 547*85d5e707SKishon Vijay Abraham I 548*85d5e707SKishon Vijay Abraham I if (!list_empty(&dep->req_queued)) { 549*85d5e707SKishon Vijay Abraham I dwc3_stop_active_transfer(dwc, dep->number, true); 550*85d5e707SKishon Vijay Abraham I 551*85d5e707SKishon Vijay Abraham I /* - giveback all requests to gadget driver */ 552*85d5e707SKishon Vijay Abraham I while (!list_empty(&dep->req_queued)) { 553*85d5e707SKishon Vijay Abraham I req = next_request(&dep->req_queued); 554*85d5e707SKishon Vijay Abraham I 555*85d5e707SKishon Vijay Abraham I dwc3_gadget_giveback(dep, req, -ESHUTDOWN); 556*85d5e707SKishon Vijay Abraham I } 557*85d5e707SKishon Vijay Abraham I } 558*85d5e707SKishon Vijay Abraham I 559*85d5e707SKishon Vijay Abraham I while (!list_empty(&dep->request_list)) { 560*85d5e707SKishon Vijay Abraham I req = next_request(&dep->request_list); 561*85d5e707SKishon Vijay Abraham I 562*85d5e707SKishon Vijay Abraham I dwc3_gadget_giveback(dep, req, -ESHUTDOWN); 563*85d5e707SKishon Vijay Abraham I } 564*85d5e707SKishon Vijay Abraham I } 565*85d5e707SKishon Vijay Abraham I 566*85d5e707SKishon Vijay Abraham I /** 567*85d5e707SKishon Vijay Abraham I * __dwc3_gadget_ep_disable - Disables a HW endpoint 568*85d5e707SKishon Vijay Abraham I * @dep: the endpoint to disable 569*85d5e707SKishon Vijay Abraham I * 570*85d5e707SKishon Vijay Abraham I * This function also removes requests which are currently processed ny the 571*85d5e707SKishon Vijay Abraham I * hardware and those which are not yet scheduled. 572*85d5e707SKishon Vijay Abraham I * Caller should take care of locking. 573*85d5e707SKishon Vijay Abraham I */ 574*85d5e707SKishon Vijay Abraham I static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) 575*85d5e707SKishon Vijay Abraham I { 576*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 577*85d5e707SKishon Vijay Abraham I u32 reg; 578*85d5e707SKishon Vijay Abraham I 579*85d5e707SKishon Vijay Abraham I dwc3_remove_requests(dwc, dep); 580*85d5e707SKishon Vijay Abraham I 581*85d5e707SKishon Vijay Abraham I /* make sure HW endpoint isn't stalled */ 582*85d5e707SKishon Vijay Abraham I if (dep->flags & DWC3_EP_STALL) 583*85d5e707SKishon Vijay Abraham I __dwc3_gadget_ep_set_halt(dep, 0, false); 584*85d5e707SKishon Vijay Abraham I 585*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); 586*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_DALEPENA_EP(dep->number); 587*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); 588*85d5e707SKishon Vijay Abraham I 589*85d5e707SKishon Vijay Abraham I dep->stream_capable = false; 590*85d5e707SKishon Vijay Abraham I dep->endpoint.desc = NULL; 591*85d5e707SKishon Vijay Abraham I dep->comp_desc = NULL; 592*85d5e707SKishon Vijay Abraham I dep->type = 0; 593*85d5e707SKishon Vijay Abraham I dep->flags = 0; 594*85d5e707SKishon Vijay Abraham I 595*85d5e707SKishon Vijay Abraham I return 0; 596*85d5e707SKishon Vijay Abraham I } 597*85d5e707SKishon Vijay Abraham I 598*85d5e707SKishon Vijay Abraham I /* -------------------------------------------------------------------------- */ 599*85d5e707SKishon Vijay Abraham I 600*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_ep0_enable(struct usb_ep *ep, 601*85d5e707SKishon Vijay Abraham I const struct usb_endpoint_descriptor *desc) 602*85d5e707SKishon Vijay Abraham I { 603*85d5e707SKishon Vijay Abraham I return -EINVAL; 604*85d5e707SKishon Vijay Abraham I } 605*85d5e707SKishon Vijay Abraham I 606*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_ep0_disable(struct usb_ep *ep) 607*85d5e707SKishon Vijay Abraham I { 608*85d5e707SKishon Vijay Abraham I return -EINVAL; 609*85d5e707SKishon Vijay Abraham I } 610*85d5e707SKishon Vijay Abraham I 611*85d5e707SKishon Vijay Abraham I /* -------------------------------------------------------------------------- */ 612*85d5e707SKishon Vijay Abraham I 613*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_ep_enable(struct usb_ep *ep, 614*85d5e707SKishon Vijay Abraham I const struct usb_endpoint_descriptor *desc) 615*85d5e707SKishon Vijay Abraham I { 616*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 617*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc; 618*85d5e707SKishon Vijay Abraham I unsigned long flags; 619*85d5e707SKishon Vijay Abraham I int ret; 620*85d5e707SKishon Vijay Abraham I 621*85d5e707SKishon Vijay Abraham I if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) { 622*85d5e707SKishon Vijay Abraham I pr_debug("dwc3: invalid parameters\n"); 623*85d5e707SKishon Vijay Abraham I return -EINVAL; 624*85d5e707SKishon Vijay Abraham I } 625*85d5e707SKishon Vijay Abraham I 626*85d5e707SKishon Vijay Abraham I if (!desc->wMaxPacketSize) { 627*85d5e707SKishon Vijay Abraham I pr_debug("dwc3: missing wMaxPacketSize\n"); 628*85d5e707SKishon Vijay Abraham I return -EINVAL; 629*85d5e707SKishon Vijay Abraham I } 630*85d5e707SKishon Vijay Abraham I 631*85d5e707SKishon Vijay Abraham I dep = to_dwc3_ep(ep); 632*85d5e707SKishon Vijay Abraham I dwc = dep->dwc; 633*85d5e707SKishon Vijay Abraham I 634*85d5e707SKishon Vijay Abraham I if (dep->flags & DWC3_EP_ENABLED) { 635*85d5e707SKishon Vijay Abraham I dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n", 636*85d5e707SKishon Vijay Abraham I dep->name); 637*85d5e707SKishon Vijay Abraham I return 0; 638*85d5e707SKishon Vijay Abraham I } 639*85d5e707SKishon Vijay Abraham I 640*85d5e707SKishon Vijay Abraham I switch (usb_endpoint_type(desc)) { 641*85d5e707SKishon Vijay Abraham I case USB_ENDPOINT_XFER_CONTROL: 642*85d5e707SKishon Vijay Abraham I strlcat(dep->name, "-control", sizeof(dep->name)); 643*85d5e707SKishon Vijay Abraham I break; 644*85d5e707SKishon Vijay Abraham I case USB_ENDPOINT_XFER_ISOC: 645*85d5e707SKishon Vijay Abraham I strlcat(dep->name, "-isoc", sizeof(dep->name)); 646*85d5e707SKishon Vijay Abraham I break; 647*85d5e707SKishon Vijay Abraham I case USB_ENDPOINT_XFER_BULK: 648*85d5e707SKishon Vijay Abraham I strlcat(dep->name, "-bulk", sizeof(dep->name)); 649*85d5e707SKishon Vijay Abraham I break; 650*85d5e707SKishon Vijay Abraham I case USB_ENDPOINT_XFER_INT: 651*85d5e707SKishon Vijay Abraham I strlcat(dep->name, "-int", sizeof(dep->name)); 652*85d5e707SKishon Vijay Abraham I break; 653*85d5e707SKishon Vijay Abraham I default: 654*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "invalid endpoint transfer type\n"); 655*85d5e707SKishon Vijay Abraham I } 656*85d5e707SKishon Vijay Abraham I 657*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 658*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false); 659*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 660*85d5e707SKishon Vijay Abraham I 661*85d5e707SKishon Vijay Abraham I return ret; 662*85d5e707SKishon Vijay Abraham I } 663*85d5e707SKishon Vijay Abraham I 664*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_ep_disable(struct usb_ep *ep) 665*85d5e707SKishon Vijay Abraham I { 666*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 667*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc; 668*85d5e707SKishon Vijay Abraham I unsigned long flags; 669*85d5e707SKishon Vijay Abraham I int ret; 670*85d5e707SKishon Vijay Abraham I 671*85d5e707SKishon Vijay Abraham I if (!ep) { 672*85d5e707SKishon Vijay Abraham I pr_debug("dwc3: invalid parameters\n"); 673*85d5e707SKishon Vijay Abraham I return -EINVAL; 674*85d5e707SKishon Vijay Abraham I } 675*85d5e707SKishon Vijay Abraham I 676*85d5e707SKishon Vijay Abraham I dep = to_dwc3_ep(ep); 677*85d5e707SKishon Vijay Abraham I dwc = dep->dwc; 678*85d5e707SKishon Vijay Abraham I 679*85d5e707SKishon Vijay Abraham I if (!(dep->flags & DWC3_EP_ENABLED)) { 680*85d5e707SKishon Vijay Abraham I dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n", 681*85d5e707SKishon Vijay Abraham I dep->name); 682*85d5e707SKishon Vijay Abraham I return 0; 683*85d5e707SKishon Vijay Abraham I } 684*85d5e707SKishon Vijay Abraham I 685*85d5e707SKishon Vijay Abraham I snprintf(dep->name, sizeof(dep->name), "ep%d%s", 686*85d5e707SKishon Vijay Abraham I dep->number >> 1, 687*85d5e707SKishon Vijay Abraham I (dep->number & 1) ? "in" : "out"); 688*85d5e707SKishon Vijay Abraham I 689*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 690*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep_disable(dep); 691*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 692*85d5e707SKishon Vijay Abraham I 693*85d5e707SKishon Vijay Abraham I return ret; 694*85d5e707SKishon Vijay Abraham I } 695*85d5e707SKishon Vijay Abraham I 696*85d5e707SKishon Vijay Abraham I static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep, 697*85d5e707SKishon Vijay Abraham I gfp_t gfp_flags) 698*85d5e707SKishon Vijay Abraham I { 699*85d5e707SKishon Vijay Abraham I struct dwc3_request *req; 700*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = to_dwc3_ep(ep); 701*85d5e707SKishon Vijay Abraham I 702*85d5e707SKishon Vijay Abraham I req = kzalloc(sizeof(*req), gfp_flags); 703*85d5e707SKishon Vijay Abraham I if (!req) 704*85d5e707SKishon Vijay Abraham I return NULL; 705*85d5e707SKishon Vijay Abraham I 706*85d5e707SKishon Vijay Abraham I req->epnum = dep->number; 707*85d5e707SKishon Vijay Abraham I req->dep = dep; 708*85d5e707SKishon Vijay Abraham I 709*85d5e707SKishon Vijay Abraham I trace_dwc3_alloc_request(req); 710*85d5e707SKishon Vijay Abraham I 711*85d5e707SKishon Vijay Abraham I return &req->request; 712*85d5e707SKishon Vijay Abraham I } 713*85d5e707SKishon Vijay Abraham I 714*85d5e707SKishon Vijay Abraham I static void dwc3_gadget_ep_free_request(struct usb_ep *ep, 715*85d5e707SKishon Vijay Abraham I struct usb_request *request) 716*85d5e707SKishon Vijay Abraham I { 717*85d5e707SKishon Vijay Abraham I struct dwc3_request *req = to_dwc3_request(request); 718*85d5e707SKishon Vijay Abraham I 719*85d5e707SKishon Vijay Abraham I trace_dwc3_free_request(req); 720*85d5e707SKishon Vijay Abraham I kfree(req); 721*85d5e707SKishon Vijay Abraham I } 722*85d5e707SKishon Vijay Abraham I 723*85d5e707SKishon Vijay Abraham I /** 724*85d5e707SKishon Vijay Abraham I * dwc3_prepare_one_trb - setup one TRB from one request 725*85d5e707SKishon Vijay Abraham I * @dep: endpoint for which this request is prepared 726*85d5e707SKishon Vijay Abraham I * @req: dwc3_request pointer 727*85d5e707SKishon Vijay Abraham I */ 728*85d5e707SKishon Vijay Abraham I static void dwc3_prepare_one_trb(struct dwc3_ep *dep, 729*85d5e707SKishon Vijay Abraham I struct dwc3_request *req, dma_addr_t dma, 730*85d5e707SKishon Vijay Abraham I unsigned length, unsigned last, unsigned chain, unsigned node) 731*85d5e707SKishon Vijay Abraham I { 732*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 733*85d5e707SKishon Vijay Abraham I struct dwc3_trb *trb; 734*85d5e707SKishon Vijay Abraham I 735*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n", 736*85d5e707SKishon Vijay Abraham I dep->name, req, (unsigned long long) dma, 737*85d5e707SKishon Vijay Abraham I length, last ? " last" : "", 738*85d5e707SKishon Vijay Abraham I chain ? " chain" : ""); 739*85d5e707SKishon Vijay Abraham I 740*85d5e707SKishon Vijay Abraham I 741*85d5e707SKishon Vijay Abraham I trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK]; 742*85d5e707SKishon Vijay Abraham I 743*85d5e707SKishon Vijay Abraham I if (!req->trb) { 744*85d5e707SKishon Vijay Abraham I dwc3_gadget_move_request_queued(req); 745*85d5e707SKishon Vijay Abraham I req->trb = trb; 746*85d5e707SKishon Vijay Abraham I req->trb_dma = dwc3_trb_dma_offset(dep, trb); 747*85d5e707SKishon Vijay Abraham I req->start_slot = dep->free_slot & DWC3_TRB_MASK; 748*85d5e707SKishon Vijay Abraham I } 749*85d5e707SKishon Vijay Abraham I 750*85d5e707SKishon Vijay Abraham I dep->free_slot++; 751*85d5e707SKishon Vijay Abraham I /* Skip the LINK-TRB on ISOC */ 752*85d5e707SKishon Vijay Abraham I if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && 753*85d5e707SKishon Vijay Abraham I usb_endpoint_xfer_isoc(dep->endpoint.desc)) 754*85d5e707SKishon Vijay Abraham I dep->free_slot++; 755*85d5e707SKishon Vijay Abraham I 756*85d5e707SKishon Vijay Abraham I trb->size = DWC3_TRB_SIZE_LENGTH(length); 757*85d5e707SKishon Vijay Abraham I trb->bpl = lower_32_bits(dma); 758*85d5e707SKishon Vijay Abraham I trb->bph = upper_32_bits(dma); 759*85d5e707SKishon Vijay Abraham I 760*85d5e707SKishon Vijay Abraham I switch (usb_endpoint_type(dep->endpoint.desc)) { 761*85d5e707SKishon Vijay Abraham I case USB_ENDPOINT_XFER_CONTROL: 762*85d5e707SKishon Vijay Abraham I trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP; 763*85d5e707SKishon Vijay Abraham I break; 764*85d5e707SKishon Vijay Abraham I 765*85d5e707SKishon Vijay Abraham I case USB_ENDPOINT_XFER_ISOC: 766*85d5e707SKishon Vijay Abraham I if (!node) 767*85d5e707SKishon Vijay Abraham I trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST; 768*85d5e707SKishon Vijay Abraham I else 769*85d5e707SKishon Vijay Abraham I trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS; 770*85d5e707SKishon Vijay Abraham I break; 771*85d5e707SKishon Vijay Abraham I 772*85d5e707SKishon Vijay Abraham I case USB_ENDPOINT_XFER_BULK: 773*85d5e707SKishon Vijay Abraham I case USB_ENDPOINT_XFER_INT: 774*85d5e707SKishon Vijay Abraham I trb->ctrl = DWC3_TRBCTL_NORMAL; 775*85d5e707SKishon Vijay Abraham I break; 776*85d5e707SKishon Vijay Abraham I default: 777*85d5e707SKishon Vijay Abraham I /* 778*85d5e707SKishon Vijay Abraham I * This is only possible with faulty memory because we 779*85d5e707SKishon Vijay Abraham I * checked it already :) 780*85d5e707SKishon Vijay Abraham I */ 781*85d5e707SKishon Vijay Abraham I BUG(); 782*85d5e707SKishon Vijay Abraham I } 783*85d5e707SKishon Vijay Abraham I 784*85d5e707SKishon Vijay Abraham I if (!req->request.no_interrupt && !chain) 785*85d5e707SKishon Vijay Abraham I trb->ctrl |= DWC3_TRB_CTRL_IOC; 786*85d5e707SKishon Vijay Abraham I 787*85d5e707SKishon Vijay Abraham I if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { 788*85d5e707SKishon Vijay Abraham I trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; 789*85d5e707SKishon Vijay Abraham I trb->ctrl |= DWC3_TRB_CTRL_CSP; 790*85d5e707SKishon Vijay Abraham I } else if (last) { 791*85d5e707SKishon Vijay Abraham I trb->ctrl |= DWC3_TRB_CTRL_LST; 792*85d5e707SKishon Vijay Abraham I } 793*85d5e707SKishon Vijay Abraham I 794*85d5e707SKishon Vijay Abraham I if (chain) 795*85d5e707SKishon Vijay Abraham I trb->ctrl |= DWC3_TRB_CTRL_CHN; 796*85d5e707SKishon Vijay Abraham I 797*85d5e707SKishon Vijay Abraham I if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable) 798*85d5e707SKishon Vijay Abraham I trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id); 799*85d5e707SKishon Vijay Abraham I 800*85d5e707SKishon Vijay Abraham I trb->ctrl |= DWC3_TRB_CTRL_HWO; 801*85d5e707SKishon Vijay Abraham I 802*85d5e707SKishon Vijay Abraham I trace_dwc3_prepare_trb(dep, trb); 803*85d5e707SKishon Vijay Abraham I } 804*85d5e707SKishon Vijay Abraham I 805*85d5e707SKishon Vijay Abraham I /* 806*85d5e707SKishon Vijay Abraham I * dwc3_prepare_trbs - setup TRBs from requests 807*85d5e707SKishon Vijay Abraham I * @dep: endpoint for which requests are being prepared 808*85d5e707SKishon Vijay Abraham I * @starting: true if the endpoint is idle and no requests are queued. 809*85d5e707SKishon Vijay Abraham I * 810*85d5e707SKishon Vijay Abraham I * The function goes through the requests list and sets up TRBs for the 811*85d5e707SKishon Vijay Abraham I * transfers. The function returns once there are no more TRBs available or 812*85d5e707SKishon Vijay Abraham I * it runs out of requests. 813*85d5e707SKishon Vijay Abraham I */ 814*85d5e707SKishon Vijay Abraham I static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) 815*85d5e707SKishon Vijay Abraham I { 816*85d5e707SKishon Vijay Abraham I struct dwc3_request *req, *n; 817*85d5e707SKishon Vijay Abraham I u32 trbs_left; 818*85d5e707SKishon Vijay Abraham I u32 max; 819*85d5e707SKishon Vijay Abraham I unsigned int last_one = 0; 820*85d5e707SKishon Vijay Abraham I 821*85d5e707SKishon Vijay Abraham I BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); 822*85d5e707SKishon Vijay Abraham I 823*85d5e707SKishon Vijay Abraham I /* the first request must not be queued */ 824*85d5e707SKishon Vijay Abraham I trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK; 825*85d5e707SKishon Vijay Abraham I 826*85d5e707SKishon Vijay Abraham I /* Can't wrap around on a non-isoc EP since there's no link TRB */ 827*85d5e707SKishon Vijay Abraham I if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { 828*85d5e707SKishon Vijay Abraham I max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK); 829*85d5e707SKishon Vijay Abraham I if (trbs_left > max) 830*85d5e707SKishon Vijay Abraham I trbs_left = max; 831*85d5e707SKishon Vijay Abraham I } 832*85d5e707SKishon Vijay Abraham I 833*85d5e707SKishon Vijay Abraham I /* 834*85d5e707SKishon Vijay Abraham I * If busy & slot are equal than it is either full or empty. If we are 835*85d5e707SKishon Vijay Abraham I * starting to process requests then we are empty. Otherwise we are 836*85d5e707SKishon Vijay Abraham I * full and don't do anything 837*85d5e707SKishon Vijay Abraham I */ 838*85d5e707SKishon Vijay Abraham I if (!trbs_left) { 839*85d5e707SKishon Vijay Abraham I if (!starting) 840*85d5e707SKishon Vijay Abraham I return; 841*85d5e707SKishon Vijay Abraham I trbs_left = DWC3_TRB_NUM; 842*85d5e707SKishon Vijay Abraham I /* 843*85d5e707SKishon Vijay Abraham I * In case we start from scratch, we queue the ISOC requests 844*85d5e707SKishon Vijay Abraham I * starting from slot 1. This is done because we use ring 845*85d5e707SKishon Vijay Abraham I * buffer and have no LST bit to stop us. Instead, we place 846*85d5e707SKishon Vijay Abraham I * IOC bit every TRB_NUM/4. We try to avoid having an interrupt 847*85d5e707SKishon Vijay Abraham I * after the first request so we start at slot 1 and have 848*85d5e707SKishon Vijay Abraham I * 7 requests proceed before we hit the first IOC. 849*85d5e707SKishon Vijay Abraham I * Other transfer types don't use the ring buffer and are 850*85d5e707SKishon Vijay Abraham I * processed from the first TRB until the last one. Since we 851*85d5e707SKishon Vijay Abraham I * don't wrap around we have to start at the beginning. 852*85d5e707SKishon Vijay Abraham I */ 853*85d5e707SKishon Vijay Abraham I if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { 854*85d5e707SKishon Vijay Abraham I dep->busy_slot = 1; 855*85d5e707SKishon Vijay Abraham I dep->free_slot = 1; 856*85d5e707SKishon Vijay Abraham I } else { 857*85d5e707SKishon Vijay Abraham I dep->busy_slot = 0; 858*85d5e707SKishon Vijay Abraham I dep->free_slot = 0; 859*85d5e707SKishon Vijay Abraham I } 860*85d5e707SKishon Vijay Abraham I } 861*85d5e707SKishon Vijay Abraham I 862*85d5e707SKishon Vijay Abraham I /* The last TRB is a link TRB, not used for xfer */ 863*85d5e707SKishon Vijay Abraham I if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) 864*85d5e707SKishon Vijay Abraham I return; 865*85d5e707SKishon Vijay Abraham I 866*85d5e707SKishon Vijay Abraham I list_for_each_entry_safe(req, n, &dep->request_list, list) { 867*85d5e707SKishon Vijay Abraham I unsigned length; 868*85d5e707SKishon Vijay Abraham I dma_addr_t dma; 869*85d5e707SKishon Vijay Abraham I last_one = false; 870*85d5e707SKishon Vijay Abraham I 871*85d5e707SKishon Vijay Abraham I if (req->request.num_mapped_sgs > 0) { 872*85d5e707SKishon Vijay Abraham I struct usb_request *request = &req->request; 873*85d5e707SKishon Vijay Abraham I struct scatterlist *sg = request->sg; 874*85d5e707SKishon Vijay Abraham I struct scatterlist *s; 875*85d5e707SKishon Vijay Abraham I int i; 876*85d5e707SKishon Vijay Abraham I 877*85d5e707SKishon Vijay Abraham I for_each_sg(sg, s, request->num_mapped_sgs, i) { 878*85d5e707SKishon Vijay Abraham I unsigned chain = true; 879*85d5e707SKishon Vijay Abraham I 880*85d5e707SKishon Vijay Abraham I length = sg_dma_len(s); 881*85d5e707SKishon Vijay Abraham I dma = sg_dma_address(s); 882*85d5e707SKishon Vijay Abraham I 883*85d5e707SKishon Vijay Abraham I if (i == (request->num_mapped_sgs - 1) || 884*85d5e707SKishon Vijay Abraham I sg_is_last(s)) { 885*85d5e707SKishon Vijay Abraham I if (list_is_last(&req->list, 886*85d5e707SKishon Vijay Abraham I &dep->request_list)) 887*85d5e707SKishon Vijay Abraham I last_one = true; 888*85d5e707SKishon Vijay Abraham I chain = false; 889*85d5e707SKishon Vijay Abraham I } 890*85d5e707SKishon Vijay Abraham I 891*85d5e707SKishon Vijay Abraham I trbs_left--; 892*85d5e707SKishon Vijay Abraham I if (!trbs_left) 893*85d5e707SKishon Vijay Abraham I last_one = true; 894*85d5e707SKishon Vijay Abraham I 895*85d5e707SKishon Vijay Abraham I if (last_one) 896*85d5e707SKishon Vijay Abraham I chain = false; 897*85d5e707SKishon Vijay Abraham I 898*85d5e707SKishon Vijay Abraham I dwc3_prepare_one_trb(dep, req, dma, length, 899*85d5e707SKishon Vijay Abraham I last_one, chain, i); 900*85d5e707SKishon Vijay Abraham I 901*85d5e707SKishon Vijay Abraham I if (last_one) 902*85d5e707SKishon Vijay Abraham I break; 903*85d5e707SKishon Vijay Abraham I } 904*85d5e707SKishon Vijay Abraham I } else { 905*85d5e707SKishon Vijay Abraham I dma = req->request.dma; 906*85d5e707SKishon Vijay Abraham I length = req->request.length; 907*85d5e707SKishon Vijay Abraham I trbs_left--; 908*85d5e707SKishon Vijay Abraham I 909*85d5e707SKishon Vijay Abraham I if (!trbs_left) 910*85d5e707SKishon Vijay Abraham I last_one = 1; 911*85d5e707SKishon Vijay Abraham I 912*85d5e707SKishon Vijay Abraham I /* Is this the last request? */ 913*85d5e707SKishon Vijay Abraham I if (list_is_last(&req->list, &dep->request_list)) 914*85d5e707SKishon Vijay Abraham I last_one = 1; 915*85d5e707SKishon Vijay Abraham I 916*85d5e707SKishon Vijay Abraham I dwc3_prepare_one_trb(dep, req, dma, length, 917*85d5e707SKishon Vijay Abraham I last_one, false, 0); 918*85d5e707SKishon Vijay Abraham I 919*85d5e707SKishon Vijay Abraham I if (last_one) 920*85d5e707SKishon Vijay Abraham I break; 921*85d5e707SKishon Vijay Abraham I } 922*85d5e707SKishon Vijay Abraham I } 923*85d5e707SKishon Vijay Abraham I } 924*85d5e707SKishon Vijay Abraham I 925*85d5e707SKishon Vijay Abraham I static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, 926*85d5e707SKishon Vijay Abraham I int start_new) 927*85d5e707SKishon Vijay Abraham I { 928*85d5e707SKishon Vijay Abraham I struct dwc3_gadget_ep_cmd_params params; 929*85d5e707SKishon Vijay Abraham I struct dwc3_request *req; 930*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 931*85d5e707SKishon Vijay Abraham I int ret; 932*85d5e707SKishon Vijay Abraham I u32 cmd; 933*85d5e707SKishon Vijay Abraham I 934*85d5e707SKishon Vijay Abraham I if (start_new && (dep->flags & DWC3_EP_BUSY)) { 935*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name); 936*85d5e707SKishon Vijay Abraham I return -EBUSY; 937*85d5e707SKishon Vijay Abraham I } 938*85d5e707SKishon Vijay Abraham I dep->flags &= ~DWC3_EP_PENDING_REQUEST; 939*85d5e707SKishon Vijay Abraham I 940*85d5e707SKishon Vijay Abraham I /* 941*85d5e707SKishon Vijay Abraham I * If we are getting here after a short-out-packet we don't enqueue any 942*85d5e707SKishon Vijay Abraham I * new requests as we try to set the IOC bit only on the last request. 943*85d5e707SKishon Vijay Abraham I */ 944*85d5e707SKishon Vijay Abraham I if (start_new) { 945*85d5e707SKishon Vijay Abraham I if (list_empty(&dep->req_queued)) 946*85d5e707SKishon Vijay Abraham I dwc3_prepare_trbs(dep, start_new); 947*85d5e707SKishon Vijay Abraham I 948*85d5e707SKishon Vijay Abraham I /* req points to the first request which will be sent */ 949*85d5e707SKishon Vijay Abraham I req = next_request(&dep->req_queued); 950*85d5e707SKishon Vijay Abraham I } else { 951*85d5e707SKishon Vijay Abraham I dwc3_prepare_trbs(dep, start_new); 952*85d5e707SKishon Vijay Abraham I 953*85d5e707SKishon Vijay Abraham I /* 954*85d5e707SKishon Vijay Abraham I * req points to the first request where HWO changed from 0 to 1 955*85d5e707SKishon Vijay Abraham I */ 956*85d5e707SKishon Vijay Abraham I req = next_request(&dep->req_queued); 957*85d5e707SKishon Vijay Abraham I } 958*85d5e707SKishon Vijay Abraham I if (!req) { 959*85d5e707SKishon Vijay Abraham I dep->flags |= DWC3_EP_PENDING_REQUEST; 960*85d5e707SKishon Vijay Abraham I return 0; 961*85d5e707SKishon Vijay Abraham I } 962*85d5e707SKishon Vijay Abraham I 963*85d5e707SKishon Vijay Abraham I memset(¶ms, 0, sizeof(params)); 964*85d5e707SKishon Vijay Abraham I 965*85d5e707SKishon Vijay Abraham I if (start_new) { 966*85d5e707SKishon Vijay Abraham I params.param0 = upper_32_bits(req->trb_dma); 967*85d5e707SKishon Vijay Abraham I params.param1 = lower_32_bits(req->trb_dma); 968*85d5e707SKishon Vijay Abraham I cmd = DWC3_DEPCMD_STARTTRANSFER; 969*85d5e707SKishon Vijay Abraham I } else { 970*85d5e707SKishon Vijay Abraham I cmd = DWC3_DEPCMD_UPDATETRANSFER; 971*85d5e707SKishon Vijay Abraham I } 972*85d5e707SKishon Vijay Abraham I 973*85d5e707SKishon Vijay Abraham I cmd |= DWC3_DEPCMD_PARAM(cmd_param); 974*85d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); 975*85d5e707SKishon Vijay Abraham I if (ret < 0) { 976*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n"); 977*85d5e707SKishon Vijay Abraham I 978*85d5e707SKishon Vijay Abraham I /* 979*85d5e707SKishon Vijay Abraham I * FIXME we need to iterate over the list of requests 980*85d5e707SKishon Vijay Abraham I * here and stop, unmap, free and del each of the linked 981*85d5e707SKishon Vijay Abraham I * requests instead of what we do now. 982*85d5e707SKishon Vijay Abraham I */ 983*85d5e707SKishon Vijay Abraham I usb_gadget_unmap_request(&dwc->gadget, &req->request, 984*85d5e707SKishon Vijay Abraham I req->direction); 985*85d5e707SKishon Vijay Abraham I list_del(&req->list); 986*85d5e707SKishon Vijay Abraham I return ret; 987*85d5e707SKishon Vijay Abraham I } 988*85d5e707SKishon Vijay Abraham I 989*85d5e707SKishon Vijay Abraham I dep->flags |= DWC3_EP_BUSY; 990*85d5e707SKishon Vijay Abraham I 991*85d5e707SKishon Vijay Abraham I if (start_new) { 992*85d5e707SKishon Vijay Abraham I dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc, 993*85d5e707SKishon Vijay Abraham I dep->number); 994*85d5e707SKishon Vijay Abraham I WARN_ON_ONCE(!dep->resource_index); 995*85d5e707SKishon Vijay Abraham I } 996*85d5e707SKishon Vijay Abraham I 997*85d5e707SKishon Vijay Abraham I return 0; 998*85d5e707SKishon Vijay Abraham I } 999*85d5e707SKishon Vijay Abraham I 1000*85d5e707SKishon Vijay Abraham I static void __dwc3_gadget_start_isoc(struct dwc3 *dwc, 1001*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep, u32 cur_uf) 1002*85d5e707SKishon Vijay Abraham I { 1003*85d5e707SKishon Vijay Abraham I u32 uf; 1004*85d5e707SKishon Vijay Abraham I 1005*85d5e707SKishon Vijay Abraham I if (list_empty(&dep->request_list)) { 1006*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n", 1007*85d5e707SKishon Vijay Abraham I dep->name); 1008*85d5e707SKishon Vijay Abraham I dep->flags |= DWC3_EP_PENDING_REQUEST; 1009*85d5e707SKishon Vijay Abraham I return; 1010*85d5e707SKishon Vijay Abraham I } 1011*85d5e707SKishon Vijay Abraham I 1012*85d5e707SKishon Vijay Abraham I /* 4 micro frames in the future */ 1013*85d5e707SKishon Vijay Abraham I uf = cur_uf + dep->interval * 4; 1014*85d5e707SKishon Vijay Abraham I 1015*85d5e707SKishon Vijay Abraham I __dwc3_gadget_kick_transfer(dep, uf, 1); 1016*85d5e707SKishon Vijay Abraham I } 1017*85d5e707SKishon Vijay Abraham I 1018*85d5e707SKishon Vijay Abraham I static void dwc3_gadget_start_isoc(struct dwc3 *dwc, 1019*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep, const struct dwc3_event_depevt *event) 1020*85d5e707SKishon Vijay Abraham I { 1021*85d5e707SKishon Vijay Abraham I u32 cur_uf, mask; 1022*85d5e707SKishon Vijay Abraham I 1023*85d5e707SKishon Vijay Abraham I mask = ~(dep->interval - 1); 1024*85d5e707SKishon Vijay Abraham I cur_uf = event->parameters & mask; 1025*85d5e707SKishon Vijay Abraham I 1026*85d5e707SKishon Vijay Abraham I __dwc3_gadget_start_isoc(dwc, dep, cur_uf); 1027*85d5e707SKishon Vijay Abraham I } 1028*85d5e707SKishon Vijay Abraham I 1029*85d5e707SKishon Vijay Abraham I static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) 1030*85d5e707SKishon Vijay Abraham I { 1031*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 1032*85d5e707SKishon Vijay Abraham I int ret; 1033*85d5e707SKishon Vijay Abraham I 1034*85d5e707SKishon Vijay Abraham I req->request.actual = 0; 1035*85d5e707SKishon Vijay Abraham I req->request.status = -EINPROGRESS; 1036*85d5e707SKishon Vijay Abraham I req->direction = dep->direction; 1037*85d5e707SKishon Vijay Abraham I req->epnum = dep->number; 1038*85d5e707SKishon Vijay Abraham I 1039*85d5e707SKishon Vijay Abraham I /* 1040*85d5e707SKishon Vijay Abraham I * We only add to our list of requests now and 1041*85d5e707SKishon Vijay Abraham I * start consuming the list once we get XferNotReady 1042*85d5e707SKishon Vijay Abraham I * IRQ. 1043*85d5e707SKishon Vijay Abraham I * 1044*85d5e707SKishon Vijay Abraham I * That way, we avoid doing anything that we don't need 1045*85d5e707SKishon Vijay Abraham I * to do now and defer it until the point we receive a 1046*85d5e707SKishon Vijay Abraham I * particular token from the Host side. 1047*85d5e707SKishon Vijay Abraham I * 1048*85d5e707SKishon Vijay Abraham I * This will also avoid Host cancelling URBs due to too 1049*85d5e707SKishon Vijay Abraham I * many NAKs. 1050*85d5e707SKishon Vijay Abraham I */ 1051*85d5e707SKishon Vijay Abraham I ret = usb_gadget_map_request(&dwc->gadget, &req->request, 1052*85d5e707SKishon Vijay Abraham I dep->direction); 1053*85d5e707SKishon Vijay Abraham I if (ret) 1054*85d5e707SKishon Vijay Abraham I return ret; 1055*85d5e707SKishon Vijay Abraham I 1056*85d5e707SKishon Vijay Abraham I list_add_tail(&req->list, &dep->request_list); 1057*85d5e707SKishon Vijay Abraham I 1058*85d5e707SKishon Vijay Abraham I /* 1059*85d5e707SKishon Vijay Abraham I * There are a few special cases: 1060*85d5e707SKishon Vijay Abraham I * 1061*85d5e707SKishon Vijay Abraham I * 1. XferNotReady with empty list of requests. We need to kick the 1062*85d5e707SKishon Vijay Abraham I * transfer here in that situation, otherwise we will be NAKing 1063*85d5e707SKishon Vijay Abraham I * forever. If we get XferNotReady before gadget driver has a 1064*85d5e707SKishon Vijay Abraham I * chance to queue a request, we will ACK the IRQ but won't be 1065*85d5e707SKishon Vijay Abraham I * able to receive the data until the next request is queued. 1066*85d5e707SKishon Vijay Abraham I * The following code is handling exactly that. 1067*85d5e707SKishon Vijay Abraham I * 1068*85d5e707SKishon Vijay Abraham I */ 1069*85d5e707SKishon Vijay Abraham I if (dep->flags & DWC3_EP_PENDING_REQUEST) { 1070*85d5e707SKishon Vijay Abraham I /* 1071*85d5e707SKishon Vijay Abraham I * If xfernotready is already elapsed and it is a case 1072*85d5e707SKishon Vijay Abraham I * of isoc transfer, then issue END TRANSFER, so that 1073*85d5e707SKishon Vijay Abraham I * you can receive xfernotready again and can have 1074*85d5e707SKishon Vijay Abraham I * notion of current microframe. 1075*85d5e707SKishon Vijay Abraham I */ 1076*85d5e707SKishon Vijay Abraham I if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { 1077*85d5e707SKishon Vijay Abraham I if (list_empty(&dep->req_queued)) { 1078*85d5e707SKishon Vijay Abraham I dwc3_stop_active_transfer(dwc, dep->number, true); 1079*85d5e707SKishon Vijay Abraham I dep->flags = DWC3_EP_ENABLED; 1080*85d5e707SKishon Vijay Abraham I } 1081*85d5e707SKishon Vijay Abraham I return 0; 1082*85d5e707SKishon Vijay Abraham I } 1083*85d5e707SKishon Vijay Abraham I 1084*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_kick_transfer(dep, 0, true); 1085*85d5e707SKishon Vijay Abraham I if (ret && ret != -EBUSY) 1086*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "%s: failed to kick transfers\n", 1087*85d5e707SKishon Vijay Abraham I dep->name); 1088*85d5e707SKishon Vijay Abraham I return ret; 1089*85d5e707SKishon Vijay Abraham I } 1090*85d5e707SKishon Vijay Abraham I 1091*85d5e707SKishon Vijay Abraham I /* 1092*85d5e707SKishon Vijay Abraham I * 2. XferInProgress on Isoc EP with an active transfer. We need to 1093*85d5e707SKishon Vijay Abraham I * kick the transfer here after queuing a request, otherwise the 1094*85d5e707SKishon Vijay Abraham I * core may not see the modified TRB(s). 1095*85d5e707SKishon Vijay Abraham I */ 1096*85d5e707SKishon Vijay Abraham I if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && 1097*85d5e707SKishon Vijay Abraham I (dep->flags & DWC3_EP_BUSY) && 1098*85d5e707SKishon Vijay Abraham I !(dep->flags & DWC3_EP_MISSED_ISOC)) { 1099*85d5e707SKishon Vijay Abraham I WARN_ON_ONCE(!dep->resource_index); 1100*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index, 1101*85d5e707SKishon Vijay Abraham I false); 1102*85d5e707SKishon Vijay Abraham I if (ret && ret != -EBUSY) 1103*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "%s: failed to kick transfers\n", 1104*85d5e707SKishon Vijay Abraham I dep->name); 1105*85d5e707SKishon Vijay Abraham I return ret; 1106*85d5e707SKishon Vijay Abraham I } 1107*85d5e707SKishon Vijay Abraham I 1108*85d5e707SKishon Vijay Abraham I /* 1109*85d5e707SKishon Vijay Abraham I * 4. Stream Capable Bulk Endpoints. We need to start the transfer 1110*85d5e707SKishon Vijay Abraham I * right away, otherwise host will not know we have streams to be 1111*85d5e707SKishon Vijay Abraham I * handled. 1112*85d5e707SKishon Vijay Abraham I */ 1113*85d5e707SKishon Vijay Abraham I if (dep->stream_capable) { 1114*85d5e707SKishon Vijay Abraham I int ret; 1115*85d5e707SKishon Vijay Abraham I 1116*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_kick_transfer(dep, 0, true); 1117*85d5e707SKishon Vijay Abraham I if (ret && ret != -EBUSY) { 1118*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 1119*85d5e707SKishon Vijay Abraham I 1120*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "%s: failed to kick transfers\n", 1121*85d5e707SKishon Vijay Abraham I dep->name); 1122*85d5e707SKishon Vijay Abraham I } 1123*85d5e707SKishon Vijay Abraham I } 1124*85d5e707SKishon Vijay Abraham I 1125*85d5e707SKishon Vijay Abraham I return 0; 1126*85d5e707SKishon Vijay Abraham I } 1127*85d5e707SKishon Vijay Abraham I 1128*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, 1129*85d5e707SKishon Vijay Abraham I gfp_t gfp_flags) 1130*85d5e707SKishon Vijay Abraham I { 1131*85d5e707SKishon Vijay Abraham I struct dwc3_request *req = to_dwc3_request(request); 1132*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = to_dwc3_ep(ep); 1133*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 1134*85d5e707SKishon Vijay Abraham I 1135*85d5e707SKishon Vijay Abraham I unsigned long flags; 1136*85d5e707SKishon Vijay Abraham I 1137*85d5e707SKishon Vijay Abraham I int ret; 1138*85d5e707SKishon Vijay Abraham I 1139*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 1140*85d5e707SKishon Vijay Abraham I if (!dep->endpoint.desc) { 1141*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n", 1142*85d5e707SKishon Vijay Abraham I request, ep->name); 1143*85d5e707SKishon Vijay Abraham I ret = -ESHUTDOWN; 1144*85d5e707SKishon Vijay Abraham I goto out; 1145*85d5e707SKishon Vijay Abraham I } 1146*85d5e707SKishon Vijay Abraham I 1147*85d5e707SKishon Vijay Abraham I if (WARN(req->dep != dep, "request %p belongs to '%s'\n", 1148*85d5e707SKishon Vijay Abraham I request, req->dep->name)) { 1149*85d5e707SKishon Vijay Abraham I ret = -EINVAL; 1150*85d5e707SKishon Vijay Abraham I goto out; 1151*85d5e707SKishon Vijay Abraham I } 1152*85d5e707SKishon Vijay Abraham I 1153*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "queing request %p to %s length %d\n", 1154*85d5e707SKishon Vijay Abraham I request, ep->name, request->length); 1155*85d5e707SKishon Vijay Abraham I trace_dwc3_ep_queue(req); 1156*85d5e707SKishon Vijay Abraham I 1157*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep_queue(dep, req); 1158*85d5e707SKishon Vijay Abraham I 1159*85d5e707SKishon Vijay Abraham I out: 1160*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 1161*85d5e707SKishon Vijay Abraham I 1162*85d5e707SKishon Vijay Abraham I return ret; 1163*85d5e707SKishon Vijay Abraham I } 1164*85d5e707SKishon Vijay Abraham I 1165*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, 1166*85d5e707SKishon Vijay Abraham I struct usb_request *request) 1167*85d5e707SKishon Vijay Abraham I { 1168*85d5e707SKishon Vijay Abraham I struct dwc3_request *req = to_dwc3_request(request); 1169*85d5e707SKishon Vijay Abraham I struct dwc3_request *r = NULL; 1170*85d5e707SKishon Vijay Abraham I 1171*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = to_dwc3_ep(ep); 1172*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 1173*85d5e707SKishon Vijay Abraham I 1174*85d5e707SKishon Vijay Abraham I unsigned long flags; 1175*85d5e707SKishon Vijay Abraham I int ret = 0; 1176*85d5e707SKishon Vijay Abraham I 1177*85d5e707SKishon Vijay Abraham I trace_dwc3_ep_dequeue(req); 1178*85d5e707SKishon Vijay Abraham I 1179*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 1180*85d5e707SKishon Vijay Abraham I 1181*85d5e707SKishon Vijay Abraham I list_for_each_entry(r, &dep->request_list, list) { 1182*85d5e707SKishon Vijay Abraham I if (r == req) 1183*85d5e707SKishon Vijay Abraham I break; 1184*85d5e707SKishon Vijay Abraham I } 1185*85d5e707SKishon Vijay Abraham I 1186*85d5e707SKishon Vijay Abraham I if (r != req) { 1187*85d5e707SKishon Vijay Abraham I list_for_each_entry(r, &dep->req_queued, list) { 1188*85d5e707SKishon Vijay Abraham I if (r == req) 1189*85d5e707SKishon Vijay Abraham I break; 1190*85d5e707SKishon Vijay Abraham I } 1191*85d5e707SKishon Vijay Abraham I if (r == req) { 1192*85d5e707SKishon Vijay Abraham I /* wait until it is processed */ 1193*85d5e707SKishon Vijay Abraham I dwc3_stop_active_transfer(dwc, dep->number, true); 1194*85d5e707SKishon Vijay Abraham I goto out1; 1195*85d5e707SKishon Vijay Abraham I } 1196*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "request %p was not queued to %s\n", 1197*85d5e707SKishon Vijay Abraham I request, ep->name); 1198*85d5e707SKishon Vijay Abraham I ret = -EINVAL; 1199*85d5e707SKishon Vijay Abraham I goto out0; 1200*85d5e707SKishon Vijay Abraham I } 1201*85d5e707SKishon Vijay Abraham I 1202*85d5e707SKishon Vijay Abraham I out1: 1203*85d5e707SKishon Vijay Abraham I /* giveback the request */ 1204*85d5e707SKishon Vijay Abraham I dwc3_gadget_giveback(dep, req, -ECONNRESET); 1205*85d5e707SKishon Vijay Abraham I 1206*85d5e707SKishon Vijay Abraham I out0: 1207*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 1208*85d5e707SKishon Vijay Abraham I 1209*85d5e707SKishon Vijay Abraham I return ret; 1210*85d5e707SKishon Vijay Abraham I } 1211*85d5e707SKishon Vijay Abraham I 1212*85d5e707SKishon Vijay Abraham I int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) 1213*85d5e707SKishon Vijay Abraham I { 1214*85d5e707SKishon Vijay Abraham I struct dwc3_gadget_ep_cmd_params params; 1215*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 1216*85d5e707SKishon Vijay Abraham I int ret; 1217*85d5e707SKishon Vijay Abraham I 1218*85d5e707SKishon Vijay Abraham I if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { 1219*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name); 1220*85d5e707SKishon Vijay Abraham I return -EINVAL; 1221*85d5e707SKishon Vijay Abraham I } 1222*85d5e707SKishon Vijay Abraham I 1223*85d5e707SKishon Vijay Abraham I memset(¶ms, 0x00, sizeof(params)); 1224*85d5e707SKishon Vijay Abraham I 1225*85d5e707SKishon Vijay Abraham I if (value) { 1226*85d5e707SKishon Vijay Abraham I if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) || 1227*85d5e707SKishon Vijay Abraham I (!list_empty(&dep->req_queued) || 1228*85d5e707SKishon Vijay Abraham I !list_empty(&dep->request_list)))) { 1229*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "%s: pending request, cannot halt\n", 1230*85d5e707SKishon Vijay Abraham I dep->name); 1231*85d5e707SKishon Vijay Abraham I return -EAGAIN; 1232*85d5e707SKishon Vijay Abraham I } 1233*85d5e707SKishon Vijay Abraham I 1234*85d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, 1235*85d5e707SKishon Vijay Abraham I DWC3_DEPCMD_SETSTALL, ¶ms); 1236*85d5e707SKishon Vijay Abraham I if (ret) 1237*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to set STALL on %s\n", 1238*85d5e707SKishon Vijay Abraham I dep->name); 1239*85d5e707SKishon Vijay Abraham I else 1240*85d5e707SKishon Vijay Abraham I dep->flags |= DWC3_EP_STALL; 1241*85d5e707SKishon Vijay Abraham I } else { 1242*85d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, 1243*85d5e707SKishon Vijay Abraham I DWC3_DEPCMD_CLEARSTALL, ¶ms); 1244*85d5e707SKishon Vijay Abraham I if (ret) 1245*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to clear STALL on %s\n", 1246*85d5e707SKishon Vijay Abraham I dep->name); 1247*85d5e707SKishon Vijay Abraham I else 1248*85d5e707SKishon Vijay Abraham I dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE); 1249*85d5e707SKishon Vijay Abraham I } 1250*85d5e707SKishon Vijay Abraham I 1251*85d5e707SKishon Vijay Abraham I return ret; 1252*85d5e707SKishon Vijay Abraham I } 1253*85d5e707SKishon Vijay Abraham I 1254*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value) 1255*85d5e707SKishon Vijay Abraham I { 1256*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = to_dwc3_ep(ep); 1257*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 1258*85d5e707SKishon Vijay Abraham I 1259*85d5e707SKishon Vijay Abraham I unsigned long flags; 1260*85d5e707SKishon Vijay Abraham I 1261*85d5e707SKishon Vijay Abraham I int ret; 1262*85d5e707SKishon Vijay Abraham I 1263*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 1264*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep_set_halt(dep, value, false); 1265*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 1266*85d5e707SKishon Vijay Abraham I 1267*85d5e707SKishon Vijay Abraham I return ret; 1268*85d5e707SKishon Vijay Abraham I } 1269*85d5e707SKishon Vijay Abraham I 1270*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) 1271*85d5e707SKishon Vijay Abraham I { 1272*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = to_dwc3_ep(ep); 1273*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 1274*85d5e707SKishon Vijay Abraham I unsigned long flags; 1275*85d5e707SKishon Vijay Abraham I int ret; 1276*85d5e707SKishon Vijay Abraham I 1277*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 1278*85d5e707SKishon Vijay Abraham I dep->flags |= DWC3_EP_WEDGE; 1279*85d5e707SKishon Vijay Abraham I 1280*85d5e707SKishon Vijay Abraham I if (dep->number == 0 || dep->number == 1) 1281*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep0_set_halt(ep, 1); 1282*85d5e707SKishon Vijay Abraham I else 1283*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep_set_halt(dep, 1, false); 1284*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 1285*85d5e707SKishon Vijay Abraham I 1286*85d5e707SKishon Vijay Abraham I return ret; 1287*85d5e707SKishon Vijay Abraham I } 1288*85d5e707SKishon Vijay Abraham I 1289*85d5e707SKishon Vijay Abraham I /* -------------------------------------------------------------------------- */ 1290*85d5e707SKishon Vijay Abraham I 1291*85d5e707SKishon Vijay Abraham I static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = { 1292*85d5e707SKishon Vijay Abraham I .bLength = USB_DT_ENDPOINT_SIZE, 1293*85d5e707SKishon Vijay Abraham I .bDescriptorType = USB_DT_ENDPOINT, 1294*85d5e707SKishon Vijay Abraham I .bmAttributes = USB_ENDPOINT_XFER_CONTROL, 1295*85d5e707SKishon Vijay Abraham I }; 1296*85d5e707SKishon Vijay Abraham I 1297*85d5e707SKishon Vijay Abraham I static const struct usb_ep_ops dwc3_gadget_ep0_ops = { 1298*85d5e707SKishon Vijay Abraham I .enable = dwc3_gadget_ep0_enable, 1299*85d5e707SKishon Vijay Abraham I .disable = dwc3_gadget_ep0_disable, 1300*85d5e707SKishon Vijay Abraham I .alloc_request = dwc3_gadget_ep_alloc_request, 1301*85d5e707SKishon Vijay Abraham I .free_request = dwc3_gadget_ep_free_request, 1302*85d5e707SKishon Vijay Abraham I .queue = dwc3_gadget_ep0_queue, 1303*85d5e707SKishon Vijay Abraham I .dequeue = dwc3_gadget_ep_dequeue, 1304*85d5e707SKishon Vijay Abraham I .set_halt = dwc3_gadget_ep0_set_halt, 1305*85d5e707SKishon Vijay Abraham I .set_wedge = dwc3_gadget_ep_set_wedge, 1306*85d5e707SKishon Vijay Abraham I }; 1307*85d5e707SKishon Vijay Abraham I 1308*85d5e707SKishon Vijay Abraham I static const struct usb_ep_ops dwc3_gadget_ep_ops = { 1309*85d5e707SKishon Vijay Abraham I .enable = dwc3_gadget_ep_enable, 1310*85d5e707SKishon Vijay Abraham I .disable = dwc3_gadget_ep_disable, 1311*85d5e707SKishon Vijay Abraham I .alloc_request = dwc3_gadget_ep_alloc_request, 1312*85d5e707SKishon Vijay Abraham I .free_request = dwc3_gadget_ep_free_request, 1313*85d5e707SKishon Vijay Abraham I .queue = dwc3_gadget_ep_queue, 1314*85d5e707SKishon Vijay Abraham I .dequeue = dwc3_gadget_ep_dequeue, 1315*85d5e707SKishon Vijay Abraham I .set_halt = dwc3_gadget_ep_set_halt, 1316*85d5e707SKishon Vijay Abraham I .set_wedge = dwc3_gadget_ep_set_wedge, 1317*85d5e707SKishon Vijay Abraham I }; 1318*85d5e707SKishon Vijay Abraham I 1319*85d5e707SKishon Vijay Abraham I /* -------------------------------------------------------------------------- */ 1320*85d5e707SKishon Vijay Abraham I 1321*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_get_frame(struct usb_gadget *g) 1322*85d5e707SKishon Vijay Abraham I { 1323*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = gadget_to_dwc(g); 1324*85d5e707SKishon Vijay Abraham I u32 reg; 1325*85d5e707SKishon Vijay Abraham I 1326*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DSTS); 1327*85d5e707SKishon Vijay Abraham I return DWC3_DSTS_SOFFN(reg); 1328*85d5e707SKishon Vijay Abraham I } 1329*85d5e707SKishon Vijay Abraham I 1330*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_wakeup(struct usb_gadget *g) 1331*85d5e707SKishon Vijay Abraham I { 1332*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = gadget_to_dwc(g); 1333*85d5e707SKishon Vijay Abraham I 1334*85d5e707SKishon Vijay Abraham I unsigned long timeout; 1335*85d5e707SKishon Vijay Abraham I unsigned long flags; 1336*85d5e707SKishon Vijay Abraham I 1337*85d5e707SKishon Vijay Abraham I u32 reg; 1338*85d5e707SKishon Vijay Abraham I 1339*85d5e707SKishon Vijay Abraham I int ret = 0; 1340*85d5e707SKishon Vijay Abraham I 1341*85d5e707SKishon Vijay Abraham I u8 link_state; 1342*85d5e707SKishon Vijay Abraham I u8 speed; 1343*85d5e707SKishon Vijay Abraham I 1344*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 1345*85d5e707SKishon Vijay Abraham I 1346*85d5e707SKishon Vijay Abraham I /* 1347*85d5e707SKishon Vijay Abraham I * According to the Databook Remote wakeup request should 1348*85d5e707SKishon Vijay Abraham I * be issued only when the device is in early suspend state. 1349*85d5e707SKishon Vijay Abraham I * 1350*85d5e707SKishon Vijay Abraham I * We can check that via USB Link State bits in DSTS register. 1351*85d5e707SKishon Vijay Abraham I */ 1352*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DSTS); 1353*85d5e707SKishon Vijay Abraham I 1354*85d5e707SKishon Vijay Abraham I speed = reg & DWC3_DSTS_CONNECTSPD; 1355*85d5e707SKishon Vijay Abraham I if (speed == DWC3_DSTS_SUPERSPEED) { 1356*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "no wakeup on SuperSpeed\n"); 1357*85d5e707SKishon Vijay Abraham I ret = -EINVAL; 1358*85d5e707SKishon Vijay Abraham I goto out; 1359*85d5e707SKishon Vijay Abraham I } 1360*85d5e707SKishon Vijay Abraham I 1361*85d5e707SKishon Vijay Abraham I link_state = DWC3_DSTS_USBLNKST(reg); 1362*85d5e707SKishon Vijay Abraham I 1363*85d5e707SKishon Vijay Abraham I switch (link_state) { 1364*85d5e707SKishon Vijay Abraham I case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */ 1365*85d5e707SKishon Vijay Abraham I case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */ 1366*85d5e707SKishon Vijay Abraham I break; 1367*85d5e707SKishon Vijay Abraham I default: 1368*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "can't wakeup from link state %d\n", 1369*85d5e707SKishon Vijay Abraham I link_state); 1370*85d5e707SKishon Vijay Abraham I ret = -EINVAL; 1371*85d5e707SKishon Vijay Abraham I goto out; 1372*85d5e707SKishon Vijay Abraham I } 1373*85d5e707SKishon Vijay Abraham I 1374*85d5e707SKishon Vijay Abraham I ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV); 1375*85d5e707SKishon Vijay Abraham I if (ret < 0) { 1376*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to put link in Recovery\n"); 1377*85d5e707SKishon Vijay Abraham I goto out; 1378*85d5e707SKishon Vijay Abraham I } 1379*85d5e707SKishon Vijay Abraham I 1380*85d5e707SKishon Vijay Abraham I /* Recent versions do this automatically */ 1381*85d5e707SKishon Vijay Abraham I if (dwc->revision < DWC3_REVISION_194A) { 1382*85d5e707SKishon Vijay Abraham I /* write zeroes to Link Change Request */ 1383*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 1384*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; 1385*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 1386*85d5e707SKishon Vijay Abraham I } 1387*85d5e707SKishon Vijay Abraham I 1388*85d5e707SKishon Vijay Abraham I /* poll until Link State changes to ON */ 1389*85d5e707SKishon Vijay Abraham I timeout = jiffies + msecs_to_jiffies(100); 1390*85d5e707SKishon Vijay Abraham I 1391*85d5e707SKishon Vijay Abraham I while (!time_after(jiffies, timeout)) { 1392*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DSTS); 1393*85d5e707SKishon Vijay Abraham I 1394*85d5e707SKishon Vijay Abraham I /* in HS, means ON */ 1395*85d5e707SKishon Vijay Abraham I if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0) 1396*85d5e707SKishon Vijay Abraham I break; 1397*85d5e707SKishon Vijay Abraham I } 1398*85d5e707SKishon Vijay Abraham I 1399*85d5e707SKishon Vijay Abraham I if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) { 1400*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to send remote wakeup\n"); 1401*85d5e707SKishon Vijay Abraham I ret = -EINVAL; 1402*85d5e707SKishon Vijay Abraham I } 1403*85d5e707SKishon Vijay Abraham I 1404*85d5e707SKishon Vijay Abraham I out: 1405*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 1406*85d5e707SKishon Vijay Abraham I 1407*85d5e707SKishon Vijay Abraham I return ret; 1408*85d5e707SKishon Vijay Abraham I } 1409*85d5e707SKishon Vijay Abraham I 1410*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, 1411*85d5e707SKishon Vijay Abraham I int is_selfpowered) 1412*85d5e707SKishon Vijay Abraham I { 1413*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = gadget_to_dwc(g); 1414*85d5e707SKishon Vijay Abraham I unsigned long flags; 1415*85d5e707SKishon Vijay Abraham I 1416*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 1417*85d5e707SKishon Vijay Abraham I dwc->is_selfpowered = !!is_selfpowered; 1418*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 1419*85d5e707SKishon Vijay Abraham I 1420*85d5e707SKishon Vijay Abraham I return 0; 1421*85d5e707SKishon Vijay Abraham I } 1422*85d5e707SKishon Vijay Abraham I 1423*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) 1424*85d5e707SKishon Vijay Abraham I { 1425*85d5e707SKishon Vijay Abraham I u32 reg; 1426*85d5e707SKishon Vijay Abraham I u32 timeout = 500; 1427*85d5e707SKishon Vijay Abraham I 1428*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 1429*85d5e707SKishon Vijay Abraham I if (is_on) { 1430*85d5e707SKishon Vijay Abraham I if (dwc->revision <= DWC3_REVISION_187A) { 1431*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_TRGTULST_MASK; 1432*85d5e707SKishon Vijay Abraham I reg |= DWC3_DCTL_TRGTULST_RX_DET; 1433*85d5e707SKishon Vijay Abraham I } 1434*85d5e707SKishon Vijay Abraham I 1435*85d5e707SKishon Vijay Abraham I if (dwc->revision >= DWC3_REVISION_194A) 1436*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_KEEP_CONNECT; 1437*85d5e707SKishon Vijay Abraham I reg |= DWC3_DCTL_RUN_STOP; 1438*85d5e707SKishon Vijay Abraham I 1439*85d5e707SKishon Vijay Abraham I if (dwc->has_hibernation) 1440*85d5e707SKishon Vijay Abraham I reg |= DWC3_DCTL_KEEP_CONNECT; 1441*85d5e707SKishon Vijay Abraham I 1442*85d5e707SKishon Vijay Abraham I dwc->pullups_connected = true; 1443*85d5e707SKishon Vijay Abraham I } else { 1444*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_RUN_STOP; 1445*85d5e707SKishon Vijay Abraham I 1446*85d5e707SKishon Vijay Abraham I if (dwc->has_hibernation && !suspend) 1447*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_KEEP_CONNECT; 1448*85d5e707SKishon Vijay Abraham I 1449*85d5e707SKishon Vijay Abraham I dwc->pullups_connected = false; 1450*85d5e707SKishon Vijay Abraham I } 1451*85d5e707SKishon Vijay Abraham I 1452*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 1453*85d5e707SKishon Vijay Abraham I 1454*85d5e707SKishon Vijay Abraham I do { 1455*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DSTS); 1456*85d5e707SKishon Vijay Abraham I if (is_on) { 1457*85d5e707SKishon Vijay Abraham I if (!(reg & DWC3_DSTS_DEVCTRLHLT)) 1458*85d5e707SKishon Vijay Abraham I break; 1459*85d5e707SKishon Vijay Abraham I } else { 1460*85d5e707SKishon Vijay Abraham I if (reg & DWC3_DSTS_DEVCTRLHLT) 1461*85d5e707SKishon Vijay Abraham I break; 1462*85d5e707SKishon Vijay Abraham I } 1463*85d5e707SKishon Vijay Abraham I timeout--; 1464*85d5e707SKishon Vijay Abraham I if (!timeout) 1465*85d5e707SKishon Vijay Abraham I return -ETIMEDOUT; 1466*85d5e707SKishon Vijay Abraham I udelay(1); 1467*85d5e707SKishon Vijay Abraham I } while (1); 1468*85d5e707SKishon Vijay Abraham I 1469*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "gadget %s data soft-%s\n", 1470*85d5e707SKishon Vijay Abraham I dwc->gadget_driver 1471*85d5e707SKishon Vijay Abraham I ? dwc->gadget_driver->function : "no-function", 1472*85d5e707SKishon Vijay Abraham I is_on ? "connect" : "disconnect"); 1473*85d5e707SKishon Vijay Abraham I 1474*85d5e707SKishon Vijay Abraham I return 0; 1475*85d5e707SKishon Vijay Abraham I } 1476*85d5e707SKishon Vijay Abraham I 1477*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) 1478*85d5e707SKishon Vijay Abraham I { 1479*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = gadget_to_dwc(g); 1480*85d5e707SKishon Vijay Abraham I unsigned long flags; 1481*85d5e707SKishon Vijay Abraham I int ret; 1482*85d5e707SKishon Vijay Abraham I 1483*85d5e707SKishon Vijay Abraham I is_on = !!is_on; 1484*85d5e707SKishon Vijay Abraham I 1485*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 1486*85d5e707SKishon Vijay Abraham I ret = dwc3_gadget_run_stop(dwc, is_on, false); 1487*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 1488*85d5e707SKishon Vijay Abraham I 1489*85d5e707SKishon Vijay Abraham I return ret; 1490*85d5e707SKishon Vijay Abraham I } 1491*85d5e707SKishon Vijay Abraham I 1492*85d5e707SKishon Vijay Abraham I static void dwc3_gadget_enable_irq(struct dwc3 *dwc) 1493*85d5e707SKishon Vijay Abraham I { 1494*85d5e707SKishon Vijay Abraham I u32 reg; 1495*85d5e707SKishon Vijay Abraham I 1496*85d5e707SKishon Vijay Abraham I /* Enable all but Start and End of Frame IRQs */ 1497*85d5e707SKishon Vijay Abraham I reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | 1498*85d5e707SKishon Vijay Abraham I DWC3_DEVTEN_EVNTOVERFLOWEN | 1499*85d5e707SKishon Vijay Abraham I DWC3_DEVTEN_CMDCMPLTEN | 1500*85d5e707SKishon Vijay Abraham I DWC3_DEVTEN_ERRTICERREN | 1501*85d5e707SKishon Vijay Abraham I DWC3_DEVTEN_WKUPEVTEN | 1502*85d5e707SKishon Vijay Abraham I DWC3_DEVTEN_ULSTCNGEN | 1503*85d5e707SKishon Vijay Abraham I DWC3_DEVTEN_CONNECTDONEEN | 1504*85d5e707SKishon Vijay Abraham I DWC3_DEVTEN_USBRSTEN | 1505*85d5e707SKishon Vijay Abraham I DWC3_DEVTEN_DISCONNEVTEN); 1506*85d5e707SKishon Vijay Abraham I 1507*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); 1508*85d5e707SKishon Vijay Abraham I } 1509*85d5e707SKishon Vijay Abraham I 1510*85d5e707SKishon Vijay Abraham I static void dwc3_gadget_disable_irq(struct dwc3 *dwc) 1511*85d5e707SKishon Vijay Abraham I { 1512*85d5e707SKishon Vijay Abraham I /* mask all interrupts */ 1513*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00); 1514*85d5e707SKishon Vijay Abraham I } 1515*85d5e707SKishon Vijay Abraham I 1516*85d5e707SKishon Vijay Abraham I static irqreturn_t dwc3_interrupt(int irq, void *_dwc); 1517*85d5e707SKishon Vijay Abraham I static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc); 1518*85d5e707SKishon Vijay Abraham I 1519*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_start(struct usb_gadget *g, 1520*85d5e707SKishon Vijay Abraham I struct usb_gadget_driver *driver) 1521*85d5e707SKishon Vijay Abraham I { 1522*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = gadget_to_dwc(g); 1523*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 1524*85d5e707SKishon Vijay Abraham I unsigned long flags; 1525*85d5e707SKishon Vijay Abraham I int ret = 0; 1526*85d5e707SKishon Vijay Abraham I int irq; 1527*85d5e707SKishon Vijay Abraham I u32 reg; 1528*85d5e707SKishon Vijay Abraham I 1529*85d5e707SKishon Vijay Abraham I irq = platform_get_irq(to_platform_device(dwc->dev), 0); 1530*85d5e707SKishon Vijay Abraham I ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, 1531*85d5e707SKishon Vijay Abraham I IRQF_SHARED, "dwc3", dwc); 1532*85d5e707SKishon Vijay Abraham I if (ret) { 1533*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to request irq #%d --> %d\n", 1534*85d5e707SKishon Vijay Abraham I irq, ret); 1535*85d5e707SKishon Vijay Abraham I goto err0; 1536*85d5e707SKishon Vijay Abraham I } 1537*85d5e707SKishon Vijay Abraham I 1538*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 1539*85d5e707SKishon Vijay Abraham I 1540*85d5e707SKishon Vijay Abraham I if (dwc->gadget_driver) { 1541*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "%s is already bound to %s\n", 1542*85d5e707SKishon Vijay Abraham I dwc->gadget.name, 1543*85d5e707SKishon Vijay Abraham I dwc->gadget_driver->driver.name); 1544*85d5e707SKishon Vijay Abraham I ret = -EBUSY; 1545*85d5e707SKishon Vijay Abraham I goto err1; 1546*85d5e707SKishon Vijay Abraham I } 1547*85d5e707SKishon Vijay Abraham I 1548*85d5e707SKishon Vijay Abraham I dwc->gadget_driver = driver; 1549*85d5e707SKishon Vijay Abraham I 1550*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCFG); 1551*85d5e707SKishon Vijay Abraham I reg &= ~(DWC3_DCFG_SPEED_MASK); 1552*85d5e707SKishon Vijay Abraham I 1553*85d5e707SKishon Vijay Abraham I /** 1554*85d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 revision < 2.20a have an issue 1555*85d5e707SKishon Vijay Abraham I * which would cause metastability state on Run/Stop 1556*85d5e707SKishon Vijay Abraham I * bit if we try to force the IP to USB2-only mode. 1557*85d5e707SKishon Vijay Abraham I * 1558*85d5e707SKishon Vijay Abraham I * Because of that, we cannot configure the IP to any 1559*85d5e707SKishon Vijay Abraham I * speed other than the SuperSpeed 1560*85d5e707SKishon Vijay Abraham I * 1561*85d5e707SKishon Vijay Abraham I * Refers to: 1562*85d5e707SKishon Vijay Abraham I * 1563*85d5e707SKishon Vijay Abraham I * STAR#9000525659: Clock Domain Crossing on DCTL in 1564*85d5e707SKishon Vijay Abraham I * USB 2.0 Mode 1565*85d5e707SKishon Vijay Abraham I */ 1566*85d5e707SKishon Vijay Abraham I if (dwc->revision < DWC3_REVISION_220A) { 1567*85d5e707SKishon Vijay Abraham I reg |= DWC3_DCFG_SUPERSPEED; 1568*85d5e707SKishon Vijay Abraham I } else { 1569*85d5e707SKishon Vijay Abraham I switch (dwc->maximum_speed) { 1570*85d5e707SKishon Vijay Abraham I case USB_SPEED_LOW: 1571*85d5e707SKishon Vijay Abraham I reg |= DWC3_DSTS_LOWSPEED; 1572*85d5e707SKishon Vijay Abraham I break; 1573*85d5e707SKishon Vijay Abraham I case USB_SPEED_FULL: 1574*85d5e707SKishon Vijay Abraham I reg |= DWC3_DSTS_FULLSPEED1; 1575*85d5e707SKishon Vijay Abraham I break; 1576*85d5e707SKishon Vijay Abraham I case USB_SPEED_HIGH: 1577*85d5e707SKishon Vijay Abraham I reg |= DWC3_DSTS_HIGHSPEED; 1578*85d5e707SKishon Vijay Abraham I break; 1579*85d5e707SKishon Vijay Abraham I case USB_SPEED_SUPER: /* FALLTHROUGH */ 1580*85d5e707SKishon Vijay Abraham I case USB_SPEED_UNKNOWN: /* FALTHROUGH */ 1581*85d5e707SKishon Vijay Abraham I default: 1582*85d5e707SKishon Vijay Abraham I reg |= DWC3_DSTS_SUPERSPEED; 1583*85d5e707SKishon Vijay Abraham I } 1584*85d5e707SKishon Vijay Abraham I } 1585*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCFG, reg); 1586*85d5e707SKishon Vijay Abraham I 1587*85d5e707SKishon Vijay Abraham I dwc->start_config_issued = false; 1588*85d5e707SKishon Vijay Abraham I 1589*85d5e707SKishon Vijay Abraham I /* Start with SuperSpeed Default */ 1590*85d5e707SKishon Vijay Abraham I dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); 1591*85d5e707SKishon Vijay Abraham I 1592*85d5e707SKishon Vijay Abraham I dep = dwc->eps[0]; 1593*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, 1594*85d5e707SKishon Vijay Abraham I false); 1595*85d5e707SKishon Vijay Abraham I if (ret) { 1596*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to enable %s\n", dep->name); 1597*85d5e707SKishon Vijay Abraham I goto err2; 1598*85d5e707SKishon Vijay Abraham I } 1599*85d5e707SKishon Vijay Abraham I 1600*85d5e707SKishon Vijay Abraham I dep = dwc->eps[1]; 1601*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, 1602*85d5e707SKishon Vijay Abraham I false); 1603*85d5e707SKishon Vijay Abraham I if (ret) { 1604*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to enable %s\n", dep->name); 1605*85d5e707SKishon Vijay Abraham I goto err3; 1606*85d5e707SKishon Vijay Abraham I } 1607*85d5e707SKishon Vijay Abraham I 1608*85d5e707SKishon Vijay Abraham I /* begin to receive SETUP packets */ 1609*85d5e707SKishon Vijay Abraham I dwc->ep0state = EP0_SETUP_PHASE; 1610*85d5e707SKishon Vijay Abraham I dwc3_ep0_out_start(dwc); 1611*85d5e707SKishon Vijay Abraham I 1612*85d5e707SKishon Vijay Abraham I dwc3_gadget_enable_irq(dwc); 1613*85d5e707SKishon Vijay Abraham I 1614*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 1615*85d5e707SKishon Vijay Abraham I 1616*85d5e707SKishon Vijay Abraham I return 0; 1617*85d5e707SKishon Vijay Abraham I 1618*85d5e707SKishon Vijay Abraham I err3: 1619*85d5e707SKishon Vijay Abraham I __dwc3_gadget_ep_disable(dwc->eps[0]); 1620*85d5e707SKishon Vijay Abraham I 1621*85d5e707SKishon Vijay Abraham I err2: 1622*85d5e707SKishon Vijay Abraham I dwc->gadget_driver = NULL; 1623*85d5e707SKishon Vijay Abraham I 1624*85d5e707SKishon Vijay Abraham I err1: 1625*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 1626*85d5e707SKishon Vijay Abraham I 1627*85d5e707SKishon Vijay Abraham I free_irq(irq, dwc); 1628*85d5e707SKishon Vijay Abraham I 1629*85d5e707SKishon Vijay Abraham I err0: 1630*85d5e707SKishon Vijay Abraham I return ret; 1631*85d5e707SKishon Vijay Abraham I } 1632*85d5e707SKishon Vijay Abraham I 1633*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_stop(struct usb_gadget *g) 1634*85d5e707SKishon Vijay Abraham I { 1635*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = gadget_to_dwc(g); 1636*85d5e707SKishon Vijay Abraham I unsigned long flags; 1637*85d5e707SKishon Vijay Abraham I int irq; 1638*85d5e707SKishon Vijay Abraham I 1639*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 1640*85d5e707SKishon Vijay Abraham I 1641*85d5e707SKishon Vijay Abraham I dwc3_gadget_disable_irq(dwc); 1642*85d5e707SKishon Vijay Abraham I __dwc3_gadget_ep_disable(dwc->eps[0]); 1643*85d5e707SKishon Vijay Abraham I __dwc3_gadget_ep_disable(dwc->eps[1]); 1644*85d5e707SKishon Vijay Abraham I 1645*85d5e707SKishon Vijay Abraham I dwc->gadget_driver = NULL; 1646*85d5e707SKishon Vijay Abraham I 1647*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 1648*85d5e707SKishon Vijay Abraham I 1649*85d5e707SKishon Vijay Abraham I irq = platform_get_irq(to_platform_device(dwc->dev), 0); 1650*85d5e707SKishon Vijay Abraham I free_irq(irq, dwc); 1651*85d5e707SKishon Vijay Abraham I 1652*85d5e707SKishon Vijay Abraham I return 0; 1653*85d5e707SKishon Vijay Abraham I } 1654*85d5e707SKishon Vijay Abraham I 1655*85d5e707SKishon Vijay Abraham I static const struct usb_gadget_ops dwc3_gadget_ops = { 1656*85d5e707SKishon Vijay Abraham I .get_frame = dwc3_gadget_get_frame, 1657*85d5e707SKishon Vijay Abraham I .wakeup = dwc3_gadget_wakeup, 1658*85d5e707SKishon Vijay Abraham I .set_selfpowered = dwc3_gadget_set_selfpowered, 1659*85d5e707SKishon Vijay Abraham I .pullup = dwc3_gadget_pullup, 1660*85d5e707SKishon Vijay Abraham I .udc_start = dwc3_gadget_start, 1661*85d5e707SKishon Vijay Abraham I .udc_stop = dwc3_gadget_stop, 1662*85d5e707SKishon Vijay Abraham I }; 1663*85d5e707SKishon Vijay Abraham I 1664*85d5e707SKishon Vijay Abraham I /* -------------------------------------------------------------------------- */ 1665*85d5e707SKishon Vijay Abraham I 1666*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, 1667*85d5e707SKishon Vijay Abraham I u8 num, u32 direction) 1668*85d5e707SKishon Vijay Abraham I { 1669*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 1670*85d5e707SKishon Vijay Abraham I u8 i; 1671*85d5e707SKishon Vijay Abraham I 1672*85d5e707SKishon Vijay Abraham I for (i = 0; i < num; i++) { 1673*85d5e707SKishon Vijay Abraham I u8 epnum = (i << 1) | (!!direction); 1674*85d5e707SKishon Vijay Abraham I 1675*85d5e707SKishon Vijay Abraham I dep = kzalloc(sizeof(*dep), GFP_KERNEL); 1676*85d5e707SKishon Vijay Abraham I if (!dep) 1677*85d5e707SKishon Vijay Abraham I return -ENOMEM; 1678*85d5e707SKishon Vijay Abraham I 1679*85d5e707SKishon Vijay Abraham I dep->dwc = dwc; 1680*85d5e707SKishon Vijay Abraham I dep->number = epnum; 1681*85d5e707SKishon Vijay Abraham I dep->direction = !!direction; 1682*85d5e707SKishon Vijay Abraham I dwc->eps[epnum] = dep; 1683*85d5e707SKishon Vijay Abraham I 1684*85d5e707SKishon Vijay Abraham I snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1, 1685*85d5e707SKishon Vijay Abraham I (epnum & 1) ? "in" : "out"); 1686*85d5e707SKishon Vijay Abraham I 1687*85d5e707SKishon Vijay Abraham I dep->endpoint.name = dep->name; 1688*85d5e707SKishon Vijay Abraham I 1689*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "initializing %s\n", dep->name); 1690*85d5e707SKishon Vijay Abraham I 1691*85d5e707SKishon Vijay Abraham I if (epnum == 0 || epnum == 1) { 1692*85d5e707SKishon Vijay Abraham I usb_ep_set_maxpacket_limit(&dep->endpoint, 512); 1693*85d5e707SKishon Vijay Abraham I dep->endpoint.maxburst = 1; 1694*85d5e707SKishon Vijay Abraham I dep->endpoint.ops = &dwc3_gadget_ep0_ops; 1695*85d5e707SKishon Vijay Abraham I if (!epnum) 1696*85d5e707SKishon Vijay Abraham I dwc->gadget.ep0 = &dep->endpoint; 1697*85d5e707SKishon Vijay Abraham I } else { 1698*85d5e707SKishon Vijay Abraham I int ret; 1699*85d5e707SKishon Vijay Abraham I 1700*85d5e707SKishon Vijay Abraham I usb_ep_set_maxpacket_limit(&dep->endpoint, 1024); 1701*85d5e707SKishon Vijay Abraham I dep->endpoint.max_streams = 15; 1702*85d5e707SKishon Vijay Abraham I dep->endpoint.ops = &dwc3_gadget_ep_ops; 1703*85d5e707SKishon Vijay Abraham I list_add_tail(&dep->endpoint.ep_list, 1704*85d5e707SKishon Vijay Abraham I &dwc->gadget.ep_list); 1705*85d5e707SKishon Vijay Abraham I 1706*85d5e707SKishon Vijay Abraham I ret = dwc3_alloc_trb_pool(dep); 1707*85d5e707SKishon Vijay Abraham I if (ret) 1708*85d5e707SKishon Vijay Abraham I return ret; 1709*85d5e707SKishon Vijay Abraham I } 1710*85d5e707SKishon Vijay Abraham I 1711*85d5e707SKishon Vijay Abraham I INIT_LIST_HEAD(&dep->request_list); 1712*85d5e707SKishon Vijay Abraham I INIT_LIST_HEAD(&dep->req_queued); 1713*85d5e707SKishon Vijay Abraham I } 1714*85d5e707SKishon Vijay Abraham I 1715*85d5e707SKishon Vijay Abraham I return 0; 1716*85d5e707SKishon Vijay Abraham I } 1717*85d5e707SKishon Vijay Abraham I 1718*85d5e707SKishon Vijay Abraham I static int dwc3_gadget_init_endpoints(struct dwc3 *dwc) 1719*85d5e707SKishon Vijay Abraham I { 1720*85d5e707SKishon Vijay Abraham I int ret; 1721*85d5e707SKishon Vijay Abraham I 1722*85d5e707SKishon Vijay Abraham I INIT_LIST_HEAD(&dwc->gadget.ep_list); 1723*85d5e707SKishon Vijay Abraham I 1724*85d5e707SKishon Vijay Abraham I ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0); 1725*85d5e707SKishon Vijay Abraham I if (ret < 0) { 1726*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n"); 1727*85d5e707SKishon Vijay Abraham I return ret; 1728*85d5e707SKishon Vijay Abraham I } 1729*85d5e707SKishon Vijay Abraham I 1730*85d5e707SKishon Vijay Abraham I ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1); 1731*85d5e707SKishon Vijay Abraham I if (ret < 0) { 1732*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n"); 1733*85d5e707SKishon Vijay Abraham I return ret; 1734*85d5e707SKishon Vijay Abraham I } 1735*85d5e707SKishon Vijay Abraham I 1736*85d5e707SKishon Vijay Abraham I return 0; 1737*85d5e707SKishon Vijay Abraham I } 1738*85d5e707SKishon Vijay Abraham I 1739*85d5e707SKishon Vijay Abraham I static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) 1740*85d5e707SKishon Vijay Abraham I { 1741*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 1742*85d5e707SKishon Vijay Abraham I u8 epnum; 1743*85d5e707SKishon Vijay Abraham I 1744*85d5e707SKishon Vijay Abraham I for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) { 1745*85d5e707SKishon Vijay Abraham I dep = dwc->eps[epnum]; 1746*85d5e707SKishon Vijay Abraham I if (!dep) 1747*85d5e707SKishon Vijay Abraham I continue; 1748*85d5e707SKishon Vijay Abraham I /* 1749*85d5e707SKishon Vijay Abraham I * Physical endpoints 0 and 1 are special; they form the 1750*85d5e707SKishon Vijay Abraham I * bi-directional USB endpoint 0. 1751*85d5e707SKishon Vijay Abraham I * 1752*85d5e707SKishon Vijay Abraham I * For those two physical endpoints, we don't allocate a TRB 1753*85d5e707SKishon Vijay Abraham I * pool nor do we add them the endpoints list. Due to that, we 1754*85d5e707SKishon Vijay Abraham I * shouldn't do these two operations otherwise we would end up 1755*85d5e707SKishon Vijay Abraham I * with all sorts of bugs when removing dwc3.ko. 1756*85d5e707SKishon Vijay Abraham I */ 1757*85d5e707SKishon Vijay Abraham I if (epnum != 0 && epnum != 1) { 1758*85d5e707SKishon Vijay Abraham I dwc3_free_trb_pool(dep); 1759*85d5e707SKishon Vijay Abraham I list_del(&dep->endpoint.ep_list); 1760*85d5e707SKishon Vijay Abraham I } 1761*85d5e707SKishon Vijay Abraham I 1762*85d5e707SKishon Vijay Abraham I kfree(dep); 1763*85d5e707SKishon Vijay Abraham I } 1764*85d5e707SKishon Vijay Abraham I } 1765*85d5e707SKishon Vijay Abraham I 1766*85d5e707SKishon Vijay Abraham I /* -------------------------------------------------------------------------- */ 1767*85d5e707SKishon Vijay Abraham I 1768*85d5e707SKishon Vijay Abraham I static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, 1769*85d5e707SKishon Vijay Abraham I struct dwc3_request *req, struct dwc3_trb *trb, 1770*85d5e707SKishon Vijay Abraham I const struct dwc3_event_depevt *event, int status) 1771*85d5e707SKishon Vijay Abraham I { 1772*85d5e707SKishon Vijay Abraham I unsigned int count; 1773*85d5e707SKishon Vijay Abraham I unsigned int s_pkt = 0; 1774*85d5e707SKishon Vijay Abraham I unsigned int trb_status; 1775*85d5e707SKishon Vijay Abraham I 1776*85d5e707SKishon Vijay Abraham I trace_dwc3_complete_trb(dep, trb); 1777*85d5e707SKishon Vijay Abraham I 1778*85d5e707SKishon Vijay Abraham I if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN) 1779*85d5e707SKishon Vijay Abraham I /* 1780*85d5e707SKishon Vijay Abraham I * We continue despite the error. There is not much we 1781*85d5e707SKishon Vijay Abraham I * can do. If we don't clean it up we loop forever. If 1782*85d5e707SKishon Vijay Abraham I * we skip the TRB then it gets overwritten after a 1783*85d5e707SKishon Vijay Abraham I * while since we use them in a ring buffer. A BUG() 1784*85d5e707SKishon Vijay Abraham I * would help. Lets hope that if this occurs, someone 1785*85d5e707SKishon Vijay Abraham I * fixes the root cause instead of looking away :) 1786*85d5e707SKishon Vijay Abraham I */ 1787*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n", 1788*85d5e707SKishon Vijay Abraham I dep->name, trb); 1789*85d5e707SKishon Vijay Abraham I count = trb->size & DWC3_TRB_SIZE_MASK; 1790*85d5e707SKishon Vijay Abraham I 1791*85d5e707SKishon Vijay Abraham I if (dep->direction) { 1792*85d5e707SKishon Vijay Abraham I if (count) { 1793*85d5e707SKishon Vijay Abraham I trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size); 1794*85d5e707SKishon Vijay Abraham I if (trb_status == DWC3_TRBSTS_MISSED_ISOC) { 1795*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "incomplete IN transfer %s\n", 1796*85d5e707SKishon Vijay Abraham I dep->name); 1797*85d5e707SKishon Vijay Abraham I /* 1798*85d5e707SKishon Vijay Abraham I * If missed isoc occurred and there is 1799*85d5e707SKishon Vijay Abraham I * no request queued then issue END 1800*85d5e707SKishon Vijay Abraham I * TRANSFER, so that core generates 1801*85d5e707SKishon Vijay Abraham I * next xfernotready and we will issue 1802*85d5e707SKishon Vijay Abraham I * a fresh START TRANSFER. 1803*85d5e707SKishon Vijay Abraham I * If there are still queued request 1804*85d5e707SKishon Vijay Abraham I * then wait, do not issue either END 1805*85d5e707SKishon Vijay Abraham I * or UPDATE TRANSFER, just attach next 1806*85d5e707SKishon Vijay Abraham I * request in request_list during 1807*85d5e707SKishon Vijay Abraham I * giveback.If any future queued request 1808*85d5e707SKishon Vijay Abraham I * is successfully transferred then we 1809*85d5e707SKishon Vijay Abraham I * will issue UPDATE TRANSFER for all 1810*85d5e707SKishon Vijay Abraham I * request in the request_list. 1811*85d5e707SKishon Vijay Abraham I */ 1812*85d5e707SKishon Vijay Abraham I dep->flags |= DWC3_EP_MISSED_ISOC; 1813*85d5e707SKishon Vijay Abraham I } else { 1814*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "incomplete IN transfer %s\n", 1815*85d5e707SKishon Vijay Abraham I dep->name); 1816*85d5e707SKishon Vijay Abraham I status = -ECONNRESET; 1817*85d5e707SKishon Vijay Abraham I } 1818*85d5e707SKishon Vijay Abraham I } else { 1819*85d5e707SKishon Vijay Abraham I dep->flags &= ~DWC3_EP_MISSED_ISOC; 1820*85d5e707SKishon Vijay Abraham I } 1821*85d5e707SKishon Vijay Abraham I } else { 1822*85d5e707SKishon Vijay Abraham I if (count && (event->status & DEPEVT_STATUS_SHORT)) 1823*85d5e707SKishon Vijay Abraham I s_pkt = 1; 1824*85d5e707SKishon Vijay Abraham I } 1825*85d5e707SKishon Vijay Abraham I 1826*85d5e707SKishon Vijay Abraham I /* 1827*85d5e707SKishon Vijay Abraham I * We assume here we will always receive the entire data block 1828*85d5e707SKishon Vijay Abraham I * which we should receive. Meaning, if we program RX to 1829*85d5e707SKishon Vijay Abraham I * receive 4K but we receive only 2K, we assume that's all we 1830*85d5e707SKishon Vijay Abraham I * should receive and we simply bounce the request back to the 1831*85d5e707SKishon Vijay Abraham I * gadget driver for further processing. 1832*85d5e707SKishon Vijay Abraham I */ 1833*85d5e707SKishon Vijay Abraham I req->request.actual += req->request.length - count; 1834*85d5e707SKishon Vijay Abraham I if (s_pkt) 1835*85d5e707SKishon Vijay Abraham I return 1; 1836*85d5e707SKishon Vijay Abraham I if ((event->status & DEPEVT_STATUS_LST) && 1837*85d5e707SKishon Vijay Abraham I (trb->ctrl & (DWC3_TRB_CTRL_LST | 1838*85d5e707SKishon Vijay Abraham I DWC3_TRB_CTRL_HWO))) 1839*85d5e707SKishon Vijay Abraham I return 1; 1840*85d5e707SKishon Vijay Abraham I if ((event->status & DEPEVT_STATUS_IOC) && 1841*85d5e707SKishon Vijay Abraham I (trb->ctrl & DWC3_TRB_CTRL_IOC)) 1842*85d5e707SKishon Vijay Abraham I return 1; 1843*85d5e707SKishon Vijay Abraham I return 0; 1844*85d5e707SKishon Vijay Abraham I } 1845*85d5e707SKishon Vijay Abraham I 1846*85d5e707SKishon Vijay Abraham I static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, 1847*85d5e707SKishon Vijay Abraham I const struct dwc3_event_depevt *event, int status) 1848*85d5e707SKishon Vijay Abraham I { 1849*85d5e707SKishon Vijay Abraham I struct dwc3_request *req; 1850*85d5e707SKishon Vijay Abraham I struct dwc3_trb *trb; 1851*85d5e707SKishon Vijay Abraham I unsigned int slot; 1852*85d5e707SKishon Vijay Abraham I unsigned int i; 1853*85d5e707SKishon Vijay Abraham I int ret; 1854*85d5e707SKishon Vijay Abraham I 1855*85d5e707SKishon Vijay Abraham I do { 1856*85d5e707SKishon Vijay Abraham I req = next_request(&dep->req_queued); 1857*85d5e707SKishon Vijay Abraham I if (!req) { 1858*85d5e707SKishon Vijay Abraham I WARN_ON_ONCE(1); 1859*85d5e707SKishon Vijay Abraham I return 1; 1860*85d5e707SKishon Vijay Abraham I } 1861*85d5e707SKishon Vijay Abraham I i = 0; 1862*85d5e707SKishon Vijay Abraham I do { 1863*85d5e707SKishon Vijay Abraham I slot = req->start_slot + i; 1864*85d5e707SKishon Vijay Abraham I if ((slot == DWC3_TRB_NUM - 1) && 1865*85d5e707SKishon Vijay Abraham I usb_endpoint_xfer_isoc(dep->endpoint.desc)) 1866*85d5e707SKishon Vijay Abraham I slot++; 1867*85d5e707SKishon Vijay Abraham I slot %= DWC3_TRB_NUM; 1868*85d5e707SKishon Vijay Abraham I trb = &dep->trb_pool[slot]; 1869*85d5e707SKishon Vijay Abraham I 1870*85d5e707SKishon Vijay Abraham I ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, 1871*85d5e707SKishon Vijay Abraham I event, status); 1872*85d5e707SKishon Vijay Abraham I if (ret) 1873*85d5e707SKishon Vijay Abraham I break; 1874*85d5e707SKishon Vijay Abraham I }while (++i < req->request.num_mapped_sgs); 1875*85d5e707SKishon Vijay Abraham I 1876*85d5e707SKishon Vijay Abraham I dwc3_gadget_giveback(dep, req, status); 1877*85d5e707SKishon Vijay Abraham I 1878*85d5e707SKishon Vijay Abraham I if (ret) 1879*85d5e707SKishon Vijay Abraham I break; 1880*85d5e707SKishon Vijay Abraham I } while (1); 1881*85d5e707SKishon Vijay Abraham I 1882*85d5e707SKishon Vijay Abraham I if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && 1883*85d5e707SKishon Vijay Abraham I list_empty(&dep->req_queued)) { 1884*85d5e707SKishon Vijay Abraham I if (list_empty(&dep->request_list)) { 1885*85d5e707SKishon Vijay Abraham I /* 1886*85d5e707SKishon Vijay Abraham I * If there is no entry in request list then do 1887*85d5e707SKishon Vijay Abraham I * not issue END TRANSFER now. Just set PENDING 1888*85d5e707SKishon Vijay Abraham I * flag, so that END TRANSFER is issued when an 1889*85d5e707SKishon Vijay Abraham I * entry is added into request list. 1890*85d5e707SKishon Vijay Abraham I */ 1891*85d5e707SKishon Vijay Abraham I dep->flags = DWC3_EP_PENDING_REQUEST; 1892*85d5e707SKishon Vijay Abraham I } else { 1893*85d5e707SKishon Vijay Abraham I dwc3_stop_active_transfer(dwc, dep->number, true); 1894*85d5e707SKishon Vijay Abraham I dep->flags = DWC3_EP_ENABLED; 1895*85d5e707SKishon Vijay Abraham I } 1896*85d5e707SKishon Vijay Abraham I return 1; 1897*85d5e707SKishon Vijay Abraham I } 1898*85d5e707SKishon Vijay Abraham I 1899*85d5e707SKishon Vijay Abraham I return 1; 1900*85d5e707SKishon Vijay Abraham I } 1901*85d5e707SKishon Vijay Abraham I 1902*85d5e707SKishon Vijay Abraham I static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, 1903*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep, const struct dwc3_event_depevt *event) 1904*85d5e707SKishon Vijay Abraham I { 1905*85d5e707SKishon Vijay Abraham I unsigned status = 0; 1906*85d5e707SKishon Vijay Abraham I int clean_busy; 1907*85d5e707SKishon Vijay Abraham I 1908*85d5e707SKishon Vijay Abraham I if (event->status & DEPEVT_STATUS_BUSERR) 1909*85d5e707SKishon Vijay Abraham I status = -ECONNRESET; 1910*85d5e707SKishon Vijay Abraham I 1911*85d5e707SKishon Vijay Abraham I clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status); 1912*85d5e707SKishon Vijay Abraham I if (clean_busy) 1913*85d5e707SKishon Vijay Abraham I dep->flags &= ~DWC3_EP_BUSY; 1914*85d5e707SKishon Vijay Abraham I 1915*85d5e707SKishon Vijay Abraham I /* 1916*85d5e707SKishon Vijay Abraham I * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround. 1917*85d5e707SKishon Vijay Abraham I * See dwc3_gadget_linksts_change_interrupt() for 1st half. 1918*85d5e707SKishon Vijay Abraham I */ 1919*85d5e707SKishon Vijay Abraham I if (dwc->revision < DWC3_REVISION_183A) { 1920*85d5e707SKishon Vijay Abraham I u32 reg; 1921*85d5e707SKishon Vijay Abraham I int i; 1922*85d5e707SKishon Vijay Abraham I 1923*85d5e707SKishon Vijay Abraham I for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { 1924*85d5e707SKishon Vijay Abraham I dep = dwc->eps[i]; 1925*85d5e707SKishon Vijay Abraham I 1926*85d5e707SKishon Vijay Abraham I if (!(dep->flags & DWC3_EP_ENABLED)) 1927*85d5e707SKishon Vijay Abraham I continue; 1928*85d5e707SKishon Vijay Abraham I 1929*85d5e707SKishon Vijay Abraham I if (!list_empty(&dep->req_queued)) 1930*85d5e707SKishon Vijay Abraham I return; 1931*85d5e707SKishon Vijay Abraham I } 1932*85d5e707SKishon Vijay Abraham I 1933*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 1934*85d5e707SKishon Vijay Abraham I reg |= dwc->u1u2; 1935*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 1936*85d5e707SKishon Vijay Abraham I 1937*85d5e707SKishon Vijay Abraham I dwc->u1u2 = 0; 1938*85d5e707SKishon Vijay Abraham I } 1939*85d5e707SKishon Vijay Abraham I } 1940*85d5e707SKishon Vijay Abraham I 1941*85d5e707SKishon Vijay Abraham I static void dwc3_endpoint_interrupt(struct dwc3 *dwc, 1942*85d5e707SKishon Vijay Abraham I const struct dwc3_event_depevt *event) 1943*85d5e707SKishon Vijay Abraham I { 1944*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 1945*85d5e707SKishon Vijay Abraham I u8 epnum = event->endpoint_number; 1946*85d5e707SKishon Vijay Abraham I 1947*85d5e707SKishon Vijay Abraham I dep = dwc->eps[epnum]; 1948*85d5e707SKishon Vijay Abraham I 1949*85d5e707SKishon Vijay Abraham I if (!(dep->flags & DWC3_EP_ENABLED)) 1950*85d5e707SKishon Vijay Abraham I return; 1951*85d5e707SKishon Vijay Abraham I 1952*85d5e707SKishon Vijay Abraham I if (epnum == 0 || epnum == 1) { 1953*85d5e707SKishon Vijay Abraham I dwc3_ep0_interrupt(dwc, event); 1954*85d5e707SKishon Vijay Abraham I return; 1955*85d5e707SKishon Vijay Abraham I } 1956*85d5e707SKishon Vijay Abraham I 1957*85d5e707SKishon Vijay Abraham I switch (event->endpoint_event) { 1958*85d5e707SKishon Vijay Abraham I case DWC3_DEPEVT_XFERCOMPLETE: 1959*85d5e707SKishon Vijay Abraham I dep->resource_index = 0; 1960*85d5e707SKishon Vijay Abraham I 1961*85d5e707SKishon Vijay Abraham I if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { 1962*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n", 1963*85d5e707SKishon Vijay Abraham I dep->name); 1964*85d5e707SKishon Vijay Abraham I return; 1965*85d5e707SKishon Vijay Abraham I } 1966*85d5e707SKishon Vijay Abraham I 1967*85d5e707SKishon Vijay Abraham I dwc3_endpoint_transfer_complete(dwc, dep, event); 1968*85d5e707SKishon Vijay Abraham I break; 1969*85d5e707SKishon Vijay Abraham I case DWC3_DEPEVT_XFERINPROGRESS: 1970*85d5e707SKishon Vijay Abraham I dwc3_endpoint_transfer_complete(dwc, dep, event); 1971*85d5e707SKishon Vijay Abraham I break; 1972*85d5e707SKishon Vijay Abraham I case DWC3_DEPEVT_XFERNOTREADY: 1973*85d5e707SKishon Vijay Abraham I if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { 1974*85d5e707SKishon Vijay Abraham I dwc3_gadget_start_isoc(dwc, dep, event); 1975*85d5e707SKishon Vijay Abraham I } else { 1976*85d5e707SKishon Vijay Abraham I int ret; 1977*85d5e707SKishon Vijay Abraham I 1978*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "%s: reason %s\n", 1979*85d5e707SKishon Vijay Abraham I dep->name, event->status & 1980*85d5e707SKishon Vijay Abraham I DEPEVT_STATUS_TRANSFER_ACTIVE 1981*85d5e707SKishon Vijay Abraham I ? "Transfer Active" 1982*85d5e707SKishon Vijay Abraham I : "Transfer Not Active"); 1983*85d5e707SKishon Vijay Abraham I 1984*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_kick_transfer(dep, 0, 1); 1985*85d5e707SKishon Vijay Abraham I if (!ret || ret == -EBUSY) 1986*85d5e707SKishon Vijay Abraham I return; 1987*85d5e707SKishon Vijay Abraham I 1988*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "%s: failed to kick transfers\n", 1989*85d5e707SKishon Vijay Abraham I dep->name); 1990*85d5e707SKishon Vijay Abraham I } 1991*85d5e707SKishon Vijay Abraham I 1992*85d5e707SKishon Vijay Abraham I break; 1993*85d5e707SKishon Vijay Abraham I case DWC3_DEPEVT_STREAMEVT: 1994*85d5e707SKishon Vijay Abraham I if (!usb_endpoint_xfer_bulk(dep->endpoint.desc)) { 1995*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "Stream event for non-Bulk %s\n", 1996*85d5e707SKishon Vijay Abraham I dep->name); 1997*85d5e707SKishon Vijay Abraham I return; 1998*85d5e707SKishon Vijay Abraham I } 1999*85d5e707SKishon Vijay Abraham I 2000*85d5e707SKishon Vijay Abraham I switch (event->status) { 2001*85d5e707SKishon Vijay Abraham I case DEPEVT_STREAMEVT_FOUND: 2002*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "Stream %d found and started\n", 2003*85d5e707SKishon Vijay Abraham I event->parameters); 2004*85d5e707SKishon Vijay Abraham I 2005*85d5e707SKishon Vijay Abraham I break; 2006*85d5e707SKishon Vijay Abraham I case DEPEVT_STREAMEVT_NOTFOUND: 2007*85d5e707SKishon Vijay Abraham I /* FALLTHROUGH */ 2008*85d5e707SKishon Vijay Abraham I default: 2009*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "Couldn't find suitable stream\n"); 2010*85d5e707SKishon Vijay Abraham I } 2011*85d5e707SKishon Vijay Abraham I break; 2012*85d5e707SKishon Vijay Abraham I case DWC3_DEPEVT_RXTXFIFOEVT: 2013*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name); 2014*85d5e707SKishon Vijay Abraham I break; 2015*85d5e707SKishon Vijay Abraham I case DWC3_DEPEVT_EPCMDCMPLT: 2016*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "Endpoint Command Complete\n"); 2017*85d5e707SKishon Vijay Abraham I break; 2018*85d5e707SKishon Vijay Abraham I } 2019*85d5e707SKishon Vijay Abraham I } 2020*85d5e707SKishon Vijay Abraham I 2021*85d5e707SKishon Vijay Abraham I static void dwc3_disconnect_gadget(struct dwc3 *dwc) 2022*85d5e707SKishon Vijay Abraham I { 2023*85d5e707SKishon Vijay Abraham I if (dwc->gadget_driver && dwc->gadget_driver->disconnect) { 2024*85d5e707SKishon Vijay Abraham I spin_unlock(&dwc->lock); 2025*85d5e707SKishon Vijay Abraham I dwc->gadget_driver->disconnect(&dwc->gadget); 2026*85d5e707SKishon Vijay Abraham I spin_lock(&dwc->lock); 2027*85d5e707SKishon Vijay Abraham I } 2028*85d5e707SKishon Vijay Abraham I } 2029*85d5e707SKishon Vijay Abraham I 2030*85d5e707SKishon Vijay Abraham I static void dwc3_suspend_gadget(struct dwc3 *dwc) 2031*85d5e707SKishon Vijay Abraham I { 2032*85d5e707SKishon Vijay Abraham I if (dwc->gadget_driver && dwc->gadget_driver->suspend) { 2033*85d5e707SKishon Vijay Abraham I spin_unlock(&dwc->lock); 2034*85d5e707SKishon Vijay Abraham I dwc->gadget_driver->suspend(&dwc->gadget); 2035*85d5e707SKishon Vijay Abraham I spin_lock(&dwc->lock); 2036*85d5e707SKishon Vijay Abraham I } 2037*85d5e707SKishon Vijay Abraham I } 2038*85d5e707SKishon Vijay Abraham I 2039*85d5e707SKishon Vijay Abraham I static void dwc3_resume_gadget(struct dwc3 *dwc) 2040*85d5e707SKishon Vijay Abraham I { 2041*85d5e707SKishon Vijay Abraham I if (dwc->gadget_driver && dwc->gadget_driver->resume) { 2042*85d5e707SKishon Vijay Abraham I spin_unlock(&dwc->lock); 2043*85d5e707SKishon Vijay Abraham I dwc->gadget_driver->resume(&dwc->gadget); 2044*85d5e707SKishon Vijay Abraham I } 2045*85d5e707SKishon Vijay Abraham I } 2046*85d5e707SKishon Vijay Abraham I 2047*85d5e707SKishon Vijay Abraham I static void dwc3_reset_gadget(struct dwc3 *dwc) 2048*85d5e707SKishon Vijay Abraham I { 2049*85d5e707SKishon Vijay Abraham I if (!dwc->gadget_driver) 2050*85d5e707SKishon Vijay Abraham I return; 2051*85d5e707SKishon Vijay Abraham I 2052*85d5e707SKishon Vijay Abraham I if (dwc->gadget.speed != USB_SPEED_UNKNOWN) { 2053*85d5e707SKishon Vijay Abraham I spin_unlock(&dwc->lock); 2054*85d5e707SKishon Vijay Abraham I usb_gadget_udc_reset(&dwc->gadget, dwc->gadget_driver); 2055*85d5e707SKishon Vijay Abraham I spin_lock(&dwc->lock); 2056*85d5e707SKishon Vijay Abraham I } 2057*85d5e707SKishon Vijay Abraham I } 2058*85d5e707SKishon Vijay Abraham I 2059*85d5e707SKishon Vijay Abraham I static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) 2060*85d5e707SKishon Vijay Abraham I { 2061*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 2062*85d5e707SKishon Vijay Abraham I struct dwc3_gadget_ep_cmd_params params; 2063*85d5e707SKishon Vijay Abraham I u32 cmd; 2064*85d5e707SKishon Vijay Abraham I int ret; 2065*85d5e707SKishon Vijay Abraham I 2066*85d5e707SKishon Vijay Abraham I dep = dwc->eps[epnum]; 2067*85d5e707SKishon Vijay Abraham I 2068*85d5e707SKishon Vijay Abraham I if (!dep->resource_index) 2069*85d5e707SKishon Vijay Abraham I return; 2070*85d5e707SKishon Vijay Abraham I 2071*85d5e707SKishon Vijay Abraham I /* 2072*85d5e707SKishon Vijay Abraham I * NOTICE: We are violating what the Databook says about the 2073*85d5e707SKishon Vijay Abraham I * EndTransfer command. Ideally we would _always_ wait for the 2074*85d5e707SKishon Vijay Abraham I * EndTransfer Command Completion IRQ, but that's causing too 2075*85d5e707SKishon Vijay Abraham I * much trouble synchronizing between us and gadget driver. 2076*85d5e707SKishon Vijay Abraham I * 2077*85d5e707SKishon Vijay Abraham I * We have discussed this with the IP Provider and it was 2078*85d5e707SKishon Vijay Abraham I * suggested to giveback all requests here, but give HW some 2079*85d5e707SKishon Vijay Abraham I * extra time to synchronize with the interconnect. We're using 2080*85d5e707SKishon Vijay Abraham I * an arbitraty 100us delay for that. 2081*85d5e707SKishon Vijay Abraham I * 2082*85d5e707SKishon Vijay Abraham I * Note also that a similar handling was tested by Synopsys 2083*85d5e707SKishon Vijay Abraham I * (thanks a lot Paul) and nothing bad has come out of it. 2084*85d5e707SKishon Vijay Abraham I * In short, what we're doing is: 2085*85d5e707SKishon Vijay Abraham I * 2086*85d5e707SKishon Vijay Abraham I * - Issue EndTransfer WITH CMDIOC bit set 2087*85d5e707SKishon Vijay Abraham I * - Wait 100us 2088*85d5e707SKishon Vijay Abraham I */ 2089*85d5e707SKishon Vijay Abraham I 2090*85d5e707SKishon Vijay Abraham I cmd = DWC3_DEPCMD_ENDTRANSFER; 2091*85d5e707SKishon Vijay Abraham I cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0; 2092*85d5e707SKishon Vijay Abraham I cmd |= DWC3_DEPCMD_CMDIOC; 2093*85d5e707SKishon Vijay Abraham I cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); 2094*85d5e707SKishon Vijay Abraham I memset(¶ms, 0, sizeof(params)); 2095*85d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); 2096*85d5e707SKishon Vijay Abraham I WARN_ON_ONCE(ret); 2097*85d5e707SKishon Vijay Abraham I dep->resource_index = 0; 2098*85d5e707SKishon Vijay Abraham I dep->flags &= ~DWC3_EP_BUSY; 2099*85d5e707SKishon Vijay Abraham I udelay(100); 2100*85d5e707SKishon Vijay Abraham I } 2101*85d5e707SKishon Vijay Abraham I 2102*85d5e707SKishon Vijay Abraham I static void dwc3_stop_active_transfers(struct dwc3 *dwc) 2103*85d5e707SKishon Vijay Abraham I { 2104*85d5e707SKishon Vijay Abraham I u32 epnum; 2105*85d5e707SKishon Vijay Abraham I 2106*85d5e707SKishon Vijay Abraham I for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) { 2107*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 2108*85d5e707SKishon Vijay Abraham I 2109*85d5e707SKishon Vijay Abraham I dep = dwc->eps[epnum]; 2110*85d5e707SKishon Vijay Abraham I if (!dep) 2111*85d5e707SKishon Vijay Abraham I continue; 2112*85d5e707SKishon Vijay Abraham I 2113*85d5e707SKishon Vijay Abraham I if (!(dep->flags & DWC3_EP_ENABLED)) 2114*85d5e707SKishon Vijay Abraham I continue; 2115*85d5e707SKishon Vijay Abraham I 2116*85d5e707SKishon Vijay Abraham I dwc3_remove_requests(dwc, dep); 2117*85d5e707SKishon Vijay Abraham I } 2118*85d5e707SKishon Vijay Abraham I } 2119*85d5e707SKishon Vijay Abraham I 2120*85d5e707SKishon Vijay Abraham I static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) 2121*85d5e707SKishon Vijay Abraham I { 2122*85d5e707SKishon Vijay Abraham I u32 epnum; 2123*85d5e707SKishon Vijay Abraham I 2124*85d5e707SKishon Vijay Abraham I for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) { 2125*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 2126*85d5e707SKishon Vijay Abraham I struct dwc3_gadget_ep_cmd_params params; 2127*85d5e707SKishon Vijay Abraham I int ret; 2128*85d5e707SKishon Vijay Abraham I 2129*85d5e707SKishon Vijay Abraham I dep = dwc->eps[epnum]; 2130*85d5e707SKishon Vijay Abraham I if (!dep) 2131*85d5e707SKishon Vijay Abraham I continue; 2132*85d5e707SKishon Vijay Abraham I 2133*85d5e707SKishon Vijay Abraham I if (!(dep->flags & DWC3_EP_STALL)) 2134*85d5e707SKishon Vijay Abraham I continue; 2135*85d5e707SKishon Vijay Abraham I 2136*85d5e707SKishon Vijay Abraham I dep->flags &= ~DWC3_EP_STALL; 2137*85d5e707SKishon Vijay Abraham I 2138*85d5e707SKishon Vijay Abraham I memset(¶ms, 0, sizeof(params)); 2139*85d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, 2140*85d5e707SKishon Vijay Abraham I DWC3_DEPCMD_CLEARSTALL, ¶ms); 2141*85d5e707SKishon Vijay Abraham I WARN_ON_ONCE(ret); 2142*85d5e707SKishon Vijay Abraham I } 2143*85d5e707SKishon Vijay Abraham I } 2144*85d5e707SKishon Vijay Abraham I 2145*85d5e707SKishon Vijay Abraham I static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) 2146*85d5e707SKishon Vijay Abraham I { 2147*85d5e707SKishon Vijay Abraham I int reg; 2148*85d5e707SKishon Vijay Abraham I 2149*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 2150*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_INITU1ENA; 2151*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 2152*85d5e707SKishon Vijay Abraham I 2153*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_INITU2ENA; 2154*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 2155*85d5e707SKishon Vijay Abraham I 2156*85d5e707SKishon Vijay Abraham I dwc3_disconnect_gadget(dwc); 2157*85d5e707SKishon Vijay Abraham I dwc->start_config_issued = false; 2158*85d5e707SKishon Vijay Abraham I 2159*85d5e707SKishon Vijay Abraham I dwc->gadget.speed = USB_SPEED_UNKNOWN; 2160*85d5e707SKishon Vijay Abraham I dwc->setup_packet_pending = false; 2161*85d5e707SKishon Vijay Abraham I usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED); 2162*85d5e707SKishon Vijay Abraham I } 2163*85d5e707SKishon Vijay Abraham I 2164*85d5e707SKishon Vijay Abraham I static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) 2165*85d5e707SKishon Vijay Abraham I { 2166*85d5e707SKishon Vijay Abraham I u32 reg; 2167*85d5e707SKishon Vijay Abraham I 2168*85d5e707SKishon Vijay Abraham I /* 2169*85d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 revisions <1.88a have an issue which 2170*85d5e707SKishon Vijay Abraham I * would cause a missing Disconnect Event if there's a 2171*85d5e707SKishon Vijay Abraham I * pending Setup Packet in the FIFO. 2172*85d5e707SKishon Vijay Abraham I * 2173*85d5e707SKishon Vijay Abraham I * There's no suggested workaround on the official Bug 2174*85d5e707SKishon Vijay Abraham I * report, which states that "unless the driver/application 2175*85d5e707SKishon Vijay Abraham I * is doing any special handling of a disconnect event, 2176*85d5e707SKishon Vijay Abraham I * there is no functional issue". 2177*85d5e707SKishon Vijay Abraham I * 2178*85d5e707SKishon Vijay Abraham I * Unfortunately, it turns out that we _do_ some special 2179*85d5e707SKishon Vijay Abraham I * handling of a disconnect event, namely complete all 2180*85d5e707SKishon Vijay Abraham I * pending transfers, notify gadget driver of the 2181*85d5e707SKishon Vijay Abraham I * disconnection, and so on. 2182*85d5e707SKishon Vijay Abraham I * 2183*85d5e707SKishon Vijay Abraham I * Our suggested workaround is to follow the Disconnect 2184*85d5e707SKishon Vijay Abraham I * Event steps here, instead, based on a setup_packet_pending 2185*85d5e707SKishon Vijay Abraham I * flag. Such flag gets set whenever we have a XferNotReady 2186*85d5e707SKishon Vijay Abraham I * event on EP0 and gets cleared on XferComplete for the 2187*85d5e707SKishon Vijay Abraham I * same endpoint. 2188*85d5e707SKishon Vijay Abraham I * 2189*85d5e707SKishon Vijay Abraham I * Refers to: 2190*85d5e707SKishon Vijay Abraham I * 2191*85d5e707SKishon Vijay Abraham I * STAR#9000466709: RTL: Device : Disconnect event not 2192*85d5e707SKishon Vijay Abraham I * generated if setup packet pending in FIFO 2193*85d5e707SKishon Vijay Abraham I */ 2194*85d5e707SKishon Vijay Abraham I if (dwc->revision < DWC3_REVISION_188A) { 2195*85d5e707SKishon Vijay Abraham I if (dwc->setup_packet_pending) 2196*85d5e707SKishon Vijay Abraham I dwc3_gadget_disconnect_interrupt(dwc); 2197*85d5e707SKishon Vijay Abraham I } 2198*85d5e707SKishon Vijay Abraham I 2199*85d5e707SKishon Vijay Abraham I dwc3_reset_gadget(dwc); 2200*85d5e707SKishon Vijay Abraham I 2201*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 2202*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_TSTCTRL_MASK; 2203*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 2204*85d5e707SKishon Vijay Abraham I dwc->test_mode = false; 2205*85d5e707SKishon Vijay Abraham I 2206*85d5e707SKishon Vijay Abraham I dwc3_stop_active_transfers(dwc); 2207*85d5e707SKishon Vijay Abraham I dwc3_clear_stall_all_ep(dwc); 2208*85d5e707SKishon Vijay Abraham I dwc->start_config_issued = false; 2209*85d5e707SKishon Vijay Abraham I 2210*85d5e707SKishon Vijay Abraham I /* Reset device address to zero */ 2211*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCFG); 2212*85d5e707SKishon Vijay Abraham I reg &= ~(DWC3_DCFG_DEVADDR_MASK); 2213*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCFG, reg); 2214*85d5e707SKishon Vijay Abraham I } 2215*85d5e707SKishon Vijay Abraham I 2216*85d5e707SKishon Vijay Abraham I static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed) 2217*85d5e707SKishon Vijay Abraham I { 2218*85d5e707SKishon Vijay Abraham I u32 reg; 2219*85d5e707SKishon Vijay Abraham I u32 usb30_clock = DWC3_GCTL_CLK_BUS; 2220*85d5e707SKishon Vijay Abraham I 2221*85d5e707SKishon Vijay Abraham I /* 2222*85d5e707SKishon Vijay Abraham I * We change the clock only at SS but I dunno why I would want to do 2223*85d5e707SKishon Vijay Abraham I * this. Maybe it becomes part of the power saving plan. 2224*85d5e707SKishon Vijay Abraham I */ 2225*85d5e707SKishon Vijay Abraham I 2226*85d5e707SKishon Vijay Abraham I if (speed != DWC3_DSTS_SUPERSPEED) 2227*85d5e707SKishon Vijay Abraham I return; 2228*85d5e707SKishon Vijay Abraham I 2229*85d5e707SKishon Vijay Abraham I /* 2230*85d5e707SKishon Vijay Abraham I * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed 2231*85d5e707SKishon Vijay Abraham I * each time on Connect Done. 2232*85d5e707SKishon Vijay Abraham I */ 2233*85d5e707SKishon Vijay Abraham I if (!usb30_clock) 2234*85d5e707SKishon Vijay Abraham I return; 2235*85d5e707SKishon Vijay Abraham I 2236*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 2237*85d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_RAMCLKSEL(usb30_clock); 2238*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 2239*85d5e707SKishon Vijay Abraham I } 2240*85d5e707SKishon Vijay Abraham I 2241*85d5e707SKishon Vijay Abraham I static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) 2242*85d5e707SKishon Vijay Abraham I { 2243*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 2244*85d5e707SKishon Vijay Abraham I int ret; 2245*85d5e707SKishon Vijay Abraham I u32 reg; 2246*85d5e707SKishon Vijay Abraham I u8 speed; 2247*85d5e707SKishon Vijay Abraham I 2248*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DSTS); 2249*85d5e707SKishon Vijay Abraham I speed = reg & DWC3_DSTS_CONNECTSPD; 2250*85d5e707SKishon Vijay Abraham I dwc->speed = speed; 2251*85d5e707SKishon Vijay Abraham I 2252*85d5e707SKishon Vijay Abraham I dwc3_update_ram_clk_sel(dwc, speed); 2253*85d5e707SKishon Vijay Abraham I 2254*85d5e707SKishon Vijay Abraham I switch (speed) { 2255*85d5e707SKishon Vijay Abraham I case DWC3_DCFG_SUPERSPEED: 2256*85d5e707SKishon Vijay Abraham I /* 2257*85d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 revisions <1.90a have an issue which 2258*85d5e707SKishon Vijay Abraham I * would cause a missing USB3 Reset event. 2259*85d5e707SKishon Vijay Abraham I * 2260*85d5e707SKishon Vijay Abraham I * In such situations, we should force a USB3 Reset 2261*85d5e707SKishon Vijay Abraham I * event by calling our dwc3_gadget_reset_interrupt() 2262*85d5e707SKishon Vijay Abraham I * routine. 2263*85d5e707SKishon Vijay Abraham I * 2264*85d5e707SKishon Vijay Abraham I * Refers to: 2265*85d5e707SKishon Vijay Abraham I * 2266*85d5e707SKishon Vijay Abraham I * STAR#9000483510: RTL: SS : USB3 reset event may 2267*85d5e707SKishon Vijay Abraham I * not be generated always when the link enters poll 2268*85d5e707SKishon Vijay Abraham I */ 2269*85d5e707SKishon Vijay Abraham I if (dwc->revision < DWC3_REVISION_190A) 2270*85d5e707SKishon Vijay Abraham I dwc3_gadget_reset_interrupt(dwc); 2271*85d5e707SKishon Vijay Abraham I 2272*85d5e707SKishon Vijay Abraham I dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); 2273*85d5e707SKishon Vijay Abraham I dwc->gadget.ep0->maxpacket = 512; 2274*85d5e707SKishon Vijay Abraham I dwc->gadget.speed = USB_SPEED_SUPER; 2275*85d5e707SKishon Vijay Abraham I break; 2276*85d5e707SKishon Vijay Abraham I case DWC3_DCFG_HIGHSPEED: 2277*85d5e707SKishon Vijay Abraham I dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64); 2278*85d5e707SKishon Vijay Abraham I dwc->gadget.ep0->maxpacket = 64; 2279*85d5e707SKishon Vijay Abraham I dwc->gadget.speed = USB_SPEED_HIGH; 2280*85d5e707SKishon Vijay Abraham I break; 2281*85d5e707SKishon Vijay Abraham I case DWC3_DCFG_FULLSPEED2: 2282*85d5e707SKishon Vijay Abraham I case DWC3_DCFG_FULLSPEED1: 2283*85d5e707SKishon Vijay Abraham I dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64); 2284*85d5e707SKishon Vijay Abraham I dwc->gadget.ep0->maxpacket = 64; 2285*85d5e707SKishon Vijay Abraham I dwc->gadget.speed = USB_SPEED_FULL; 2286*85d5e707SKishon Vijay Abraham I break; 2287*85d5e707SKishon Vijay Abraham I case DWC3_DCFG_LOWSPEED: 2288*85d5e707SKishon Vijay Abraham I dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8); 2289*85d5e707SKishon Vijay Abraham I dwc->gadget.ep0->maxpacket = 8; 2290*85d5e707SKishon Vijay Abraham I dwc->gadget.speed = USB_SPEED_LOW; 2291*85d5e707SKishon Vijay Abraham I break; 2292*85d5e707SKishon Vijay Abraham I } 2293*85d5e707SKishon Vijay Abraham I 2294*85d5e707SKishon Vijay Abraham I /* Enable USB2 LPM Capability */ 2295*85d5e707SKishon Vijay Abraham I 2296*85d5e707SKishon Vijay Abraham I if ((dwc->revision > DWC3_REVISION_194A) 2297*85d5e707SKishon Vijay Abraham I && (speed != DWC3_DCFG_SUPERSPEED)) { 2298*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCFG); 2299*85d5e707SKishon Vijay Abraham I reg |= DWC3_DCFG_LPM_CAP; 2300*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCFG, reg); 2301*85d5e707SKishon Vijay Abraham I 2302*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 2303*85d5e707SKishon Vijay Abraham I reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN); 2304*85d5e707SKishon Vijay Abraham I 2305*85d5e707SKishon Vijay Abraham I reg |= DWC3_DCTL_HIRD_THRES(dwc->hird_threshold); 2306*85d5e707SKishon Vijay Abraham I 2307*85d5e707SKishon Vijay Abraham I /* 2308*85d5e707SKishon Vijay Abraham I * When dwc3 revisions >= 2.40a, LPM Erratum is enabled and 2309*85d5e707SKishon Vijay Abraham I * DCFG.LPMCap is set, core responses with an ACK and the 2310*85d5e707SKishon Vijay Abraham I * BESL value in the LPM token is less than or equal to LPM 2311*85d5e707SKishon Vijay Abraham I * NYET threshold. 2312*85d5e707SKishon Vijay Abraham I */ 2313*85d5e707SKishon Vijay Abraham I WARN_ONCE(dwc->revision < DWC3_REVISION_240A 2314*85d5e707SKishon Vijay Abraham I && dwc->has_lpm_erratum, 2315*85d5e707SKishon Vijay Abraham I "LPM Erratum not available on dwc3 revisisions < 2.40a\n"); 2316*85d5e707SKishon Vijay Abraham I 2317*85d5e707SKishon Vijay Abraham I if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A) 2318*85d5e707SKishon Vijay Abraham I reg |= DWC3_DCTL_LPM_ERRATA(dwc->lpm_nyet_threshold); 2319*85d5e707SKishon Vijay Abraham I 2320*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 2321*85d5e707SKishon Vijay Abraham I } else { 2322*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 2323*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_HIRD_THRES_MASK; 2324*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 2325*85d5e707SKishon Vijay Abraham I } 2326*85d5e707SKishon Vijay Abraham I 2327*85d5e707SKishon Vijay Abraham I dep = dwc->eps[0]; 2328*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true, 2329*85d5e707SKishon Vijay Abraham I false); 2330*85d5e707SKishon Vijay Abraham I if (ret) { 2331*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to enable %s\n", dep->name); 2332*85d5e707SKishon Vijay Abraham I return; 2333*85d5e707SKishon Vijay Abraham I } 2334*85d5e707SKishon Vijay Abraham I 2335*85d5e707SKishon Vijay Abraham I dep = dwc->eps[1]; 2336*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true, 2337*85d5e707SKishon Vijay Abraham I false); 2338*85d5e707SKishon Vijay Abraham I if (ret) { 2339*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to enable %s\n", dep->name); 2340*85d5e707SKishon Vijay Abraham I return; 2341*85d5e707SKishon Vijay Abraham I } 2342*85d5e707SKishon Vijay Abraham I 2343*85d5e707SKishon Vijay Abraham I /* 2344*85d5e707SKishon Vijay Abraham I * Configure PHY via GUSB3PIPECTLn if required. 2345*85d5e707SKishon Vijay Abraham I * 2346*85d5e707SKishon Vijay Abraham I * Update GTXFIFOSIZn 2347*85d5e707SKishon Vijay Abraham I * 2348*85d5e707SKishon Vijay Abraham I * In both cases reset values should be sufficient. 2349*85d5e707SKishon Vijay Abraham I */ 2350*85d5e707SKishon Vijay Abraham I } 2351*85d5e707SKishon Vijay Abraham I 2352*85d5e707SKishon Vijay Abraham I static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) 2353*85d5e707SKishon Vijay Abraham I { 2354*85d5e707SKishon Vijay Abraham I /* 2355*85d5e707SKishon Vijay Abraham I * TODO take core out of low power mode when that's 2356*85d5e707SKishon Vijay Abraham I * implemented. 2357*85d5e707SKishon Vijay Abraham I */ 2358*85d5e707SKishon Vijay Abraham I 2359*85d5e707SKishon Vijay Abraham I dwc->gadget_driver->resume(&dwc->gadget); 2360*85d5e707SKishon Vijay Abraham I } 2361*85d5e707SKishon Vijay Abraham I 2362*85d5e707SKishon Vijay Abraham I static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, 2363*85d5e707SKishon Vijay Abraham I unsigned int evtinfo) 2364*85d5e707SKishon Vijay Abraham I { 2365*85d5e707SKishon Vijay Abraham I enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; 2366*85d5e707SKishon Vijay Abraham I unsigned int pwropt; 2367*85d5e707SKishon Vijay Abraham I 2368*85d5e707SKishon Vijay Abraham I /* 2369*85d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 < 2.50a have an issue when configured without 2370*85d5e707SKishon Vijay Abraham I * Hibernation mode enabled which would show up when device detects 2371*85d5e707SKishon Vijay Abraham I * host-initiated U3 exit. 2372*85d5e707SKishon Vijay Abraham I * 2373*85d5e707SKishon Vijay Abraham I * In that case, device will generate a Link State Change Interrupt 2374*85d5e707SKishon Vijay Abraham I * from U3 to RESUME which is only necessary if Hibernation is 2375*85d5e707SKishon Vijay Abraham I * configured in. 2376*85d5e707SKishon Vijay Abraham I * 2377*85d5e707SKishon Vijay Abraham I * There are no functional changes due to such spurious event and we 2378*85d5e707SKishon Vijay Abraham I * just need to ignore it. 2379*85d5e707SKishon Vijay Abraham I * 2380*85d5e707SKishon Vijay Abraham I * Refers to: 2381*85d5e707SKishon Vijay Abraham I * 2382*85d5e707SKishon Vijay Abraham I * STAR#9000570034 RTL: SS Resume event generated in non-Hibernation 2383*85d5e707SKishon Vijay Abraham I * operational mode 2384*85d5e707SKishon Vijay Abraham I */ 2385*85d5e707SKishon Vijay Abraham I pwropt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1); 2386*85d5e707SKishon Vijay Abraham I if ((dwc->revision < DWC3_REVISION_250A) && 2387*85d5e707SKishon Vijay Abraham I (pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) { 2388*85d5e707SKishon Vijay Abraham I if ((dwc->link_state == DWC3_LINK_STATE_U3) && 2389*85d5e707SKishon Vijay Abraham I (next == DWC3_LINK_STATE_RESUME)) { 2390*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n"); 2391*85d5e707SKishon Vijay Abraham I return; 2392*85d5e707SKishon Vijay Abraham I } 2393*85d5e707SKishon Vijay Abraham I } 2394*85d5e707SKishon Vijay Abraham I 2395*85d5e707SKishon Vijay Abraham I /* 2396*85d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending 2397*85d5e707SKishon Vijay Abraham I * on the link partner, the USB session might do multiple entry/exit 2398*85d5e707SKishon Vijay Abraham I * of low power states before a transfer takes place. 2399*85d5e707SKishon Vijay Abraham I * 2400*85d5e707SKishon Vijay Abraham I * Due to this problem, we might experience lower throughput. The 2401*85d5e707SKishon Vijay Abraham I * suggested workaround is to disable DCTL[12:9] bits if we're 2402*85d5e707SKishon Vijay Abraham I * transitioning from U1/U2 to U0 and enable those bits again 2403*85d5e707SKishon Vijay Abraham I * after a transfer completes and there are no pending transfers 2404*85d5e707SKishon Vijay Abraham I * on any of the enabled endpoints. 2405*85d5e707SKishon Vijay Abraham I * 2406*85d5e707SKishon Vijay Abraham I * This is the first half of that workaround. 2407*85d5e707SKishon Vijay Abraham I * 2408*85d5e707SKishon Vijay Abraham I * Refers to: 2409*85d5e707SKishon Vijay Abraham I * 2410*85d5e707SKishon Vijay Abraham I * STAR#9000446952: RTL: Device SS : if U1/U2 ->U0 takes >128us 2411*85d5e707SKishon Vijay Abraham I * core send LGO_Ux entering U0 2412*85d5e707SKishon Vijay Abraham I */ 2413*85d5e707SKishon Vijay Abraham I if (dwc->revision < DWC3_REVISION_183A) { 2414*85d5e707SKishon Vijay Abraham I if (next == DWC3_LINK_STATE_U0) { 2415*85d5e707SKishon Vijay Abraham I u32 u1u2; 2416*85d5e707SKishon Vijay Abraham I u32 reg; 2417*85d5e707SKishon Vijay Abraham I 2418*85d5e707SKishon Vijay Abraham I switch (dwc->link_state) { 2419*85d5e707SKishon Vijay Abraham I case DWC3_LINK_STATE_U1: 2420*85d5e707SKishon Vijay Abraham I case DWC3_LINK_STATE_U2: 2421*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 2422*85d5e707SKishon Vijay Abraham I u1u2 = reg & (DWC3_DCTL_INITU2ENA 2423*85d5e707SKishon Vijay Abraham I | DWC3_DCTL_ACCEPTU2ENA 2424*85d5e707SKishon Vijay Abraham I | DWC3_DCTL_INITU1ENA 2425*85d5e707SKishon Vijay Abraham I | DWC3_DCTL_ACCEPTU1ENA); 2426*85d5e707SKishon Vijay Abraham I 2427*85d5e707SKishon Vijay Abraham I if (!dwc->u1u2) 2428*85d5e707SKishon Vijay Abraham I dwc->u1u2 = reg & u1u2; 2429*85d5e707SKishon Vijay Abraham I 2430*85d5e707SKishon Vijay Abraham I reg &= ~u1u2; 2431*85d5e707SKishon Vijay Abraham I 2432*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 2433*85d5e707SKishon Vijay Abraham I break; 2434*85d5e707SKishon Vijay Abraham I default: 2435*85d5e707SKishon Vijay Abraham I /* do nothing */ 2436*85d5e707SKishon Vijay Abraham I break; 2437*85d5e707SKishon Vijay Abraham I } 2438*85d5e707SKishon Vijay Abraham I } 2439*85d5e707SKishon Vijay Abraham I } 2440*85d5e707SKishon Vijay Abraham I 2441*85d5e707SKishon Vijay Abraham I switch (next) { 2442*85d5e707SKishon Vijay Abraham I case DWC3_LINK_STATE_U1: 2443*85d5e707SKishon Vijay Abraham I if (dwc->speed == USB_SPEED_SUPER) 2444*85d5e707SKishon Vijay Abraham I dwc3_suspend_gadget(dwc); 2445*85d5e707SKishon Vijay Abraham I break; 2446*85d5e707SKishon Vijay Abraham I case DWC3_LINK_STATE_U2: 2447*85d5e707SKishon Vijay Abraham I case DWC3_LINK_STATE_U3: 2448*85d5e707SKishon Vijay Abraham I dwc3_suspend_gadget(dwc); 2449*85d5e707SKishon Vijay Abraham I break; 2450*85d5e707SKishon Vijay Abraham I case DWC3_LINK_STATE_RESUME: 2451*85d5e707SKishon Vijay Abraham I dwc3_resume_gadget(dwc); 2452*85d5e707SKishon Vijay Abraham I break; 2453*85d5e707SKishon Vijay Abraham I default: 2454*85d5e707SKishon Vijay Abraham I /* do nothing */ 2455*85d5e707SKishon Vijay Abraham I break; 2456*85d5e707SKishon Vijay Abraham I } 2457*85d5e707SKishon Vijay Abraham I 2458*85d5e707SKishon Vijay Abraham I dwc->link_state = next; 2459*85d5e707SKishon Vijay Abraham I } 2460*85d5e707SKishon Vijay Abraham I 2461*85d5e707SKishon Vijay Abraham I static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, 2462*85d5e707SKishon Vijay Abraham I unsigned int evtinfo) 2463*85d5e707SKishon Vijay Abraham I { 2464*85d5e707SKishon Vijay Abraham I unsigned int is_ss = evtinfo & BIT(4); 2465*85d5e707SKishon Vijay Abraham I 2466*85d5e707SKishon Vijay Abraham I /** 2467*85d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 revison 2.20a with hibernation support 2468*85d5e707SKishon Vijay Abraham I * have a known issue which can cause USB CV TD.9.23 to fail 2469*85d5e707SKishon Vijay Abraham I * randomly. 2470*85d5e707SKishon Vijay Abraham I * 2471*85d5e707SKishon Vijay Abraham I * Because of this issue, core could generate bogus hibernation 2472*85d5e707SKishon Vijay Abraham I * events which SW needs to ignore. 2473*85d5e707SKishon Vijay Abraham I * 2474*85d5e707SKishon Vijay Abraham I * Refers to: 2475*85d5e707SKishon Vijay Abraham I * 2476*85d5e707SKishon Vijay Abraham I * STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0 2477*85d5e707SKishon Vijay Abraham I * Device Fallback from SuperSpeed 2478*85d5e707SKishon Vijay Abraham I */ 2479*85d5e707SKishon Vijay Abraham I if (is_ss ^ (dwc->speed == USB_SPEED_SUPER)) 2480*85d5e707SKishon Vijay Abraham I return; 2481*85d5e707SKishon Vijay Abraham I 2482*85d5e707SKishon Vijay Abraham I /* enter hibernation here */ 2483*85d5e707SKishon Vijay Abraham I } 2484*85d5e707SKishon Vijay Abraham I 2485*85d5e707SKishon Vijay Abraham I static void dwc3_gadget_interrupt(struct dwc3 *dwc, 2486*85d5e707SKishon Vijay Abraham I const struct dwc3_event_devt *event) 2487*85d5e707SKishon Vijay Abraham I { 2488*85d5e707SKishon Vijay Abraham I switch (event->type) { 2489*85d5e707SKishon Vijay Abraham I case DWC3_DEVICE_EVENT_DISCONNECT: 2490*85d5e707SKishon Vijay Abraham I dwc3_gadget_disconnect_interrupt(dwc); 2491*85d5e707SKishon Vijay Abraham I break; 2492*85d5e707SKishon Vijay Abraham I case DWC3_DEVICE_EVENT_RESET: 2493*85d5e707SKishon Vijay Abraham I dwc3_gadget_reset_interrupt(dwc); 2494*85d5e707SKishon Vijay Abraham I break; 2495*85d5e707SKishon Vijay Abraham I case DWC3_DEVICE_EVENT_CONNECT_DONE: 2496*85d5e707SKishon Vijay Abraham I dwc3_gadget_conndone_interrupt(dwc); 2497*85d5e707SKishon Vijay Abraham I break; 2498*85d5e707SKishon Vijay Abraham I case DWC3_DEVICE_EVENT_WAKEUP: 2499*85d5e707SKishon Vijay Abraham I dwc3_gadget_wakeup_interrupt(dwc); 2500*85d5e707SKishon Vijay Abraham I break; 2501*85d5e707SKishon Vijay Abraham I case DWC3_DEVICE_EVENT_HIBER_REQ: 2502*85d5e707SKishon Vijay Abraham I if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation, 2503*85d5e707SKishon Vijay Abraham I "unexpected hibernation event\n")) 2504*85d5e707SKishon Vijay Abraham I break; 2505*85d5e707SKishon Vijay Abraham I 2506*85d5e707SKishon Vijay Abraham I dwc3_gadget_hibernation_interrupt(dwc, event->event_info); 2507*85d5e707SKishon Vijay Abraham I break; 2508*85d5e707SKishon Vijay Abraham I case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: 2509*85d5e707SKishon Vijay Abraham I dwc3_gadget_linksts_change_interrupt(dwc, event->event_info); 2510*85d5e707SKishon Vijay Abraham I break; 2511*85d5e707SKishon Vijay Abraham I case DWC3_DEVICE_EVENT_EOPF: 2512*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "End of Periodic Frame\n"); 2513*85d5e707SKishon Vijay Abraham I break; 2514*85d5e707SKishon Vijay Abraham I case DWC3_DEVICE_EVENT_SOF: 2515*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "Start of Periodic Frame\n"); 2516*85d5e707SKishon Vijay Abraham I break; 2517*85d5e707SKishon Vijay Abraham I case DWC3_DEVICE_EVENT_ERRATIC_ERROR: 2518*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "Erratic Error\n"); 2519*85d5e707SKishon Vijay Abraham I break; 2520*85d5e707SKishon Vijay Abraham I case DWC3_DEVICE_EVENT_CMD_CMPL: 2521*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "Command Complete\n"); 2522*85d5e707SKishon Vijay Abraham I break; 2523*85d5e707SKishon Vijay Abraham I case DWC3_DEVICE_EVENT_OVERFLOW: 2524*85d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "Overflow\n"); 2525*85d5e707SKishon Vijay Abraham I break; 2526*85d5e707SKishon Vijay Abraham I default: 2527*85d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type); 2528*85d5e707SKishon Vijay Abraham I } 2529*85d5e707SKishon Vijay Abraham I } 2530*85d5e707SKishon Vijay Abraham I 2531*85d5e707SKishon Vijay Abraham I static void dwc3_process_event_entry(struct dwc3 *dwc, 2532*85d5e707SKishon Vijay Abraham I const union dwc3_event *event) 2533*85d5e707SKishon Vijay Abraham I { 2534*85d5e707SKishon Vijay Abraham I trace_dwc3_event(event->raw); 2535*85d5e707SKishon Vijay Abraham I 2536*85d5e707SKishon Vijay Abraham I /* Endpoint IRQ, handle it and return early */ 2537*85d5e707SKishon Vijay Abraham I if (event->type.is_devspec == 0) { 2538*85d5e707SKishon Vijay Abraham I /* depevt */ 2539*85d5e707SKishon Vijay Abraham I return dwc3_endpoint_interrupt(dwc, &event->depevt); 2540*85d5e707SKishon Vijay Abraham I } 2541*85d5e707SKishon Vijay Abraham I 2542*85d5e707SKishon Vijay Abraham I switch (event->type.type) { 2543*85d5e707SKishon Vijay Abraham I case DWC3_EVENT_TYPE_DEV: 2544*85d5e707SKishon Vijay Abraham I dwc3_gadget_interrupt(dwc, &event->devt); 2545*85d5e707SKishon Vijay Abraham I break; 2546*85d5e707SKishon Vijay Abraham I /* REVISIT what to do with Carkit and I2C events ? */ 2547*85d5e707SKishon Vijay Abraham I default: 2548*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "UNKNOWN IRQ type %d\n", event->raw); 2549*85d5e707SKishon Vijay Abraham I } 2550*85d5e707SKishon Vijay Abraham I } 2551*85d5e707SKishon Vijay Abraham I 2552*85d5e707SKishon Vijay Abraham I static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) 2553*85d5e707SKishon Vijay Abraham I { 2554*85d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 2555*85d5e707SKishon Vijay Abraham I irqreturn_t ret = IRQ_NONE; 2556*85d5e707SKishon Vijay Abraham I int left; 2557*85d5e707SKishon Vijay Abraham I u32 reg; 2558*85d5e707SKishon Vijay Abraham I 2559*85d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[buf]; 2560*85d5e707SKishon Vijay Abraham I left = evt->count; 2561*85d5e707SKishon Vijay Abraham I 2562*85d5e707SKishon Vijay Abraham I if (!(evt->flags & DWC3_EVENT_PENDING)) 2563*85d5e707SKishon Vijay Abraham I return IRQ_NONE; 2564*85d5e707SKishon Vijay Abraham I 2565*85d5e707SKishon Vijay Abraham I while (left > 0) { 2566*85d5e707SKishon Vijay Abraham I union dwc3_event event; 2567*85d5e707SKishon Vijay Abraham I 2568*85d5e707SKishon Vijay Abraham I event.raw = *(u32 *) (evt->buf + evt->lpos); 2569*85d5e707SKishon Vijay Abraham I 2570*85d5e707SKishon Vijay Abraham I dwc3_process_event_entry(dwc, &event); 2571*85d5e707SKishon Vijay Abraham I 2572*85d5e707SKishon Vijay Abraham I /* 2573*85d5e707SKishon Vijay Abraham I * FIXME we wrap around correctly to the next entry as 2574*85d5e707SKishon Vijay Abraham I * almost all entries are 4 bytes in size. There is one 2575*85d5e707SKishon Vijay Abraham I * entry which has 12 bytes which is a regular entry 2576*85d5e707SKishon Vijay Abraham I * followed by 8 bytes data. ATM I don't know how 2577*85d5e707SKishon Vijay Abraham I * things are organized if we get next to the a 2578*85d5e707SKishon Vijay Abraham I * boundary so I worry about that once we try to handle 2579*85d5e707SKishon Vijay Abraham I * that. 2580*85d5e707SKishon Vijay Abraham I */ 2581*85d5e707SKishon Vijay Abraham I evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; 2582*85d5e707SKishon Vijay Abraham I left -= 4; 2583*85d5e707SKishon Vijay Abraham I 2584*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4); 2585*85d5e707SKishon Vijay Abraham I } 2586*85d5e707SKishon Vijay Abraham I 2587*85d5e707SKishon Vijay Abraham I evt->count = 0; 2588*85d5e707SKishon Vijay Abraham I evt->flags &= ~DWC3_EVENT_PENDING; 2589*85d5e707SKishon Vijay Abraham I ret = IRQ_HANDLED; 2590*85d5e707SKishon Vijay Abraham I 2591*85d5e707SKishon Vijay Abraham I /* Unmask interrupt */ 2592*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf)); 2593*85d5e707SKishon Vijay Abraham I reg &= ~DWC3_GEVNTSIZ_INTMASK; 2594*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); 2595*85d5e707SKishon Vijay Abraham I 2596*85d5e707SKishon Vijay Abraham I return ret; 2597*85d5e707SKishon Vijay Abraham I } 2598*85d5e707SKishon Vijay Abraham I 2599*85d5e707SKishon Vijay Abraham I static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) 2600*85d5e707SKishon Vijay Abraham I { 2601*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = _dwc; 2602*85d5e707SKishon Vijay Abraham I unsigned long flags; 2603*85d5e707SKishon Vijay Abraham I irqreturn_t ret = IRQ_NONE; 2604*85d5e707SKishon Vijay Abraham I int i; 2605*85d5e707SKishon Vijay Abraham I 2606*85d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 2607*85d5e707SKishon Vijay Abraham I 2608*85d5e707SKishon Vijay Abraham I for (i = 0; i < dwc->num_event_buffers; i++) 2609*85d5e707SKishon Vijay Abraham I ret |= dwc3_process_event_buf(dwc, i); 2610*85d5e707SKishon Vijay Abraham I 2611*85d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 2612*85d5e707SKishon Vijay Abraham I 2613*85d5e707SKishon Vijay Abraham I return ret; 2614*85d5e707SKishon Vijay Abraham I } 2615*85d5e707SKishon Vijay Abraham I 2616*85d5e707SKishon Vijay Abraham I static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf) 2617*85d5e707SKishon Vijay Abraham I { 2618*85d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 2619*85d5e707SKishon Vijay Abraham I u32 count; 2620*85d5e707SKishon Vijay Abraham I u32 reg; 2621*85d5e707SKishon Vijay Abraham I 2622*85d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[buf]; 2623*85d5e707SKishon Vijay Abraham I 2624*85d5e707SKishon Vijay Abraham I count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf)); 2625*85d5e707SKishon Vijay Abraham I count &= DWC3_GEVNTCOUNT_MASK; 2626*85d5e707SKishon Vijay Abraham I if (!count) 2627*85d5e707SKishon Vijay Abraham I return IRQ_NONE; 2628*85d5e707SKishon Vijay Abraham I 2629*85d5e707SKishon Vijay Abraham I evt->count = count; 2630*85d5e707SKishon Vijay Abraham I evt->flags |= DWC3_EVENT_PENDING; 2631*85d5e707SKishon Vijay Abraham I 2632*85d5e707SKishon Vijay Abraham I /* Mask interrupt */ 2633*85d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf)); 2634*85d5e707SKishon Vijay Abraham I reg |= DWC3_GEVNTSIZ_INTMASK; 2635*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); 2636*85d5e707SKishon Vijay Abraham I 2637*85d5e707SKishon Vijay Abraham I return IRQ_WAKE_THREAD; 2638*85d5e707SKishon Vijay Abraham I } 2639*85d5e707SKishon Vijay Abraham I 2640*85d5e707SKishon Vijay Abraham I static irqreturn_t dwc3_interrupt(int irq, void *_dwc) 2641*85d5e707SKishon Vijay Abraham I { 2642*85d5e707SKishon Vijay Abraham I struct dwc3 *dwc = _dwc; 2643*85d5e707SKishon Vijay Abraham I int i; 2644*85d5e707SKishon Vijay Abraham I irqreturn_t ret = IRQ_NONE; 2645*85d5e707SKishon Vijay Abraham I 2646*85d5e707SKishon Vijay Abraham I spin_lock(&dwc->lock); 2647*85d5e707SKishon Vijay Abraham I 2648*85d5e707SKishon Vijay Abraham I for (i = 0; i < dwc->num_event_buffers; i++) { 2649*85d5e707SKishon Vijay Abraham I irqreturn_t status; 2650*85d5e707SKishon Vijay Abraham I 2651*85d5e707SKishon Vijay Abraham I status = dwc3_check_event_buf(dwc, i); 2652*85d5e707SKishon Vijay Abraham I if (status == IRQ_WAKE_THREAD) 2653*85d5e707SKishon Vijay Abraham I ret = status; 2654*85d5e707SKishon Vijay Abraham I } 2655*85d5e707SKishon Vijay Abraham I 2656*85d5e707SKishon Vijay Abraham I spin_unlock(&dwc->lock); 2657*85d5e707SKishon Vijay Abraham I 2658*85d5e707SKishon Vijay Abraham I return ret; 2659*85d5e707SKishon Vijay Abraham I } 2660*85d5e707SKishon Vijay Abraham I 2661*85d5e707SKishon Vijay Abraham I /** 2662*85d5e707SKishon Vijay Abraham I * dwc3_gadget_init - Initializes gadget related registers 2663*85d5e707SKishon Vijay Abraham I * @dwc: pointer to our controller context structure 2664*85d5e707SKishon Vijay Abraham I * 2665*85d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. 2666*85d5e707SKishon Vijay Abraham I */ 2667*85d5e707SKishon Vijay Abraham I int dwc3_gadget_init(struct dwc3 *dwc) 2668*85d5e707SKishon Vijay Abraham I { 2669*85d5e707SKishon Vijay Abraham I int ret; 2670*85d5e707SKishon Vijay Abraham I 2671*85d5e707SKishon Vijay Abraham I dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req), 2672*85d5e707SKishon Vijay Abraham I &dwc->ctrl_req_addr, GFP_KERNEL); 2673*85d5e707SKishon Vijay Abraham I if (!dwc->ctrl_req) { 2674*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to allocate ctrl request\n"); 2675*85d5e707SKishon Vijay Abraham I ret = -ENOMEM; 2676*85d5e707SKishon Vijay Abraham I goto err0; 2677*85d5e707SKishon Vijay Abraham I } 2678*85d5e707SKishon Vijay Abraham I 2679*85d5e707SKishon Vijay Abraham I dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb), 2680*85d5e707SKishon Vijay Abraham I &dwc->ep0_trb_addr, GFP_KERNEL); 2681*85d5e707SKishon Vijay Abraham I if (!dwc->ep0_trb) { 2682*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to allocate ep0 trb\n"); 2683*85d5e707SKishon Vijay Abraham I ret = -ENOMEM; 2684*85d5e707SKishon Vijay Abraham I goto err1; 2685*85d5e707SKishon Vijay Abraham I } 2686*85d5e707SKishon Vijay Abraham I 2687*85d5e707SKishon Vijay Abraham I dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL); 2688*85d5e707SKishon Vijay Abraham I if (!dwc->setup_buf) { 2689*85d5e707SKishon Vijay Abraham I ret = -ENOMEM; 2690*85d5e707SKishon Vijay Abraham I goto err2; 2691*85d5e707SKishon Vijay Abraham I } 2692*85d5e707SKishon Vijay Abraham I 2693*85d5e707SKishon Vijay Abraham I dwc->ep0_bounce = dma_alloc_coherent(dwc->dev, 2694*85d5e707SKishon Vijay Abraham I DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr, 2695*85d5e707SKishon Vijay Abraham I GFP_KERNEL); 2696*85d5e707SKishon Vijay Abraham I if (!dwc->ep0_bounce) { 2697*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n"); 2698*85d5e707SKishon Vijay Abraham I ret = -ENOMEM; 2699*85d5e707SKishon Vijay Abraham I goto err3; 2700*85d5e707SKishon Vijay Abraham I } 2701*85d5e707SKishon Vijay Abraham I 2702*85d5e707SKishon Vijay Abraham I dwc->gadget.ops = &dwc3_gadget_ops; 2703*85d5e707SKishon Vijay Abraham I dwc->gadget.max_speed = USB_SPEED_SUPER; 2704*85d5e707SKishon Vijay Abraham I dwc->gadget.speed = USB_SPEED_UNKNOWN; 2705*85d5e707SKishon Vijay Abraham I dwc->gadget.sg_supported = true; 2706*85d5e707SKishon Vijay Abraham I dwc->gadget.name = "dwc3-gadget"; 2707*85d5e707SKishon Vijay Abraham I 2708*85d5e707SKishon Vijay Abraham I /* 2709*85d5e707SKishon Vijay Abraham I * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize 2710*85d5e707SKishon Vijay Abraham I * on ep out. 2711*85d5e707SKishon Vijay Abraham I */ 2712*85d5e707SKishon Vijay Abraham I dwc->gadget.quirk_ep_out_aligned_size = true; 2713*85d5e707SKishon Vijay Abraham I 2714*85d5e707SKishon Vijay Abraham I /* 2715*85d5e707SKishon Vijay Abraham I * REVISIT: Here we should clear all pending IRQs to be 2716*85d5e707SKishon Vijay Abraham I * sure we're starting from a well known location. 2717*85d5e707SKishon Vijay Abraham I */ 2718*85d5e707SKishon Vijay Abraham I 2719*85d5e707SKishon Vijay Abraham I ret = dwc3_gadget_init_endpoints(dwc); 2720*85d5e707SKishon Vijay Abraham I if (ret) 2721*85d5e707SKishon Vijay Abraham I goto err4; 2722*85d5e707SKishon Vijay Abraham I 2723*85d5e707SKishon Vijay Abraham I ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); 2724*85d5e707SKishon Vijay Abraham I if (ret) { 2725*85d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to register udc\n"); 2726*85d5e707SKishon Vijay Abraham I goto err4; 2727*85d5e707SKishon Vijay Abraham I } 2728*85d5e707SKishon Vijay Abraham I 2729*85d5e707SKishon Vijay Abraham I return 0; 2730*85d5e707SKishon Vijay Abraham I 2731*85d5e707SKishon Vijay Abraham I err4: 2732*85d5e707SKishon Vijay Abraham I dwc3_gadget_free_endpoints(dwc); 2733*85d5e707SKishon Vijay Abraham I dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE, 2734*85d5e707SKishon Vijay Abraham I dwc->ep0_bounce, dwc->ep0_bounce_addr); 2735*85d5e707SKishon Vijay Abraham I 2736*85d5e707SKishon Vijay Abraham I err3: 2737*85d5e707SKishon Vijay Abraham I kfree(dwc->setup_buf); 2738*85d5e707SKishon Vijay Abraham I 2739*85d5e707SKishon Vijay Abraham I err2: 2740*85d5e707SKishon Vijay Abraham I dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb), 2741*85d5e707SKishon Vijay Abraham I dwc->ep0_trb, dwc->ep0_trb_addr); 2742*85d5e707SKishon Vijay Abraham I 2743*85d5e707SKishon Vijay Abraham I err1: 2744*85d5e707SKishon Vijay Abraham I dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req), 2745*85d5e707SKishon Vijay Abraham I dwc->ctrl_req, dwc->ctrl_req_addr); 2746*85d5e707SKishon Vijay Abraham I 2747*85d5e707SKishon Vijay Abraham I err0: 2748*85d5e707SKishon Vijay Abraham I return ret; 2749*85d5e707SKishon Vijay Abraham I } 2750*85d5e707SKishon Vijay Abraham I 2751*85d5e707SKishon Vijay Abraham I /* -------------------------------------------------------------------------- */ 2752*85d5e707SKishon Vijay Abraham I 2753*85d5e707SKishon Vijay Abraham I void dwc3_gadget_exit(struct dwc3 *dwc) 2754*85d5e707SKishon Vijay Abraham I { 2755*85d5e707SKishon Vijay Abraham I usb_del_gadget_udc(&dwc->gadget); 2756*85d5e707SKishon Vijay Abraham I 2757*85d5e707SKishon Vijay Abraham I dwc3_gadget_free_endpoints(dwc); 2758*85d5e707SKishon Vijay Abraham I 2759*85d5e707SKishon Vijay Abraham I dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE, 2760*85d5e707SKishon Vijay Abraham I dwc->ep0_bounce, dwc->ep0_bounce_addr); 2761*85d5e707SKishon Vijay Abraham I 2762*85d5e707SKishon Vijay Abraham I kfree(dwc->setup_buf); 2763*85d5e707SKishon Vijay Abraham I 2764*85d5e707SKishon Vijay Abraham I dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb), 2765*85d5e707SKishon Vijay Abraham I dwc->ep0_trb, dwc->ep0_trb_addr); 2766*85d5e707SKishon Vijay Abraham I 2767*85d5e707SKishon Vijay Abraham I dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req), 2768*85d5e707SKishon Vijay Abraham I dwc->ctrl_req, dwc->ctrl_req_addr); 2769*85d5e707SKishon Vijay Abraham I } 2770*85d5e707SKishon Vijay Abraham I 2771*85d5e707SKishon Vijay Abraham I int dwc3_gadget_suspend(struct dwc3 *dwc) 2772*85d5e707SKishon Vijay Abraham I { 2773*85d5e707SKishon Vijay Abraham I if (dwc->pullups_connected) { 2774*85d5e707SKishon Vijay Abraham I dwc3_gadget_disable_irq(dwc); 2775*85d5e707SKishon Vijay Abraham I dwc3_gadget_run_stop(dwc, true, true); 2776*85d5e707SKishon Vijay Abraham I } 2777*85d5e707SKishon Vijay Abraham I 2778*85d5e707SKishon Vijay Abraham I __dwc3_gadget_ep_disable(dwc->eps[0]); 2779*85d5e707SKishon Vijay Abraham I __dwc3_gadget_ep_disable(dwc->eps[1]); 2780*85d5e707SKishon Vijay Abraham I 2781*85d5e707SKishon Vijay Abraham I dwc->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG); 2782*85d5e707SKishon Vijay Abraham I 2783*85d5e707SKishon Vijay Abraham I return 0; 2784*85d5e707SKishon Vijay Abraham I } 2785*85d5e707SKishon Vijay Abraham I 2786*85d5e707SKishon Vijay Abraham I int dwc3_gadget_resume(struct dwc3 *dwc) 2787*85d5e707SKishon Vijay Abraham I { 2788*85d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 2789*85d5e707SKishon Vijay Abraham I int ret; 2790*85d5e707SKishon Vijay Abraham I 2791*85d5e707SKishon Vijay Abraham I /* Start with SuperSpeed Default */ 2792*85d5e707SKishon Vijay Abraham I dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); 2793*85d5e707SKishon Vijay Abraham I 2794*85d5e707SKishon Vijay Abraham I dep = dwc->eps[0]; 2795*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, 2796*85d5e707SKishon Vijay Abraham I false); 2797*85d5e707SKishon Vijay Abraham I if (ret) 2798*85d5e707SKishon Vijay Abraham I goto err0; 2799*85d5e707SKishon Vijay Abraham I 2800*85d5e707SKishon Vijay Abraham I dep = dwc->eps[1]; 2801*85d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, 2802*85d5e707SKishon Vijay Abraham I false); 2803*85d5e707SKishon Vijay Abraham I if (ret) 2804*85d5e707SKishon Vijay Abraham I goto err1; 2805*85d5e707SKishon Vijay Abraham I 2806*85d5e707SKishon Vijay Abraham I /* begin to receive SETUP packets */ 2807*85d5e707SKishon Vijay Abraham I dwc->ep0state = EP0_SETUP_PHASE; 2808*85d5e707SKishon Vijay Abraham I dwc3_ep0_out_start(dwc); 2809*85d5e707SKishon Vijay Abraham I 2810*85d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg); 2811*85d5e707SKishon Vijay Abraham I 2812*85d5e707SKishon Vijay Abraham I if (dwc->pullups_connected) { 2813*85d5e707SKishon Vijay Abraham I dwc3_gadget_enable_irq(dwc); 2814*85d5e707SKishon Vijay Abraham I dwc3_gadget_run_stop(dwc, true, false); 2815*85d5e707SKishon Vijay Abraham I } 2816*85d5e707SKishon Vijay Abraham I 2817*85d5e707SKishon Vijay Abraham I return 0; 2818*85d5e707SKishon Vijay Abraham I 2819*85d5e707SKishon Vijay Abraham I err1: 2820*85d5e707SKishon Vijay Abraham I __dwc3_gadget_ep_disable(dwc->eps[0]); 2821*85d5e707SKishon Vijay Abraham I 2822*85d5e707SKishon Vijay Abraham I err0: 2823*85d5e707SKishon Vijay Abraham I return ret; 2824*85d5e707SKishon Vijay Abraham I } 2825