18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Felipe Balbi <balbi@ti.com>, 88c2ecf20Sopenharmony_ci * Sebastian Andrzej Siewior <bigeasy@linutronix.de> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/io.h> 188c2ecf20Sopenharmony_ci#include <linux/list.h> 198c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/usb/ch9.h> 228c2ecf20Sopenharmony_ci#include <linux/usb/gadget.h> 238c2ecf20Sopenharmony_ci#include <linux/usb/composite.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "core.h" 268c2ecf20Sopenharmony_ci#include "debug.h" 278c2ecf20Sopenharmony_ci#include "gadget.h" 288c2ecf20Sopenharmony_ci#include "io.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); 318c2ecf20Sopenharmony_cistatic void __dwc3_ep0_do_control_data(struct dwc3 *dwc, 328c2ecf20Sopenharmony_ci struct dwc3_ep *dep, struct dwc3_request *req); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep, 358c2ecf20Sopenharmony_ci dma_addr_t buf_dma, u32 len, u32 type, bool chain) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct dwc3_trb *trb; 388c2ecf20Sopenharmony_ci struct dwc3 *dwc; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci dwc = dep->dwc; 418c2ecf20Sopenharmony_ci trb = &dwc->ep0_trb[dep->trb_enqueue]; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (chain) 448c2ecf20Sopenharmony_ci dep->trb_enqueue++; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci trb->bpl = lower_32_bits(buf_dma); 478c2ecf20Sopenharmony_ci trb->bph = upper_32_bits(buf_dma); 488c2ecf20Sopenharmony_ci trb->size = len; 498c2ecf20Sopenharmony_ci trb->ctrl = type; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci trb->ctrl |= (DWC3_TRB_CTRL_HWO 528c2ecf20Sopenharmony_ci | DWC3_TRB_CTRL_ISP_IMI); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (chain) 558c2ecf20Sopenharmony_ci trb->ctrl |= DWC3_TRB_CTRL_CHN; 568c2ecf20Sopenharmony_ci else 578c2ecf20Sopenharmony_ci trb->ctrl |= (DWC3_TRB_CTRL_IOC 588c2ecf20Sopenharmony_ci | DWC3_TRB_CTRL_LST); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci trace_dwc3_prepare_trb(dep, trb); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int dwc3_ep0_start_trans(struct dwc3_ep *dep) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct dwc3_gadget_ep_cmd_params params; 668c2ecf20Sopenharmony_ci struct dwc3 *dwc; 678c2ecf20Sopenharmony_ci int ret; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (dep->flags & DWC3_EP_TRANSFER_STARTED) 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci dwc = dep->dwc; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 758c2ecf20Sopenharmony_ci params.param0 = upper_32_bits(dwc->ep0_trb_addr); 768c2ecf20Sopenharmony_ci params.param1 = lower_32_bits(dwc->ep0_trb_addr); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_STARTTRANSFER, ¶ms); 798c2ecf20Sopenharmony_ci if (ret < 0) 808c2ecf20Sopenharmony_ci return ret; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci dwc->ep0_next_event = DWC3_EP0_COMPLETE; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return 0; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, 888c2ecf20Sopenharmony_ci struct dwc3_request *req) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct dwc3 *dwc = dep->dwc; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci req->request.actual = 0; 938c2ecf20Sopenharmony_ci req->request.status = -EINPROGRESS; 948c2ecf20Sopenharmony_ci req->epnum = dep->number; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci list_add_tail(&req->list, &dep->pending_list); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* 998c2ecf20Sopenharmony_ci * Gadget driver might not be quick enough to queue a request 1008c2ecf20Sopenharmony_ci * before we get a Transfer Not Ready event on this endpoint. 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci * In that case, we will set DWC3_EP_PENDING_REQUEST. When that 1038c2ecf20Sopenharmony_ci * flag is set, it's telling us that as soon as Gadget queues the 1048c2ecf20Sopenharmony_ci * required request, we should kick the transfer here because the 1058c2ecf20Sopenharmony_ci * IRQ we were waiting for is long gone. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci if (dep->flags & DWC3_EP_PENDING_REQUEST) { 1088c2ecf20Sopenharmony_ci unsigned int direction; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci direction = !!(dep->flags & DWC3_EP0_DIR_IN); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (dwc->ep0state != EP0_DATA_PHASE) { 1138c2ecf20Sopenharmony_ci dev_WARN(dwc->dev, "Unexpected pending request\n"); 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci __dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci dep->flags &= ~(DWC3_EP_PENDING_REQUEST | 1208c2ecf20Sopenharmony_ci DWC3_EP0_DIR_IN); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* 1268c2ecf20Sopenharmony_ci * In case gadget driver asked us to delay the STATUS phase, 1278c2ecf20Sopenharmony_ci * handle it here. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci if (dwc->delayed_status) { 1308c2ecf20Sopenharmony_ci unsigned int direction; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci direction = !dwc->ep0_expect_in; 1338c2ecf20Sopenharmony_ci dwc->delayed_status = false; 1348c2ecf20Sopenharmony_ci usb_gadget_set_state(dwc->gadget, USB_STATE_CONFIGURED); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (dwc->ep0state == EP0_STATUS_PHASE) 1378c2ecf20Sopenharmony_ci __dwc3_ep0_do_control_status(dwc, dwc->eps[direction]); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* 1438c2ecf20Sopenharmony_ci * Unfortunately we have uncovered a limitation wrt the Data Phase. 1448c2ecf20Sopenharmony_ci * 1458c2ecf20Sopenharmony_ci * Section 9.4 says we can wait for the XferNotReady(DATA) event to 1468c2ecf20Sopenharmony_ci * come before issueing Start Transfer command, but if we do, we will 1478c2ecf20Sopenharmony_ci * miss situations where the host starts another SETUP phase instead of 1488c2ecf20Sopenharmony_ci * the DATA phase. Such cases happen at least on TD.7.6 of the Link 1498c2ecf20Sopenharmony_ci * Layer Compliance Suite. 1508c2ecf20Sopenharmony_ci * 1518c2ecf20Sopenharmony_ci * The problem surfaces due to the fact that in case of back-to-back 1528c2ecf20Sopenharmony_ci * SETUP packets there will be no XferNotReady(DATA) generated and we 1538c2ecf20Sopenharmony_ci * will be stuck waiting for XferNotReady(DATA) forever. 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * By looking at tables 9-13 and 9-14 of the Databook, we can see that 1568c2ecf20Sopenharmony_ci * it tells us to start Data Phase right away. It also mentions that if 1578c2ecf20Sopenharmony_ci * we receive a SETUP phase instead of the DATA phase, core will issue 1588c2ecf20Sopenharmony_ci * XferComplete for the DATA phase, before actually initiating it in 1598c2ecf20Sopenharmony_ci * the wire, with the TRB's status set to "SETUP_PENDING". Such status 1608c2ecf20Sopenharmony_ci * can only be used to print some debugging logs, as the core expects 1618c2ecf20Sopenharmony_ci * us to go through to the STATUS phase and start a CONTROL_STATUS TRB, 1628c2ecf20Sopenharmony_ci * just so it completes right away, without transferring anything and, 1638c2ecf20Sopenharmony_ci * only then, we can go back to the SETUP phase. 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * Because of this scenario, SNPS decided to change the programming 1668c2ecf20Sopenharmony_ci * model of control transfers and support on-demand transfers only for 1678c2ecf20Sopenharmony_ci * the STATUS phase. To fix the issue we have now, we will always wait 1688c2ecf20Sopenharmony_ci * for gadget driver to queue the DATA phase's struct usb_request, then 1698c2ecf20Sopenharmony_ci * start it right away. 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * If we're actually in a 2-stage transfer, we will wait for 1728c2ecf20Sopenharmony_ci * XferNotReady(STATUS). 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci if (dwc->three_stage_setup) { 1758c2ecf20Sopenharmony_ci unsigned int direction; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci direction = dwc->ep0_expect_in; 1788c2ecf20Sopenharmony_ci dwc->ep0state = EP0_DATA_PHASE; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci __dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci dep->flags &= ~DWC3_EP0_DIR_IN; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ciint dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, 1898c2ecf20Sopenharmony_ci gfp_t gfp_flags) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct dwc3_request *req = to_dwc3_request(request); 1928c2ecf20Sopenharmony_ci struct dwc3_ep *dep = to_dwc3_ep(ep); 1938c2ecf20Sopenharmony_ci struct dwc3 *dwc = dep->dwc; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci unsigned long flags; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci int ret; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 2008c2ecf20Sopenharmony_ci if (!dep->endpoint.desc || !dwc->pullups_connected) { 2018c2ecf20Sopenharmony_ci dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n", 2028c2ecf20Sopenharmony_ci dep->name); 2038c2ecf20Sopenharmony_ci ret = -ESHUTDOWN; 2048c2ecf20Sopenharmony_ci goto out; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* we share one TRB for ep0/1 */ 2088c2ecf20Sopenharmony_ci if (!list_empty(&dep->pending_list)) { 2098c2ecf20Sopenharmony_ci ret = -EBUSY; 2108c2ecf20Sopenharmony_ci goto out; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ret = __dwc3_gadget_ep0_queue(dep, req); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ciout: 2168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return ret; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct dwc3_ep *dep; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* reinitialize physical ep1 */ 2268c2ecf20Sopenharmony_ci dep = dwc->eps[1]; 2278c2ecf20Sopenharmony_ci dep->flags = DWC3_EP_ENABLED; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* stall is always issued on EP0 */ 2308c2ecf20Sopenharmony_ci dep = dwc->eps[0]; 2318c2ecf20Sopenharmony_ci __dwc3_gadget_ep_set_halt(dep, 1, false); 2328c2ecf20Sopenharmony_ci dep->flags = DWC3_EP_ENABLED; 2338c2ecf20Sopenharmony_ci dwc->delayed_status = false; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (!list_empty(&dep->pending_list)) { 2368c2ecf20Sopenharmony_ci struct dwc3_request *req; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci req = next_request(&dep->pending_list); 2398c2ecf20Sopenharmony_ci if (!dwc->connected) 2408c2ecf20Sopenharmony_ci dwc3_gadget_giveback(dep, req, -ESHUTDOWN); 2418c2ecf20Sopenharmony_ci else 2428c2ecf20Sopenharmony_ci dwc3_gadget_giveback(dep, req, -ECONNRESET); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci dwc->ep0state = EP0_SETUP_PHASE; 2468c2ecf20Sopenharmony_ci dwc3_ep0_out_start(dwc); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ciint __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct dwc3_ep *dep = to_dwc3_ep(ep); 2528c2ecf20Sopenharmony_ci struct dwc3 *dwc = dep->dwc; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci dwc3_ep0_stall_and_restart(dwc); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ciint dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct dwc3_ep *dep = to_dwc3_ep(ep); 2628c2ecf20Sopenharmony_ci struct dwc3 *dwc = dep->dwc; 2638c2ecf20Sopenharmony_ci unsigned long flags; 2648c2ecf20Sopenharmony_ci int ret; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 2678c2ecf20Sopenharmony_ci ret = __dwc3_gadget_ep0_set_halt(ep, value); 2688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return ret; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_civoid dwc3_ep0_out_start(struct dwc3 *dwc) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct dwc3_ep *dep; 2768c2ecf20Sopenharmony_ci int ret; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci complete(&dwc->ep0_in_setup); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci dep = dwc->eps[0]; 2818c2ecf20Sopenharmony_ci dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 8, 2828c2ecf20Sopenharmony_ci DWC3_TRBCTL_CONTROL_SETUP, false); 2838c2ecf20Sopenharmony_ci ret = dwc3_ep0_start_trans(dep); 2848c2ecf20Sopenharmony_ci WARN_ON(ret < 0); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct dwc3_ep *dep; 2908c2ecf20Sopenharmony_ci u32 windex = le16_to_cpu(wIndex_le); 2918c2ecf20Sopenharmony_ci u32 epnum; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1; 2948c2ecf20Sopenharmony_ci if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) 2958c2ecf20Sopenharmony_ci epnum |= 1; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci dep = dwc->eps[epnum]; 2988c2ecf20Sopenharmony_ci if (dep == NULL) 2998c2ecf20Sopenharmony_ci return NULL; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (dep->flags & DWC3_EP_ENABLED) 3028c2ecf20Sopenharmony_ci return dep; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return NULL; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci/* 3118c2ecf20Sopenharmony_ci * ch 9.4.5 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_cistatic int dwc3_ep0_handle_status(struct dwc3 *dwc, 3148c2ecf20Sopenharmony_ci struct usb_ctrlrequest *ctrl) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct dwc3_ep *dep; 3178c2ecf20Sopenharmony_ci u32 recip; 3188c2ecf20Sopenharmony_ci u32 value; 3198c2ecf20Sopenharmony_ci u32 reg; 3208c2ecf20Sopenharmony_ci u16 usb_status = 0; 3218c2ecf20Sopenharmony_ci __le16 *response_pkt; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* We don't support PTM_STATUS */ 3248c2ecf20Sopenharmony_ci value = le16_to_cpu(ctrl->wValue); 3258c2ecf20Sopenharmony_ci if (value != 0) 3268c2ecf20Sopenharmony_ci return -EINVAL; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci recip = ctrl->bRequestType & USB_RECIP_MASK; 3298c2ecf20Sopenharmony_ci switch (recip) { 3308c2ecf20Sopenharmony_ci case USB_RECIP_DEVICE: 3318c2ecf20Sopenharmony_ci /* 3328c2ecf20Sopenharmony_ci * LTM will be set once we know how to set this in HW. 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_ci usb_status |= dwc->gadget->is_selfpowered; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if ((dwc->speed == DWC3_DSTS_SUPERSPEED) || 3378c2ecf20Sopenharmony_ci (dwc->speed == DWC3_DSTS_SUPERSPEED_PLUS)) { 3388c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_DCTL); 3398c2ecf20Sopenharmony_ci if (reg & DWC3_DCTL_INITU1ENA) 3408c2ecf20Sopenharmony_ci usb_status |= 1 << USB_DEV_STAT_U1_ENABLED; 3418c2ecf20Sopenharmony_ci if (reg & DWC3_DCTL_INITU2ENA) 3428c2ecf20Sopenharmony_ci usb_status |= 1 << USB_DEV_STAT_U2_ENABLED; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci case USB_RECIP_INTERFACE: 3488c2ecf20Sopenharmony_ci /* 3498c2ecf20Sopenharmony_ci * Function Remote Wake Capable D0 3508c2ecf20Sopenharmony_ci * Function Remote Wakeup D1 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci case USB_RECIP_ENDPOINT: 3558c2ecf20Sopenharmony_ci dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); 3568c2ecf20Sopenharmony_ci if (!dep) 3578c2ecf20Sopenharmony_ci return -EINVAL; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (dep->flags & DWC3_EP_STALL) 3608c2ecf20Sopenharmony_ci usb_status = 1 << USB_ENDPOINT_HALT; 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci default: 3638c2ecf20Sopenharmony_ci return -EINVAL; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci response_pkt = (__le16 *) dwc->setup_buf; 3678c2ecf20Sopenharmony_ci *response_pkt = cpu_to_le16(usb_status); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci dep = dwc->eps[0]; 3708c2ecf20Sopenharmony_ci dwc->ep0_usb_req.dep = dep; 3718c2ecf20Sopenharmony_ci dwc->ep0_usb_req.request.length = sizeof(*response_pkt); 3728c2ecf20Sopenharmony_ci dwc->ep0_usb_req.request.buf = dwc->setup_buf; 3738c2ecf20Sopenharmony_ci dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state, 3798c2ecf20Sopenharmony_ci int set) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci u32 reg; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (state != USB_STATE_CONFIGURED) 3848c2ecf20Sopenharmony_ci return -EINVAL; 3858c2ecf20Sopenharmony_ci if ((dwc->speed != DWC3_DSTS_SUPERSPEED) && 3868c2ecf20Sopenharmony_ci (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS)) 3878c2ecf20Sopenharmony_ci return -EINVAL; 3888c2ecf20Sopenharmony_ci if (set && dwc->dis_u1_entry_quirk) 3898c2ecf20Sopenharmony_ci return -EINVAL; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_DCTL); 3928c2ecf20Sopenharmony_ci if (set) 3938c2ecf20Sopenharmony_ci reg |= DWC3_DCTL_INITU1ENA; 3948c2ecf20Sopenharmony_ci else 3958c2ecf20Sopenharmony_ci reg &= ~DWC3_DCTL_INITU1ENA; 3968c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_DCTL, reg); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic int dwc3_ep0_handle_u2(struct dwc3 *dwc, enum usb_device_state state, 4028c2ecf20Sopenharmony_ci int set) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci u32 reg; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (state != USB_STATE_CONFIGURED) 4088c2ecf20Sopenharmony_ci return -EINVAL; 4098c2ecf20Sopenharmony_ci if ((dwc->speed != DWC3_DSTS_SUPERSPEED) && 4108c2ecf20Sopenharmony_ci (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS)) 4118c2ecf20Sopenharmony_ci return -EINVAL; 4128c2ecf20Sopenharmony_ci if (set && dwc->dis_u2_entry_quirk) 4138c2ecf20Sopenharmony_ci return -EINVAL; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_DCTL); 4168c2ecf20Sopenharmony_ci if (set) 4178c2ecf20Sopenharmony_ci reg |= DWC3_DCTL_INITU2ENA; 4188c2ecf20Sopenharmony_ci else 4198c2ecf20Sopenharmony_ci reg &= ~DWC3_DCTL_INITU2ENA; 4208c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_DCTL, reg); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return 0; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int dwc3_ep0_handle_test(struct dwc3 *dwc, enum usb_device_state state, 4268c2ecf20Sopenharmony_ci u32 wIndex, int set) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci if ((wIndex & 0xff) != 0) 4298c2ecf20Sopenharmony_ci return -EINVAL; 4308c2ecf20Sopenharmony_ci if (!set) 4318c2ecf20Sopenharmony_ci return -EINVAL; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci switch (wIndex >> 8) { 4348c2ecf20Sopenharmony_ci case USB_TEST_J: 4358c2ecf20Sopenharmony_ci case USB_TEST_K: 4368c2ecf20Sopenharmony_ci case USB_TEST_SE0_NAK: 4378c2ecf20Sopenharmony_ci case USB_TEST_PACKET: 4388c2ecf20Sopenharmony_ci case USB_TEST_FORCE_ENABLE: 4398c2ecf20Sopenharmony_ci dwc->test_mode_nr = wIndex >> 8; 4408c2ecf20Sopenharmony_ci dwc->test_mode = true; 4418c2ecf20Sopenharmony_ci break; 4428c2ecf20Sopenharmony_ci default: 4438c2ecf20Sopenharmony_ci return -EINVAL; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int dwc3_ep0_handle_device(struct dwc3 *dwc, 4508c2ecf20Sopenharmony_ci struct usb_ctrlrequest *ctrl, int set) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci enum usb_device_state state; 4538c2ecf20Sopenharmony_ci u32 wValue; 4548c2ecf20Sopenharmony_ci u32 wIndex; 4558c2ecf20Sopenharmony_ci int ret = 0; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci wValue = le16_to_cpu(ctrl->wValue); 4588c2ecf20Sopenharmony_ci wIndex = le16_to_cpu(ctrl->wIndex); 4598c2ecf20Sopenharmony_ci state = dwc->gadget->state; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci switch (wValue) { 4628c2ecf20Sopenharmony_ci case USB_DEVICE_REMOTE_WAKEUP: 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci /* 4658c2ecf20Sopenharmony_ci * 9.4.1 says only only for SS, in AddressState only for 4668c2ecf20Sopenharmony_ci * default control pipe 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_ci case USB_DEVICE_U1_ENABLE: 4698c2ecf20Sopenharmony_ci ret = dwc3_ep0_handle_u1(dwc, state, set); 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci case USB_DEVICE_U2_ENABLE: 4728c2ecf20Sopenharmony_ci ret = dwc3_ep0_handle_u2(dwc, state, set); 4738c2ecf20Sopenharmony_ci break; 4748c2ecf20Sopenharmony_ci case USB_DEVICE_LTM_ENABLE: 4758c2ecf20Sopenharmony_ci ret = -EINVAL; 4768c2ecf20Sopenharmony_ci break; 4778c2ecf20Sopenharmony_ci case USB_DEVICE_TEST_MODE: 4788c2ecf20Sopenharmony_ci ret = dwc3_ep0_handle_test(dwc, state, wIndex, set); 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci default: 4818c2ecf20Sopenharmony_ci ret = -EINVAL; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci return ret; 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic int dwc3_ep0_handle_intf(struct dwc3 *dwc, 4888c2ecf20Sopenharmony_ci struct usb_ctrlrequest *ctrl, int set) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci u32 wValue; 4918c2ecf20Sopenharmony_ci int ret = 0; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci wValue = le16_to_cpu(ctrl->wValue); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci switch (wValue) { 4968c2ecf20Sopenharmony_ci case USB_INTRF_FUNC_SUSPEND: 4978c2ecf20Sopenharmony_ci /* 4988c2ecf20Sopenharmony_ci * REVISIT: Ideally we would enable some low power mode here, 4998c2ecf20Sopenharmony_ci * however it's unclear what we should be doing here. 5008c2ecf20Sopenharmony_ci * 5018c2ecf20Sopenharmony_ci * For now, we're not doing anything, just making sure we return 5028c2ecf20Sopenharmony_ci * 0 so USB Command Verifier tests pass without any errors. 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_ci break; 5058c2ecf20Sopenharmony_ci default: 5068c2ecf20Sopenharmony_ci ret = -EINVAL; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return ret; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic int dwc3_ep0_handle_endpoint(struct dwc3 *dwc, 5138c2ecf20Sopenharmony_ci struct usb_ctrlrequest *ctrl, int set) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci struct dwc3_ep *dep; 5168c2ecf20Sopenharmony_ci u32 wValue; 5178c2ecf20Sopenharmony_ci int ret; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci wValue = le16_to_cpu(ctrl->wValue); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci switch (wValue) { 5228c2ecf20Sopenharmony_ci case USB_ENDPOINT_HALT: 5238c2ecf20Sopenharmony_ci dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); 5248c2ecf20Sopenharmony_ci if (!dep) 5258c2ecf20Sopenharmony_ci return -EINVAL; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (set == 0 && (dep->flags & DWC3_EP_WEDGE)) 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci ret = __dwc3_gadget_ep_set_halt(dep, set, true); 5318c2ecf20Sopenharmony_ci if (ret) 5328c2ecf20Sopenharmony_ci return -EINVAL; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* ClearFeature(Halt) may need delayed status */ 5358c2ecf20Sopenharmony_ci if (!set && (dep->flags & DWC3_EP_END_TRANSFER_PENDING)) 5368c2ecf20Sopenharmony_ci return USB_GADGET_DELAYED_STATUS; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci break; 5398c2ecf20Sopenharmony_ci default: 5408c2ecf20Sopenharmony_ci return -EINVAL; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return 0; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic int dwc3_ep0_handle_feature(struct dwc3 *dwc, 5478c2ecf20Sopenharmony_ci struct usb_ctrlrequest *ctrl, int set) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci u32 recip; 5508c2ecf20Sopenharmony_ci int ret; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci recip = ctrl->bRequestType & USB_RECIP_MASK; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci switch (recip) { 5558c2ecf20Sopenharmony_ci case USB_RECIP_DEVICE: 5568c2ecf20Sopenharmony_ci ret = dwc3_ep0_handle_device(dwc, ctrl, set); 5578c2ecf20Sopenharmony_ci break; 5588c2ecf20Sopenharmony_ci case USB_RECIP_INTERFACE: 5598c2ecf20Sopenharmony_ci ret = dwc3_ep0_handle_intf(dwc, ctrl, set); 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci case USB_RECIP_ENDPOINT: 5628c2ecf20Sopenharmony_ci ret = dwc3_ep0_handle_endpoint(dwc, ctrl, set); 5638c2ecf20Sopenharmony_ci break; 5648c2ecf20Sopenharmony_ci default: 5658c2ecf20Sopenharmony_ci ret = -EINVAL; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci return ret; 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci enum usb_device_state state = dwc->gadget->state; 5748c2ecf20Sopenharmony_ci u32 addr; 5758c2ecf20Sopenharmony_ci u32 reg; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci addr = le16_to_cpu(ctrl->wValue); 5788c2ecf20Sopenharmony_ci if (addr > 127) { 5798c2ecf20Sopenharmony_ci dev_err(dwc->dev, "invalid device address %d\n", addr); 5808c2ecf20Sopenharmony_ci return -EINVAL; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (state == USB_STATE_CONFIGURED) { 5848c2ecf20Sopenharmony_ci dev_err(dwc->dev, "can't SetAddress() from Configured State\n"); 5858c2ecf20Sopenharmony_ci return -EINVAL; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_DCFG); 5898c2ecf20Sopenharmony_ci reg &= ~(DWC3_DCFG_DEVADDR_MASK); 5908c2ecf20Sopenharmony_ci reg |= DWC3_DCFG_DEVADDR(addr); 5918c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_DCFG, reg); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (addr) 5948c2ecf20Sopenharmony_ci usb_gadget_set_state(dwc->gadget, USB_STATE_ADDRESS); 5958c2ecf20Sopenharmony_ci else 5968c2ecf20Sopenharmony_ci usb_gadget_set_state(dwc->gadget, USB_STATE_DEFAULT); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci return 0; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci int ret; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci spin_unlock(&dwc->lock); 6068c2ecf20Sopenharmony_ci ret = dwc->gadget_driver->setup(dwc->gadget, ctrl); 6078c2ecf20Sopenharmony_ci spin_lock(&dwc->lock); 6088c2ecf20Sopenharmony_ci return ret; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci enum usb_device_state state = dwc->gadget->state; 6148c2ecf20Sopenharmony_ci u32 cfg; 6158c2ecf20Sopenharmony_ci int ret; 6168c2ecf20Sopenharmony_ci u32 reg; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci cfg = le16_to_cpu(ctrl->wValue); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci switch (state) { 6218c2ecf20Sopenharmony_ci case USB_STATE_DEFAULT: 6228c2ecf20Sopenharmony_ci return -EINVAL; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci case USB_STATE_ADDRESS: 6258c2ecf20Sopenharmony_ci ret = dwc3_ep0_delegate_req(dwc, ctrl); 6268c2ecf20Sopenharmony_ci /* if the cfg matches and the cfg is non zero */ 6278c2ecf20Sopenharmony_ci if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* 6308c2ecf20Sopenharmony_ci * only change state if set_config has already 6318c2ecf20Sopenharmony_ci * been processed. If gadget driver returns 6328c2ecf20Sopenharmony_ci * USB_GADGET_DELAYED_STATUS, we will wait 6338c2ecf20Sopenharmony_ci * to change the state on the next usb_ep_queue() 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ci if (ret == 0) 6368c2ecf20Sopenharmony_ci usb_gadget_set_state(dwc->gadget, 6378c2ecf20Sopenharmony_ci USB_STATE_CONFIGURED); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci /* 6408c2ecf20Sopenharmony_ci * Enable transition to U1/U2 state when 6418c2ecf20Sopenharmony_ci * nothing is pending from application. 6428c2ecf20Sopenharmony_ci */ 6438c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_DCTL); 6448c2ecf20Sopenharmony_ci if (!dwc->dis_u1_entry_quirk) 6458c2ecf20Sopenharmony_ci reg |= DWC3_DCTL_ACCEPTU1ENA; 6468c2ecf20Sopenharmony_ci if (!dwc->dis_u2_entry_quirk) 6478c2ecf20Sopenharmony_ci reg |= DWC3_DCTL_ACCEPTU2ENA; 6488c2ecf20Sopenharmony_ci dwc3_writel(dwc->regs, DWC3_DCTL, reg); 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci break; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci case USB_STATE_CONFIGURED: 6538c2ecf20Sopenharmony_ci ret = dwc3_ep0_delegate_req(dwc, ctrl); 6548c2ecf20Sopenharmony_ci if (!cfg && !ret) 6558c2ecf20Sopenharmony_ci usb_gadget_set_state(dwc->gadget, 6568c2ecf20Sopenharmony_ci USB_STATE_ADDRESS); 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci default: 6598c2ecf20Sopenharmony_ci ret = -EINVAL; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci return ret; 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct dwc3_ep *dep = to_dwc3_ep(ep); 6678c2ecf20Sopenharmony_ci struct dwc3 *dwc = dep->dwc; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci u32 param = 0; 6708c2ecf20Sopenharmony_ci u32 reg; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci struct timing { 6738c2ecf20Sopenharmony_ci u8 u1sel; 6748c2ecf20Sopenharmony_ci u8 u1pel; 6758c2ecf20Sopenharmony_ci __le16 u2sel; 6768c2ecf20Sopenharmony_ci __le16 u2pel; 6778c2ecf20Sopenharmony_ci } __packed timing; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci int ret; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci memcpy(&timing, req->buf, sizeof(timing)); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci dwc->u1sel = timing.u1sel; 6848c2ecf20Sopenharmony_ci dwc->u1pel = timing.u1pel; 6858c2ecf20Sopenharmony_ci dwc->u2sel = le16_to_cpu(timing.u2sel); 6868c2ecf20Sopenharmony_ci dwc->u2pel = le16_to_cpu(timing.u2pel); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci reg = dwc3_readl(dwc->regs, DWC3_DCTL); 6898c2ecf20Sopenharmony_ci if (reg & DWC3_DCTL_INITU2ENA) 6908c2ecf20Sopenharmony_ci param = dwc->u2pel; 6918c2ecf20Sopenharmony_ci if (reg & DWC3_DCTL_INITU1ENA) 6928c2ecf20Sopenharmony_ci param = dwc->u1pel; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* 6958c2ecf20Sopenharmony_ci * According to Synopsys Databook, if parameter is 6968c2ecf20Sopenharmony_ci * greater than 125, a value of zero should be 6978c2ecf20Sopenharmony_ci * programmed in the register. 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_ci if (param > 125) 7008c2ecf20Sopenharmony_ci param = 0; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* now that we have the time, issue DGCMD Set Sel */ 7038c2ecf20Sopenharmony_ci ret = dwc3_send_gadget_generic_command(dwc, 7048c2ecf20Sopenharmony_ci DWC3_DGCMD_SET_PERIODIC_PAR, param); 7058c2ecf20Sopenharmony_ci WARN_ON(ret < 0); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct dwc3_ep *dep; 7118c2ecf20Sopenharmony_ci enum usb_device_state state = dwc->gadget->state; 7128c2ecf20Sopenharmony_ci u16 wLength; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci if (state == USB_STATE_DEFAULT) 7158c2ecf20Sopenharmony_ci return -EINVAL; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci wLength = le16_to_cpu(ctrl->wLength); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (wLength != 6) { 7208c2ecf20Sopenharmony_ci dev_err(dwc->dev, "Set SEL should be 6 bytes, got %d\n", 7218c2ecf20Sopenharmony_ci wLength); 7228c2ecf20Sopenharmony_ci return -EINVAL; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci /* 7268c2ecf20Sopenharmony_ci * To handle Set SEL we need to receive 6 bytes from Host. So let's 7278c2ecf20Sopenharmony_ci * queue a usb_request for 6 bytes. 7288c2ecf20Sopenharmony_ci * 7298c2ecf20Sopenharmony_ci * Remember, though, this controller can't handle non-wMaxPacketSize 7308c2ecf20Sopenharmony_ci * aligned transfers on the OUT direction, so we queue a request for 7318c2ecf20Sopenharmony_ci * wMaxPacketSize instead. 7328c2ecf20Sopenharmony_ci */ 7338c2ecf20Sopenharmony_ci dep = dwc->eps[0]; 7348c2ecf20Sopenharmony_ci dwc->ep0_usb_req.dep = dep; 7358c2ecf20Sopenharmony_ci dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket; 7368c2ecf20Sopenharmony_ci dwc->ep0_usb_req.request.buf = dwc->setup_buf; 7378c2ecf20Sopenharmony_ci dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci u16 wLength; 7458c2ecf20Sopenharmony_ci u16 wValue; 7468c2ecf20Sopenharmony_ci u16 wIndex; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci wValue = le16_to_cpu(ctrl->wValue); 7498c2ecf20Sopenharmony_ci wLength = le16_to_cpu(ctrl->wLength); 7508c2ecf20Sopenharmony_ci wIndex = le16_to_cpu(ctrl->wIndex); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (wIndex || wLength) 7538c2ecf20Sopenharmony_ci return -EINVAL; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci dwc->gadget->isoch_delay = wValue; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci return 0; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci int ret; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci switch (ctrl->bRequest) { 7658c2ecf20Sopenharmony_ci case USB_REQ_GET_STATUS: 7668c2ecf20Sopenharmony_ci ret = dwc3_ep0_handle_status(dwc, ctrl); 7678c2ecf20Sopenharmony_ci break; 7688c2ecf20Sopenharmony_ci case USB_REQ_CLEAR_FEATURE: 7698c2ecf20Sopenharmony_ci ret = dwc3_ep0_handle_feature(dwc, ctrl, 0); 7708c2ecf20Sopenharmony_ci break; 7718c2ecf20Sopenharmony_ci case USB_REQ_SET_FEATURE: 7728c2ecf20Sopenharmony_ci ret = dwc3_ep0_handle_feature(dwc, ctrl, 1); 7738c2ecf20Sopenharmony_ci break; 7748c2ecf20Sopenharmony_ci case USB_REQ_SET_ADDRESS: 7758c2ecf20Sopenharmony_ci ret = dwc3_ep0_set_address(dwc, ctrl); 7768c2ecf20Sopenharmony_ci break; 7778c2ecf20Sopenharmony_ci case USB_REQ_SET_CONFIGURATION: 7788c2ecf20Sopenharmony_ci ret = dwc3_ep0_set_config(dwc, ctrl); 7798c2ecf20Sopenharmony_ci break; 7808c2ecf20Sopenharmony_ci case USB_REQ_SET_SEL: 7818c2ecf20Sopenharmony_ci ret = dwc3_ep0_set_sel(dwc, ctrl); 7828c2ecf20Sopenharmony_ci break; 7838c2ecf20Sopenharmony_ci case USB_REQ_SET_ISOCH_DELAY: 7848c2ecf20Sopenharmony_ci ret = dwc3_ep0_set_isoch_delay(dwc, ctrl); 7858c2ecf20Sopenharmony_ci break; 7868c2ecf20Sopenharmony_ci default: 7878c2ecf20Sopenharmony_ci ret = dwc3_ep0_delegate_req(dwc, ctrl); 7888c2ecf20Sopenharmony_ci break; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci return ret; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic void dwc3_ep0_inspect_setup(struct dwc3 *dwc, 7958c2ecf20Sopenharmony_ci const struct dwc3_event_depevt *event) 7968c2ecf20Sopenharmony_ci{ 7978c2ecf20Sopenharmony_ci struct usb_ctrlrequest *ctrl = (void *) dwc->ep0_trb; 7988c2ecf20Sopenharmony_ci int ret = -EINVAL; 7998c2ecf20Sopenharmony_ci u32 len; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (!dwc->gadget_driver) 8028c2ecf20Sopenharmony_ci goto out; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci trace_dwc3_ctrl_req(ctrl); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci len = le16_to_cpu(ctrl->wLength); 8078c2ecf20Sopenharmony_ci if (!len) { 8088c2ecf20Sopenharmony_ci dwc->three_stage_setup = false; 8098c2ecf20Sopenharmony_ci dwc->ep0_expect_in = false; 8108c2ecf20Sopenharmony_ci dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; 8118c2ecf20Sopenharmony_ci } else { 8128c2ecf20Sopenharmony_ci dwc->three_stage_setup = true; 8138c2ecf20Sopenharmony_ci dwc->ep0_expect_in = !!(ctrl->bRequestType & USB_DIR_IN); 8148c2ecf20Sopenharmony_ci dwc->ep0_next_event = DWC3_EP0_NRDY_DATA; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) 8188c2ecf20Sopenharmony_ci ret = dwc3_ep0_std_request(dwc, ctrl); 8198c2ecf20Sopenharmony_ci else 8208c2ecf20Sopenharmony_ci ret = dwc3_ep0_delegate_req(dwc, ctrl); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (ret == USB_GADGET_DELAYED_STATUS) 8238c2ecf20Sopenharmony_ci dwc->delayed_status = true; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ciout: 8268c2ecf20Sopenharmony_ci if (ret < 0) 8278c2ecf20Sopenharmony_ci dwc3_ep0_stall_and_restart(dwc); 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cistatic void dwc3_ep0_complete_data(struct dwc3 *dwc, 8318c2ecf20Sopenharmony_ci const struct dwc3_event_depevt *event) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci struct dwc3_request *r; 8348c2ecf20Sopenharmony_ci struct usb_request *ur; 8358c2ecf20Sopenharmony_ci struct dwc3_trb *trb; 8368c2ecf20Sopenharmony_ci struct dwc3_ep *ep0; 8378c2ecf20Sopenharmony_ci u32 transferred = 0; 8388c2ecf20Sopenharmony_ci u32 status; 8398c2ecf20Sopenharmony_ci u32 length; 8408c2ecf20Sopenharmony_ci u8 epnum; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci epnum = event->endpoint_number; 8438c2ecf20Sopenharmony_ci ep0 = dwc->eps[0]; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; 8468c2ecf20Sopenharmony_ci trb = dwc->ep0_trb; 8478c2ecf20Sopenharmony_ci trace_dwc3_complete_trb(ep0, trb); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci r = next_request(&ep0->pending_list); 8508c2ecf20Sopenharmony_ci if (!r) 8518c2ecf20Sopenharmony_ci return; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci status = DWC3_TRB_SIZE_TRBSTS(trb->size); 8548c2ecf20Sopenharmony_ci if (status == DWC3_TRBSTS_SETUP_PENDING) { 8558c2ecf20Sopenharmony_ci dwc->setup_packet_pending = true; 8568c2ecf20Sopenharmony_ci if (r) 8578c2ecf20Sopenharmony_ci dwc3_gadget_giveback(ep0, r, -ECONNRESET); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci return; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci ur = &r->request; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci length = trb->size & DWC3_TRB_SIZE_MASK; 8658c2ecf20Sopenharmony_ci transferred = ur->length - length; 8668c2ecf20Sopenharmony_ci ur->actual += transferred; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if ((IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) && 8698c2ecf20Sopenharmony_ci ur->length && ur->zero) || dwc->ep0_bounced) { 8708c2ecf20Sopenharmony_ci trb++; 8718c2ecf20Sopenharmony_ci trb->ctrl &= ~DWC3_TRB_CTRL_HWO; 8728c2ecf20Sopenharmony_ci trace_dwc3_complete_trb(ep0, trb); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (r->direction) 8758c2ecf20Sopenharmony_ci dwc->eps[1]->trb_enqueue = 0; 8768c2ecf20Sopenharmony_ci else 8778c2ecf20Sopenharmony_ci dwc->eps[0]->trb_enqueue = 0; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci dwc->ep0_bounced = false; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if ((epnum & 1) && ur->actual < ur->length) 8838c2ecf20Sopenharmony_ci dwc3_ep0_stall_and_restart(dwc); 8848c2ecf20Sopenharmony_ci else 8858c2ecf20Sopenharmony_ci dwc3_gadget_giveback(ep0, r, 0); 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic void dwc3_ep0_complete_status(struct dwc3 *dwc, 8898c2ecf20Sopenharmony_ci const struct dwc3_event_depevt *event) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci struct dwc3_request *r; 8928c2ecf20Sopenharmony_ci struct dwc3_ep *dep; 8938c2ecf20Sopenharmony_ci struct dwc3_trb *trb; 8948c2ecf20Sopenharmony_ci u32 status; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci dep = dwc->eps[0]; 8978c2ecf20Sopenharmony_ci trb = dwc->ep0_trb; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci trace_dwc3_complete_trb(dep, trb); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (!list_empty(&dep->pending_list)) { 9028c2ecf20Sopenharmony_ci r = next_request(&dep->pending_list); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci dwc3_gadget_giveback(dep, r, 0); 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci if (dwc->test_mode) { 9088c2ecf20Sopenharmony_ci int ret; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci ret = dwc3_gadget_set_test_mode(dwc, dwc->test_mode_nr); 9118c2ecf20Sopenharmony_ci if (ret < 0) { 9128c2ecf20Sopenharmony_ci dev_err(dwc->dev, "invalid test #%d\n", 9138c2ecf20Sopenharmony_ci dwc->test_mode_nr); 9148c2ecf20Sopenharmony_ci dwc3_ep0_stall_and_restart(dwc); 9158c2ecf20Sopenharmony_ci return; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci status = DWC3_TRB_SIZE_TRBSTS(trb->size); 9208c2ecf20Sopenharmony_ci if (status == DWC3_TRBSTS_SETUP_PENDING) 9218c2ecf20Sopenharmony_ci dwc->setup_packet_pending = true; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci dwc->ep0state = EP0_SETUP_PHASE; 9248c2ecf20Sopenharmony_ci dwc3_ep0_out_start(dwc); 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cistatic void dwc3_ep0_xfer_complete(struct dwc3 *dwc, 9288c2ecf20Sopenharmony_ci const struct dwc3_event_depevt *event) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci dep->flags &= ~DWC3_EP_TRANSFER_STARTED; 9338c2ecf20Sopenharmony_ci dep->resource_index = 0; 9348c2ecf20Sopenharmony_ci dwc->setup_packet_pending = false; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci switch (dwc->ep0state) { 9378c2ecf20Sopenharmony_ci case EP0_SETUP_PHASE: 9388c2ecf20Sopenharmony_ci dwc3_ep0_inspect_setup(dwc, event); 9398c2ecf20Sopenharmony_ci break; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci case EP0_DATA_PHASE: 9428c2ecf20Sopenharmony_ci dwc3_ep0_complete_data(dwc, event); 9438c2ecf20Sopenharmony_ci break; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci case EP0_STATUS_PHASE: 9468c2ecf20Sopenharmony_ci dwc3_ep0_complete_status(dwc, event); 9478c2ecf20Sopenharmony_ci break; 9488c2ecf20Sopenharmony_ci default: 9498c2ecf20Sopenharmony_ci WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state); 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic void __dwc3_ep0_do_control_data(struct dwc3 *dwc, 9548c2ecf20Sopenharmony_ci struct dwc3_ep *dep, struct dwc3_request *req) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci unsigned int trb_length = 0; 9578c2ecf20Sopenharmony_ci int ret; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci req->direction = !!dep->number; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (req->request.length == 0) { 9628c2ecf20Sopenharmony_ci if (!req->direction) 9638c2ecf20Sopenharmony_ci trb_length = dep->endpoint.maxpacket; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr, trb_length, 9668c2ecf20Sopenharmony_ci DWC3_TRBCTL_CONTROL_DATA, false); 9678c2ecf20Sopenharmony_ci ret = dwc3_ep0_start_trans(dep); 9688c2ecf20Sopenharmony_ci } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) 9698c2ecf20Sopenharmony_ci && (dep->number == 0)) { 9708c2ecf20Sopenharmony_ci u32 maxpacket; 9718c2ecf20Sopenharmony_ci u32 rem; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci ret = usb_gadget_map_request_by_dev(dwc->sysdev, 9748c2ecf20Sopenharmony_ci &req->request, dep->number); 9758c2ecf20Sopenharmony_ci if (ret) 9768c2ecf20Sopenharmony_ci return; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci maxpacket = dep->endpoint.maxpacket; 9798c2ecf20Sopenharmony_ci rem = req->request.length % maxpacket; 9808c2ecf20Sopenharmony_ci dwc->ep0_bounced = true; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* prepare normal TRB */ 9838c2ecf20Sopenharmony_ci dwc3_ep0_prepare_one_trb(dep, req->request.dma, 9848c2ecf20Sopenharmony_ci req->request.length, 9858c2ecf20Sopenharmony_ci DWC3_TRBCTL_CONTROL_DATA, 9868c2ecf20Sopenharmony_ci true); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci req->trb = &dwc->ep0_trb[dep->trb_enqueue - 1]; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* Now prepare one extra TRB to align transfer size */ 9918c2ecf20Sopenharmony_ci dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr, 9928c2ecf20Sopenharmony_ci maxpacket - rem, 9938c2ecf20Sopenharmony_ci DWC3_TRBCTL_CONTROL_DATA, 9948c2ecf20Sopenharmony_ci false); 9958c2ecf20Sopenharmony_ci ret = dwc3_ep0_start_trans(dep); 9968c2ecf20Sopenharmony_ci } else if (IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) && 9978c2ecf20Sopenharmony_ci req->request.length && req->request.zero) { 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci ret = usb_gadget_map_request_by_dev(dwc->sysdev, 10008c2ecf20Sopenharmony_ci &req->request, dep->number); 10018c2ecf20Sopenharmony_ci if (ret) 10028c2ecf20Sopenharmony_ci return; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci /* prepare normal TRB */ 10058c2ecf20Sopenharmony_ci dwc3_ep0_prepare_one_trb(dep, req->request.dma, 10068c2ecf20Sopenharmony_ci req->request.length, 10078c2ecf20Sopenharmony_ci DWC3_TRBCTL_CONTROL_DATA, 10088c2ecf20Sopenharmony_ci true); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci req->trb = &dwc->ep0_trb[dep->trb_enqueue - 1]; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (!req->direction) 10138c2ecf20Sopenharmony_ci trb_length = dep->endpoint.maxpacket; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci /* Now prepare one extra TRB to align transfer size */ 10168c2ecf20Sopenharmony_ci dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr, 10178c2ecf20Sopenharmony_ci trb_length, DWC3_TRBCTL_CONTROL_DATA, 10188c2ecf20Sopenharmony_ci false); 10198c2ecf20Sopenharmony_ci ret = dwc3_ep0_start_trans(dep); 10208c2ecf20Sopenharmony_ci } else { 10218c2ecf20Sopenharmony_ci ret = usb_gadget_map_request_by_dev(dwc->sysdev, 10228c2ecf20Sopenharmony_ci &req->request, dep->number); 10238c2ecf20Sopenharmony_ci if (ret) 10248c2ecf20Sopenharmony_ci return; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci dwc3_ep0_prepare_one_trb(dep, req->request.dma, 10278c2ecf20Sopenharmony_ci req->request.length, DWC3_TRBCTL_CONTROL_DATA, 10288c2ecf20Sopenharmony_ci false); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci req->trb = &dwc->ep0_trb[dep->trb_enqueue]; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci ret = dwc3_ep0_start_trans(dep); 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci WARN_ON(ret < 0); 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic int dwc3_ep0_start_control_status(struct dwc3_ep *dep) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci struct dwc3 *dwc = dep->dwc; 10418c2ecf20Sopenharmony_ci u32 type; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3 10448c2ecf20Sopenharmony_ci : DWC3_TRBCTL_CONTROL_STATUS2; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 0, type, false); 10478c2ecf20Sopenharmony_ci return dwc3_ep0_start_trans(dep); 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci WARN_ON(dwc3_ep0_start_control_status(dep)); 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_cistatic void dwc3_ep0_do_control_status(struct dwc3 *dwc, 10568c2ecf20Sopenharmony_ci const struct dwc3_event_depevt *event) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci __dwc3_ep0_do_control_status(dwc, dep); 10618c2ecf20Sopenharmony_ci} 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_civoid dwc3_ep0_send_delayed_status(struct dwc3 *dwc) 10648c2ecf20Sopenharmony_ci{ 10658c2ecf20Sopenharmony_ci unsigned int direction = !dwc->ep0_expect_in; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci dwc->delayed_status = false; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci if (dwc->ep0state != EP0_STATUS_PHASE) 10708c2ecf20Sopenharmony_ci return; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci __dwc3_ep0_do_control_status(dwc, dwc->eps[direction]); 10738c2ecf20Sopenharmony_ci} 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_cistatic void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci struct dwc3_gadget_ep_cmd_params params; 10788c2ecf20Sopenharmony_ci u32 cmd; 10798c2ecf20Sopenharmony_ci int ret; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if (!dep->resource_index) 10828c2ecf20Sopenharmony_ci return; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci cmd = DWC3_DEPCMD_ENDTRANSFER; 10858c2ecf20Sopenharmony_ci cmd |= DWC3_DEPCMD_CMDIOC; 10868c2ecf20Sopenharmony_ci cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); 10878c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 10888c2ecf20Sopenharmony_ci ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); 10898c2ecf20Sopenharmony_ci WARN_ON_ONCE(ret); 10908c2ecf20Sopenharmony_ci dep->resource_index = 0; 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_cistatic void dwc3_ep0_xfernotready(struct dwc3 *dwc, 10948c2ecf20Sopenharmony_ci const struct dwc3_event_depevt *event) 10958c2ecf20Sopenharmony_ci{ 10968c2ecf20Sopenharmony_ci switch (event->status) { 10978c2ecf20Sopenharmony_ci case DEPEVT_STATUS_CONTROL_DATA: 10988c2ecf20Sopenharmony_ci /* 10998c2ecf20Sopenharmony_ci * We already have a DATA transfer in the controller's cache, 11008c2ecf20Sopenharmony_ci * if we receive a XferNotReady(DATA) we will ignore it, unless 11018c2ecf20Sopenharmony_ci * it's for the wrong direction. 11028c2ecf20Sopenharmony_ci * 11038c2ecf20Sopenharmony_ci * In that case, we must issue END_TRANSFER command to the Data 11048c2ecf20Sopenharmony_ci * Phase we already have started and issue SetStall on the 11058c2ecf20Sopenharmony_ci * control endpoint. 11068c2ecf20Sopenharmony_ci */ 11078c2ecf20Sopenharmony_ci if (dwc->ep0_expect_in != event->endpoint_number) { 11088c2ecf20Sopenharmony_ci struct dwc3_ep *dep = dwc->eps[dwc->ep0_expect_in]; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci dev_err(dwc->dev, "unexpected direction for Data Phase\n"); 11118c2ecf20Sopenharmony_ci dwc3_ep0_end_control_data(dwc, dep); 11128c2ecf20Sopenharmony_ci dwc3_ep0_stall_and_restart(dwc); 11138c2ecf20Sopenharmony_ci return; 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci break; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci case DEPEVT_STATUS_CONTROL_STATUS: 11198c2ecf20Sopenharmony_ci if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) 11208c2ecf20Sopenharmony_ci return; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci dwc->ep0state = EP0_STATUS_PHASE; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci if (dwc->delayed_status) { 11258c2ecf20Sopenharmony_ci struct dwc3_ep *dep = dwc->eps[0]; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci WARN_ON_ONCE(event->endpoint_number != 1); 11288c2ecf20Sopenharmony_ci /* 11298c2ecf20Sopenharmony_ci * We should handle the delay STATUS phase here if the 11308c2ecf20Sopenharmony_ci * request for handling delay STATUS has been queued 11318c2ecf20Sopenharmony_ci * into the list. 11328c2ecf20Sopenharmony_ci */ 11338c2ecf20Sopenharmony_ci if (!list_empty(&dep->pending_list)) { 11348c2ecf20Sopenharmony_ci dwc->delayed_status = false; 11358c2ecf20Sopenharmony_ci usb_gadget_set_state(dwc->gadget, 11368c2ecf20Sopenharmony_ci USB_STATE_CONFIGURED); 11378c2ecf20Sopenharmony_ci dwc3_ep0_do_control_status(dwc, event); 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci return; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci dwc3_ep0_do_control_status(dwc, event); 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_civoid dwc3_ep0_interrupt(struct dwc3 *dwc, 11488c2ecf20Sopenharmony_ci const struct dwc3_event_depevt *event) 11498c2ecf20Sopenharmony_ci{ 11508c2ecf20Sopenharmony_ci struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; 11518c2ecf20Sopenharmony_ci u8 cmd; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci switch (event->endpoint_event) { 11548c2ecf20Sopenharmony_ci case DWC3_DEPEVT_XFERCOMPLETE: 11558c2ecf20Sopenharmony_ci dwc3_ep0_xfer_complete(dwc, event); 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci case DWC3_DEPEVT_XFERNOTREADY: 11598c2ecf20Sopenharmony_ci dwc3_ep0_xfernotready(dwc, event); 11608c2ecf20Sopenharmony_ci break; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci case DWC3_DEPEVT_XFERINPROGRESS: 11638c2ecf20Sopenharmony_ci case DWC3_DEPEVT_RXTXFIFOEVT: 11648c2ecf20Sopenharmony_ci case DWC3_DEPEVT_STREAMEVT: 11658c2ecf20Sopenharmony_ci break; 11668c2ecf20Sopenharmony_ci case DWC3_DEPEVT_EPCMDCMPLT: 11678c2ecf20Sopenharmony_ci cmd = DEPEVT_PARAMETER_CMD(event->parameters); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (cmd == DWC3_DEPCMD_ENDTRANSFER) { 11708c2ecf20Sopenharmony_ci dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; 11718c2ecf20Sopenharmony_ci dep->flags &= ~DWC3_EP_TRANSFER_STARTED; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci break; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci} 1176