185d5e707SKishon Vijay Abraham I /** 285d5e707SKishon Vijay Abraham I * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling 385d5e707SKishon Vijay Abraham I * 430c31d58SKishon Vijay Abraham I * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com 585d5e707SKishon Vijay Abraham I * 685d5e707SKishon Vijay Abraham I * Authors: Felipe Balbi <balbi@ti.com>, 785d5e707SKishon Vijay Abraham I * Sebastian Andrzej Siewior <bigeasy@linutronix.de> 885d5e707SKishon Vijay Abraham I * 930c31d58SKishon Vijay Abraham I * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/ep0.c) and ported 1030c31d58SKishon Vijay Abraham I * to uboot. 1185d5e707SKishon Vijay Abraham I * 1230c31d58SKishon Vijay Abraham I * commit c00552ebaf : Merge 3.18-rc7 into usb-next 1330c31d58SKishon Vijay Abraham I * 1430c31d58SKishon Vijay Abraham I * SPDX-License-Identifier: GPL-2.0 1585d5e707SKishon Vijay Abraham I */ 1685d5e707SKishon Vijay Abraham I 1785d5e707SKishon Vijay Abraham I #include <linux/kernel.h> 1885d5e707SKishon Vijay Abraham I #include <linux/list.h> 1985d5e707SKishon Vijay Abraham I 2085d5e707SKishon Vijay Abraham I #include <linux/usb/ch9.h> 2185d5e707SKishon Vijay Abraham I #include <linux/usb/gadget.h> 2285d5e707SKishon Vijay Abraham I #include <linux/usb/composite.h> 2385d5e707SKishon Vijay Abraham I 2485d5e707SKishon Vijay Abraham I #include "core.h" 2585d5e707SKishon Vijay Abraham I #include "gadget.h" 2685d5e707SKishon Vijay Abraham I #include "io.h" 2785d5e707SKishon Vijay Abraham I 28b6d959acSKishon Vijay Abraham I #include "linux-compat.h" 29b6d959acSKishon Vijay Abraham I 3085d5e707SKishon Vijay Abraham I static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); 3185d5e707SKishon Vijay Abraham I static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, 3285d5e707SKishon Vijay Abraham I struct dwc3_ep *dep, struct dwc3_request *req); 3385d5e707SKishon Vijay Abraham I 3485d5e707SKishon Vijay Abraham I static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) 3585d5e707SKishon Vijay Abraham I { 3685d5e707SKishon Vijay Abraham I switch (state) { 3785d5e707SKishon Vijay Abraham I case EP0_UNCONNECTED: 3885d5e707SKishon Vijay Abraham I return "Unconnected"; 3985d5e707SKishon Vijay Abraham I case EP0_SETUP_PHASE: 4085d5e707SKishon Vijay Abraham I return "Setup Phase"; 4185d5e707SKishon Vijay Abraham I case EP0_DATA_PHASE: 4285d5e707SKishon Vijay Abraham I return "Data Phase"; 4385d5e707SKishon Vijay Abraham I case EP0_STATUS_PHASE: 4485d5e707SKishon Vijay Abraham I return "Status Phase"; 4585d5e707SKishon Vijay Abraham I default: 4685d5e707SKishon Vijay Abraham I return "UNKNOWN"; 4785d5e707SKishon Vijay Abraham I } 4885d5e707SKishon Vijay Abraham I } 4985d5e707SKishon Vijay Abraham I 5085d5e707SKishon Vijay Abraham I static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, 51*8d488f3eSKishon Vijay Abraham I u32 len, u32 type, unsigned chain) 5285d5e707SKishon Vijay Abraham I { 5385d5e707SKishon Vijay Abraham I struct dwc3_gadget_ep_cmd_params params; 5485d5e707SKishon Vijay Abraham I struct dwc3_trb *trb; 5585d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 5685d5e707SKishon Vijay Abraham I 5785d5e707SKishon Vijay Abraham I int ret; 5885d5e707SKishon Vijay Abraham I 5985d5e707SKishon Vijay Abraham I dep = dwc->eps[epnum]; 6085d5e707SKishon Vijay Abraham I if (dep->flags & DWC3_EP_BUSY) { 619de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "%s still busy", dep->name); 6285d5e707SKishon Vijay Abraham I return 0; 6385d5e707SKishon Vijay Abraham I } 6485d5e707SKishon Vijay Abraham I 65*8d488f3eSKishon Vijay Abraham I trb = &dwc->ep0_trb[dep->free_slot]; 66*8d488f3eSKishon Vijay Abraham I 67*8d488f3eSKishon Vijay Abraham I if (chain) 68*8d488f3eSKishon Vijay Abraham I dep->free_slot++; 6985d5e707SKishon Vijay Abraham I 7085d5e707SKishon Vijay Abraham I trb->bpl = lower_32_bits(buf_dma); 7185d5e707SKishon Vijay Abraham I trb->bph = upper_32_bits(buf_dma); 7285d5e707SKishon Vijay Abraham I trb->size = len; 7385d5e707SKishon Vijay Abraham I trb->ctrl = type; 7485d5e707SKishon Vijay Abraham I 7585d5e707SKishon Vijay Abraham I trb->ctrl |= (DWC3_TRB_CTRL_HWO 7685d5e707SKishon Vijay Abraham I | DWC3_TRB_CTRL_ISP_IMI); 7785d5e707SKishon Vijay Abraham I 78*8d488f3eSKishon Vijay Abraham I if (chain) 79*8d488f3eSKishon Vijay Abraham I trb->ctrl |= DWC3_TRB_CTRL_CHN; 80*8d488f3eSKishon Vijay Abraham I else 81*8d488f3eSKishon Vijay Abraham I trb->ctrl |= (DWC3_TRB_CTRL_IOC 82*8d488f3eSKishon Vijay Abraham I | DWC3_TRB_CTRL_LST); 83*8d488f3eSKishon Vijay Abraham I 84526a50f8SKishon Vijay Abraham I dwc3_flush_cache((int)buf_dma, len); 85526a50f8SKishon Vijay Abraham I dwc3_flush_cache((int)trb, sizeof(*trb)); 86526a50f8SKishon Vijay Abraham I 87*8d488f3eSKishon Vijay Abraham I if (chain) 88*8d488f3eSKishon Vijay Abraham I return 0; 89*8d488f3eSKishon Vijay Abraham I 9085d5e707SKishon Vijay Abraham I memset(¶ms, 0, sizeof(params)); 9185d5e707SKishon Vijay Abraham I params.param0 = upper_32_bits(dwc->ep0_trb_addr); 9285d5e707SKishon Vijay Abraham I params.param1 = lower_32_bits(dwc->ep0_trb_addr); 9385d5e707SKishon Vijay Abraham I 9485d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, 9585d5e707SKishon Vijay Abraham I DWC3_DEPCMD_STARTTRANSFER, ¶ms); 9685d5e707SKishon Vijay Abraham I if (ret < 0) { 979de1115dSKishon Vijay Abraham I dev_dbg(dwc->dev, "%s STARTTRANSFER failed", dep->name); 9885d5e707SKishon Vijay Abraham I return ret; 9985d5e707SKishon Vijay Abraham I } 10085d5e707SKishon Vijay Abraham I 10185d5e707SKishon Vijay Abraham I dep->flags |= DWC3_EP_BUSY; 10285d5e707SKishon Vijay Abraham I dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc, 10385d5e707SKishon Vijay Abraham I dep->number); 10485d5e707SKishon Vijay Abraham I 10585d5e707SKishon Vijay Abraham I dwc->ep0_next_event = DWC3_EP0_COMPLETE; 10685d5e707SKishon Vijay Abraham I 10785d5e707SKishon Vijay Abraham I return 0; 10885d5e707SKishon Vijay Abraham I } 10985d5e707SKishon Vijay Abraham I 11085d5e707SKishon Vijay Abraham I static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, 11185d5e707SKishon Vijay Abraham I struct dwc3_request *req) 11285d5e707SKishon Vijay Abraham I { 11385d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 11485d5e707SKishon Vijay Abraham I 11585d5e707SKishon Vijay Abraham I req->request.actual = 0; 11685d5e707SKishon Vijay Abraham I req->request.status = -EINPROGRESS; 11785d5e707SKishon Vijay Abraham I req->epnum = dep->number; 11885d5e707SKishon Vijay Abraham I 11985d5e707SKishon Vijay Abraham I list_add_tail(&req->list, &dep->request_list); 12085d5e707SKishon Vijay Abraham I 12185d5e707SKishon Vijay Abraham I /* 12285d5e707SKishon Vijay Abraham I * Gadget driver might not be quick enough to queue a request 12385d5e707SKishon Vijay Abraham I * before we get a Transfer Not Ready event on this endpoint. 12485d5e707SKishon Vijay Abraham I * 12585d5e707SKishon Vijay Abraham I * In that case, we will set DWC3_EP_PENDING_REQUEST. When that 12685d5e707SKishon Vijay Abraham I * flag is set, it's telling us that as soon as Gadget queues the 12785d5e707SKishon Vijay Abraham I * required request, we should kick the transfer here because the 12885d5e707SKishon Vijay Abraham I * IRQ we were waiting for is long gone. 12985d5e707SKishon Vijay Abraham I */ 13085d5e707SKishon Vijay Abraham I if (dep->flags & DWC3_EP_PENDING_REQUEST) { 13185d5e707SKishon Vijay Abraham I unsigned direction; 13285d5e707SKishon Vijay Abraham I 13385d5e707SKishon Vijay Abraham I direction = !!(dep->flags & DWC3_EP0_DIR_IN); 13485d5e707SKishon Vijay Abraham I 13585d5e707SKishon Vijay Abraham I if (dwc->ep0state != EP0_DATA_PHASE) { 13685d5e707SKishon Vijay Abraham I dev_WARN(dwc->dev, "Unexpected pending request\n"); 13785d5e707SKishon Vijay Abraham I return 0; 13885d5e707SKishon Vijay Abraham I } 13985d5e707SKishon Vijay Abraham I 14085d5e707SKishon Vijay Abraham I __dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req); 14185d5e707SKishon Vijay Abraham I 14285d5e707SKishon Vijay Abraham I dep->flags &= ~(DWC3_EP_PENDING_REQUEST | 14385d5e707SKishon Vijay Abraham I DWC3_EP0_DIR_IN); 14485d5e707SKishon Vijay Abraham I 14585d5e707SKishon Vijay Abraham I return 0; 14685d5e707SKishon Vijay Abraham I } 14785d5e707SKishon Vijay Abraham I 14885d5e707SKishon Vijay Abraham I /* 14985d5e707SKishon Vijay Abraham I * In case gadget driver asked us to delay the STATUS phase, 15085d5e707SKishon Vijay Abraham I * handle it here. 15185d5e707SKishon Vijay Abraham I */ 15285d5e707SKishon Vijay Abraham I if (dwc->delayed_status) { 15385d5e707SKishon Vijay Abraham I unsigned direction; 15485d5e707SKishon Vijay Abraham I 15585d5e707SKishon Vijay Abraham I direction = !dwc->ep0_expect_in; 15685d5e707SKishon Vijay Abraham I dwc->delayed_status = false; 15785d5e707SKishon Vijay Abraham I usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED); 15885d5e707SKishon Vijay Abraham I 15985d5e707SKishon Vijay Abraham I if (dwc->ep0state == EP0_STATUS_PHASE) 16085d5e707SKishon Vijay Abraham I __dwc3_ep0_do_control_status(dwc, dwc->eps[direction]); 16185d5e707SKishon Vijay Abraham I else 1629de1115dSKishon Vijay Abraham I dev_dbg(dwc->dev, "too early for delayed status"); 16385d5e707SKishon Vijay Abraham I 16485d5e707SKishon Vijay Abraham I return 0; 16585d5e707SKishon Vijay Abraham I } 16685d5e707SKishon Vijay Abraham I 16785d5e707SKishon Vijay Abraham I /* 16885d5e707SKishon Vijay Abraham I * Unfortunately we have uncovered a limitation wrt the Data Phase. 16985d5e707SKishon Vijay Abraham I * 17085d5e707SKishon Vijay Abraham I * Section 9.4 says we can wait for the XferNotReady(DATA) event to 17185d5e707SKishon Vijay Abraham I * come before issueing Start Transfer command, but if we do, we will 17285d5e707SKishon Vijay Abraham I * miss situations where the host starts another SETUP phase instead of 17385d5e707SKishon Vijay Abraham I * the DATA phase. Such cases happen at least on TD.7.6 of the Link 17485d5e707SKishon Vijay Abraham I * Layer Compliance Suite. 17585d5e707SKishon Vijay Abraham I * 17685d5e707SKishon Vijay Abraham I * The problem surfaces due to the fact that in case of back-to-back 17785d5e707SKishon Vijay Abraham I * SETUP packets there will be no XferNotReady(DATA) generated and we 17885d5e707SKishon Vijay Abraham I * will be stuck waiting for XferNotReady(DATA) forever. 17985d5e707SKishon Vijay Abraham I * 18085d5e707SKishon Vijay Abraham I * By looking at tables 9-13 and 9-14 of the Databook, we can see that 18185d5e707SKishon Vijay Abraham I * it tells us to start Data Phase right away. It also mentions that if 18285d5e707SKishon Vijay Abraham I * we receive a SETUP phase instead of the DATA phase, core will issue 18385d5e707SKishon Vijay Abraham I * XferComplete for the DATA phase, before actually initiating it in 18485d5e707SKishon Vijay Abraham I * the wire, with the TRB's status set to "SETUP_PENDING". Such status 18585d5e707SKishon Vijay Abraham I * can only be used to print some debugging logs, as the core expects 18685d5e707SKishon Vijay Abraham I * us to go through to the STATUS phase and start a CONTROL_STATUS TRB, 18785d5e707SKishon Vijay Abraham I * just so it completes right away, without transferring anything and, 18885d5e707SKishon Vijay Abraham I * only then, we can go back to the SETUP phase. 18985d5e707SKishon Vijay Abraham I * 19085d5e707SKishon Vijay Abraham I * Because of this scenario, SNPS decided to change the programming 19185d5e707SKishon Vijay Abraham I * model of control transfers and support on-demand transfers only for 19285d5e707SKishon Vijay Abraham I * the STATUS phase. To fix the issue we have now, we will always wait 19385d5e707SKishon Vijay Abraham I * for gadget driver to queue the DATA phase's struct usb_request, then 19485d5e707SKishon Vijay Abraham I * start it right away. 19585d5e707SKishon Vijay Abraham I * 19685d5e707SKishon Vijay Abraham I * If we're actually in a 2-stage transfer, we will wait for 19785d5e707SKishon Vijay Abraham I * XferNotReady(STATUS). 19885d5e707SKishon Vijay Abraham I */ 19985d5e707SKishon Vijay Abraham I if (dwc->three_stage_setup) { 20085d5e707SKishon Vijay Abraham I unsigned direction; 20185d5e707SKishon Vijay Abraham I 20285d5e707SKishon Vijay Abraham I direction = dwc->ep0_expect_in; 20385d5e707SKishon Vijay Abraham I dwc->ep0state = EP0_DATA_PHASE; 20485d5e707SKishon Vijay Abraham I 20585d5e707SKishon Vijay Abraham I __dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req); 20685d5e707SKishon Vijay Abraham I 20785d5e707SKishon Vijay Abraham I dep->flags &= ~DWC3_EP0_DIR_IN; 20885d5e707SKishon Vijay Abraham I } 20985d5e707SKishon Vijay Abraham I 21085d5e707SKishon Vijay Abraham I return 0; 21185d5e707SKishon Vijay Abraham I } 21285d5e707SKishon Vijay Abraham I 21385d5e707SKishon Vijay Abraham I int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, 21485d5e707SKishon Vijay Abraham I gfp_t gfp_flags) 21585d5e707SKishon Vijay Abraham I { 21685d5e707SKishon Vijay Abraham I struct dwc3_request *req = to_dwc3_request(request); 21785d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = to_dwc3_ep(ep); 21885d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 21985d5e707SKishon Vijay Abraham I 22085d5e707SKishon Vijay Abraham I unsigned long flags; 22185d5e707SKishon Vijay Abraham I 22285d5e707SKishon Vijay Abraham I int ret; 22385d5e707SKishon Vijay Abraham I 22485d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 22585d5e707SKishon Vijay Abraham I if (!dep->endpoint.desc) { 2269de1115dSKishon Vijay Abraham I dev_dbg(dwc->dev, "trying to queue request %p to disabled %s", 22785d5e707SKishon Vijay Abraham I request, dep->name); 22885d5e707SKishon Vijay Abraham I ret = -ESHUTDOWN; 22985d5e707SKishon Vijay Abraham I goto out; 23085d5e707SKishon Vijay Abraham I } 23185d5e707SKishon Vijay Abraham I 23285d5e707SKishon Vijay Abraham I /* we share one TRB for ep0/1 */ 23385d5e707SKishon Vijay Abraham I if (!list_empty(&dep->request_list)) { 23485d5e707SKishon Vijay Abraham I ret = -EBUSY; 23585d5e707SKishon Vijay Abraham I goto out; 23685d5e707SKishon Vijay Abraham I } 23785d5e707SKishon Vijay Abraham I 2389de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "queueing request %p to %s length %d state '%s'", 23985d5e707SKishon Vijay Abraham I request, dep->name, request->length, 24085d5e707SKishon Vijay Abraham I dwc3_ep0_state_string(dwc->ep0state)); 24185d5e707SKishon Vijay Abraham I 24285d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep0_queue(dep, req); 24385d5e707SKishon Vijay Abraham I 24485d5e707SKishon Vijay Abraham I out: 24585d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 24685d5e707SKishon Vijay Abraham I 24785d5e707SKishon Vijay Abraham I return ret; 24885d5e707SKishon Vijay Abraham I } 24985d5e707SKishon Vijay Abraham I 25085d5e707SKishon Vijay Abraham I static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) 25185d5e707SKishon Vijay Abraham I { 25285d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 25385d5e707SKishon Vijay Abraham I 25485d5e707SKishon Vijay Abraham I /* reinitialize physical ep1 */ 25585d5e707SKishon Vijay Abraham I dep = dwc->eps[1]; 25685d5e707SKishon Vijay Abraham I dep->flags = DWC3_EP_ENABLED; 25785d5e707SKishon Vijay Abraham I 25885d5e707SKishon Vijay Abraham I /* stall is always issued on EP0 */ 25985d5e707SKishon Vijay Abraham I dep = dwc->eps[0]; 26085d5e707SKishon Vijay Abraham I __dwc3_gadget_ep_set_halt(dep, 1, false); 26185d5e707SKishon Vijay Abraham I dep->flags = DWC3_EP_ENABLED; 26285d5e707SKishon Vijay Abraham I dwc->delayed_status = false; 26385d5e707SKishon Vijay Abraham I 26485d5e707SKishon Vijay Abraham I if (!list_empty(&dep->request_list)) { 26585d5e707SKishon Vijay Abraham I struct dwc3_request *req; 26685d5e707SKishon Vijay Abraham I 26785d5e707SKishon Vijay Abraham I req = next_request(&dep->request_list); 26885d5e707SKishon Vijay Abraham I dwc3_gadget_giveback(dep, req, -ECONNRESET); 26985d5e707SKishon Vijay Abraham I } 27085d5e707SKishon Vijay Abraham I 27185d5e707SKishon Vijay Abraham I dwc->ep0state = EP0_SETUP_PHASE; 27285d5e707SKishon Vijay Abraham I dwc3_ep0_out_start(dwc); 27385d5e707SKishon Vijay Abraham I } 27485d5e707SKishon Vijay Abraham I 27585d5e707SKishon Vijay Abraham I int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) 27685d5e707SKishon Vijay Abraham I { 27785d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = to_dwc3_ep(ep); 27885d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 27985d5e707SKishon Vijay Abraham I 28085d5e707SKishon Vijay Abraham I dwc3_ep0_stall_and_restart(dwc); 28185d5e707SKishon Vijay Abraham I 28285d5e707SKishon Vijay Abraham I return 0; 28385d5e707SKishon Vijay Abraham I } 28485d5e707SKishon Vijay Abraham I 28585d5e707SKishon Vijay Abraham I int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) 28685d5e707SKishon Vijay Abraham I { 28785d5e707SKishon Vijay Abraham I unsigned long flags; 28885d5e707SKishon Vijay Abraham I int ret; 28985d5e707SKishon Vijay Abraham I 29085d5e707SKishon Vijay Abraham I spin_lock_irqsave(&dwc->lock, flags); 29185d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep0_set_halt(ep, value); 29285d5e707SKishon Vijay Abraham I spin_unlock_irqrestore(&dwc->lock, flags); 29385d5e707SKishon Vijay Abraham I 29485d5e707SKishon Vijay Abraham I return ret; 29585d5e707SKishon Vijay Abraham I } 29685d5e707SKishon Vijay Abraham I 29785d5e707SKishon Vijay Abraham I void dwc3_ep0_out_start(struct dwc3 *dwc) 29885d5e707SKishon Vijay Abraham I { 29985d5e707SKishon Vijay Abraham I int ret; 30085d5e707SKishon Vijay Abraham I 30185d5e707SKishon Vijay Abraham I ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8, 302*8d488f3eSKishon Vijay Abraham I DWC3_TRBCTL_CONTROL_SETUP, 0); 30385d5e707SKishon Vijay Abraham I WARN_ON(ret < 0); 30485d5e707SKishon Vijay Abraham I } 30585d5e707SKishon Vijay Abraham I 30685d5e707SKishon Vijay Abraham I static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) 30785d5e707SKishon Vijay Abraham I { 30885d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 30985d5e707SKishon Vijay Abraham I u32 windex = le16_to_cpu(wIndex_le); 31085d5e707SKishon Vijay Abraham I u32 epnum; 31185d5e707SKishon Vijay Abraham I 31285d5e707SKishon Vijay Abraham I epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1; 31385d5e707SKishon Vijay Abraham I if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) 31485d5e707SKishon Vijay Abraham I epnum |= 1; 31585d5e707SKishon Vijay Abraham I 31685d5e707SKishon Vijay Abraham I dep = dwc->eps[epnum]; 31785d5e707SKishon Vijay Abraham I if (dep->flags & DWC3_EP_ENABLED) 31885d5e707SKishon Vijay Abraham I return dep; 31985d5e707SKishon Vijay Abraham I 32085d5e707SKishon Vijay Abraham I return NULL; 32185d5e707SKishon Vijay Abraham I } 32285d5e707SKishon Vijay Abraham I 32385d5e707SKishon Vijay Abraham I static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req) 32485d5e707SKishon Vijay Abraham I { 32585d5e707SKishon Vijay Abraham I } 32685d5e707SKishon Vijay Abraham I /* 32785d5e707SKishon Vijay Abraham I * ch 9.4.5 32885d5e707SKishon Vijay Abraham I */ 32985d5e707SKishon Vijay Abraham I static int dwc3_ep0_handle_status(struct dwc3 *dwc, 33085d5e707SKishon Vijay Abraham I struct usb_ctrlrequest *ctrl) 33185d5e707SKishon Vijay Abraham I { 33285d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 33385d5e707SKishon Vijay Abraham I u32 recip; 33485d5e707SKishon Vijay Abraham I u32 reg; 33585d5e707SKishon Vijay Abraham I u16 usb_status = 0; 33685d5e707SKishon Vijay Abraham I __le16 *response_pkt; 33785d5e707SKishon Vijay Abraham I 33885d5e707SKishon Vijay Abraham I recip = ctrl->bRequestType & USB_RECIP_MASK; 33985d5e707SKishon Vijay Abraham I switch (recip) { 34085d5e707SKishon Vijay Abraham I case USB_RECIP_DEVICE: 34185d5e707SKishon Vijay Abraham I /* 34285d5e707SKishon Vijay Abraham I * LTM will be set once we know how to set this in HW. 34385d5e707SKishon Vijay Abraham I */ 34485d5e707SKishon Vijay Abraham I usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED; 34585d5e707SKishon Vijay Abraham I 34685d5e707SKishon Vijay Abraham I if (dwc->speed == DWC3_DSTS_SUPERSPEED) { 34785d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 34885d5e707SKishon Vijay Abraham I if (reg & DWC3_DCTL_INITU1ENA) 34985d5e707SKishon Vijay Abraham I usb_status |= 1 << USB_DEV_STAT_U1_ENABLED; 35085d5e707SKishon Vijay Abraham I if (reg & DWC3_DCTL_INITU2ENA) 35185d5e707SKishon Vijay Abraham I usb_status |= 1 << USB_DEV_STAT_U2_ENABLED; 35285d5e707SKishon Vijay Abraham I } 35385d5e707SKishon Vijay Abraham I 35485d5e707SKishon Vijay Abraham I break; 35585d5e707SKishon Vijay Abraham I 35685d5e707SKishon Vijay Abraham I case USB_RECIP_INTERFACE: 35785d5e707SKishon Vijay Abraham I /* 35885d5e707SKishon Vijay Abraham I * Function Remote Wake Capable D0 35985d5e707SKishon Vijay Abraham I * Function Remote Wakeup D1 36085d5e707SKishon Vijay Abraham I */ 36185d5e707SKishon Vijay Abraham I break; 36285d5e707SKishon Vijay Abraham I 36385d5e707SKishon Vijay Abraham I case USB_RECIP_ENDPOINT: 36485d5e707SKishon Vijay Abraham I dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); 36585d5e707SKishon Vijay Abraham I if (!dep) 36685d5e707SKishon Vijay Abraham I return -EINVAL; 36785d5e707SKishon Vijay Abraham I 36885d5e707SKishon Vijay Abraham I if (dep->flags & DWC3_EP_STALL) 36985d5e707SKishon Vijay Abraham I usb_status = 1 << USB_ENDPOINT_HALT; 37085d5e707SKishon Vijay Abraham I break; 37185d5e707SKishon Vijay Abraham I default: 37285d5e707SKishon Vijay Abraham I return -EINVAL; 37385d5e707SKishon Vijay Abraham I } 37485d5e707SKishon Vijay Abraham I 37585d5e707SKishon Vijay Abraham I response_pkt = (__le16 *) dwc->setup_buf; 37685d5e707SKishon Vijay Abraham I *response_pkt = cpu_to_le16(usb_status); 37785d5e707SKishon Vijay Abraham I 37885d5e707SKishon Vijay Abraham I dep = dwc->eps[0]; 37985d5e707SKishon Vijay Abraham I dwc->ep0_usb_req.dep = dep; 38085d5e707SKishon Vijay Abraham I dwc->ep0_usb_req.request.length = sizeof(*response_pkt); 38185d5e707SKishon Vijay Abraham I dwc->ep0_usb_req.request.buf = dwc->setup_buf; 38285d5e707SKishon Vijay Abraham I dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; 38385d5e707SKishon Vijay Abraham I 38485d5e707SKishon Vijay Abraham I return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); 38585d5e707SKishon Vijay Abraham I } 38685d5e707SKishon Vijay Abraham I 38785d5e707SKishon Vijay Abraham I static int dwc3_ep0_handle_feature(struct dwc3 *dwc, 38885d5e707SKishon Vijay Abraham I struct usb_ctrlrequest *ctrl, int set) 38985d5e707SKishon Vijay Abraham I { 39085d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 39185d5e707SKishon Vijay Abraham I u32 recip; 39285d5e707SKishon Vijay Abraham I u32 wValue; 39385d5e707SKishon Vijay Abraham I u32 wIndex; 39485d5e707SKishon Vijay Abraham I u32 reg; 39585d5e707SKishon Vijay Abraham I int ret; 39685d5e707SKishon Vijay Abraham I enum usb_device_state state; 39785d5e707SKishon Vijay Abraham I 39885d5e707SKishon Vijay Abraham I wValue = le16_to_cpu(ctrl->wValue); 39985d5e707SKishon Vijay Abraham I wIndex = le16_to_cpu(ctrl->wIndex); 40085d5e707SKishon Vijay Abraham I recip = ctrl->bRequestType & USB_RECIP_MASK; 40185d5e707SKishon Vijay Abraham I state = dwc->gadget.state; 40285d5e707SKishon Vijay Abraham I 40385d5e707SKishon Vijay Abraham I switch (recip) { 40485d5e707SKishon Vijay Abraham I case USB_RECIP_DEVICE: 40585d5e707SKishon Vijay Abraham I 40685d5e707SKishon Vijay Abraham I switch (wValue) { 40785d5e707SKishon Vijay Abraham I case USB_DEVICE_REMOTE_WAKEUP: 40885d5e707SKishon Vijay Abraham I break; 40985d5e707SKishon Vijay Abraham I /* 41085d5e707SKishon Vijay Abraham I * 9.4.1 says only only for SS, in AddressState only for 41185d5e707SKishon Vijay Abraham I * default control pipe 41285d5e707SKishon Vijay Abraham I */ 41385d5e707SKishon Vijay Abraham I case USB_DEVICE_U1_ENABLE: 41485d5e707SKishon Vijay Abraham I if (state != USB_STATE_CONFIGURED) 41585d5e707SKishon Vijay Abraham I return -EINVAL; 41685d5e707SKishon Vijay Abraham I if (dwc->speed != DWC3_DSTS_SUPERSPEED) 41785d5e707SKishon Vijay Abraham I return -EINVAL; 41885d5e707SKishon Vijay Abraham I 41985d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 42085d5e707SKishon Vijay Abraham I if (set) 42185d5e707SKishon Vijay Abraham I reg |= DWC3_DCTL_INITU1ENA; 42285d5e707SKishon Vijay Abraham I else 42385d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_INITU1ENA; 42485d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 42585d5e707SKishon Vijay Abraham I break; 42685d5e707SKishon Vijay Abraham I 42785d5e707SKishon Vijay Abraham I case USB_DEVICE_U2_ENABLE: 42885d5e707SKishon Vijay Abraham I if (state != USB_STATE_CONFIGURED) 42985d5e707SKishon Vijay Abraham I return -EINVAL; 43085d5e707SKishon Vijay Abraham I if (dwc->speed != DWC3_DSTS_SUPERSPEED) 43185d5e707SKishon Vijay Abraham I return -EINVAL; 43285d5e707SKishon Vijay Abraham I 43385d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 43485d5e707SKishon Vijay Abraham I if (set) 43585d5e707SKishon Vijay Abraham I reg |= DWC3_DCTL_INITU2ENA; 43685d5e707SKishon Vijay Abraham I else 43785d5e707SKishon Vijay Abraham I reg &= ~DWC3_DCTL_INITU2ENA; 43885d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 43985d5e707SKishon Vijay Abraham I break; 44085d5e707SKishon Vijay Abraham I 44185d5e707SKishon Vijay Abraham I case USB_DEVICE_LTM_ENABLE: 44285d5e707SKishon Vijay Abraham I return -EINVAL; 44385d5e707SKishon Vijay Abraham I 44485d5e707SKishon Vijay Abraham I case USB_DEVICE_TEST_MODE: 44585d5e707SKishon Vijay Abraham I if ((wIndex & 0xff) != 0) 44685d5e707SKishon Vijay Abraham I return -EINVAL; 44785d5e707SKishon Vijay Abraham I if (!set) 44885d5e707SKishon Vijay Abraham I return -EINVAL; 44985d5e707SKishon Vijay Abraham I 45085d5e707SKishon Vijay Abraham I dwc->test_mode_nr = wIndex >> 8; 45185d5e707SKishon Vijay Abraham I dwc->test_mode = true; 45285d5e707SKishon Vijay Abraham I break; 45385d5e707SKishon Vijay Abraham I default: 45485d5e707SKishon Vijay Abraham I return -EINVAL; 45585d5e707SKishon Vijay Abraham I } 45685d5e707SKishon Vijay Abraham I break; 45785d5e707SKishon Vijay Abraham I 45885d5e707SKishon Vijay Abraham I case USB_RECIP_INTERFACE: 45985d5e707SKishon Vijay Abraham I switch (wValue) { 46085d5e707SKishon Vijay Abraham I case USB_INTRF_FUNC_SUSPEND: 46185d5e707SKishon Vijay Abraham I if (wIndex & USB_INTRF_FUNC_SUSPEND_LP) 46285d5e707SKishon Vijay Abraham I /* XXX enable Low power suspend */ 46385d5e707SKishon Vijay Abraham I ; 46485d5e707SKishon Vijay Abraham I if (wIndex & USB_INTRF_FUNC_SUSPEND_RW) 46585d5e707SKishon Vijay Abraham I /* XXX enable remote wakeup */ 46685d5e707SKishon Vijay Abraham I ; 46785d5e707SKishon Vijay Abraham I break; 46885d5e707SKishon Vijay Abraham I default: 46985d5e707SKishon Vijay Abraham I return -EINVAL; 47085d5e707SKishon Vijay Abraham I } 47185d5e707SKishon Vijay Abraham I break; 47285d5e707SKishon Vijay Abraham I 47385d5e707SKishon Vijay Abraham I case USB_RECIP_ENDPOINT: 47485d5e707SKishon Vijay Abraham I switch (wValue) { 47585d5e707SKishon Vijay Abraham I case USB_ENDPOINT_HALT: 47685d5e707SKishon Vijay Abraham I dep = dwc3_wIndex_to_dep(dwc, wIndex); 47785d5e707SKishon Vijay Abraham I if (!dep) 47885d5e707SKishon Vijay Abraham I return -EINVAL; 47985d5e707SKishon Vijay Abraham I if (set == 0 && (dep->flags & DWC3_EP_WEDGE)) 48085d5e707SKishon Vijay Abraham I break; 48185d5e707SKishon Vijay Abraham I ret = __dwc3_gadget_ep_set_halt(dep, set, true); 48285d5e707SKishon Vijay Abraham I if (ret) 48385d5e707SKishon Vijay Abraham I return -EINVAL; 48485d5e707SKishon Vijay Abraham I break; 48585d5e707SKishon Vijay Abraham I default: 48685d5e707SKishon Vijay Abraham I return -EINVAL; 48785d5e707SKishon Vijay Abraham I } 48885d5e707SKishon Vijay Abraham I break; 48985d5e707SKishon Vijay Abraham I 49085d5e707SKishon Vijay Abraham I default: 49185d5e707SKishon Vijay Abraham I return -EINVAL; 49285d5e707SKishon Vijay Abraham I } 49385d5e707SKishon Vijay Abraham I 49485d5e707SKishon Vijay Abraham I return 0; 49585d5e707SKishon Vijay Abraham I } 49685d5e707SKishon Vijay Abraham I 49785d5e707SKishon Vijay Abraham I static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 49885d5e707SKishon Vijay Abraham I { 49985d5e707SKishon Vijay Abraham I enum usb_device_state state = dwc->gadget.state; 50085d5e707SKishon Vijay Abraham I u32 addr; 50185d5e707SKishon Vijay Abraham I u32 reg; 50285d5e707SKishon Vijay Abraham I 50385d5e707SKishon Vijay Abraham I addr = le16_to_cpu(ctrl->wValue); 50485d5e707SKishon Vijay Abraham I if (addr > 127) { 5059de1115dSKishon Vijay Abraham I dev_dbg(dwc->dev, "invalid device address %d", addr); 50685d5e707SKishon Vijay Abraham I return -EINVAL; 50785d5e707SKishon Vijay Abraham I } 50885d5e707SKishon Vijay Abraham I 50985d5e707SKishon Vijay Abraham I if (state == USB_STATE_CONFIGURED) { 5109de1115dSKishon Vijay Abraham I dev_dbg(dwc->dev, "trying to set address when configured"); 51185d5e707SKishon Vijay Abraham I return -EINVAL; 51285d5e707SKishon Vijay Abraham I } 51385d5e707SKishon Vijay Abraham I 51485d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCFG); 51585d5e707SKishon Vijay Abraham I reg &= ~(DWC3_DCFG_DEVADDR_MASK); 51685d5e707SKishon Vijay Abraham I reg |= DWC3_DCFG_DEVADDR(addr); 51785d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCFG, reg); 51885d5e707SKishon Vijay Abraham I 51985d5e707SKishon Vijay Abraham I if (addr) 52085d5e707SKishon Vijay Abraham I usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS); 52185d5e707SKishon Vijay Abraham I else 52285d5e707SKishon Vijay Abraham I usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT); 52385d5e707SKishon Vijay Abraham I 52485d5e707SKishon Vijay Abraham I return 0; 52585d5e707SKishon Vijay Abraham I } 52685d5e707SKishon Vijay Abraham I 52785d5e707SKishon Vijay Abraham I static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 52885d5e707SKishon Vijay Abraham I { 52985d5e707SKishon Vijay Abraham I int ret; 53085d5e707SKishon Vijay Abraham I 53185d5e707SKishon Vijay Abraham I spin_unlock(&dwc->lock); 53285d5e707SKishon Vijay Abraham I ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl); 53385d5e707SKishon Vijay Abraham I spin_lock(&dwc->lock); 53485d5e707SKishon Vijay Abraham I return ret; 53585d5e707SKishon Vijay Abraham I } 53685d5e707SKishon Vijay Abraham I 53785d5e707SKishon Vijay Abraham I static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 53885d5e707SKishon Vijay Abraham I { 53985d5e707SKishon Vijay Abraham I enum usb_device_state state = dwc->gadget.state; 54085d5e707SKishon Vijay Abraham I u32 cfg; 54185d5e707SKishon Vijay Abraham I int ret; 54285d5e707SKishon Vijay Abraham I u32 reg; 54385d5e707SKishon Vijay Abraham I 54485d5e707SKishon Vijay Abraham I dwc->start_config_issued = false; 54585d5e707SKishon Vijay Abraham I cfg = le16_to_cpu(ctrl->wValue); 54685d5e707SKishon Vijay Abraham I 54785d5e707SKishon Vijay Abraham I switch (state) { 54885d5e707SKishon Vijay Abraham I case USB_STATE_DEFAULT: 54985d5e707SKishon Vijay Abraham I return -EINVAL; 55085d5e707SKishon Vijay Abraham I 55185d5e707SKishon Vijay Abraham I case USB_STATE_ADDRESS: 55285d5e707SKishon Vijay Abraham I ret = dwc3_ep0_delegate_req(dwc, ctrl); 55385d5e707SKishon Vijay Abraham I /* if the cfg matches and the cfg is non zero */ 55485d5e707SKishon Vijay Abraham I if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { 55585d5e707SKishon Vijay Abraham I 55685d5e707SKishon Vijay Abraham I /* 55785d5e707SKishon Vijay Abraham I * only change state if set_config has already 55885d5e707SKishon Vijay Abraham I * been processed. If gadget driver returns 55985d5e707SKishon Vijay Abraham I * USB_GADGET_DELAYED_STATUS, we will wait 56085d5e707SKishon Vijay Abraham I * to change the state on the next usb_ep_queue() 56185d5e707SKishon Vijay Abraham I */ 56285d5e707SKishon Vijay Abraham I if (ret == 0) 56385d5e707SKishon Vijay Abraham I usb_gadget_set_state(&dwc->gadget, 56485d5e707SKishon Vijay Abraham I USB_STATE_CONFIGURED); 56585d5e707SKishon Vijay Abraham I 56685d5e707SKishon Vijay Abraham I /* 56785d5e707SKishon Vijay Abraham I * Enable transition to U1/U2 state when 56885d5e707SKishon Vijay Abraham I * nothing is pending from application. 56985d5e707SKishon Vijay Abraham I */ 57085d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 57185d5e707SKishon Vijay Abraham I reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); 57285d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, reg); 57385d5e707SKishon Vijay Abraham I 57485d5e707SKishon Vijay Abraham I dwc->resize_fifos = true; 5759de1115dSKishon Vijay Abraham I dev_dbg(dwc->dev, "resize FIFOs flag SET"); 57685d5e707SKishon Vijay Abraham I } 57785d5e707SKishon Vijay Abraham I break; 57885d5e707SKishon Vijay Abraham I 57985d5e707SKishon Vijay Abraham I case USB_STATE_CONFIGURED: 58085d5e707SKishon Vijay Abraham I ret = dwc3_ep0_delegate_req(dwc, ctrl); 58185d5e707SKishon Vijay Abraham I if (!cfg && !ret) 58285d5e707SKishon Vijay Abraham I usb_gadget_set_state(&dwc->gadget, 58385d5e707SKishon Vijay Abraham I USB_STATE_ADDRESS); 58485d5e707SKishon Vijay Abraham I break; 58585d5e707SKishon Vijay Abraham I default: 58685d5e707SKishon Vijay Abraham I ret = -EINVAL; 58785d5e707SKishon Vijay Abraham I } 58885d5e707SKishon Vijay Abraham I return ret; 58985d5e707SKishon Vijay Abraham I } 59085d5e707SKishon Vijay Abraham I 59185d5e707SKishon Vijay Abraham I static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) 59285d5e707SKishon Vijay Abraham I { 59385d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = to_dwc3_ep(ep); 59485d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 59585d5e707SKishon Vijay Abraham I 59685d5e707SKishon Vijay Abraham I u32 param = 0; 59785d5e707SKishon Vijay Abraham I u32 reg; 59885d5e707SKishon Vijay Abraham I 59985d5e707SKishon Vijay Abraham I struct timing { 60085d5e707SKishon Vijay Abraham I u8 u1sel; 60185d5e707SKishon Vijay Abraham I u8 u1pel; 60285d5e707SKishon Vijay Abraham I u16 u2sel; 60385d5e707SKishon Vijay Abraham I u16 u2pel; 60485d5e707SKishon Vijay Abraham I } __packed timing; 60585d5e707SKishon Vijay Abraham I 60685d5e707SKishon Vijay Abraham I int ret; 60785d5e707SKishon Vijay Abraham I 60885d5e707SKishon Vijay Abraham I memcpy(&timing, req->buf, sizeof(timing)); 60985d5e707SKishon Vijay Abraham I 61085d5e707SKishon Vijay Abraham I dwc->u1sel = timing.u1sel; 61185d5e707SKishon Vijay Abraham I dwc->u1pel = timing.u1pel; 61285d5e707SKishon Vijay Abraham I dwc->u2sel = le16_to_cpu(timing.u2sel); 61385d5e707SKishon Vijay Abraham I dwc->u2pel = le16_to_cpu(timing.u2pel); 61485d5e707SKishon Vijay Abraham I 61585d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 61685d5e707SKishon Vijay Abraham I if (reg & DWC3_DCTL_INITU2ENA) 61785d5e707SKishon Vijay Abraham I param = dwc->u2pel; 61885d5e707SKishon Vijay Abraham I if (reg & DWC3_DCTL_INITU1ENA) 61985d5e707SKishon Vijay Abraham I param = dwc->u1pel; 62085d5e707SKishon Vijay Abraham I 62185d5e707SKishon Vijay Abraham I /* 62285d5e707SKishon Vijay Abraham I * According to Synopsys Databook, if parameter is 62385d5e707SKishon Vijay Abraham I * greater than 125, a value of zero should be 62485d5e707SKishon Vijay Abraham I * programmed in the register. 62585d5e707SKishon Vijay Abraham I */ 62685d5e707SKishon Vijay Abraham I if (param > 125) 62785d5e707SKishon Vijay Abraham I param = 0; 62885d5e707SKishon Vijay Abraham I 62985d5e707SKishon Vijay Abraham I /* now that we have the time, issue DGCMD Set Sel */ 63085d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_generic_command(dwc, 63185d5e707SKishon Vijay Abraham I DWC3_DGCMD_SET_PERIODIC_PAR, param); 63285d5e707SKishon Vijay Abraham I WARN_ON(ret < 0); 63385d5e707SKishon Vijay Abraham I } 63485d5e707SKishon Vijay Abraham I 63585d5e707SKishon Vijay Abraham I static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 63685d5e707SKishon Vijay Abraham I { 63785d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 63885d5e707SKishon Vijay Abraham I enum usb_device_state state = dwc->gadget.state; 63985d5e707SKishon Vijay Abraham I u16 wLength; 64085d5e707SKishon Vijay Abraham I 64185d5e707SKishon Vijay Abraham I if (state == USB_STATE_DEFAULT) 64285d5e707SKishon Vijay Abraham I return -EINVAL; 64385d5e707SKishon Vijay Abraham I 64485d5e707SKishon Vijay Abraham I wLength = le16_to_cpu(ctrl->wLength); 64585d5e707SKishon Vijay Abraham I 64685d5e707SKishon Vijay Abraham I if (wLength != 6) { 64785d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "Set SEL should be 6 bytes, got %d\n", 64885d5e707SKishon Vijay Abraham I wLength); 64985d5e707SKishon Vijay Abraham I return -EINVAL; 65085d5e707SKishon Vijay Abraham I } 65185d5e707SKishon Vijay Abraham I 65285d5e707SKishon Vijay Abraham I /* 65385d5e707SKishon Vijay Abraham I * To handle Set SEL we need to receive 6 bytes from Host. So let's 65485d5e707SKishon Vijay Abraham I * queue a usb_request for 6 bytes. 65585d5e707SKishon Vijay Abraham I * 65685d5e707SKishon Vijay Abraham I * Remember, though, this controller can't handle non-wMaxPacketSize 65785d5e707SKishon Vijay Abraham I * aligned transfers on the OUT direction, so we queue a request for 65885d5e707SKishon Vijay Abraham I * wMaxPacketSize instead. 65985d5e707SKishon Vijay Abraham I */ 66085d5e707SKishon Vijay Abraham I dep = dwc->eps[0]; 66185d5e707SKishon Vijay Abraham I dwc->ep0_usb_req.dep = dep; 66285d5e707SKishon Vijay Abraham I dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket; 66385d5e707SKishon Vijay Abraham I dwc->ep0_usb_req.request.buf = dwc->setup_buf; 66485d5e707SKishon Vijay Abraham I dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl; 66585d5e707SKishon Vijay Abraham I 66685d5e707SKishon Vijay Abraham I return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); 66785d5e707SKishon Vijay Abraham I } 66885d5e707SKishon Vijay Abraham I 66985d5e707SKishon Vijay Abraham I static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 67085d5e707SKishon Vijay Abraham I { 67185d5e707SKishon Vijay Abraham I u16 wLength; 67285d5e707SKishon Vijay Abraham I u16 wValue; 67385d5e707SKishon Vijay Abraham I u16 wIndex; 67485d5e707SKishon Vijay Abraham I 67585d5e707SKishon Vijay Abraham I wValue = le16_to_cpu(ctrl->wValue); 67685d5e707SKishon Vijay Abraham I wLength = le16_to_cpu(ctrl->wLength); 67785d5e707SKishon Vijay Abraham I wIndex = le16_to_cpu(ctrl->wIndex); 67885d5e707SKishon Vijay Abraham I 67985d5e707SKishon Vijay Abraham I if (wIndex || wLength) 68085d5e707SKishon Vijay Abraham I return -EINVAL; 68185d5e707SKishon Vijay Abraham I 68285d5e707SKishon Vijay Abraham I /* 68385d5e707SKishon Vijay Abraham I * REVISIT It's unclear from Databook what to do with this 68485d5e707SKishon Vijay Abraham I * value. For now, just cache it. 68585d5e707SKishon Vijay Abraham I */ 68685d5e707SKishon Vijay Abraham I dwc->isoch_delay = wValue; 68785d5e707SKishon Vijay Abraham I 68885d5e707SKishon Vijay Abraham I return 0; 68985d5e707SKishon Vijay Abraham I } 69085d5e707SKishon Vijay Abraham I 69185d5e707SKishon Vijay Abraham I static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 69285d5e707SKishon Vijay Abraham I { 69385d5e707SKishon Vijay Abraham I int ret; 69485d5e707SKishon Vijay Abraham I 69585d5e707SKishon Vijay Abraham I switch (ctrl->bRequest) { 69685d5e707SKishon Vijay Abraham I case USB_REQ_GET_STATUS: 6979de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS"); 69885d5e707SKishon Vijay Abraham I ret = dwc3_ep0_handle_status(dwc, ctrl); 69985d5e707SKishon Vijay Abraham I break; 70085d5e707SKishon Vijay Abraham I case USB_REQ_CLEAR_FEATURE: 7019de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE"); 70285d5e707SKishon Vijay Abraham I ret = dwc3_ep0_handle_feature(dwc, ctrl, 0); 70385d5e707SKishon Vijay Abraham I break; 70485d5e707SKishon Vijay Abraham I case USB_REQ_SET_FEATURE: 7059de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE"); 70685d5e707SKishon Vijay Abraham I ret = dwc3_ep0_handle_feature(dwc, ctrl, 1); 70785d5e707SKishon Vijay Abraham I break; 70885d5e707SKishon Vijay Abraham I case USB_REQ_SET_ADDRESS: 7099de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS"); 71085d5e707SKishon Vijay Abraham I ret = dwc3_ep0_set_address(dwc, ctrl); 71185d5e707SKishon Vijay Abraham I break; 71285d5e707SKishon Vijay Abraham I case USB_REQ_SET_CONFIGURATION: 7139de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION"); 71485d5e707SKishon Vijay Abraham I ret = dwc3_ep0_set_config(dwc, ctrl); 71585d5e707SKishon Vijay Abraham I break; 71685d5e707SKishon Vijay Abraham I case USB_REQ_SET_SEL: 7179de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "USB_REQ_SET_SEL"); 71885d5e707SKishon Vijay Abraham I ret = dwc3_ep0_set_sel(dwc, ctrl); 71985d5e707SKishon Vijay Abraham I break; 72085d5e707SKishon Vijay Abraham I case USB_REQ_SET_ISOCH_DELAY: 7219de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "USB_REQ_SET_ISOCH_DELAY"); 72285d5e707SKishon Vijay Abraham I ret = dwc3_ep0_set_isoch_delay(dwc, ctrl); 72385d5e707SKishon Vijay Abraham I break; 72485d5e707SKishon Vijay Abraham I default: 7259de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "Forwarding to gadget driver"); 72685d5e707SKishon Vijay Abraham I ret = dwc3_ep0_delegate_req(dwc, ctrl); 72785d5e707SKishon Vijay Abraham I break; 72885d5e707SKishon Vijay Abraham I } 72985d5e707SKishon Vijay Abraham I 73085d5e707SKishon Vijay Abraham I return ret; 73185d5e707SKishon Vijay Abraham I } 73285d5e707SKishon Vijay Abraham I 73385d5e707SKishon Vijay Abraham I static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, 73485d5e707SKishon Vijay Abraham I const struct dwc3_event_depevt *event) 73585d5e707SKishon Vijay Abraham I { 73685d5e707SKishon Vijay Abraham I struct usb_ctrlrequest *ctrl = dwc->ctrl_req; 73785d5e707SKishon Vijay Abraham I int ret = -EINVAL; 73885d5e707SKishon Vijay Abraham I u32 len; 73985d5e707SKishon Vijay Abraham I 74085d5e707SKishon Vijay Abraham I if (!dwc->gadget_driver) 74185d5e707SKishon Vijay Abraham I goto out; 74285d5e707SKishon Vijay Abraham I 74385d5e707SKishon Vijay Abraham I len = le16_to_cpu(ctrl->wLength); 74485d5e707SKishon Vijay Abraham I if (!len) { 74585d5e707SKishon Vijay Abraham I dwc->three_stage_setup = false; 74685d5e707SKishon Vijay Abraham I dwc->ep0_expect_in = false; 74785d5e707SKishon Vijay Abraham I dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; 74885d5e707SKishon Vijay Abraham I } else { 74985d5e707SKishon Vijay Abraham I dwc->three_stage_setup = true; 75085d5e707SKishon Vijay Abraham I dwc->ep0_expect_in = !!(ctrl->bRequestType & USB_DIR_IN); 75185d5e707SKishon Vijay Abraham I dwc->ep0_next_event = DWC3_EP0_NRDY_DATA; 75285d5e707SKishon Vijay Abraham I } 75385d5e707SKishon Vijay Abraham I 75485d5e707SKishon Vijay Abraham I if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) 75585d5e707SKishon Vijay Abraham I ret = dwc3_ep0_std_request(dwc, ctrl); 75685d5e707SKishon Vijay Abraham I else 75785d5e707SKishon Vijay Abraham I ret = dwc3_ep0_delegate_req(dwc, ctrl); 75885d5e707SKishon Vijay Abraham I 75985d5e707SKishon Vijay Abraham I if (ret == USB_GADGET_DELAYED_STATUS) 76085d5e707SKishon Vijay Abraham I dwc->delayed_status = true; 76185d5e707SKishon Vijay Abraham I 76285d5e707SKishon Vijay Abraham I out: 76385d5e707SKishon Vijay Abraham I if (ret < 0) 76485d5e707SKishon Vijay Abraham I dwc3_ep0_stall_and_restart(dwc); 76585d5e707SKishon Vijay Abraham I } 76685d5e707SKishon Vijay Abraham I 76785d5e707SKishon Vijay Abraham I static void dwc3_ep0_complete_data(struct dwc3 *dwc, 76885d5e707SKishon Vijay Abraham I const struct dwc3_event_depevt *event) 76985d5e707SKishon Vijay Abraham I { 77085d5e707SKishon Vijay Abraham I struct dwc3_request *r = NULL; 77185d5e707SKishon Vijay Abraham I struct usb_request *ur; 77285d5e707SKishon Vijay Abraham I struct dwc3_trb *trb; 77385d5e707SKishon Vijay Abraham I struct dwc3_ep *ep0; 7741f78f8feSKishon Vijay Abraham I unsigned transfer_size = 0; 7751f78f8feSKishon Vijay Abraham I unsigned maxp; 7761f78f8feSKishon Vijay Abraham I void *buf; 7771f78f8feSKishon Vijay Abraham I u32 transferred = 0; 77885d5e707SKishon Vijay Abraham I u32 status; 77985d5e707SKishon Vijay Abraham I u32 length; 78085d5e707SKishon Vijay Abraham I u8 epnum; 78185d5e707SKishon Vijay Abraham I 78285d5e707SKishon Vijay Abraham I epnum = event->endpoint_number; 78385d5e707SKishon Vijay Abraham I ep0 = dwc->eps[0]; 78485d5e707SKishon Vijay Abraham I 78585d5e707SKishon Vijay Abraham I dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; 78685d5e707SKishon Vijay Abraham I 78785d5e707SKishon Vijay Abraham I trb = dwc->ep0_trb; 78885d5e707SKishon Vijay Abraham I 78985d5e707SKishon Vijay Abraham I r = next_request(&ep0->request_list); 79085d5e707SKishon Vijay Abraham I if (!r) 79185d5e707SKishon Vijay Abraham I return; 79285d5e707SKishon Vijay Abraham I 793526a50f8SKishon Vijay Abraham I dwc3_flush_cache((int)trb, sizeof(*trb)); 794526a50f8SKishon Vijay Abraham I 79585d5e707SKishon Vijay Abraham I status = DWC3_TRB_SIZE_TRBSTS(trb->size); 79685d5e707SKishon Vijay Abraham I if (status == DWC3_TRBSTS_SETUP_PENDING) { 7979de1115dSKishon Vijay Abraham I dev_dbg(dwc->dev, "Setup Pending received"); 79885d5e707SKishon Vijay Abraham I 79985d5e707SKishon Vijay Abraham I if (r) 80085d5e707SKishon Vijay Abraham I dwc3_gadget_giveback(ep0, r, -ECONNRESET); 80185d5e707SKishon Vijay Abraham I 80285d5e707SKishon Vijay Abraham I return; 80385d5e707SKishon Vijay Abraham I } 80485d5e707SKishon Vijay Abraham I 80585d5e707SKishon Vijay Abraham I ur = &r->request; 8061f78f8feSKishon Vijay Abraham I buf = ur->buf; 80785d5e707SKishon Vijay Abraham I 80885d5e707SKishon Vijay Abraham I length = trb->size & DWC3_TRB_SIZE_MASK; 80985d5e707SKishon Vijay Abraham I 8101f78f8feSKishon Vijay Abraham I maxp = ep0->endpoint.maxpacket; 81185d5e707SKishon Vijay Abraham I 8121f78f8feSKishon Vijay Abraham I if (dwc->ep0_bounced) { 813*8d488f3eSKishon Vijay Abraham I /* 814*8d488f3eSKishon Vijay Abraham I * Handle the first TRB before handling the bounce buffer if 815*8d488f3eSKishon Vijay Abraham I * the request length is greater than the bounce buffer size. 816*8d488f3eSKishon Vijay Abraham I */ 817*8d488f3eSKishon Vijay Abraham I if (ur->length > DWC3_EP0_BOUNCE_SIZE) { 818*8d488f3eSKishon Vijay Abraham I transfer_size = (ur->length / maxp) * maxp; 819*8d488f3eSKishon Vijay Abraham I transferred = transfer_size - length; 820*8d488f3eSKishon Vijay Abraham I buf = (u8 *)buf + transferred; 821*8d488f3eSKishon Vijay Abraham I ur->actual += transferred; 822*8d488f3eSKishon Vijay Abraham I 823*8d488f3eSKishon Vijay Abraham I trb++; 824*8d488f3eSKishon Vijay Abraham I dwc3_flush_cache((int)trb, sizeof(*trb)); 825*8d488f3eSKishon Vijay Abraham I length = trb->size & DWC3_TRB_SIZE_MASK; 826*8d488f3eSKishon Vijay Abraham I 827*8d488f3eSKishon Vijay Abraham I ep0->free_slot = 0; 828*8d488f3eSKishon Vijay Abraham I } 829*8d488f3eSKishon Vijay Abraham I 8301f78f8feSKishon Vijay Abraham I transfer_size = roundup((ur->length - transfer_size), 8311f78f8feSKishon Vijay Abraham I maxp); 8321f78f8feSKishon Vijay Abraham I transferred = min_t(u32, ur->length - transferred, 83385d5e707SKishon Vijay Abraham I transfer_size - length); 834526a50f8SKishon Vijay Abraham I dwc3_flush_cache((int)dwc->ep0_bounce, DWC3_EP0_BOUNCE_SIZE); 8351f78f8feSKishon Vijay Abraham I memcpy(buf, dwc->ep0_bounce, transferred); 83685d5e707SKishon Vijay Abraham I } else { 83785d5e707SKishon Vijay Abraham I transferred = ur->length - length; 83885d5e707SKishon Vijay Abraham I } 83985d5e707SKishon Vijay Abraham I 84085d5e707SKishon Vijay Abraham I ur->actual += transferred; 84185d5e707SKishon Vijay Abraham I 84285d5e707SKishon Vijay Abraham I if ((epnum & 1) && ur->actual < ur->length) { 84385d5e707SKishon Vijay Abraham I /* for some reason we did not get everything out */ 84485d5e707SKishon Vijay Abraham I 84585d5e707SKishon Vijay Abraham I dwc3_ep0_stall_and_restart(dwc); 84685d5e707SKishon Vijay Abraham I } else { 84785d5e707SKishon Vijay Abraham I dwc3_gadget_giveback(ep0, r, 0); 84885d5e707SKishon Vijay Abraham I 84985d5e707SKishon Vijay Abraham I if (IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) && 85085d5e707SKishon Vijay Abraham I ur->length && ur->zero) { 85185d5e707SKishon Vijay Abraham I int ret; 85285d5e707SKishon Vijay Abraham I 85385d5e707SKishon Vijay Abraham I dwc->ep0_next_event = DWC3_EP0_COMPLETE; 85485d5e707SKishon Vijay Abraham I 85585d5e707SKishon Vijay Abraham I ret = dwc3_ep0_start_trans(dwc, epnum, 85685d5e707SKishon Vijay Abraham I dwc->ctrl_req_addr, 0, 857*8d488f3eSKishon Vijay Abraham I DWC3_TRBCTL_CONTROL_DATA, 0); 85885d5e707SKishon Vijay Abraham I WARN_ON(ret < 0); 85985d5e707SKishon Vijay Abraham I } 86085d5e707SKishon Vijay Abraham I } 86185d5e707SKishon Vijay Abraham I } 86285d5e707SKishon Vijay Abraham I 86385d5e707SKishon Vijay Abraham I static void dwc3_ep0_complete_status(struct dwc3 *dwc, 86485d5e707SKishon Vijay Abraham I const struct dwc3_event_depevt *event) 86585d5e707SKishon Vijay Abraham I { 86685d5e707SKishon Vijay Abraham I struct dwc3_request *r; 86785d5e707SKishon Vijay Abraham I struct dwc3_ep *dep; 86885d5e707SKishon Vijay Abraham I struct dwc3_trb *trb; 86985d5e707SKishon Vijay Abraham I u32 status; 87085d5e707SKishon Vijay Abraham I 87185d5e707SKishon Vijay Abraham I dep = dwc->eps[0]; 87285d5e707SKishon Vijay Abraham I trb = dwc->ep0_trb; 87385d5e707SKishon Vijay Abraham I 87485d5e707SKishon Vijay Abraham I if (!list_empty(&dep->request_list)) { 87585d5e707SKishon Vijay Abraham I r = next_request(&dep->request_list); 87685d5e707SKishon Vijay Abraham I 87785d5e707SKishon Vijay Abraham I dwc3_gadget_giveback(dep, r, 0); 87885d5e707SKishon Vijay Abraham I } 87985d5e707SKishon Vijay Abraham I 88085d5e707SKishon Vijay Abraham I if (dwc->test_mode) { 88185d5e707SKishon Vijay Abraham I int ret; 88285d5e707SKishon Vijay Abraham I 88385d5e707SKishon Vijay Abraham I ret = dwc3_gadget_set_test_mode(dwc, dwc->test_mode_nr); 88485d5e707SKishon Vijay Abraham I if (ret < 0) { 8859de1115dSKishon Vijay Abraham I dev_dbg(dwc->dev, "Invalid Test #%d", 88685d5e707SKishon Vijay Abraham I dwc->test_mode_nr); 88785d5e707SKishon Vijay Abraham I dwc3_ep0_stall_and_restart(dwc); 88885d5e707SKishon Vijay Abraham I return; 88985d5e707SKishon Vijay Abraham I } 89085d5e707SKishon Vijay Abraham I } 89185d5e707SKishon Vijay Abraham I 89285d5e707SKishon Vijay Abraham I status = DWC3_TRB_SIZE_TRBSTS(trb->size); 89385d5e707SKishon Vijay Abraham I if (status == DWC3_TRBSTS_SETUP_PENDING) 8949de1115dSKishon Vijay Abraham I dev_dbg(dwc->dev, "Setup Pending received"); 89585d5e707SKishon Vijay Abraham I 89685d5e707SKishon Vijay Abraham I dwc->ep0state = EP0_SETUP_PHASE; 89785d5e707SKishon Vijay Abraham I dwc3_ep0_out_start(dwc); 89885d5e707SKishon Vijay Abraham I } 89985d5e707SKishon Vijay Abraham I 90085d5e707SKishon Vijay Abraham I static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, 90185d5e707SKishon Vijay Abraham I const struct dwc3_event_depevt *event) 90285d5e707SKishon Vijay Abraham I { 90385d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; 90485d5e707SKishon Vijay Abraham I 90585d5e707SKishon Vijay Abraham I dep->flags &= ~DWC3_EP_BUSY; 90685d5e707SKishon Vijay Abraham I dep->resource_index = 0; 90785d5e707SKishon Vijay Abraham I dwc->setup_packet_pending = false; 90885d5e707SKishon Vijay Abraham I 90985d5e707SKishon Vijay Abraham I switch (dwc->ep0state) { 91085d5e707SKishon Vijay Abraham I case EP0_SETUP_PHASE: 9119de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "Setup Phase"); 91285d5e707SKishon Vijay Abraham I dwc3_ep0_inspect_setup(dwc, event); 91385d5e707SKishon Vijay Abraham I break; 91485d5e707SKishon Vijay Abraham I 91585d5e707SKishon Vijay Abraham I case EP0_DATA_PHASE: 9169de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "Data Phase"); 91785d5e707SKishon Vijay Abraham I dwc3_ep0_complete_data(dwc, event); 91885d5e707SKishon Vijay Abraham I break; 91985d5e707SKishon Vijay Abraham I 92085d5e707SKishon Vijay Abraham I case EP0_STATUS_PHASE: 9219de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "Status Phase"); 92285d5e707SKishon Vijay Abraham I dwc3_ep0_complete_status(dwc, event); 92385d5e707SKishon Vijay Abraham I break; 92485d5e707SKishon Vijay Abraham I default: 92585d5e707SKishon Vijay Abraham I WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state); 92685d5e707SKishon Vijay Abraham I } 92785d5e707SKishon Vijay Abraham I } 92885d5e707SKishon Vijay Abraham I 92985d5e707SKishon Vijay Abraham I static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, 93085d5e707SKishon Vijay Abraham I struct dwc3_ep *dep, struct dwc3_request *req) 93185d5e707SKishon Vijay Abraham I { 93285d5e707SKishon Vijay Abraham I int ret; 93385d5e707SKishon Vijay Abraham I 93485d5e707SKishon Vijay Abraham I req->direction = !!dep->number; 93585d5e707SKishon Vijay Abraham I 93685d5e707SKishon Vijay Abraham I if (req->request.length == 0) { 93785d5e707SKishon Vijay Abraham I ret = dwc3_ep0_start_trans(dwc, dep->number, 93885d5e707SKishon Vijay Abraham I dwc->ctrl_req_addr, 0, 939*8d488f3eSKishon Vijay Abraham I DWC3_TRBCTL_CONTROL_DATA, 0); 940*8d488f3eSKishon Vijay Abraham I } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) && 941*8d488f3eSKishon Vijay Abraham I (dep->number == 0)) { 942*8d488f3eSKishon Vijay Abraham I u32 transfer_size = 0; 94385d5e707SKishon Vijay Abraham I u32 maxpacket; 94485d5e707SKishon Vijay Abraham I 94585d5e707SKishon Vijay Abraham I ret = usb_gadget_map_request(&dwc->gadget, &req->request, 94685d5e707SKishon Vijay Abraham I dep->number); 94785d5e707SKishon Vijay Abraham I if (ret) { 94885d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "failed to map request\n"); 94985d5e707SKishon Vijay Abraham I return; 95085d5e707SKishon Vijay Abraham I } 95185d5e707SKishon Vijay Abraham I 95285d5e707SKishon Vijay Abraham I maxpacket = dep->endpoint.maxpacket; 953*8d488f3eSKishon Vijay Abraham I if (req->request.length > DWC3_EP0_BOUNCE_SIZE) { 954*8d488f3eSKishon Vijay Abraham I transfer_size = (req->request.length / maxpacket) * 955*8d488f3eSKishon Vijay Abraham I maxpacket; 956*8d488f3eSKishon Vijay Abraham I ret = dwc3_ep0_start_trans(dwc, dep->number, 957*8d488f3eSKishon Vijay Abraham I req->request.dma, 958*8d488f3eSKishon Vijay Abraham I transfer_size, 959*8d488f3eSKishon Vijay Abraham I DWC3_TRBCTL_CONTROL_DATA, 1); 960*8d488f3eSKishon Vijay Abraham I } 961*8d488f3eSKishon Vijay Abraham I 962*8d488f3eSKishon Vijay Abraham I transfer_size = roundup((req->request.length - transfer_size), 963*8d488f3eSKishon Vijay Abraham I maxpacket); 96485d5e707SKishon Vijay Abraham I 96585d5e707SKishon Vijay Abraham I dwc->ep0_bounced = true; 96685d5e707SKishon Vijay Abraham I 96785d5e707SKishon Vijay Abraham I /* 96885d5e707SKishon Vijay Abraham I * REVISIT in case request length is bigger than 96985d5e707SKishon Vijay Abraham I * DWC3_EP0_BOUNCE_SIZE we will need two chained 97085d5e707SKishon Vijay Abraham I * TRBs to handle the transfer. 97185d5e707SKishon Vijay Abraham I */ 97285d5e707SKishon Vijay Abraham I ret = dwc3_ep0_start_trans(dwc, dep->number, 97385d5e707SKishon Vijay Abraham I dwc->ep0_bounce_addr, transfer_size, 974*8d488f3eSKishon Vijay Abraham I DWC3_TRBCTL_CONTROL_DATA, 0); 97585d5e707SKishon Vijay Abraham I } else { 97685d5e707SKishon Vijay Abraham I ret = usb_gadget_map_request(&dwc->gadget, &req->request, 97785d5e707SKishon Vijay Abraham I dep->number); 97885d5e707SKishon Vijay Abraham I if (ret) { 97985d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "failed to map request\n"); 98085d5e707SKishon Vijay Abraham I return; 98185d5e707SKishon Vijay Abraham I } 98285d5e707SKishon Vijay Abraham I 98385d5e707SKishon Vijay Abraham I ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma, 984*8d488f3eSKishon Vijay Abraham I req->request.length, 985*8d488f3eSKishon Vijay Abraham I DWC3_TRBCTL_CONTROL_DATA, 0); 98685d5e707SKishon Vijay Abraham I } 98785d5e707SKishon Vijay Abraham I 98885d5e707SKishon Vijay Abraham I WARN_ON(ret < 0); 98985d5e707SKishon Vijay Abraham I } 99085d5e707SKishon Vijay Abraham I 99185d5e707SKishon Vijay Abraham I static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) 99285d5e707SKishon Vijay Abraham I { 99385d5e707SKishon Vijay Abraham I struct dwc3 *dwc = dep->dwc; 99485d5e707SKishon Vijay Abraham I u32 type; 99585d5e707SKishon Vijay Abraham I 99685d5e707SKishon Vijay Abraham I type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3 99785d5e707SKishon Vijay Abraham I : DWC3_TRBCTL_CONTROL_STATUS2; 99885d5e707SKishon Vijay Abraham I 99985d5e707SKishon Vijay Abraham I return dwc3_ep0_start_trans(dwc, dep->number, 1000*8d488f3eSKishon Vijay Abraham I dwc->ctrl_req_addr, 0, type, 0); 100185d5e707SKishon Vijay Abraham I } 100285d5e707SKishon Vijay Abraham I 100385d5e707SKishon Vijay Abraham I static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) 100485d5e707SKishon Vijay Abraham I { 100585d5e707SKishon Vijay Abraham I if (dwc->resize_fifos) { 10069de1115dSKishon Vijay Abraham I dev_dbg(dwc->dev, "Resizing FIFOs"); 100785d5e707SKishon Vijay Abraham I dwc3_gadget_resize_tx_fifos(dwc); 100885d5e707SKishon Vijay Abraham I dwc->resize_fifos = 0; 100985d5e707SKishon Vijay Abraham I } 101085d5e707SKishon Vijay Abraham I 101185d5e707SKishon Vijay Abraham I WARN_ON(dwc3_ep0_start_control_status(dep)); 101285d5e707SKishon Vijay Abraham I } 101385d5e707SKishon Vijay Abraham I 101485d5e707SKishon Vijay Abraham I static void dwc3_ep0_do_control_status(struct dwc3 *dwc, 101585d5e707SKishon Vijay Abraham I const struct dwc3_event_depevt *event) 101685d5e707SKishon Vijay Abraham I { 101785d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; 101885d5e707SKishon Vijay Abraham I 101985d5e707SKishon Vijay Abraham I __dwc3_ep0_do_control_status(dwc, dep); 102085d5e707SKishon Vijay Abraham I } 102185d5e707SKishon Vijay Abraham I 102285d5e707SKishon Vijay Abraham I static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep) 102385d5e707SKishon Vijay Abraham I { 102485d5e707SKishon Vijay Abraham I struct dwc3_gadget_ep_cmd_params params; 102585d5e707SKishon Vijay Abraham I u32 cmd; 102685d5e707SKishon Vijay Abraham I int ret; 102785d5e707SKishon Vijay Abraham I 102885d5e707SKishon Vijay Abraham I if (!dep->resource_index) 102985d5e707SKishon Vijay Abraham I return; 103085d5e707SKishon Vijay Abraham I 103185d5e707SKishon Vijay Abraham I cmd = DWC3_DEPCMD_ENDTRANSFER; 103285d5e707SKishon Vijay Abraham I cmd |= DWC3_DEPCMD_CMDIOC; 103385d5e707SKishon Vijay Abraham I cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); 103485d5e707SKishon Vijay Abraham I memset(¶ms, 0, sizeof(params)); 103585d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); 103685d5e707SKishon Vijay Abraham I WARN_ON_ONCE(ret); 103785d5e707SKishon Vijay Abraham I dep->resource_index = 0; 103885d5e707SKishon Vijay Abraham I } 103985d5e707SKishon Vijay Abraham I 104085d5e707SKishon Vijay Abraham I static void dwc3_ep0_xfernotready(struct dwc3 *dwc, 104185d5e707SKishon Vijay Abraham I const struct dwc3_event_depevt *event) 104285d5e707SKishon Vijay Abraham I { 104385d5e707SKishon Vijay Abraham I dwc->setup_packet_pending = true; 104485d5e707SKishon Vijay Abraham I 104585d5e707SKishon Vijay Abraham I switch (event->status) { 104685d5e707SKishon Vijay Abraham I case DEPEVT_STATUS_CONTROL_DATA: 10479de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "Control Data"); 104885d5e707SKishon Vijay Abraham I 104985d5e707SKishon Vijay Abraham I /* 105085d5e707SKishon Vijay Abraham I * We already have a DATA transfer in the controller's cache, 105185d5e707SKishon Vijay Abraham I * if we receive a XferNotReady(DATA) we will ignore it, unless 105285d5e707SKishon Vijay Abraham I * it's for the wrong direction. 105385d5e707SKishon Vijay Abraham I * 105485d5e707SKishon Vijay Abraham I * In that case, we must issue END_TRANSFER command to the Data 105585d5e707SKishon Vijay Abraham I * Phase we already have started and issue SetStall on the 105685d5e707SKishon Vijay Abraham I * control endpoint. 105785d5e707SKishon Vijay Abraham I */ 105885d5e707SKishon Vijay Abraham I if (dwc->ep0_expect_in != event->endpoint_number) { 105985d5e707SKishon Vijay Abraham I struct dwc3_ep *dep = dwc->eps[dwc->ep0_expect_in]; 106085d5e707SKishon Vijay Abraham I 10619de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "Wrong direction for Data phase"); 106285d5e707SKishon Vijay Abraham I dwc3_ep0_end_control_data(dwc, dep); 106385d5e707SKishon Vijay Abraham I dwc3_ep0_stall_and_restart(dwc); 106485d5e707SKishon Vijay Abraham I return; 106585d5e707SKishon Vijay Abraham I } 106685d5e707SKishon Vijay Abraham I 106785d5e707SKishon Vijay Abraham I break; 106885d5e707SKishon Vijay Abraham I 106985d5e707SKishon Vijay Abraham I case DEPEVT_STATUS_CONTROL_STATUS: 107085d5e707SKishon Vijay Abraham I if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) 107185d5e707SKishon Vijay Abraham I return; 107285d5e707SKishon Vijay Abraham I 10739de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "Control Status"); 107485d5e707SKishon Vijay Abraham I 107585d5e707SKishon Vijay Abraham I dwc->ep0state = EP0_STATUS_PHASE; 107685d5e707SKishon Vijay Abraham I 107785d5e707SKishon Vijay Abraham I if (dwc->delayed_status) { 107885d5e707SKishon Vijay Abraham I WARN_ON_ONCE(event->endpoint_number != 1); 10799de1115dSKishon Vijay Abraham I dev_vdbg(dwc->dev, "Delayed Status"); 108085d5e707SKishon Vijay Abraham I return; 108185d5e707SKishon Vijay Abraham I } 108285d5e707SKishon Vijay Abraham I 108385d5e707SKishon Vijay Abraham I dwc3_ep0_do_control_status(dwc, event); 108485d5e707SKishon Vijay Abraham I } 108585d5e707SKishon Vijay Abraham I } 108685d5e707SKishon Vijay Abraham I 108785d5e707SKishon Vijay Abraham I void dwc3_ep0_interrupt(struct dwc3 *dwc, 108885d5e707SKishon Vijay Abraham I const struct dwc3_event_depevt *event) 108985d5e707SKishon Vijay Abraham I { 109085d5e707SKishon Vijay Abraham I u8 epnum = event->endpoint_number; 109185d5e707SKishon Vijay Abraham I 10929de1115dSKishon Vijay Abraham I dev_dbg(dwc->dev, "%s while ep%d%s in state '%s'", 109385d5e707SKishon Vijay Abraham I dwc3_ep_event_string(event->endpoint_event), 109485d5e707SKishon Vijay Abraham I epnum >> 1, (epnum & 1) ? "in" : "out", 109585d5e707SKishon Vijay Abraham I dwc3_ep0_state_string(dwc->ep0state)); 109685d5e707SKishon Vijay Abraham I 109785d5e707SKishon Vijay Abraham I switch (event->endpoint_event) { 109885d5e707SKishon Vijay Abraham I case DWC3_DEPEVT_XFERCOMPLETE: 109985d5e707SKishon Vijay Abraham I dwc3_ep0_xfer_complete(dwc, event); 110085d5e707SKishon Vijay Abraham I break; 110185d5e707SKishon Vijay Abraham I 110285d5e707SKishon Vijay Abraham I case DWC3_DEPEVT_XFERNOTREADY: 110385d5e707SKishon Vijay Abraham I dwc3_ep0_xfernotready(dwc, event); 110485d5e707SKishon Vijay Abraham I break; 110585d5e707SKishon Vijay Abraham I 110685d5e707SKishon Vijay Abraham I case DWC3_DEPEVT_XFERINPROGRESS: 110785d5e707SKishon Vijay Abraham I case DWC3_DEPEVT_RXTXFIFOEVT: 110885d5e707SKishon Vijay Abraham I case DWC3_DEPEVT_STREAMEVT: 110985d5e707SKishon Vijay Abraham I case DWC3_DEPEVT_EPCMDCMPLT: 111085d5e707SKishon Vijay Abraham I break; 111185d5e707SKishon Vijay Abraham I } 111285d5e707SKishon Vijay Abraham I } 1113