18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2011 Samsung Electronics Co., Ltd. 48c2ecf20Sopenharmony_ci * http://www.samsung.com 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2008 Openmoko, Inc. 78c2ecf20Sopenharmony_ci * Copyright 2008 Simtec Electronics 88c2ecf20Sopenharmony_ci * Ben Dooks <ben@simtec.co.uk> 98c2ecf20Sopenharmony_ci * http://armlinux.simtec.co.uk/ 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * S3C USB2.0 High-speed / OtG driver 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 208c2ecf20Sopenharmony_ci#include <linux/mutex.h> 218c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 228c2ecf20Sopenharmony_ci#include <linux/delay.h> 238c2ecf20Sopenharmony_ci#include <linux/io.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/usb/ch9.h> 288c2ecf20Sopenharmony_ci#include <linux/usb/gadget.h> 298c2ecf20Sopenharmony_ci#include <linux/usb/phy.h> 308c2ecf20Sopenharmony_ci#include <linux/usb/composite.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "core.h" 348c2ecf20Sopenharmony_ci#include "hw.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* conversion functions */ 378c2ecf20Sopenharmony_cistatic inline struct dwc2_hsotg_req *our_req(struct usb_request *req) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci return container_of(req, struct dwc2_hsotg_req, req); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic inline struct dwc2_hsotg_ep *our_ep(struct usb_ep *ep) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci return container_of(ep, struct dwc2_hsotg_ep, ep); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic inline struct dwc2_hsotg *to_hsotg(struct usb_gadget *gadget) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci return container_of(gadget, struct dwc2_hsotg, gadget); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic inline void dwc2_set_bit(struct dwc2_hsotg *hsotg, u32 offset, u32 val) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dwc2_readl(hsotg, offset) | val, offset); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic inline void dwc2_clear_bit(struct dwc2_hsotg *hsotg, u32 offset, u32 val) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dwc2_readl(hsotg, offset) & ~val, offset); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic inline struct dwc2_hsotg_ep *index_to_ep(struct dwc2_hsotg *hsotg, 638c2ecf20Sopenharmony_ci u32 ep_index, u32 dir_in) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci if (dir_in) 668c2ecf20Sopenharmony_ci return hsotg->eps_in[ep_index]; 678c2ecf20Sopenharmony_ci else 688c2ecf20Sopenharmony_ci return hsotg->eps_out[ep_index]; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* forward declaration of functions */ 728c2ecf20Sopenharmony_cistatic void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/** 758c2ecf20Sopenharmony_ci * using_dma - return the DMA status of the driver. 768c2ecf20Sopenharmony_ci * @hsotg: The driver state. 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * Return true if we're using DMA. 798c2ecf20Sopenharmony_ci * 808c2ecf20Sopenharmony_ci * Currently, we have the DMA support code worked into everywhere 818c2ecf20Sopenharmony_ci * that needs it, but the AMBA DMA implementation in the hardware can 828c2ecf20Sopenharmony_ci * only DMA from 32bit aligned addresses. This means that gadgets such 838c2ecf20Sopenharmony_ci * as the CDC Ethernet cannot work as they often pass packets which are 848c2ecf20Sopenharmony_ci * not 32bit aligned. 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * Unfortunately the choice to use DMA or not is global to the controller 878c2ecf20Sopenharmony_ci * and seems to be only settable when the controller is being put through 888c2ecf20Sopenharmony_ci * a core reset. This means we either need to fix the gadgets to take 898c2ecf20Sopenharmony_ci * account of DMA alignment, or add bounce buffers (yuerk). 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * g_using_dma is set depending on dts flag. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_cistatic inline bool using_dma(struct dwc2_hsotg *hsotg) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci return hsotg->params.g_dma; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* 998c2ecf20Sopenharmony_ci * using_desc_dma - return the descriptor DMA status of the driver. 1008c2ecf20Sopenharmony_ci * @hsotg: The driver state. 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci * Return true if we're using descriptor DMA. 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_cistatic inline bool using_desc_dma(struct dwc2_hsotg *hsotg) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci return hsotg->params.g_dma_desc; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/** 1108c2ecf20Sopenharmony_ci * dwc2_gadget_incr_frame_num - Increments the targeted frame number. 1118c2ecf20Sopenharmony_ci * @hs_ep: The endpoint 1128c2ecf20Sopenharmony_ci * 1138c2ecf20Sopenharmony_ci * This function will also check if the frame number overruns DSTS_SOFFN_LIMIT. 1148c2ecf20Sopenharmony_ci * If an overrun occurs it will wrap the value and set the frame_overrun flag. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_cistatic inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 1198c2ecf20Sopenharmony_ci u16 limit = DSTS_SOFFN_LIMIT; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (hsotg->gadget.speed != USB_SPEED_HIGH) 1228c2ecf20Sopenharmony_ci limit >>= 3; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci hs_ep->target_frame += hs_ep->interval; 1258c2ecf20Sopenharmony_ci if (hs_ep->target_frame > limit) { 1268c2ecf20Sopenharmony_ci hs_ep->frame_overrun = true; 1278c2ecf20Sopenharmony_ci hs_ep->target_frame &= limit; 1288c2ecf20Sopenharmony_ci } else { 1298c2ecf20Sopenharmony_ci hs_ep->frame_overrun = false; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/** 1348c2ecf20Sopenharmony_ci * dwc2_gadget_dec_frame_num_by_one - Decrements the targeted frame number 1358c2ecf20Sopenharmony_ci * by one. 1368c2ecf20Sopenharmony_ci * @hs_ep: The endpoint. 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * This function used in service interval based scheduling flow to calculate 1398c2ecf20Sopenharmony_ci * descriptor frame number filed value. For service interval mode frame 1408c2ecf20Sopenharmony_ci * number in descriptor should point to last (u)frame in the interval. 1418c2ecf20Sopenharmony_ci * 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic inline void dwc2_gadget_dec_frame_num_by_one(struct dwc2_hsotg_ep *hs_ep) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 1468c2ecf20Sopenharmony_ci u16 limit = DSTS_SOFFN_LIMIT; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (hsotg->gadget.speed != USB_SPEED_HIGH) 1498c2ecf20Sopenharmony_ci limit >>= 3; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (hs_ep->target_frame) 1528c2ecf20Sopenharmony_ci hs_ep->target_frame -= 1; 1538c2ecf20Sopenharmony_ci else 1548c2ecf20Sopenharmony_ci hs_ep->target_frame = limit; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/** 1588c2ecf20Sopenharmony_ci * dwc2_hsotg_en_gsint - enable one or more of the general interrupt 1598c2ecf20Sopenharmony_ci * @hsotg: The device state 1608c2ecf20Sopenharmony_ci * @ints: A bitmask of the interrupts to enable 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_cistatic void dwc2_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci u32 gsintmsk = dwc2_readl(hsotg, GINTMSK); 1658c2ecf20Sopenharmony_ci u32 new_gsintmsk; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci new_gsintmsk = gsintmsk | ints; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (new_gsintmsk != gsintmsk) { 1708c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); 1718c2ecf20Sopenharmony_ci dwc2_writel(hsotg, new_gsintmsk, GINTMSK); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/** 1768c2ecf20Sopenharmony_ci * dwc2_hsotg_disable_gsint - disable one or more of the general interrupt 1778c2ecf20Sopenharmony_ci * @hsotg: The device state 1788c2ecf20Sopenharmony_ci * @ints: A bitmask of the interrupts to enable 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_cistatic void dwc2_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci u32 gsintmsk = dwc2_readl(hsotg, GINTMSK); 1838c2ecf20Sopenharmony_ci u32 new_gsintmsk; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci new_gsintmsk = gsintmsk & ~ints; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (new_gsintmsk != gsintmsk) 1888c2ecf20Sopenharmony_ci dwc2_writel(hsotg, new_gsintmsk, GINTMSK); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/** 1928c2ecf20Sopenharmony_ci * dwc2_hsotg_ctrl_epint - enable/disable an endpoint irq 1938c2ecf20Sopenharmony_ci * @hsotg: The device state 1948c2ecf20Sopenharmony_ci * @ep: The endpoint index 1958c2ecf20Sopenharmony_ci * @dir_in: True if direction is in. 1968c2ecf20Sopenharmony_ci * @en: The enable value, true to enable 1978c2ecf20Sopenharmony_ci * 1988c2ecf20Sopenharmony_ci * Set or clear the mask for an individual endpoint's interrupt 1998c2ecf20Sopenharmony_ci * request. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_cistatic void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, 2028c2ecf20Sopenharmony_ci unsigned int ep, unsigned int dir_in, 2038c2ecf20Sopenharmony_ci unsigned int en) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci unsigned long flags; 2068c2ecf20Sopenharmony_ci u32 bit = 1 << ep; 2078c2ecf20Sopenharmony_ci u32 daint; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (!dir_in) 2108c2ecf20Sopenharmony_ci bit <<= 16; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci local_irq_save(flags); 2138c2ecf20Sopenharmony_ci daint = dwc2_readl(hsotg, DAINTMSK); 2148c2ecf20Sopenharmony_ci if (en) 2158c2ecf20Sopenharmony_ci daint |= bit; 2168c2ecf20Sopenharmony_ci else 2178c2ecf20Sopenharmony_ci daint &= ~bit; 2188c2ecf20Sopenharmony_ci dwc2_writel(hsotg, daint, DAINTMSK); 2198c2ecf20Sopenharmony_ci local_irq_restore(flags); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/** 2238c2ecf20Sopenharmony_ci * dwc2_hsotg_tx_fifo_count - return count of TX FIFOs in device mode 2248c2ecf20Sopenharmony_ci * 2258c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_ciint dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci if (hsotg->hw_params.en_multiple_tx_fifo) 2308c2ecf20Sopenharmony_ci /* In dedicated FIFO mode we need count of IN EPs */ 2318c2ecf20Sopenharmony_ci return hsotg->hw_params.num_dev_in_eps; 2328c2ecf20Sopenharmony_ci else 2338c2ecf20Sopenharmony_ci /* In shared FIFO mode we need count of Periodic IN EPs */ 2348c2ecf20Sopenharmony_ci return hsotg->hw_params.num_dev_perio_in_ep; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/** 2388c2ecf20Sopenharmony_ci * dwc2_hsotg_tx_fifo_total_depth - return total FIFO depth available for 2398c2ecf20Sopenharmony_ci * device mode TX FIFOs 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ciint dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci int addr; 2468c2ecf20Sopenharmony_ci int tx_addr_max; 2478c2ecf20Sopenharmony_ci u32 np_tx_fifo_size; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci np_tx_fifo_size = min_t(u32, hsotg->hw_params.dev_nperio_tx_fifo_size, 2508c2ecf20Sopenharmony_ci hsotg->params.g_np_tx_fifo_size); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* Get Endpoint Info Control block size in DWORDs. */ 2538c2ecf20Sopenharmony_ci tx_addr_max = hsotg->hw_params.total_fifo_size; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci addr = hsotg->params.g_rx_fifo_size + np_tx_fifo_size; 2568c2ecf20Sopenharmony_ci if (tx_addr_max <= addr) 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return tx_addr_max - addr; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/** 2638c2ecf20Sopenharmony_ci * dwc2_gadget_wkup_alert_handler - Handler for WKUP_ALERT interrupt 2648c2ecf20Sopenharmony_ci * 2658c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 2668c2ecf20Sopenharmony_ci * 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_cistatic void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci u32 gintsts2; 2718c2ecf20Sopenharmony_ci u32 gintmsk2; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci gintsts2 = dwc2_readl(hsotg, GINTSTS2); 2748c2ecf20Sopenharmony_ci gintmsk2 = dwc2_readl(hsotg, GINTMSK2); 2758c2ecf20Sopenharmony_ci gintsts2 &= gintmsk2; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) { 2788c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__); 2798c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT); 2808c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_RMTWKUPSIG); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/** 2858c2ecf20Sopenharmony_ci * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode 2868c2ecf20Sopenharmony_ci * TX FIFOs 2878c2ecf20Sopenharmony_ci * 2888c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ciint dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci int tx_fifo_count; 2938c2ecf20Sopenharmony_ci int tx_fifo_depth; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci tx_fifo_depth = dwc2_hsotg_tx_fifo_total_depth(hsotg); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci tx_fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (!tx_fifo_count) 3008c2ecf20Sopenharmony_ci return tx_fifo_depth; 3018c2ecf20Sopenharmony_ci else 3028c2ecf20Sopenharmony_ci return tx_fifo_depth / tx_fifo_count; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/** 3068c2ecf20Sopenharmony_ci * dwc2_hsotg_init_fifo - initialise non-periodic FIFOs 3078c2ecf20Sopenharmony_ci * @hsotg: The device instance. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_cistatic void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci unsigned int ep; 3128c2ecf20Sopenharmony_ci unsigned int addr; 3138c2ecf20Sopenharmony_ci int timeout; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci u32 val; 3168c2ecf20Sopenharmony_ci u32 *txfsz = hsotg->params.g_tx_fifo_size; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* Reset fifo map if not correctly cleared during previous session */ 3198c2ecf20Sopenharmony_ci WARN_ON(hsotg->fifo_map); 3208c2ecf20Sopenharmony_ci hsotg->fifo_map = 0; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* set RX/NPTX FIFO sizes */ 3238c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hsotg->params.g_rx_fifo_size, GRXFSIZ); 3248c2ecf20Sopenharmony_ci dwc2_writel(hsotg, (hsotg->params.g_rx_fifo_size << 3258c2ecf20Sopenharmony_ci FIFOSIZE_STARTADDR_SHIFT) | 3268c2ecf20Sopenharmony_ci (hsotg->params.g_np_tx_fifo_size << FIFOSIZE_DEPTH_SHIFT), 3278c2ecf20Sopenharmony_ci GNPTXFSIZ); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* 3308c2ecf20Sopenharmony_ci * arange all the rest of the TX FIFOs, as some versions of this 3318c2ecf20Sopenharmony_ci * block have overlapping default addresses. This also ensures 3328c2ecf20Sopenharmony_ci * that if the settings have been changed, then they are set to 3338c2ecf20Sopenharmony_ci * known values. 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* start at the end of the GNPTXFSIZ, rounded up */ 3378c2ecf20Sopenharmony_ci addr = hsotg->params.g_rx_fifo_size + hsotg->params.g_np_tx_fifo_size; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* 3408c2ecf20Sopenharmony_ci * Configure fifos sizes from provided configuration and assign 3418c2ecf20Sopenharmony_ci * them to endpoints dynamically according to maxpacket size value of 3428c2ecf20Sopenharmony_ci * given endpoint. 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_ci for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) { 3458c2ecf20Sopenharmony_ci if (!txfsz[ep]) 3468c2ecf20Sopenharmony_ci continue; 3478c2ecf20Sopenharmony_ci val = addr; 3488c2ecf20Sopenharmony_ci val |= txfsz[ep] << FIFOSIZE_DEPTH_SHIFT; 3498c2ecf20Sopenharmony_ci WARN_ONCE(addr + txfsz[ep] > hsotg->fifo_mem, 3508c2ecf20Sopenharmony_ci "insufficient fifo memory"); 3518c2ecf20Sopenharmony_ci addr += txfsz[ep]; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci dwc2_writel(hsotg, val, DPTXFSIZN(ep)); 3548c2ecf20Sopenharmony_ci val = dwc2_readl(hsotg, DPTXFSIZN(ep)); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hsotg->hw_params.total_fifo_size | 3588c2ecf20Sopenharmony_ci addr << GDFIFOCFG_EPINFOBASE_SHIFT, 3598c2ecf20Sopenharmony_ci GDFIFOCFG); 3608c2ecf20Sopenharmony_ci /* 3618c2ecf20Sopenharmony_ci * according to p428 of the design guide, we need to ensure that 3628c2ecf20Sopenharmony_ci * all fifos are flushed before continuing 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci dwc2_writel(hsotg, GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | 3668c2ecf20Sopenharmony_ci GRSTCTL_RXFFLSH, GRSTCTL); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* wait until the fifos are both flushed */ 3698c2ecf20Sopenharmony_ci timeout = 100; 3708c2ecf20Sopenharmony_ci while (1) { 3718c2ecf20Sopenharmony_ci val = dwc2_readl(hsotg, GRSTCTL); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0) 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (--timeout == 0) { 3778c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 3788c2ecf20Sopenharmony_ci "%s: timeout flushing fifos (GRSTCTL=%08x)\n", 3798c2ecf20Sopenharmony_ci __func__, val); 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci udelay(1); 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci/** 3908c2ecf20Sopenharmony_ci * dwc2_hsotg_ep_alloc_request - allocate USB rerequest structure 3918c2ecf20Sopenharmony_ci * @ep: USB endpoint to allocate request for. 3928c2ecf20Sopenharmony_ci * @flags: Allocation flags 3938c2ecf20Sopenharmony_ci * 3948c2ecf20Sopenharmony_ci * Allocate a new USB request structure appropriate for the specified endpoint 3958c2ecf20Sopenharmony_ci */ 3968c2ecf20Sopenharmony_cistatic struct usb_request *dwc2_hsotg_ep_alloc_request(struct usb_ep *ep, 3978c2ecf20Sopenharmony_ci gfp_t flags) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *req; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci req = kzalloc(sizeof(*req), flags); 4028c2ecf20Sopenharmony_ci if (!req) 4038c2ecf20Sopenharmony_ci return NULL; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&req->queue); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci return &req->req; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci/** 4118c2ecf20Sopenharmony_ci * is_ep_periodic - return true if the endpoint is in periodic mode. 4128c2ecf20Sopenharmony_ci * @hs_ep: The endpoint to query. 4138c2ecf20Sopenharmony_ci * 4148c2ecf20Sopenharmony_ci * Returns true if the endpoint is in periodic mode, meaning it is being 4158c2ecf20Sopenharmony_ci * used for an Interrupt or ISO transfer. 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_cistatic inline int is_ep_periodic(struct dwc2_hsotg_ep *hs_ep) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci return hs_ep->periodic; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci/** 4238c2ecf20Sopenharmony_ci * dwc2_hsotg_unmap_dma - unmap the DMA memory being used for the request 4248c2ecf20Sopenharmony_ci * @hsotg: The device state. 4258c2ecf20Sopenharmony_ci * @hs_ep: The endpoint for the request 4268c2ecf20Sopenharmony_ci * @hs_req: The request being processed. 4278c2ecf20Sopenharmony_ci * 4288c2ecf20Sopenharmony_ci * This is the reverse of dwc2_hsotg_map_dma(), called for the completion 4298c2ecf20Sopenharmony_ci * of a request to ensure the buffer is ready for access by the caller. 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_cistatic void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg, 4328c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 4338c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct usb_request *req = &hs_req->req; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->map_dir); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci/* 4418c2ecf20Sopenharmony_ci * dwc2_gadget_alloc_ctrl_desc_chains - allocate DMA descriptor chains 4428c2ecf20Sopenharmony_ci * for Control endpoint 4438c2ecf20Sopenharmony_ci * @hsotg: The device state. 4448c2ecf20Sopenharmony_ci * 4458c2ecf20Sopenharmony_ci * This function will allocate 4 descriptor chains for EP 0: 2 for 4468c2ecf20Sopenharmony_ci * Setup stage, per one for IN and OUT data/status transactions. 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_cistatic int dwc2_gadget_alloc_ctrl_desc_chains(struct dwc2_hsotg *hsotg) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci hsotg->setup_desc[0] = 4518c2ecf20Sopenharmony_ci dmam_alloc_coherent(hsotg->dev, 4528c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 4538c2ecf20Sopenharmony_ci &hsotg->setup_desc_dma[0], 4548c2ecf20Sopenharmony_ci GFP_KERNEL); 4558c2ecf20Sopenharmony_ci if (!hsotg->setup_desc[0]) 4568c2ecf20Sopenharmony_ci goto fail; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci hsotg->setup_desc[1] = 4598c2ecf20Sopenharmony_ci dmam_alloc_coherent(hsotg->dev, 4608c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 4618c2ecf20Sopenharmony_ci &hsotg->setup_desc_dma[1], 4628c2ecf20Sopenharmony_ci GFP_KERNEL); 4638c2ecf20Sopenharmony_ci if (!hsotg->setup_desc[1]) 4648c2ecf20Sopenharmony_ci goto fail; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci hsotg->ctrl_in_desc = 4678c2ecf20Sopenharmony_ci dmam_alloc_coherent(hsotg->dev, 4688c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 4698c2ecf20Sopenharmony_ci &hsotg->ctrl_in_desc_dma, 4708c2ecf20Sopenharmony_ci GFP_KERNEL); 4718c2ecf20Sopenharmony_ci if (!hsotg->ctrl_in_desc) 4728c2ecf20Sopenharmony_ci goto fail; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci hsotg->ctrl_out_desc = 4758c2ecf20Sopenharmony_ci dmam_alloc_coherent(hsotg->dev, 4768c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 4778c2ecf20Sopenharmony_ci &hsotg->ctrl_out_desc_dma, 4788c2ecf20Sopenharmony_ci GFP_KERNEL); 4798c2ecf20Sopenharmony_ci if (!hsotg->ctrl_out_desc) 4808c2ecf20Sopenharmony_ci goto fail; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cifail: 4858c2ecf20Sopenharmony_ci return -ENOMEM; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci/** 4898c2ecf20Sopenharmony_ci * dwc2_hsotg_write_fifo - write packet Data to the TxFIFO 4908c2ecf20Sopenharmony_ci * @hsotg: The controller state. 4918c2ecf20Sopenharmony_ci * @hs_ep: The endpoint we're going to write for. 4928c2ecf20Sopenharmony_ci * @hs_req: The request to write data for. 4938c2ecf20Sopenharmony_ci * 4948c2ecf20Sopenharmony_ci * This is called when the TxFIFO has some space in it to hold a new 4958c2ecf20Sopenharmony_ci * transmission and we have something to give it. The actual setup of 4968c2ecf20Sopenharmony_ci * the data size is done elsewhere, so all we have to do is to actually 4978c2ecf20Sopenharmony_ci * write the data. 4988c2ecf20Sopenharmony_ci * 4998c2ecf20Sopenharmony_ci * The return value is zero if there is more space (or nothing was done) 5008c2ecf20Sopenharmony_ci * otherwise -ENOSPC is returned if the FIFO space was used up. 5018c2ecf20Sopenharmony_ci * 5028c2ecf20Sopenharmony_ci * This routine is only needed for PIO 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_cistatic int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, 5058c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 5068c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci bool periodic = is_ep_periodic(hs_ep); 5098c2ecf20Sopenharmony_ci u32 gnptxsts = dwc2_readl(hsotg, GNPTXSTS); 5108c2ecf20Sopenharmony_ci int buf_pos = hs_req->req.actual; 5118c2ecf20Sopenharmony_ci int to_write = hs_ep->size_loaded; 5128c2ecf20Sopenharmony_ci void *data; 5138c2ecf20Sopenharmony_ci int can_write; 5148c2ecf20Sopenharmony_ci int pkt_round; 5158c2ecf20Sopenharmony_ci int max_transfer; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci to_write -= (buf_pos - hs_ep->last_load); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* if there's nothing to write, get out early */ 5208c2ecf20Sopenharmony_ci if (to_write == 0) 5218c2ecf20Sopenharmony_ci return 0; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (periodic && !hsotg->dedicated_fifos) { 5248c2ecf20Sopenharmony_ci u32 epsize = dwc2_readl(hsotg, DIEPTSIZ(hs_ep->index)); 5258c2ecf20Sopenharmony_ci int size_left; 5268c2ecf20Sopenharmony_ci int size_done; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* 5298c2ecf20Sopenharmony_ci * work out how much data was loaded so we can calculate 5308c2ecf20Sopenharmony_ci * how much data is left in the fifo. 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* 5368c2ecf20Sopenharmony_ci * if shared fifo, we cannot write anything until the 5378c2ecf20Sopenharmony_ci * previous data has been completely sent. 5388c2ecf20Sopenharmony_ci */ 5398c2ecf20Sopenharmony_ci if (hs_ep->fifo_load != 0) { 5408c2ecf20Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 5418c2ecf20Sopenharmony_ci return -ENOSPC; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", 5458c2ecf20Sopenharmony_ci __func__, size_left, 5468c2ecf20Sopenharmony_ci hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* how much of the data has moved */ 5498c2ecf20Sopenharmony_ci size_done = hs_ep->size_loaded - size_left; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci /* how much data is left in the fifo */ 5528c2ecf20Sopenharmony_ci can_write = hs_ep->fifo_load - size_done; 5538c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", 5548c2ecf20Sopenharmony_ci __func__, can_write); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci can_write = hs_ep->fifo_size - can_write; 5578c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", 5588c2ecf20Sopenharmony_ci __func__, can_write); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (can_write <= 0) { 5618c2ecf20Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 5628c2ecf20Sopenharmony_ci return -ENOSPC; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { 5658c2ecf20Sopenharmony_ci can_write = dwc2_readl(hsotg, 5668c2ecf20Sopenharmony_ci DTXFSTS(hs_ep->fifo_index)); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci can_write &= 0xffff; 5698c2ecf20Sopenharmony_ci can_write *= 4; 5708c2ecf20Sopenharmony_ci } else { 5718c2ecf20Sopenharmony_ci if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) { 5728c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 5738c2ecf20Sopenharmony_ci "%s: no queue slots available (0x%08x)\n", 5748c2ecf20Sopenharmony_ci __func__, gnptxsts); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP); 5778c2ecf20Sopenharmony_ci return -ENOSPC; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts); 5818c2ecf20Sopenharmony_ci can_write *= 4; /* fifo size is in 32bit quantities. */ 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", 5878c2ecf20Sopenharmony_ci __func__, gnptxsts, can_write, to_write, max_transfer); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* 5908c2ecf20Sopenharmony_ci * limit to 512 bytes of data, it seems at least on the non-periodic 5918c2ecf20Sopenharmony_ci * FIFO, requests of >512 cause the endpoint to get stuck with a 5928c2ecf20Sopenharmony_ci * fragment of the end of the transfer in it. 5938c2ecf20Sopenharmony_ci */ 5948c2ecf20Sopenharmony_ci if (can_write > 512 && !periodic) 5958c2ecf20Sopenharmony_ci can_write = 512; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* 5988c2ecf20Sopenharmony_ci * limit the write to one max-packet size worth of data, but allow 5998c2ecf20Sopenharmony_ci * the transfer to return that it did not run out of fifo space 6008c2ecf20Sopenharmony_ci * doing it. 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci if (to_write > max_transfer) { 6038c2ecf20Sopenharmony_ci to_write = max_transfer; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* it's needed only when we do not use dedicated fifos */ 6068c2ecf20Sopenharmony_ci if (!hsotg->dedicated_fifos) 6078c2ecf20Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, 6088c2ecf20Sopenharmony_ci periodic ? GINTSTS_PTXFEMP : 6098c2ecf20Sopenharmony_ci GINTSTS_NPTXFEMP); 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* see if we can write data */ 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (to_write > can_write) { 6158c2ecf20Sopenharmony_ci to_write = can_write; 6168c2ecf20Sopenharmony_ci pkt_round = to_write % max_transfer; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci /* 6198c2ecf20Sopenharmony_ci * Round the write down to an 6208c2ecf20Sopenharmony_ci * exact number of packets. 6218c2ecf20Sopenharmony_ci * 6228c2ecf20Sopenharmony_ci * Note, we do not currently check to see if we can ever 6238c2ecf20Sopenharmony_ci * write a full packet or not to the FIFO. 6248c2ecf20Sopenharmony_ci */ 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (pkt_round) 6278c2ecf20Sopenharmony_ci to_write -= pkt_round; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* 6308c2ecf20Sopenharmony_ci * enable correct FIFO interrupt to alert us when there 6318c2ecf20Sopenharmony_ci * is more room left. 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* it's needed only when we do not use dedicated fifos */ 6358c2ecf20Sopenharmony_ci if (!hsotg->dedicated_fifos) 6368c2ecf20Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, 6378c2ecf20Sopenharmony_ci periodic ? GINTSTS_PTXFEMP : 6388c2ecf20Sopenharmony_ci GINTSTS_NPTXFEMP); 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", 6428c2ecf20Sopenharmony_ci to_write, hs_req->req.length, can_write, buf_pos); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (to_write <= 0) 6458c2ecf20Sopenharmony_ci return -ENOSPC; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci hs_req->req.actual = buf_pos + to_write; 6488c2ecf20Sopenharmony_ci hs_ep->total_data += to_write; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (periodic) 6518c2ecf20Sopenharmony_ci hs_ep->fifo_load += to_write; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci to_write = DIV_ROUND_UP(to_write, 4); 6548c2ecf20Sopenharmony_ci data = hs_req->req.buf + buf_pos; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci dwc2_writel_rep(hsotg, EPFIFO(hs_ep->index), data, to_write); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci return (to_write >= can_write) ? -ENOSPC : 0; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci/** 6628c2ecf20Sopenharmony_ci * get_ep_limit - get the maximum data legnth for this endpoint 6638c2ecf20Sopenharmony_ci * @hs_ep: The endpoint 6648c2ecf20Sopenharmony_ci * 6658c2ecf20Sopenharmony_ci * Return the maximum data that can be queued in one go on a given endpoint 6668c2ecf20Sopenharmony_ci * so that transfers that are too long can be split. 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_cistatic unsigned int get_ep_limit(struct dwc2_hsotg_ep *hs_ep) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci int index = hs_ep->index; 6718c2ecf20Sopenharmony_ci unsigned int maxsize; 6728c2ecf20Sopenharmony_ci unsigned int maxpkt; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (index != 0) { 6758c2ecf20Sopenharmony_ci maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; 6768c2ecf20Sopenharmony_ci maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; 6778c2ecf20Sopenharmony_ci } else { 6788c2ecf20Sopenharmony_ci maxsize = 64 + 64; 6798c2ecf20Sopenharmony_ci if (hs_ep->dir_in) 6808c2ecf20Sopenharmony_ci maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; 6818c2ecf20Sopenharmony_ci else 6828c2ecf20Sopenharmony_ci maxpkt = 2; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* we made the constant loading easier above by using +1 */ 6868c2ecf20Sopenharmony_ci maxpkt--; 6878c2ecf20Sopenharmony_ci maxsize--; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* 6908c2ecf20Sopenharmony_ci * constrain by packet count if maxpkts*pktsize is greater 6918c2ecf20Sopenharmony_ci * than the length register size. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) 6958c2ecf20Sopenharmony_ci maxsize = maxpkt * hs_ep->ep.maxpacket; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci return maxsize; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci/** 7018c2ecf20Sopenharmony_ci * dwc2_hsotg_read_frameno - read current frame number 7028c2ecf20Sopenharmony_ci * @hsotg: The device instance 7038c2ecf20Sopenharmony_ci * 7048c2ecf20Sopenharmony_ci * Return the current frame number 7058c2ecf20Sopenharmony_ci */ 7068c2ecf20Sopenharmony_cistatic u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci u32 dsts; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci dsts = dwc2_readl(hsotg, DSTS); 7118c2ecf20Sopenharmony_ci dsts &= DSTS_SOFFN_MASK; 7128c2ecf20Sopenharmony_ci dsts >>= DSTS_SOFFN_SHIFT; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci return dsts; 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci/** 7188c2ecf20Sopenharmony_ci * dwc2_gadget_get_chain_limit - get the maximum data payload value of the 7198c2ecf20Sopenharmony_ci * DMA descriptor chain prepared for specific endpoint 7208c2ecf20Sopenharmony_ci * @hs_ep: The endpoint 7218c2ecf20Sopenharmony_ci * 7228c2ecf20Sopenharmony_ci * Return the maximum data that can be queued in one go on a given endpoint 7238c2ecf20Sopenharmony_ci * depending on its descriptor chain capacity so that transfers that 7248c2ecf20Sopenharmony_ci * are too long can be split. 7258c2ecf20Sopenharmony_ci */ 7268c2ecf20Sopenharmony_cistatic unsigned int dwc2_gadget_get_chain_limit(struct dwc2_hsotg_ep *hs_ep) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci const struct usb_endpoint_descriptor *ep_desc = hs_ep->ep.desc; 7298c2ecf20Sopenharmony_ci int is_isoc = hs_ep->isochronous; 7308c2ecf20Sopenharmony_ci unsigned int maxsize; 7318c2ecf20Sopenharmony_ci u32 mps = hs_ep->ep.maxpacket; 7328c2ecf20Sopenharmony_ci int dir_in = hs_ep->dir_in; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (is_isoc) 7358c2ecf20Sopenharmony_ci maxsize = (hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_LIMIT : 7368c2ecf20Sopenharmony_ci DEV_DMA_ISOC_RX_NBYTES_LIMIT) * 7378c2ecf20Sopenharmony_ci MAX_DMA_DESC_NUM_HS_ISOC; 7388c2ecf20Sopenharmony_ci else 7398c2ecf20Sopenharmony_ci maxsize = DEV_DMA_NBYTES_LIMIT * MAX_DMA_DESC_NUM_GENERIC; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* Interrupt OUT EP with mps not multiple of 4 */ 7428c2ecf20Sopenharmony_ci if (hs_ep->index) 7438c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_int(ep_desc) && !dir_in && (mps % 4)) 7448c2ecf20Sopenharmony_ci maxsize = mps * MAX_DMA_DESC_NUM_GENERIC; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return maxsize; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci/* 7508c2ecf20Sopenharmony_ci * dwc2_gadget_get_desc_params - get DMA descriptor parameters. 7518c2ecf20Sopenharmony_ci * @hs_ep: The endpoint 7528c2ecf20Sopenharmony_ci * @mask: RX/TX bytes mask to be defined 7538c2ecf20Sopenharmony_ci * 7548c2ecf20Sopenharmony_ci * Returns maximum data payload for one descriptor after analyzing endpoint 7558c2ecf20Sopenharmony_ci * characteristics. 7568c2ecf20Sopenharmony_ci * DMA descriptor transfer bytes limit depends on EP type: 7578c2ecf20Sopenharmony_ci * Control out - MPS, 7588c2ecf20Sopenharmony_ci * Isochronous - descriptor rx/tx bytes bitfield limit, 7598c2ecf20Sopenharmony_ci * Control In/Bulk/Interrupt - multiple of mps. This will allow to not 7608c2ecf20Sopenharmony_ci * have concatenations from various descriptors within one packet. 7618c2ecf20Sopenharmony_ci * Interrupt OUT - if mps not multiple of 4 then a single packet corresponds 7628c2ecf20Sopenharmony_ci * to a single descriptor. 7638c2ecf20Sopenharmony_ci * 7648c2ecf20Sopenharmony_ci * Selects corresponding mask for RX/TX bytes as well. 7658c2ecf20Sopenharmony_ci */ 7668c2ecf20Sopenharmony_cistatic u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci const struct usb_endpoint_descriptor *ep_desc = hs_ep->ep.desc; 7698c2ecf20Sopenharmony_ci u32 mps = hs_ep->ep.maxpacket; 7708c2ecf20Sopenharmony_ci int dir_in = hs_ep->dir_in; 7718c2ecf20Sopenharmony_ci u32 desc_size = 0; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (!hs_ep->index && !dir_in) { 7748c2ecf20Sopenharmony_ci desc_size = mps; 7758c2ecf20Sopenharmony_ci *mask = DEV_DMA_NBYTES_MASK; 7768c2ecf20Sopenharmony_ci } else if (hs_ep->isochronous) { 7778c2ecf20Sopenharmony_ci if (dir_in) { 7788c2ecf20Sopenharmony_ci desc_size = DEV_DMA_ISOC_TX_NBYTES_LIMIT; 7798c2ecf20Sopenharmony_ci *mask = DEV_DMA_ISOC_TX_NBYTES_MASK; 7808c2ecf20Sopenharmony_ci } else { 7818c2ecf20Sopenharmony_ci desc_size = DEV_DMA_ISOC_RX_NBYTES_LIMIT; 7828c2ecf20Sopenharmony_ci *mask = DEV_DMA_ISOC_RX_NBYTES_MASK; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci } else { 7858c2ecf20Sopenharmony_ci desc_size = DEV_DMA_NBYTES_LIMIT; 7868c2ecf20Sopenharmony_ci *mask = DEV_DMA_NBYTES_MASK; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* Round down desc_size to be mps multiple */ 7898c2ecf20Sopenharmony_ci desc_size -= desc_size % mps; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* Interrupt OUT EP with mps not multiple of 4 */ 7938c2ecf20Sopenharmony_ci if (hs_ep->index) 7948c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_int(ep_desc) && !dir_in && (mps % 4)) { 7958c2ecf20Sopenharmony_ci desc_size = mps; 7968c2ecf20Sopenharmony_ci *mask = DEV_DMA_NBYTES_MASK; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci return desc_size; 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic void dwc2_gadget_fill_nonisoc_xfer_ddma_one(struct dwc2_hsotg_ep *hs_ep, 8038c2ecf20Sopenharmony_ci struct dwc2_dma_desc **desc, 8048c2ecf20Sopenharmony_ci dma_addr_t dma_buff, 8058c2ecf20Sopenharmony_ci unsigned int len, 8068c2ecf20Sopenharmony_ci bool true_last) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci int dir_in = hs_ep->dir_in; 8098c2ecf20Sopenharmony_ci u32 mps = hs_ep->ep.maxpacket; 8108c2ecf20Sopenharmony_ci u32 maxsize = 0; 8118c2ecf20Sopenharmony_ci u32 offset = 0; 8128c2ecf20Sopenharmony_ci u32 mask = 0; 8138c2ecf20Sopenharmony_ci int i; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci hs_ep->desc_count = (len / maxsize) + 8188c2ecf20Sopenharmony_ci ((len % maxsize) ? 1 : 0); 8198c2ecf20Sopenharmony_ci if (len == 0) 8208c2ecf20Sopenharmony_ci hs_ep->desc_count = 1; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci for (i = 0; i < hs_ep->desc_count; ++i) { 8238c2ecf20Sopenharmony_ci (*desc)->status = 0; 8248c2ecf20Sopenharmony_ci (*desc)->status |= (DEV_DMA_BUFF_STS_HBUSY 8258c2ecf20Sopenharmony_ci << DEV_DMA_BUFF_STS_SHIFT); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (len > maxsize) { 8288c2ecf20Sopenharmony_ci if (!hs_ep->index && !dir_in) 8298c2ecf20Sopenharmony_ci (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci (*desc)->status |= 8328c2ecf20Sopenharmony_ci maxsize << DEV_DMA_NBYTES_SHIFT & mask; 8338c2ecf20Sopenharmony_ci (*desc)->buf = dma_buff + offset; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci len -= maxsize; 8368c2ecf20Sopenharmony_ci offset += maxsize; 8378c2ecf20Sopenharmony_ci } else { 8388c2ecf20Sopenharmony_ci if (true_last) 8398c2ecf20Sopenharmony_ci (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci if (dir_in) 8428c2ecf20Sopenharmony_ci (*desc)->status |= (len % mps) ? DEV_DMA_SHORT : 8438c2ecf20Sopenharmony_ci ((hs_ep->send_zlp && true_last) ? 8448c2ecf20Sopenharmony_ci DEV_DMA_SHORT : 0); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci (*desc)->status |= 8478c2ecf20Sopenharmony_ci len << DEV_DMA_NBYTES_SHIFT & mask; 8488c2ecf20Sopenharmony_ci (*desc)->buf = dma_buff + offset; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci (*desc)->status &= ~DEV_DMA_BUFF_STS_MASK; 8528c2ecf20Sopenharmony_ci (*desc)->status |= (DEV_DMA_BUFF_STS_HREADY 8538c2ecf20Sopenharmony_ci << DEV_DMA_BUFF_STS_SHIFT); 8548c2ecf20Sopenharmony_ci (*desc)++; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci/* 8598c2ecf20Sopenharmony_ci * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. 8608c2ecf20Sopenharmony_ci * @hs_ep: The endpoint 8618c2ecf20Sopenharmony_ci * @ureq: Request to transfer 8628c2ecf20Sopenharmony_ci * @offset: offset in bytes 8638c2ecf20Sopenharmony_ci * @len: Length of the transfer 8648c2ecf20Sopenharmony_ci * 8658c2ecf20Sopenharmony_ci * This function will iterate over descriptor chain and fill its entries 8668c2ecf20Sopenharmony_ci * with corresponding information based on transfer data. 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_cistatic void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, 8698c2ecf20Sopenharmony_ci dma_addr_t dma_buff, 8708c2ecf20Sopenharmony_ci unsigned int len) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci struct usb_request *ureq = NULL; 8738c2ecf20Sopenharmony_ci struct dwc2_dma_desc *desc = hs_ep->desc_list; 8748c2ecf20Sopenharmony_ci struct scatterlist *sg; 8758c2ecf20Sopenharmony_ci int i; 8768c2ecf20Sopenharmony_ci u8 desc_count = 0; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (hs_ep->req) 8798c2ecf20Sopenharmony_ci ureq = &hs_ep->req->req; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* non-DMA sg buffer */ 8828c2ecf20Sopenharmony_ci if (!ureq || !ureq->num_sgs) { 8838c2ecf20Sopenharmony_ci dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc, 8848c2ecf20Sopenharmony_ci dma_buff, len, true); 8858c2ecf20Sopenharmony_ci return; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* DMA sg buffer */ 8898c2ecf20Sopenharmony_ci for_each_sg(ureq->sg, sg, ureq->num_sgs, i) { 8908c2ecf20Sopenharmony_ci dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc, 8918c2ecf20Sopenharmony_ci sg_dma_address(sg) + sg->offset, sg_dma_len(sg), 8928c2ecf20Sopenharmony_ci sg_is_last(sg)); 8938c2ecf20Sopenharmony_ci desc_count += hs_ep->desc_count; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci hs_ep->desc_count = desc_count; 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci/* 9008c2ecf20Sopenharmony_ci * dwc2_gadget_fill_isoc_desc - fills next isochronous descriptor in chain. 9018c2ecf20Sopenharmony_ci * @hs_ep: The isochronous endpoint. 9028c2ecf20Sopenharmony_ci * @dma_buff: usb requests dma buffer. 9038c2ecf20Sopenharmony_ci * @len: usb request transfer length. 9048c2ecf20Sopenharmony_ci * 9058c2ecf20Sopenharmony_ci * Fills next free descriptor with the data of the arrived usb request, 9068c2ecf20Sopenharmony_ci * frame info, sets Last and IOC bits increments next_desc. If filled 9078c2ecf20Sopenharmony_ci * descriptor is not the first one, removes L bit from the previous descriptor 9088c2ecf20Sopenharmony_ci * status. 9098c2ecf20Sopenharmony_ci */ 9108c2ecf20Sopenharmony_cistatic int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, 9118c2ecf20Sopenharmony_ci dma_addr_t dma_buff, unsigned int len) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci struct dwc2_dma_desc *desc; 9148c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 9158c2ecf20Sopenharmony_ci u32 index; 9168c2ecf20Sopenharmony_ci u32 mask = 0; 9178c2ecf20Sopenharmony_ci u8 pid = 0; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci dwc2_gadget_get_desc_params(hs_ep, &mask); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci index = hs_ep->next_desc; 9228c2ecf20Sopenharmony_ci desc = &hs_ep->desc_list[index]; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci /* Check if descriptor chain full */ 9258c2ecf20Sopenharmony_ci if ((desc->status >> DEV_DMA_BUFF_STS_SHIFT) == 9268c2ecf20Sopenharmony_ci DEV_DMA_BUFF_STS_HREADY) { 9278c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__); 9288c2ecf20Sopenharmony_ci return 1; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* Clear L bit of previous desc if more than one entries in the chain */ 9328c2ecf20Sopenharmony_ci if (hs_ep->next_desc) 9338c2ecf20Sopenharmony_ci hs_ep->desc_list[index - 1].status &= ~DEV_DMA_L; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: Filling ep %d, dir %s isoc desc # %d\n", 9368c2ecf20Sopenharmony_ci __func__, hs_ep->index, hs_ep->dir_in ? "in" : "out", index); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci desc->status = 0; 9398c2ecf20Sopenharmony_ci desc->status |= (DEV_DMA_BUFF_STS_HBUSY << DEV_DMA_BUFF_STS_SHIFT); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci desc->buf = dma_buff; 9428c2ecf20Sopenharmony_ci desc->status |= (DEV_DMA_L | DEV_DMA_IOC | 9438c2ecf20Sopenharmony_ci ((len << DEV_DMA_NBYTES_SHIFT) & mask)); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (hs_ep->dir_in) { 9468c2ecf20Sopenharmony_ci if (len) 9478c2ecf20Sopenharmony_ci pid = DIV_ROUND_UP(len, hs_ep->ep.maxpacket); 9488c2ecf20Sopenharmony_ci else 9498c2ecf20Sopenharmony_ci pid = 1; 9508c2ecf20Sopenharmony_ci desc->status |= ((pid << DEV_DMA_ISOC_PID_SHIFT) & 9518c2ecf20Sopenharmony_ci DEV_DMA_ISOC_PID_MASK) | 9528c2ecf20Sopenharmony_ci ((len % hs_ep->ep.maxpacket) ? 9538c2ecf20Sopenharmony_ci DEV_DMA_SHORT : 0) | 9548c2ecf20Sopenharmony_ci ((hs_ep->target_frame << 9558c2ecf20Sopenharmony_ci DEV_DMA_ISOC_FRNUM_SHIFT) & 9568c2ecf20Sopenharmony_ci DEV_DMA_ISOC_FRNUM_MASK); 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci desc->status &= ~DEV_DMA_BUFF_STS_MASK; 9608c2ecf20Sopenharmony_ci desc->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci /* Increment frame number by interval for IN */ 9638c2ecf20Sopenharmony_ci if (hs_ep->dir_in) 9648c2ecf20Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci /* Update index of last configured entry in the chain */ 9678c2ecf20Sopenharmony_ci hs_ep->next_desc++; 9688c2ecf20Sopenharmony_ci if (hs_ep->next_desc >= MAX_DMA_DESC_NUM_HS_ISOC) 9698c2ecf20Sopenharmony_ci hs_ep->next_desc = 0; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci return 0; 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci/* 9758c2ecf20Sopenharmony_ci * dwc2_gadget_start_isoc_ddma - start isochronous transfer in DDMA 9768c2ecf20Sopenharmony_ci * @hs_ep: The isochronous endpoint. 9778c2ecf20Sopenharmony_ci * 9788c2ecf20Sopenharmony_ci * Prepare descriptor chain for isochronous endpoints. Afterwards 9798c2ecf20Sopenharmony_ci * write DMA address to HW and enable the endpoint. 9808c2ecf20Sopenharmony_ci */ 9818c2ecf20Sopenharmony_cistatic void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) 9828c2ecf20Sopenharmony_ci{ 9838c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 9848c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req, *treq; 9858c2ecf20Sopenharmony_ci int index = hs_ep->index; 9868c2ecf20Sopenharmony_ci int ret; 9878c2ecf20Sopenharmony_ci int i; 9888c2ecf20Sopenharmony_ci u32 dma_reg; 9898c2ecf20Sopenharmony_ci u32 depctl; 9908c2ecf20Sopenharmony_ci u32 ctrl; 9918c2ecf20Sopenharmony_ci struct dwc2_dma_desc *desc; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (list_empty(&hs_ep->queue)) { 9948c2ecf20Sopenharmony_ci hs_ep->target_frame = TARGET_FRAME_INITIAL; 9958c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__); 9968c2ecf20Sopenharmony_ci return; 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci /* Initialize descriptor chain by Host Busy status */ 10008c2ecf20Sopenharmony_ci for (i = 0; i < MAX_DMA_DESC_NUM_HS_ISOC; i++) { 10018c2ecf20Sopenharmony_ci desc = &hs_ep->desc_list[i]; 10028c2ecf20Sopenharmony_ci desc->status = 0; 10038c2ecf20Sopenharmony_ci desc->status |= (DEV_DMA_BUFF_STS_HBUSY 10048c2ecf20Sopenharmony_ci << DEV_DMA_BUFF_STS_SHIFT); 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci hs_ep->next_desc = 0; 10088c2ecf20Sopenharmony_ci list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) { 10098c2ecf20Sopenharmony_ci dma_addr_t dma_addr = hs_req->req.dma; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (hs_req->req.num_sgs) { 10128c2ecf20Sopenharmony_ci WARN_ON(hs_req->req.num_sgs > 1); 10138c2ecf20Sopenharmony_ci dma_addr = sg_dma_address(hs_req->req.sg); 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci ret = dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, 10168c2ecf20Sopenharmony_ci hs_req->req.length); 10178c2ecf20Sopenharmony_ci if (ret) 10188c2ecf20Sopenharmony_ci break; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci hs_ep->compl_desc = 0; 10228c2ecf20Sopenharmony_ci depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 10238c2ecf20Sopenharmony_ci dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci /* write descriptor chain address to control register */ 10268c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hs_ep->desc_list_dma, dma_reg); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci ctrl = dwc2_readl(hsotg, depctl); 10298c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK; 10308c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ctrl, depctl); 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cistatic bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep); 10348c2ecf20Sopenharmony_cistatic void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, 10358c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 10368c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req, 10378c2ecf20Sopenharmony_ci int result); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci/** 10408c2ecf20Sopenharmony_ci * dwc2_hsotg_start_req - start a USB request from an endpoint's queue 10418c2ecf20Sopenharmony_ci * @hsotg: The controller state. 10428c2ecf20Sopenharmony_ci * @hs_ep: The endpoint to process a request for 10438c2ecf20Sopenharmony_ci * @hs_req: The request to start. 10448c2ecf20Sopenharmony_ci * @continuing: True if we are doing more for the current request. 10458c2ecf20Sopenharmony_ci * 10468c2ecf20Sopenharmony_ci * Start the given request running by setting the endpoint registers 10478c2ecf20Sopenharmony_ci * appropriately, and writing any data to the FIFOs. 10488c2ecf20Sopenharmony_ci */ 10498c2ecf20Sopenharmony_cistatic void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, 10508c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 10518c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req, 10528c2ecf20Sopenharmony_ci bool continuing) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci struct usb_request *ureq = &hs_req->req; 10558c2ecf20Sopenharmony_ci int index = hs_ep->index; 10568c2ecf20Sopenharmony_ci int dir_in = hs_ep->dir_in; 10578c2ecf20Sopenharmony_ci u32 epctrl_reg; 10588c2ecf20Sopenharmony_ci u32 epsize_reg; 10598c2ecf20Sopenharmony_ci u32 epsize; 10608c2ecf20Sopenharmony_ci u32 ctrl; 10618c2ecf20Sopenharmony_ci unsigned int length; 10628c2ecf20Sopenharmony_ci unsigned int packets; 10638c2ecf20Sopenharmony_ci unsigned int maxreq; 10648c2ecf20Sopenharmony_ci unsigned int dma_reg; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci if (index != 0) { 10678c2ecf20Sopenharmony_ci if (hs_ep->req && !continuing) { 10688c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: active request\n", __func__); 10698c2ecf20Sopenharmony_ci WARN_ON(1); 10708c2ecf20Sopenharmony_ci return; 10718c2ecf20Sopenharmony_ci } else if (hs_ep->req != hs_req && continuing) { 10728c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 10738c2ecf20Sopenharmony_ci "%s: continue different req\n", __func__); 10748c2ecf20Sopenharmony_ci WARN_ON(1); 10758c2ecf20Sopenharmony_ci return; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); 10808c2ecf20Sopenharmony_ci epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 10818c2ecf20Sopenharmony_ci epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", 10848c2ecf20Sopenharmony_ci __func__, dwc2_readl(hsotg, epctrl_reg), index, 10858c2ecf20Sopenharmony_ci hs_ep->dir_in ? "in" : "out"); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* If endpoint is stalled, we will restart request later */ 10888c2ecf20Sopenharmony_ci ctrl = dwc2_readl(hsotg, epctrl_reg); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci if (index && ctrl & DXEPCTL_STALL) { 10918c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); 10928c2ecf20Sopenharmony_ci return; 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci length = ureq->length - ureq->actual; 10968c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", 10978c2ecf20Sopenharmony_ci ureq->length, ureq->actual); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (!using_desc_dma(hsotg)) 11008c2ecf20Sopenharmony_ci maxreq = get_ep_limit(hs_ep); 11018c2ecf20Sopenharmony_ci else 11028c2ecf20Sopenharmony_ci maxreq = dwc2_gadget_get_chain_limit(hs_ep); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci if (length > maxreq) { 11058c2ecf20Sopenharmony_ci int round = maxreq % hs_ep->ep.maxpacket; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", 11088c2ecf20Sopenharmony_ci __func__, length, maxreq, round); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci /* round down to multiple of packets */ 11118c2ecf20Sopenharmony_ci if (round) 11128c2ecf20Sopenharmony_ci maxreq -= round; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci length = maxreq; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci if (length) 11188c2ecf20Sopenharmony_ci packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); 11198c2ecf20Sopenharmony_ci else 11208c2ecf20Sopenharmony_ci packets = 1; /* send one packet if length is zero. */ 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci if (dir_in && index != 0) 11238c2ecf20Sopenharmony_ci if (hs_ep->isochronous) 11248c2ecf20Sopenharmony_ci epsize = DXEPTSIZ_MC(packets); 11258c2ecf20Sopenharmony_ci else 11268c2ecf20Sopenharmony_ci epsize = DXEPTSIZ_MC(1); 11278c2ecf20Sopenharmony_ci else 11288c2ecf20Sopenharmony_ci epsize = 0; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci /* 11318c2ecf20Sopenharmony_ci * zero length packet should be programmed on its own and should not 11328c2ecf20Sopenharmony_ci * be counted in DIEPTSIZ.PktCnt with other packets. 11338c2ecf20Sopenharmony_ci */ 11348c2ecf20Sopenharmony_ci if (dir_in && ureq->zero && !continuing) { 11358c2ecf20Sopenharmony_ci /* Test if zlp is actually required. */ 11368c2ecf20Sopenharmony_ci if ((ureq->length >= hs_ep->ep.maxpacket) && 11378c2ecf20Sopenharmony_ci !(ureq->length % hs_ep->ep.maxpacket)) 11388c2ecf20Sopenharmony_ci hs_ep->send_zlp = 1; 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci epsize |= DXEPTSIZ_PKTCNT(packets); 11428c2ecf20Sopenharmony_ci epsize |= DXEPTSIZ_XFERSIZE(length); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", 11458c2ecf20Sopenharmony_ci __func__, packets, length, ureq->length, epsize, epsize_reg); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci /* store the request as the current one we're doing */ 11488c2ecf20Sopenharmony_ci hs_ep->req = hs_req; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg)) { 11518c2ecf20Sopenharmony_ci u32 offset = 0; 11528c2ecf20Sopenharmony_ci u32 mps = hs_ep->ep.maxpacket; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci /* Adjust length: EP0 - MPS, other OUT EPs - multiple of MPS */ 11558c2ecf20Sopenharmony_ci if (!dir_in) { 11568c2ecf20Sopenharmony_ci if (!index) 11578c2ecf20Sopenharmony_ci length = mps; 11588c2ecf20Sopenharmony_ci else if (length % mps) 11598c2ecf20Sopenharmony_ci length += (mps - (length % mps)); 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (continuing) 11638c2ecf20Sopenharmony_ci offset = ureq->actual; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* Fill DDMA chain entries */ 11668c2ecf20Sopenharmony_ci dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq->dma + offset, 11678c2ecf20Sopenharmony_ci length); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci /* write descriptor chain address to control register */ 11708c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hs_ep->desc_list_dma, dma_reg); 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %08x pad => 0x%08x\n", 11738c2ecf20Sopenharmony_ci __func__, (u32)hs_ep->desc_list_dma, dma_reg); 11748c2ecf20Sopenharmony_ci } else { 11758c2ecf20Sopenharmony_ci /* write size / packets */ 11768c2ecf20Sopenharmony_ci dwc2_writel(hsotg, epsize, epsize_reg); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (using_dma(hsotg) && !continuing && (length != 0)) { 11798c2ecf20Sopenharmony_ci /* 11808c2ecf20Sopenharmony_ci * write DMA address to control register, buffer 11818c2ecf20Sopenharmony_ci * already synced by dwc2_hsotg_ep_queue(). 11828c2ecf20Sopenharmony_ci */ 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ureq->dma, dma_reg); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n", 11878c2ecf20Sopenharmony_ci __func__, &ureq->dma, dma_reg); 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci if (hs_ep->isochronous) { 11928c2ecf20Sopenharmony_ci if (!dwc2_gadget_target_frame_elapsed(hs_ep)) { 11938c2ecf20Sopenharmony_ci if (hs_ep->interval == 1) { 11948c2ecf20Sopenharmony_ci if (hs_ep->target_frame & 0x1) 11958c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_SETODDFR; 11968c2ecf20Sopenharmony_ci else 11978c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_SETEVENFR; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_CNAK; 12008c2ecf20Sopenharmony_ci } else { 12018c2ecf20Sopenharmony_ci hs_req->req.frame_number = hs_ep->target_frame; 12028c2ecf20Sopenharmony_ci hs_req->req.actual = 0; 12038c2ecf20Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ENODATA); 12048c2ecf20Sopenharmony_ci return; 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci /* For Setup request do not clear NAK */ 12138c2ecf20Sopenharmony_ci if (!(index == 0 && hsotg->ep0_state == DWC2_EP0_SETUP)) 12148c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 12178c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ctrl, epctrl_reg); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci /* 12208c2ecf20Sopenharmony_ci * set these, it seems that DMA support increments past the end 12218c2ecf20Sopenharmony_ci * of the packet buffer so we need to calculate the length from 12228c2ecf20Sopenharmony_ci * this information. 12238c2ecf20Sopenharmony_ci */ 12248c2ecf20Sopenharmony_ci hs_ep->size_loaded = length; 12258c2ecf20Sopenharmony_ci hs_ep->last_load = ureq->actual; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (dir_in && !using_dma(hsotg)) { 12288c2ecf20Sopenharmony_ci /* set these anyway, we may need them for non-periodic in */ 12298c2ecf20Sopenharmony_ci hs_ep->fifo_load = 0; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci /* 12358c2ecf20Sopenharmony_ci * Note, trying to clear the NAK here causes problems with transmit 12368c2ecf20Sopenharmony_ci * on the S3C6400 ending up with the TXFIFO becoming full. 12378c2ecf20Sopenharmony_ci */ 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* check ep is enabled */ 12408c2ecf20Sopenharmony_ci if (!(dwc2_readl(hsotg, epctrl_reg) & DXEPCTL_EPENA)) 12418c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 12428c2ecf20Sopenharmony_ci "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", 12438c2ecf20Sopenharmony_ci index, dwc2_readl(hsotg, epctrl_reg)); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", 12468c2ecf20Sopenharmony_ci __func__, dwc2_readl(hsotg, epctrl_reg)); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci /* enable ep interrupts */ 12498c2ecf20Sopenharmony_ci dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1); 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci/** 12538c2ecf20Sopenharmony_ci * dwc2_hsotg_map_dma - map the DMA memory being used for the request 12548c2ecf20Sopenharmony_ci * @hsotg: The device state. 12558c2ecf20Sopenharmony_ci * @hs_ep: The endpoint the request is on. 12568c2ecf20Sopenharmony_ci * @req: The request being processed. 12578c2ecf20Sopenharmony_ci * 12588c2ecf20Sopenharmony_ci * We've been asked to queue a request, so ensure that the memory buffer 12598c2ecf20Sopenharmony_ci * is correctly setup for DMA. If we've been passed an extant DMA address 12608c2ecf20Sopenharmony_ci * then ensure the buffer has been synced to memory. If our buffer has no 12618c2ecf20Sopenharmony_ci * DMA memory, then we map the memory and mark our request to allow us to 12628c2ecf20Sopenharmony_ci * cleanup on completion. 12638c2ecf20Sopenharmony_ci */ 12648c2ecf20Sopenharmony_cistatic int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg, 12658c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 12668c2ecf20Sopenharmony_ci struct usb_request *req) 12678c2ecf20Sopenharmony_ci{ 12688c2ecf20Sopenharmony_ci int ret; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci hs_ep->map_dir = hs_ep->dir_in; 12718c2ecf20Sopenharmony_ci ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); 12728c2ecf20Sopenharmony_ci if (ret) 12738c2ecf20Sopenharmony_ci goto dma_error; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci return 0; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_cidma_error: 12788c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", 12798c2ecf20Sopenharmony_ci __func__, req->buf, req->length); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci return -EIO; 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_cistatic int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, 12858c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 12868c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci void *req_buf = hs_req->req.buf; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci /* If dma is not being used or buffer is aligned */ 12918c2ecf20Sopenharmony_ci if (!using_dma(hsotg) || !((long)req_buf & 3)) 12928c2ecf20Sopenharmony_ci return 0; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci WARN_ON(hs_req->saved_req_buf); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__, 12978c2ecf20Sopenharmony_ci hs_ep->ep.name, req_buf, hs_req->req.length); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC); 13008c2ecf20Sopenharmony_ci if (!hs_req->req.buf) { 13018c2ecf20Sopenharmony_ci hs_req->req.buf = req_buf; 13028c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 13038c2ecf20Sopenharmony_ci "%s: unable to allocate memory for bounce buffer\n", 13048c2ecf20Sopenharmony_ci __func__); 13058c2ecf20Sopenharmony_ci return -ENOMEM; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci /* Save actual buffer */ 13098c2ecf20Sopenharmony_ci hs_req->saved_req_buf = req_buf; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci if (hs_ep->dir_in) 13128c2ecf20Sopenharmony_ci memcpy(hs_req->req.buf, req_buf, hs_req->req.length); 13138c2ecf20Sopenharmony_ci return 0; 13148c2ecf20Sopenharmony_ci} 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_cistatic void 13178c2ecf20Sopenharmony_cidwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, 13188c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 13198c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req) 13208c2ecf20Sopenharmony_ci{ 13218c2ecf20Sopenharmony_ci /* If dma is not being used or buffer was aligned */ 13228c2ecf20Sopenharmony_ci if (!using_dma(hsotg) || !hs_req->saved_req_buf) 13238c2ecf20Sopenharmony_ci return; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %s: status=%d actual-length=%d\n", __func__, 13268c2ecf20Sopenharmony_ci hs_ep->ep.name, hs_req->req.status, hs_req->req.actual); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci /* Copy data from bounce buffer on successful out transfer */ 13298c2ecf20Sopenharmony_ci if (!hs_ep->dir_in && !hs_req->req.status) 13308c2ecf20Sopenharmony_ci memcpy(hs_req->saved_req_buf, hs_req->req.buf, 13318c2ecf20Sopenharmony_ci hs_req->req.actual); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci /* Free bounce buffer */ 13348c2ecf20Sopenharmony_ci kfree(hs_req->req.buf); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci hs_req->req.buf = hs_req->saved_req_buf; 13378c2ecf20Sopenharmony_ci hs_req->saved_req_buf = NULL; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci/** 13418c2ecf20Sopenharmony_ci * dwc2_gadget_target_frame_elapsed - Checks target frame 13428c2ecf20Sopenharmony_ci * @hs_ep: The driver endpoint to check 13438c2ecf20Sopenharmony_ci * 13448c2ecf20Sopenharmony_ci * Returns 1 if targeted frame elapsed. If returned 1 then we need to drop 13458c2ecf20Sopenharmony_ci * corresponding transfer. 13468c2ecf20Sopenharmony_ci */ 13478c2ecf20Sopenharmony_cistatic bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep) 13488c2ecf20Sopenharmony_ci{ 13498c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 13508c2ecf20Sopenharmony_ci u32 target_frame = hs_ep->target_frame; 13518c2ecf20Sopenharmony_ci u32 current_frame = hsotg->frame_number; 13528c2ecf20Sopenharmony_ci bool frame_overrun = hs_ep->frame_overrun; 13538c2ecf20Sopenharmony_ci u16 limit = DSTS_SOFFN_LIMIT; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci if (hsotg->gadget.speed != USB_SPEED_HIGH) 13568c2ecf20Sopenharmony_ci limit >>= 3; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci if (!frame_overrun && current_frame >= target_frame) 13598c2ecf20Sopenharmony_ci return true; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if (frame_overrun && current_frame >= target_frame && 13628c2ecf20Sopenharmony_ci ((current_frame - target_frame) < limit / 2)) 13638c2ecf20Sopenharmony_ci return true; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci return false; 13668c2ecf20Sopenharmony_ci} 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci/* 13698c2ecf20Sopenharmony_ci * dwc2_gadget_set_ep0_desc_chain - Set EP's desc chain pointers 13708c2ecf20Sopenharmony_ci * @hsotg: The driver state 13718c2ecf20Sopenharmony_ci * @hs_ep: the ep descriptor chain is for 13728c2ecf20Sopenharmony_ci * 13738c2ecf20Sopenharmony_ci * Called to update EP0 structure's pointers depend on stage of 13748c2ecf20Sopenharmony_ci * control transfer. 13758c2ecf20Sopenharmony_ci */ 13768c2ecf20Sopenharmony_cistatic int dwc2_gadget_set_ep0_desc_chain(struct dwc2_hsotg *hsotg, 13778c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep) 13788c2ecf20Sopenharmony_ci{ 13798c2ecf20Sopenharmony_ci switch (hsotg->ep0_state) { 13808c2ecf20Sopenharmony_ci case DWC2_EP0_SETUP: 13818c2ecf20Sopenharmony_ci case DWC2_EP0_STATUS_OUT: 13828c2ecf20Sopenharmony_ci hs_ep->desc_list = hsotg->setup_desc[0]; 13838c2ecf20Sopenharmony_ci hs_ep->desc_list_dma = hsotg->setup_desc_dma[0]; 13848c2ecf20Sopenharmony_ci break; 13858c2ecf20Sopenharmony_ci case DWC2_EP0_DATA_IN: 13868c2ecf20Sopenharmony_ci case DWC2_EP0_STATUS_IN: 13878c2ecf20Sopenharmony_ci hs_ep->desc_list = hsotg->ctrl_in_desc; 13888c2ecf20Sopenharmony_ci hs_ep->desc_list_dma = hsotg->ctrl_in_desc_dma; 13898c2ecf20Sopenharmony_ci break; 13908c2ecf20Sopenharmony_ci case DWC2_EP0_DATA_OUT: 13918c2ecf20Sopenharmony_ci hs_ep->desc_list = hsotg->ctrl_out_desc; 13928c2ecf20Sopenharmony_ci hs_ep->desc_list_dma = hsotg->ctrl_out_desc_dma; 13938c2ecf20Sopenharmony_ci break; 13948c2ecf20Sopenharmony_ci default: 13958c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "invalid EP 0 state in queue %d\n", 13968c2ecf20Sopenharmony_ci hsotg->ep0_state); 13978c2ecf20Sopenharmony_ci return -EINVAL; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci return 0; 14018c2ecf20Sopenharmony_ci} 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_cistatic int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, 14048c2ecf20Sopenharmony_ci gfp_t gfp_flags) 14058c2ecf20Sopenharmony_ci{ 14068c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req = our_req(req); 14078c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 14088c2ecf20Sopenharmony_ci struct dwc2_hsotg *hs = hs_ep->parent; 14098c2ecf20Sopenharmony_ci bool first; 14108c2ecf20Sopenharmony_ci int ret; 14118c2ecf20Sopenharmony_ci u32 maxsize = 0; 14128c2ecf20Sopenharmony_ci u32 mask = 0; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", 14168c2ecf20Sopenharmony_ci ep->name, req, req->length, req->buf, req->no_interrupt, 14178c2ecf20Sopenharmony_ci req->zero, req->short_not_ok); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci /* Prevent new request submission when controller is suspended */ 14208c2ecf20Sopenharmony_ci if (hs->lx_state != DWC2_L0) { 14218c2ecf20Sopenharmony_ci dev_dbg(hs->dev, "%s: submit request only in active state\n", 14228c2ecf20Sopenharmony_ci __func__); 14238c2ecf20Sopenharmony_ci return -EAGAIN; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci /* initialise status of the request */ 14278c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hs_req->queue); 14288c2ecf20Sopenharmony_ci req->actual = 0; 14298c2ecf20Sopenharmony_ci req->status = -EINPROGRESS; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci /* Don't queue ISOC request if length greater than mps*mc */ 14328c2ecf20Sopenharmony_ci if (hs_ep->isochronous && 14338c2ecf20Sopenharmony_ci req->length > (hs_ep->mc * hs_ep->ep.maxpacket)) { 14348c2ecf20Sopenharmony_ci dev_err(hs->dev, "req length > maxpacket*mc\n"); 14358c2ecf20Sopenharmony_ci return -EINVAL; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci /* In DDMA mode for ISOC's don't queue request if length greater 14398c2ecf20Sopenharmony_ci * than descriptor limits. 14408c2ecf20Sopenharmony_ci */ 14418c2ecf20Sopenharmony_ci if (using_desc_dma(hs) && hs_ep->isochronous) { 14428c2ecf20Sopenharmony_ci maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); 14438c2ecf20Sopenharmony_ci if (hs_ep->dir_in && req->length > maxsize) { 14448c2ecf20Sopenharmony_ci dev_err(hs->dev, "wrong length %d (maxsize=%d)\n", 14458c2ecf20Sopenharmony_ci req->length, maxsize); 14468c2ecf20Sopenharmony_ci return -EINVAL; 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci if (!hs_ep->dir_in && req->length > hs_ep->ep.maxpacket) { 14508c2ecf20Sopenharmony_ci dev_err(hs->dev, "ISOC OUT: wrong length %d (mps=%d)\n", 14518c2ecf20Sopenharmony_ci req->length, hs_ep->ep.maxpacket); 14528c2ecf20Sopenharmony_ci return -EINVAL; 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci ret = dwc2_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req); 14578c2ecf20Sopenharmony_ci if (ret) 14588c2ecf20Sopenharmony_ci return ret; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* if we're using DMA, sync the buffers as necessary */ 14618c2ecf20Sopenharmony_ci if (using_dma(hs)) { 14628c2ecf20Sopenharmony_ci ret = dwc2_hsotg_map_dma(hs, hs_ep, req); 14638c2ecf20Sopenharmony_ci if (ret) 14648c2ecf20Sopenharmony_ci return ret; 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci /* If using descriptor DMA configure EP0 descriptor chain pointers */ 14678c2ecf20Sopenharmony_ci if (using_desc_dma(hs) && !hs_ep->index) { 14688c2ecf20Sopenharmony_ci ret = dwc2_gadget_set_ep0_desc_chain(hs, hs_ep); 14698c2ecf20Sopenharmony_ci if (ret) 14708c2ecf20Sopenharmony_ci return ret; 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci first = list_empty(&hs_ep->queue); 14748c2ecf20Sopenharmony_ci list_add_tail(&hs_req->queue, &hs_ep->queue); 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci /* 14778c2ecf20Sopenharmony_ci * Handle DDMA isochronous transfers separately - just add new entry 14788c2ecf20Sopenharmony_ci * to the descriptor chain. 14798c2ecf20Sopenharmony_ci * Transfer will be started once SW gets either one of NAK or 14808c2ecf20Sopenharmony_ci * OutTknEpDis interrupts. 14818c2ecf20Sopenharmony_ci */ 14828c2ecf20Sopenharmony_ci if (using_desc_dma(hs) && hs_ep->isochronous) { 14838c2ecf20Sopenharmony_ci if (hs_ep->target_frame != TARGET_FRAME_INITIAL) { 14848c2ecf20Sopenharmony_ci dma_addr_t dma_addr = hs_req->req.dma; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (hs_req->req.num_sgs) { 14878c2ecf20Sopenharmony_ci WARN_ON(hs_req->req.num_sgs > 1); 14888c2ecf20Sopenharmony_ci dma_addr = sg_dma_address(hs_req->req.sg); 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, 14918c2ecf20Sopenharmony_ci hs_req->req.length); 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci return 0; 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci /* Change EP direction if status phase request is after data out */ 14978c2ecf20Sopenharmony_ci if (!hs_ep->index && !req->length && !hs_ep->dir_in && 14988c2ecf20Sopenharmony_ci hs->ep0_state == DWC2_EP0_DATA_OUT) 14998c2ecf20Sopenharmony_ci hs_ep->dir_in = 1; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci if (first) { 15028c2ecf20Sopenharmony_ci if (!hs_ep->isochronous) { 15038c2ecf20Sopenharmony_ci dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 15048c2ecf20Sopenharmony_ci return 0; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci /* Update current frame number value. */ 15088c2ecf20Sopenharmony_ci hs->frame_number = dwc2_hsotg_read_frameno(hs); 15098c2ecf20Sopenharmony_ci while (dwc2_gadget_target_frame_elapsed(hs_ep)) { 15108c2ecf20Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 15118c2ecf20Sopenharmony_ci /* Update current frame number value once more as it 15128c2ecf20Sopenharmony_ci * changes here. 15138c2ecf20Sopenharmony_ci */ 15148c2ecf20Sopenharmony_ci hs->frame_number = dwc2_hsotg_read_frameno(hs); 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci if (hs_ep->target_frame != TARGET_FRAME_INITIAL) 15188c2ecf20Sopenharmony_ci dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci return 0; 15218c2ecf20Sopenharmony_ci} 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_cistatic int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, 15248c2ecf20Sopenharmony_ci gfp_t gfp_flags) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 15278c2ecf20Sopenharmony_ci struct dwc2_hsotg *hs = hs_ep->parent; 15288c2ecf20Sopenharmony_ci unsigned long flags = 0; 15298c2ecf20Sopenharmony_ci int ret = 0; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci spin_lock_irqsave(&hs->lock, flags); 15328c2ecf20Sopenharmony_ci ret = dwc2_hsotg_ep_queue(ep, req, gfp_flags); 15338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hs->lock, flags); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci return ret; 15368c2ecf20Sopenharmony_ci} 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_cistatic void dwc2_hsotg_ep_free_request(struct usb_ep *ep, 15398c2ecf20Sopenharmony_ci struct usb_request *req) 15408c2ecf20Sopenharmony_ci{ 15418c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req = our_req(req); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci kfree(hs_req); 15448c2ecf20Sopenharmony_ci} 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci/** 15478c2ecf20Sopenharmony_ci * dwc2_hsotg_complete_oursetup - setup completion callback 15488c2ecf20Sopenharmony_ci * @ep: The endpoint the request was on. 15498c2ecf20Sopenharmony_ci * @req: The request completed. 15508c2ecf20Sopenharmony_ci * 15518c2ecf20Sopenharmony_ci * Called on completion of any requests the driver itself 15528c2ecf20Sopenharmony_ci * submitted that need cleaning up. 15538c2ecf20Sopenharmony_ci */ 15548c2ecf20Sopenharmony_cistatic void dwc2_hsotg_complete_oursetup(struct usb_ep *ep, 15558c2ecf20Sopenharmony_ci struct usb_request *req) 15568c2ecf20Sopenharmony_ci{ 15578c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 15588c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci dwc2_hsotg_ep_free_request(ep, req); 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci/** 15668c2ecf20Sopenharmony_ci * ep_from_windex - convert control wIndex value to endpoint 15678c2ecf20Sopenharmony_ci * @hsotg: The driver state. 15688c2ecf20Sopenharmony_ci * @windex: The control request wIndex field (in host order). 15698c2ecf20Sopenharmony_ci * 15708c2ecf20Sopenharmony_ci * Convert the given wIndex into a pointer to an driver endpoint 15718c2ecf20Sopenharmony_ci * structure, or return NULL if it is not a valid endpoint. 15728c2ecf20Sopenharmony_ci */ 15738c2ecf20Sopenharmony_cistatic struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, 15748c2ecf20Sopenharmony_ci u32 windex) 15758c2ecf20Sopenharmony_ci{ 15768c2ecf20Sopenharmony_ci int dir = (windex & USB_DIR_IN) ? 1 : 0; 15778c2ecf20Sopenharmony_ci int idx = windex & 0x7F; 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci if (windex >= 0x100) 15808c2ecf20Sopenharmony_ci return NULL; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci if (idx > hsotg->num_of_eps) 15838c2ecf20Sopenharmony_ci return NULL; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci return index_to_ep(hsotg, idx, dir); 15868c2ecf20Sopenharmony_ci} 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci/** 15898c2ecf20Sopenharmony_ci * dwc2_hsotg_set_test_mode - Enable usb Test Modes 15908c2ecf20Sopenharmony_ci * @hsotg: The driver state. 15918c2ecf20Sopenharmony_ci * @testmode: requested usb test mode 15928c2ecf20Sopenharmony_ci * Enable usb Test Mode requested by the Host. 15938c2ecf20Sopenharmony_ci */ 15948c2ecf20Sopenharmony_ciint dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode) 15958c2ecf20Sopenharmony_ci{ 15968c2ecf20Sopenharmony_ci int dctl = dwc2_readl(hsotg, DCTL); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci dctl &= ~DCTL_TSTCTL_MASK; 15998c2ecf20Sopenharmony_ci switch (testmode) { 16008c2ecf20Sopenharmony_ci case USB_TEST_J: 16018c2ecf20Sopenharmony_ci case USB_TEST_K: 16028c2ecf20Sopenharmony_ci case USB_TEST_SE0_NAK: 16038c2ecf20Sopenharmony_ci case USB_TEST_PACKET: 16048c2ecf20Sopenharmony_ci case USB_TEST_FORCE_ENABLE: 16058c2ecf20Sopenharmony_ci dctl |= testmode << DCTL_TSTCTL_SHIFT; 16068c2ecf20Sopenharmony_ci break; 16078c2ecf20Sopenharmony_ci default: 16088c2ecf20Sopenharmony_ci return -EINVAL; 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dctl, DCTL); 16118c2ecf20Sopenharmony_ci return 0; 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci/** 16158c2ecf20Sopenharmony_ci * dwc2_hsotg_send_reply - send reply to control request 16168c2ecf20Sopenharmony_ci * @hsotg: The device state 16178c2ecf20Sopenharmony_ci * @ep: Endpoint 0 16188c2ecf20Sopenharmony_ci * @buff: Buffer for request 16198c2ecf20Sopenharmony_ci * @length: Length of reply. 16208c2ecf20Sopenharmony_ci * 16218c2ecf20Sopenharmony_ci * Create a request and queue it on the given endpoint. This is useful as 16228c2ecf20Sopenharmony_ci * an internal method of sending replies to certain control requests, etc. 16238c2ecf20Sopenharmony_ci */ 16248c2ecf20Sopenharmony_cistatic int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg, 16258c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *ep, 16268c2ecf20Sopenharmony_ci void *buff, 16278c2ecf20Sopenharmony_ci int length) 16288c2ecf20Sopenharmony_ci{ 16298c2ecf20Sopenharmony_ci struct usb_request *req; 16308c2ecf20Sopenharmony_ci int ret; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci req = dwc2_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); 16358c2ecf20Sopenharmony_ci hsotg->ep0_reply = req; 16368c2ecf20Sopenharmony_ci if (!req) { 16378c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); 16388c2ecf20Sopenharmony_ci return -ENOMEM; 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci req->buf = hsotg->ep0_buff; 16428c2ecf20Sopenharmony_ci req->length = length; 16438c2ecf20Sopenharmony_ci /* 16448c2ecf20Sopenharmony_ci * zero flag is for sending zlp in DATA IN stage. It has no impact on 16458c2ecf20Sopenharmony_ci * STATUS stage. 16468c2ecf20Sopenharmony_ci */ 16478c2ecf20Sopenharmony_ci req->zero = 0; 16488c2ecf20Sopenharmony_ci req->complete = dwc2_hsotg_complete_oursetup; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci if (length) 16518c2ecf20Sopenharmony_ci memcpy(req->buf, buff, length); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci ret = dwc2_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); 16548c2ecf20Sopenharmony_ci if (ret) { 16558c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); 16568c2ecf20Sopenharmony_ci return ret; 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci return 0; 16608c2ecf20Sopenharmony_ci} 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci/** 16638c2ecf20Sopenharmony_ci * dwc2_hsotg_process_req_status - process request GET_STATUS 16648c2ecf20Sopenharmony_ci * @hsotg: The device state 16658c2ecf20Sopenharmony_ci * @ctrl: USB control request 16668c2ecf20Sopenharmony_ci */ 16678c2ecf20Sopenharmony_cistatic int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, 16688c2ecf20Sopenharmony_ci struct usb_ctrlrequest *ctrl) 16698c2ecf20Sopenharmony_ci{ 16708c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 16718c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *ep; 16728c2ecf20Sopenharmony_ci __le16 reply; 16738c2ecf20Sopenharmony_ci u16 status; 16748c2ecf20Sopenharmony_ci int ret; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci if (!ep0->dir_in) { 16798c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: direction out?\n", __func__); 16808c2ecf20Sopenharmony_ci return -EINVAL; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci switch (ctrl->bRequestType & USB_RECIP_MASK) { 16848c2ecf20Sopenharmony_ci case USB_RECIP_DEVICE: 16858c2ecf20Sopenharmony_ci status = hsotg->gadget.is_selfpowered << 16868c2ecf20Sopenharmony_ci USB_DEVICE_SELF_POWERED; 16878c2ecf20Sopenharmony_ci status |= hsotg->remote_wakeup_allowed << 16888c2ecf20Sopenharmony_ci USB_DEVICE_REMOTE_WAKEUP; 16898c2ecf20Sopenharmony_ci reply = cpu_to_le16(status); 16908c2ecf20Sopenharmony_ci break; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci case USB_RECIP_INTERFACE: 16938c2ecf20Sopenharmony_ci /* currently, the data result should be zero */ 16948c2ecf20Sopenharmony_ci reply = cpu_to_le16(0); 16958c2ecf20Sopenharmony_ci break; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci case USB_RECIP_ENDPOINT: 16988c2ecf20Sopenharmony_ci ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); 16998c2ecf20Sopenharmony_ci if (!ep) 17008c2ecf20Sopenharmony_ci return -ENOENT; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci reply = cpu_to_le16(ep->halted ? 1 : 0); 17038c2ecf20Sopenharmony_ci break; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci default: 17068c2ecf20Sopenharmony_ci return 0; 17078c2ecf20Sopenharmony_ci } 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci if (le16_to_cpu(ctrl->wLength) != 2) 17108c2ecf20Sopenharmony_ci return -EINVAL; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci ret = dwc2_hsotg_send_reply(hsotg, ep0, &reply, 2); 17138c2ecf20Sopenharmony_ci if (ret) { 17148c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); 17158c2ecf20Sopenharmony_ci return ret; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci return 1; 17198c2ecf20Sopenharmony_ci} 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_cistatic int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci/** 17248c2ecf20Sopenharmony_ci * get_ep_head - return the first request on the endpoint 17258c2ecf20Sopenharmony_ci * @hs_ep: The controller endpoint to get 17268c2ecf20Sopenharmony_ci * 17278c2ecf20Sopenharmony_ci * Get the first request on the endpoint. 17288c2ecf20Sopenharmony_ci */ 17298c2ecf20Sopenharmony_cistatic struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep) 17308c2ecf20Sopenharmony_ci{ 17318c2ecf20Sopenharmony_ci return list_first_entry_or_null(&hs_ep->queue, struct dwc2_hsotg_req, 17328c2ecf20Sopenharmony_ci queue); 17338c2ecf20Sopenharmony_ci} 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci/** 17368c2ecf20Sopenharmony_ci * dwc2_gadget_start_next_request - Starts next request from ep queue 17378c2ecf20Sopenharmony_ci * @hs_ep: Endpoint structure 17388c2ecf20Sopenharmony_ci * 17398c2ecf20Sopenharmony_ci * If queue is empty and EP is ISOC-OUT - unmasks OUTTKNEPDIS which is masked 17408c2ecf20Sopenharmony_ci * in its handler. Hence we need to unmask it here to be able to do 17418c2ecf20Sopenharmony_ci * resynchronization. 17428c2ecf20Sopenharmony_ci */ 17438c2ecf20Sopenharmony_cistatic void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep) 17448c2ecf20Sopenharmony_ci{ 17458c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 17468c2ecf20Sopenharmony_ci int dir_in = hs_ep->dir_in; 17478c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci if (!list_empty(&hs_ep->queue)) { 17508c2ecf20Sopenharmony_ci hs_req = get_ep_head(hs_ep); 17518c2ecf20Sopenharmony_ci dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false); 17528c2ecf20Sopenharmony_ci return; 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci if (!hs_ep->isochronous) 17558c2ecf20Sopenharmony_ci return; 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci if (dir_in) { 17588c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: No more ISOC-IN requests\n", 17598c2ecf20Sopenharmony_ci __func__); 17608c2ecf20Sopenharmony_ci } else { 17618c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: No more ISOC-OUT requests\n", 17628c2ecf20Sopenharmony_ci __func__); 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci} 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci/** 17678c2ecf20Sopenharmony_ci * dwc2_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE 17688c2ecf20Sopenharmony_ci * @hsotg: The device state 17698c2ecf20Sopenharmony_ci * @ctrl: USB control request 17708c2ecf20Sopenharmony_ci */ 17718c2ecf20Sopenharmony_cistatic int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, 17728c2ecf20Sopenharmony_ci struct usb_ctrlrequest *ctrl) 17738c2ecf20Sopenharmony_ci{ 17748c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 17758c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req; 17768c2ecf20Sopenharmony_ci bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); 17778c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *ep; 17788c2ecf20Sopenharmony_ci int ret; 17798c2ecf20Sopenharmony_ci bool halted; 17808c2ecf20Sopenharmony_ci u32 recip; 17818c2ecf20Sopenharmony_ci u32 wValue; 17828c2ecf20Sopenharmony_ci u32 wIndex; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", 17858c2ecf20Sopenharmony_ci __func__, set ? "SET" : "CLEAR"); 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci wValue = le16_to_cpu(ctrl->wValue); 17888c2ecf20Sopenharmony_ci wIndex = le16_to_cpu(ctrl->wIndex); 17898c2ecf20Sopenharmony_ci recip = ctrl->bRequestType & USB_RECIP_MASK; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci switch (recip) { 17928c2ecf20Sopenharmony_ci case USB_RECIP_DEVICE: 17938c2ecf20Sopenharmony_ci switch (wValue) { 17948c2ecf20Sopenharmony_ci case USB_DEVICE_REMOTE_WAKEUP: 17958c2ecf20Sopenharmony_ci if (set) 17968c2ecf20Sopenharmony_ci hsotg->remote_wakeup_allowed = 1; 17978c2ecf20Sopenharmony_ci else 17988c2ecf20Sopenharmony_ci hsotg->remote_wakeup_allowed = 0; 17998c2ecf20Sopenharmony_ci break; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci case USB_DEVICE_TEST_MODE: 18028c2ecf20Sopenharmony_ci if ((wIndex & 0xff) != 0) 18038c2ecf20Sopenharmony_ci return -EINVAL; 18048c2ecf20Sopenharmony_ci if (!set) 18058c2ecf20Sopenharmony_ci return -EINVAL; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci hsotg->test_mode = wIndex >> 8; 18088c2ecf20Sopenharmony_ci break; 18098c2ecf20Sopenharmony_ci default: 18108c2ecf20Sopenharmony_ci return -ENOENT; 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 18148c2ecf20Sopenharmony_ci if (ret) { 18158c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 18168c2ecf20Sopenharmony_ci "%s: failed to send reply\n", __func__); 18178c2ecf20Sopenharmony_ci return ret; 18188c2ecf20Sopenharmony_ci } 18198c2ecf20Sopenharmony_ci break; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci case USB_RECIP_ENDPOINT: 18228c2ecf20Sopenharmony_ci ep = ep_from_windex(hsotg, wIndex); 18238c2ecf20Sopenharmony_ci if (!ep) { 18248c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", 18258c2ecf20Sopenharmony_ci __func__, wIndex); 18268c2ecf20Sopenharmony_ci return -ENOENT; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci switch (wValue) { 18308c2ecf20Sopenharmony_ci case USB_ENDPOINT_HALT: 18318c2ecf20Sopenharmony_ci halted = ep->halted; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci dwc2_hsotg_ep_sethalt(&ep->ep, set, true); 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 18368c2ecf20Sopenharmony_ci if (ret) { 18378c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 18388c2ecf20Sopenharmony_ci "%s: failed to send reply\n", __func__); 18398c2ecf20Sopenharmony_ci return ret; 18408c2ecf20Sopenharmony_ci } 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci /* 18438c2ecf20Sopenharmony_ci * we have to complete all requests for ep if it was 18448c2ecf20Sopenharmony_ci * halted, and the halt was cleared by CLEAR_FEATURE 18458c2ecf20Sopenharmony_ci */ 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci if (!set && halted) { 18488c2ecf20Sopenharmony_ci /* 18498c2ecf20Sopenharmony_ci * If we have request in progress, 18508c2ecf20Sopenharmony_ci * then complete it 18518c2ecf20Sopenharmony_ci */ 18528c2ecf20Sopenharmony_ci if (ep->req) { 18538c2ecf20Sopenharmony_ci hs_req = ep->req; 18548c2ecf20Sopenharmony_ci ep->req = NULL; 18558c2ecf20Sopenharmony_ci list_del_init(&hs_req->queue); 18568c2ecf20Sopenharmony_ci if (hs_req->req.complete) { 18578c2ecf20Sopenharmony_ci spin_unlock(&hsotg->lock); 18588c2ecf20Sopenharmony_ci usb_gadget_giveback_request( 18598c2ecf20Sopenharmony_ci &ep->ep, &hs_req->req); 18608c2ecf20Sopenharmony_ci spin_lock(&hsotg->lock); 18618c2ecf20Sopenharmony_ci } 18628c2ecf20Sopenharmony_ci } 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci /* If we have pending request, then start it */ 18658c2ecf20Sopenharmony_ci if (!ep->req) 18668c2ecf20Sopenharmony_ci dwc2_gadget_start_next_request(ep); 18678c2ecf20Sopenharmony_ci } 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci break; 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci default: 18728c2ecf20Sopenharmony_ci return -ENOENT; 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci break; 18758c2ecf20Sopenharmony_ci default: 18768c2ecf20Sopenharmony_ci return -ENOENT; 18778c2ecf20Sopenharmony_ci } 18788c2ecf20Sopenharmony_ci return 1; 18798c2ecf20Sopenharmony_ci} 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_cistatic void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg); 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci/** 18848c2ecf20Sopenharmony_ci * dwc2_hsotg_stall_ep0 - stall ep0 18858c2ecf20Sopenharmony_ci * @hsotg: The device state 18868c2ecf20Sopenharmony_ci * 18878c2ecf20Sopenharmony_ci * Set stall for ep0 as response for setup request. 18888c2ecf20Sopenharmony_ci */ 18898c2ecf20Sopenharmony_cistatic void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg) 18908c2ecf20Sopenharmony_ci{ 18918c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 18928c2ecf20Sopenharmony_ci u32 reg; 18938c2ecf20Sopenharmony_ci u32 ctrl; 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); 18968c2ecf20Sopenharmony_ci reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci /* 18998c2ecf20Sopenharmony_ci * DxEPCTL_Stall will be cleared by EP once it has 19008c2ecf20Sopenharmony_ci * taken effect, so no need to clear later. 19018c2ecf20Sopenharmony_ci */ 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci ctrl = dwc2_readl(hsotg, reg); 19048c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_STALL; 19058c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_CNAK; 19068c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ctrl, reg); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 19098c2ecf20Sopenharmony_ci "written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n", 19108c2ecf20Sopenharmony_ci ctrl, reg, dwc2_readl(hsotg, reg)); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci /* 19138c2ecf20Sopenharmony_ci * complete won't be called, so we enqueue 19148c2ecf20Sopenharmony_ci * setup request here 19158c2ecf20Sopenharmony_ci */ 19168c2ecf20Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 19178c2ecf20Sopenharmony_ci} 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci/** 19208c2ecf20Sopenharmony_ci * dwc2_hsotg_process_control - process a control request 19218c2ecf20Sopenharmony_ci * @hsotg: The device state 19228c2ecf20Sopenharmony_ci * @ctrl: The control request received 19238c2ecf20Sopenharmony_ci * 19248c2ecf20Sopenharmony_ci * The controller has received the SETUP phase of a control request, and 19258c2ecf20Sopenharmony_ci * needs to work out what to do next (and whether to pass it on to the 19268c2ecf20Sopenharmony_ci * gadget driver). 19278c2ecf20Sopenharmony_ci */ 19288c2ecf20Sopenharmony_cistatic void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, 19298c2ecf20Sopenharmony_ci struct usb_ctrlrequest *ctrl) 19308c2ecf20Sopenharmony_ci{ 19318c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 19328c2ecf20Sopenharmony_ci int ret = 0; 19338c2ecf20Sopenharmony_ci u32 dcfg; 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 19368c2ecf20Sopenharmony_ci "ctrl Type=%02x, Req=%02x, V=%04x, I=%04x, L=%04x\n", 19378c2ecf20Sopenharmony_ci ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, 19388c2ecf20Sopenharmony_ci ctrl->wIndex, ctrl->wLength); 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci if (ctrl->wLength == 0) { 19418c2ecf20Sopenharmony_ci ep0->dir_in = 1; 19428c2ecf20Sopenharmony_ci hsotg->ep0_state = DWC2_EP0_STATUS_IN; 19438c2ecf20Sopenharmony_ci } else if (ctrl->bRequestType & USB_DIR_IN) { 19448c2ecf20Sopenharmony_ci ep0->dir_in = 1; 19458c2ecf20Sopenharmony_ci hsotg->ep0_state = DWC2_EP0_DATA_IN; 19468c2ecf20Sopenharmony_ci } else { 19478c2ecf20Sopenharmony_ci ep0->dir_in = 0; 19488c2ecf20Sopenharmony_ci hsotg->ep0_state = DWC2_EP0_DATA_OUT; 19498c2ecf20Sopenharmony_ci } 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 19528c2ecf20Sopenharmony_ci switch (ctrl->bRequest) { 19538c2ecf20Sopenharmony_ci case USB_REQ_SET_ADDRESS: 19548c2ecf20Sopenharmony_ci hsotg->connected = 1; 19558c2ecf20Sopenharmony_ci dcfg = dwc2_readl(hsotg, DCFG); 19568c2ecf20Sopenharmony_ci dcfg &= ~DCFG_DEVADDR_MASK; 19578c2ecf20Sopenharmony_ci dcfg |= (le16_to_cpu(ctrl->wValue) << 19588c2ecf20Sopenharmony_ci DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK; 19598c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dcfg, DCFG); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 19648c2ecf20Sopenharmony_ci return; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci case USB_REQ_GET_STATUS: 19678c2ecf20Sopenharmony_ci ret = dwc2_hsotg_process_req_status(hsotg, ctrl); 19688c2ecf20Sopenharmony_ci break; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci case USB_REQ_CLEAR_FEATURE: 19718c2ecf20Sopenharmony_ci case USB_REQ_SET_FEATURE: 19728c2ecf20Sopenharmony_ci ret = dwc2_hsotg_process_req_feature(hsotg, ctrl); 19738c2ecf20Sopenharmony_ci break; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci /* as a fallback, try delivering it to the driver to deal with */ 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci if (ret == 0 && hsotg->driver) { 19808c2ecf20Sopenharmony_ci spin_unlock(&hsotg->lock); 19818c2ecf20Sopenharmony_ci ret = hsotg->driver->setup(&hsotg->gadget, ctrl); 19828c2ecf20Sopenharmony_ci spin_lock(&hsotg->lock); 19838c2ecf20Sopenharmony_ci if (ret < 0) 19848c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci hsotg->delayed_status = false; 19888c2ecf20Sopenharmony_ci if (ret == USB_GADGET_DELAYED_STATUS) 19898c2ecf20Sopenharmony_ci hsotg->delayed_status = true; 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci /* 19928c2ecf20Sopenharmony_ci * the request is either unhandlable, or is not formatted correctly 19938c2ecf20Sopenharmony_ci * so respond with a STALL for the status stage to indicate failure. 19948c2ecf20Sopenharmony_ci */ 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci if (ret < 0) 19978c2ecf20Sopenharmony_ci dwc2_hsotg_stall_ep0(hsotg); 19988c2ecf20Sopenharmony_ci} 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci/** 20018c2ecf20Sopenharmony_ci * dwc2_hsotg_complete_setup - completion of a setup transfer 20028c2ecf20Sopenharmony_ci * @ep: The endpoint the request was on. 20038c2ecf20Sopenharmony_ci * @req: The request completed. 20048c2ecf20Sopenharmony_ci * 20058c2ecf20Sopenharmony_ci * Called on completion of any requests the driver itself submitted for 20068c2ecf20Sopenharmony_ci * EP0 setup packets 20078c2ecf20Sopenharmony_ci */ 20088c2ecf20Sopenharmony_cistatic void dwc2_hsotg_complete_setup(struct usb_ep *ep, 20098c2ecf20Sopenharmony_ci struct usb_request *req) 20108c2ecf20Sopenharmony_ci{ 20118c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 20128c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci if (req->status < 0) { 20158c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); 20168c2ecf20Sopenharmony_ci return; 20178c2ecf20Sopenharmony_ci } 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci spin_lock(&hsotg->lock); 20208c2ecf20Sopenharmony_ci if (req->actual == 0) 20218c2ecf20Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 20228c2ecf20Sopenharmony_ci else 20238c2ecf20Sopenharmony_ci dwc2_hsotg_process_control(hsotg, req->buf); 20248c2ecf20Sopenharmony_ci spin_unlock(&hsotg->lock); 20258c2ecf20Sopenharmony_ci} 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci/** 20288c2ecf20Sopenharmony_ci * dwc2_hsotg_enqueue_setup - start a request for EP0 packets 20298c2ecf20Sopenharmony_ci * @hsotg: The device state. 20308c2ecf20Sopenharmony_ci * 20318c2ecf20Sopenharmony_ci * Enqueue a request on EP0 if necessary to received any SETUP packets 20328c2ecf20Sopenharmony_ci * received from the host. 20338c2ecf20Sopenharmony_ci */ 20348c2ecf20Sopenharmony_cistatic void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg) 20358c2ecf20Sopenharmony_ci{ 20368c2ecf20Sopenharmony_ci struct usb_request *req = hsotg->ctrl_req; 20378c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req = our_req(req); 20388c2ecf20Sopenharmony_ci int ret; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci req->zero = 0; 20438c2ecf20Sopenharmony_ci req->length = 8; 20448c2ecf20Sopenharmony_ci req->buf = hsotg->ctrl_buff; 20458c2ecf20Sopenharmony_ci req->complete = dwc2_hsotg_complete_setup; 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci if (!list_empty(&hs_req->queue)) { 20488c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s already queued???\n", __func__); 20498c2ecf20Sopenharmony_ci return; 20508c2ecf20Sopenharmony_ci } 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci hsotg->eps_out[0]->dir_in = 0; 20538c2ecf20Sopenharmony_ci hsotg->eps_out[0]->send_zlp = 0; 20548c2ecf20Sopenharmony_ci hsotg->ep0_state = DWC2_EP0_SETUP; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci ret = dwc2_hsotg_ep_queue(&hsotg->eps_out[0]->ep, req, GFP_ATOMIC); 20578c2ecf20Sopenharmony_ci if (ret < 0) { 20588c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); 20598c2ecf20Sopenharmony_ci /* 20608c2ecf20Sopenharmony_ci * Don't think there's much we can do other than watch the 20618c2ecf20Sopenharmony_ci * driver fail. 20628c2ecf20Sopenharmony_ci */ 20638c2ecf20Sopenharmony_ci } 20648c2ecf20Sopenharmony_ci} 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_cistatic void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, 20678c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep) 20688c2ecf20Sopenharmony_ci{ 20698c2ecf20Sopenharmony_ci u32 ctrl; 20708c2ecf20Sopenharmony_ci u8 index = hs_ep->index; 20718c2ecf20Sopenharmony_ci u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 20728c2ecf20Sopenharmony_ci u32 epsiz_reg = hs_ep->dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci if (hs_ep->dir_in) 20758c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n", 20768c2ecf20Sopenharmony_ci index); 20778c2ecf20Sopenharmony_ci else 20788c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n", 20798c2ecf20Sopenharmony_ci index); 20808c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg)) { 20818c2ecf20Sopenharmony_ci /* Not specific buffer needed for ep0 ZLP */ 20828c2ecf20Sopenharmony_ci dma_addr_t dma = hs_ep->desc_list_dma; 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci if (!index) 20858c2ecf20Sopenharmony_ci dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0); 20888c2ecf20Sopenharmony_ci } else { 20898c2ecf20Sopenharmony_ci dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 20908c2ecf20Sopenharmony_ci DXEPTSIZ_XFERSIZE(0), 20918c2ecf20Sopenharmony_ci epsiz_reg); 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci ctrl = dwc2_readl(hsotg, epctl_reg); 20958c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 20968c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 20978c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_USBACTEP; 20988c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ctrl, epctl_reg); 20998c2ecf20Sopenharmony_ci} 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci/** 21028c2ecf20Sopenharmony_ci * dwc2_hsotg_complete_request - complete a request given to us 21038c2ecf20Sopenharmony_ci * @hsotg: The device state. 21048c2ecf20Sopenharmony_ci * @hs_ep: The endpoint the request was on. 21058c2ecf20Sopenharmony_ci * @hs_req: The request to complete. 21068c2ecf20Sopenharmony_ci * @result: The result code (0 => Ok, otherwise errno) 21078c2ecf20Sopenharmony_ci * 21088c2ecf20Sopenharmony_ci * The given request has finished, so call the necessary completion 21098c2ecf20Sopenharmony_ci * if it has one and then look to see if we can start a new request 21108c2ecf20Sopenharmony_ci * on the endpoint. 21118c2ecf20Sopenharmony_ci * 21128c2ecf20Sopenharmony_ci * Note, expects the ep to already be locked as appropriate. 21138c2ecf20Sopenharmony_ci */ 21148c2ecf20Sopenharmony_cistatic void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, 21158c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 21168c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req, 21178c2ecf20Sopenharmony_ci int result) 21188c2ecf20Sopenharmony_ci{ 21198c2ecf20Sopenharmony_ci if (!hs_req) { 21208c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); 21218c2ecf20Sopenharmony_ci return; 21228c2ecf20Sopenharmony_ci } 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", 21258c2ecf20Sopenharmony_ci hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci /* 21288c2ecf20Sopenharmony_ci * only replace the status if we've not already set an error 21298c2ecf20Sopenharmony_ci * from a previous transaction 21308c2ecf20Sopenharmony_ci */ 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci if (hs_req->req.status == -EINPROGRESS) 21338c2ecf20Sopenharmony_ci hs_req->req.status = result; 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci if (using_dma(hsotg)) 21368c2ecf20Sopenharmony_ci dwc2_hsotg_unmap_dma(hsotg, hs_ep, hs_req); 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci dwc2_hsotg_handle_unaligned_buf_complete(hsotg, hs_ep, hs_req); 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci hs_ep->req = NULL; 21418c2ecf20Sopenharmony_ci list_del_init(&hs_req->queue); 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci /* 21448c2ecf20Sopenharmony_ci * call the complete request with the locks off, just in case the 21458c2ecf20Sopenharmony_ci * request tries to queue more work for this endpoint. 21468c2ecf20Sopenharmony_ci */ 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci if (hs_req->req.complete) { 21498c2ecf20Sopenharmony_ci spin_unlock(&hsotg->lock); 21508c2ecf20Sopenharmony_ci usb_gadget_giveback_request(&hs_ep->ep, &hs_req->req); 21518c2ecf20Sopenharmony_ci spin_lock(&hsotg->lock); 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci /* In DDMA don't need to proceed to starting of next ISOC request */ 21558c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg) && hs_ep->isochronous) 21568c2ecf20Sopenharmony_ci return; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci /* 21598c2ecf20Sopenharmony_ci * Look to see if there is anything else to do. Note, the completion 21608c2ecf20Sopenharmony_ci * of the previous request may have caused a new request to be started 21618c2ecf20Sopenharmony_ci * so be careful when doing this. 21628c2ecf20Sopenharmony_ci */ 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci if (!hs_ep->req && result >= 0) 21658c2ecf20Sopenharmony_ci dwc2_gadget_start_next_request(hs_ep); 21668c2ecf20Sopenharmony_ci} 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci/* 21698c2ecf20Sopenharmony_ci * dwc2_gadget_complete_isoc_request_ddma - complete an isoc request in DDMA 21708c2ecf20Sopenharmony_ci * @hs_ep: The endpoint the request was on. 21718c2ecf20Sopenharmony_ci * 21728c2ecf20Sopenharmony_ci * Get first request from the ep queue, determine descriptor on which complete 21738c2ecf20Sopenharmony_ci * happened. SW discovers which descriptor currently in use by HW, adjusts 21748c2ecf20Sopenharmony_ci * dma_address and calculates index of completed descriptor based on the value 21758c2ecf20Sopenharmony_ci * of DEPDMA register. Update actual length of request, giveback to gadget. 21768c2ecf20Sopenharmony_ci */ 21778c2ecf20Sopenharmony_cistatic void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep) 21788c2ecf20Sopenharmony_ci{ 21798c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 21808c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req; 21818c2ecf20Sopenharmony_ci struct usb_request *ureq; 21828c2ecf20Sopenharmony_ci u32 desc_sts; 21838c2ecf20Sopenharmony_ci u32 mask; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status; 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci /* Process only descriptors with buffer status set to DMA done */ 21888c2ecf20Sopenharmony_ci while ((desc_sts & DEV_DMA_BUFF_STS_MASK) >> 21898c2ecf20Sopenharmony_ci DEV_DMA_BUFF_STS_SHIFT == DEV_DMA_BUFF_STS_DMADONE) { 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci hs_req = get_ep_head(hs_ep); 21928c2ecf20Sopenharmony_ci if (!hs_req) { 21938c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n", __func__); 21948c2ecf20Sopenharmony_ci return; 21958c2ecf20Sopenharmony_ci } 21968c2ecf20Sopenharmony_ci ureq = &hs_req->req; 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci /* Check completion status */ 21998c2ecf20Sopenharmony_ci if ((desc_sts & DEV_DMA_STS_MASK) >> DEV_DMA_STS_SHIFT == 22008c2ecf20Sopenharmony_ci DEV_DMA_STS_SUCC) { 22018c2ecf20Sopenharmony_ci mask = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_MASK : 22028c2ecf20Sopenharmony_ci DEV_DMA_ISOC_RX_NBYTES_MASK; 22038c2ecf20Sopenharmony_ci ureq->actual = ureq->length - ((desc_sts & mask) >> 22048c2ecf20Sopenharmony_ci DEV_DMA_ISOC_NBYTES_SHIFT); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci /* Adjust actual len for ISOC Out if len is 22078c2ecf20Sopenharmony_ci * not align of 4 22088c2ecf20Sopenharmony_ci */ 22098c2ecf20Sopenharmony_ci if (!hs_ep->dir_in && ureq->length & 0x3) 22108c2ecf20Sopenharmony_ci ureq->actual += 4 - (ureq->length & 0x3); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci /* Set actual frame number for completed transfers */ 22138c2ecf20Sopenharmony_ci ureq->frame_number = 22148c2ecf20Sopenharmony_ci (desc_sts & DEV_DMA_ISOC_FRNUM_MASK) >> 22158c2ecf20Sopenharmony_ci DEV_DMA_ISOC_FRNUM_SHIFT; 22168c2ecf20Sopenharmony_ci } 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci hs_ep->compl_desc++; 22218c2ecf20Sopenharmony_ci if (hs_ep->compl_desc > (MAX_DMA_DESC_NUM_HS_ISOC - 1)) 22228c2ecf20Sopenharmony_ci hs_ep->compl_desc = 0; 22238c2ecf20Sopenharmony_ci desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status; 22248c2ecf20Sopenharmony_ci } 22258c2ecf20Sopenharmony_ci} 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci/* 22288c2ecf20Sopenharmony_ci * dwc2_gadget_handle_isoc_bna - handle BNA interrupt for ISOC. 22298c2ecf20Sopenharmony_ci * @hs_ep: The isochronous endpoint. 22308c2ecf20Sopenharmony_ci * 22318c2ecf20Sopenharmony_ci * If EP ISOC OUT then need to flush RX FIFO to remove source of BNA 22328c2ecf20Sopenharmony_ci * interrupt. Reset target frame and next_desc to allow to start 22338c2ecf20Sopenharmony_ci * ISOC's on NAK interrupt for IN direction or on OUTTKNEPDIS 22348c2ecf20Sopenharmony_ci * interrupt for OUT direction. 22358c2ecf20Sopenharmony_ci */ 22368c2ecf20Sopenharmony_cistatic void dwc2_gadget_handle_isoc_bna(struct dwc2_hsotg_ep *hs_ep) 22378c2ecf20Sopenharmony_ci{ 22388c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci if (!hs_ep->dir_in) 22418c2ecf20Sopenharmony_ci dwc2_flush_rx_fifo(hsotg); 22428c2ecf20Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, get_ep_head(hs_ep), 0); 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci hs_ep->target_frame = TARGET_FRAME_INITIAL; 22458c2ecf20Sopenharmony_ci hs_ep->next_desc = 0; 22468c2ecf20Sopenharmony_ci hs_ep->compl_desc = 0; 22478c2ecf20Sopenharmony_ci} 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci/** 22508c2ecf20Sopenharmony_ci * dwc2_hsotg_rx_data - receive data from the FIFO for an endpoint 22518c2ecf20Sopenharmony_ci * @hsotg: The device state. 22528c2ecf20Sopenharmony_ci * @ep_idx: The endpoint index for the data 22538c2ecf20Sopenharmony_ci * @size: The size of data in the fifo, in bytes 22548c2ecf20Sopenharmony_ci * 22558c2ecf20Sopenharmony_ci * The FIFO status shows there is data to read from the FIFO for a given 22568c2ecf20Sopenharmony_ci * endpoint, so sort out whether we need to read the data into a request 22578c2ecf20Sopenharmony_ci * that has been made for that endpoint. 22588c2ecf20Sopenharmony_ci */ 22598c2ecf20Sopenharmony_cistatic void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size) 22608c2ecf20Sopenharmony_ci{ 22618c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[ep_idx]; 22628c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req = hs_ep->req; 22638c2ecf20Sopenharmony_ci int to_read; 22648c2ecf20Sopenharmony_ci int max_req; 22658c2ecf20Sopenharmony_ci int read_ptr; 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci if (!hs_req) { 22688c2ecf20Sopenharmony_ci u32 epctl = dwc2_readl(hsotg, DOEPCTL(ep_idx)); 22698c2ecf20Sopenharmony_ci int ptr; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 22728c2ecf20Sopenharmony_ci "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", 22738c2ecf20Sopenharmony_ci __func__, size, ep_idx, epctl); 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci /* dump the data from the FIFO, we've nothing we can do */ 22768c2ecf20Sopenharmony_ci for (ptr = 0; ptr < size; ptr += 4) 22778c2ecf20Sopenharmony_ci (void)dwc2_readl(hsotg, EPFIFO(ep_idx)); 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci return; 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci to_read = size; 22838c2ecf20Sopenharmony_ci read_ptr = hs_req->req.actual; 22848c2ecf20Sopenharmony_ci max_req = hs_req->req.length - read_ptr; 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", 22878c2ecf20Sopenharmony_ci __func__, to_read, max_req, read_ptr, hs_req->req.length); 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci if (to_read > max_req) { 22908c2ecf20Sopenharmony_ci /* 22918c2ecf20Sopenharmony_ci * more data appeared than we where willing 22928c2ecf20Sopenharmony_ci * to deal with in this request. 22938c2ecf20Sopenharmony_ci */ 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci /* currently we don't deal this */ 22968c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 22978c2ecf20Sopenharmony_ci } 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci hs_ep->total_data += to_read; 23008c2ecf20Sopenharmony_ci hs_req->req.actual += to_read; 23018c2ecf20Sopenharmony_ci to_read = DIV_ROUND_UP(to_read, 4); 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci /* 23048c2ecf20Sopenharmony_ci * note, we might over-write the buffer end by 3 bytes depending on 23058c2ecf20Sopenharmony_ci * alignment of the data. 23068c2ecf20Sopenharmony_ci */ 23078c2ecf20Sopenharmony_ci dwc2_readl_rep(hsotg, EPFIFO(ep_idx), 23088c2ecf20Sopenharmony_ci hs_req->req.buf + read_ptr, to_read); 23098c2ecf20Sopenharmony_ci} 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci/** 23128c2ecf20Sopenharmony_ci * dwc2_hsotg_ep0_zlp - send/receive zero-length packet on control endpoint 23138c2ecf20Sopenharmony_ci * @hsotg: The device instance 23148c2ecf20Sopenharmony_ci * @dir_in: If IN zlp 23158c2ecf20Sopenharmony_ci * 23168c2ecf20Sopenharmony_ci * Generate a zero-length IN packet request for terminating a SETUP 23178c2ecf20Sopenharmony_ci * transaction. 23188c2ecf20Sopenharmony_ci * 23198c2ecf20Sopenharmony_ci * Note, since we don't write any data to the TxFIFO, then it is 23208c2ecf20Sopenharmony_ci * currently believed that we do not need to wait for any space in 23218c2ecf20Sopenharmony_ci * the TxFIFO. 23228c2ecf20Sopenharmony_ci */ 23238c2ecf20Sopenharmony_cistatic void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in) 23248c2ecf20Sopenharmony_ci{ 23258c2ecf20Sopenharmony_ci /* eps_out[0] is used in both directions */ 23268c2ecf20Sopenharmony_ci hsotg->eps_out[0]->dir_in = dir_in; 23278c2ecf20Sopenharmony_ci hsotg->ep0_state = dir_in ? DWC2_EP0_STATUS_IN : DWC2_EP0_STATUS_OUT; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci dwc2_hsotg_program_zlp(hsotg, hsotg->eps_out[0]); 23308c2ecf20Sopenharmony_ci} 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci/* 23338c2ecf20Sopenharmony_ci * dwc2_gadget_get_xfersize_ddma - get transferred bytes amount from desc 23348c2ecf20Sopenharmony_ci * @hs_ep - The endpoint on which transfer went 23358c2ecf20Sopenharmony_ci * 23368c2ecf20Sopenharmony_ci * Iterate over endpoints descriptor chain and get info on bytes remained 23378c2ecf20Sopenharmony_ci * in DMA descriptors after transfer has completed. Used for non isoc EPs. 23388c2ecf20Sopenharmony_ci */ 23398c2ecf20Sopenharmony_cistatic unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep) 23408c2ecf20Sopenharmony_ci{ 23418c2ecf20Sopenharmony_ci const struct usb_endpoint_descriptor *ep_desc = hs_ep->ep.desc; 23428c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 23438c2ecf20Sopenharmony_ci unsigned int bytes_rem = 0; 23448c2ecf20Sopenharmony_ci unsigned int bytes_rem_correction = 0; 23458c2ecf20Sopenharmony_ci struct dwc2_dma_desc *desc = hs_ep->desc_list; 23468c2ecf20Sopenharmony_ci int i; 23478c2ecf20Sopenharmony_ci u32 status; 23488c2ecf20Sopenharmony_ci u32 mps = hs_ep->ep.maxpacket; 23498c2ecf20Sopenharmony_ci int dir_in = hs_ep->dir_in; 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci if (!desc) 23528c2ecf20Sopenharmony_ci return -EINVAL; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci /* Interrupt OUT EP with mps not multiple of 4 */ 23558c2ecf20Sopenharmony_ci if (hs_ep->index) 23568c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_int(ep_desc) && !dir_in && (mps % 4)) 23578c2ecf20Sopenharmony_ci bytes_rem_correction = 4 - (mps % 4); 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci for (i = 0; i < hs_ep->desc_count; ++i) { 23608c2ecf20Sopenharmony_ci status = desc->status; 23618c2ecf20Sopenharmony_ci bytes_rem += status & DEV_DMA_NBYTES_MASK; 23628c2ecf20Sopenharmony_ci bytes_rem -= bytes_rem_correction; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci if (status & DEV_DMA_STS_MASK) 23658c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "descriptor %d closed with %x\n", 23668c2ecf20Sopenharmony_ci i, status & DEV_DMA_STS_MASK); 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci if (status & DEV_DMA_L) 23698c2ecf20Sopenharmony_ci break; 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci desc++; 23728c2ecf20Sopenharmony_ci } 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci return bytes_rem; 23758c2ecf20Sopenharmony_ci} 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci/** 23788c2ecf20Sopenharmony_ci * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO 23798c2ecf20Sopenharmony_ci * @hsotg: The device instance 23808c2ecf20Sopenharmony_ci * @epnum: The endpoint received from 23818c2ecf20Sopenharmony_ci * 23828c2ecf20Sopenharmony_ci * The RXFIFO has delivered an OutDone event, which means that the data 23838c2ecf20Sopenharmony_ci * transfer for an OUT endpoint has been completed, either by a short 23848c2ecf20Sopenharmony_ci * packet or by the finish of a transfer. 23858c2ecf20Sopenharmony_ci */ 23868c2ecf20Sopenharmony_cistatic void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) 23878c2ecf20Sopenharmony_ci{ 23888c2ecf20Sopenharmony_ci u32 epsize = dwc2_readl(hsotg, DOEPTSIZ(epnum)); 23898c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[epnum]; 23908c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req = hs_ep->req; 23918c2ecf20Sopenharmony_ci struct usb_request *req = &hs_req->req; 23928c2ecf20Sopenharmony_ci unsigned int size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 23938c2ecf20Sopenharmony_ci int result = 0; 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci if (!hs_req) { 23968c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: no request active\n", __func__); 23978c2ecf20Sopenharmony_ci return; 23988c2ecf20Sopenharmony_ci } 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_OUT) { 24018c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "zlp packet received\n"); 24028c2ecf20Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 24038c2ecf20Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 24048c2ecf20Sopenharmony_ci return; 24058c2ecf20Sopenharmony_ci } 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg)) 24088c2ecf20Sopenharmony_ci size_left = dwc2_gadget_get_xfersize_ddma(hs_ep); 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci if (using_dma(hsotg)) { 24118c2ecf20Sopenharmony_ci unsigned int size_done; 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci /* 24148c2ecf20Sopenharmony_ci * Calculate the size of the transfer by checking how much 24158c2ecf20Sopenharmony_ci * is left in the endpoint size register and then working it 24168c2ecf20Sopenharmony_ci * out from the amount we loaded for the transfer. 24178c2ecf20Sopenharmony_ci * 24188c2ecf20Sopenharmony_ci * We need to do this as DMA pointers are always 32bit aligned 24198c2ecf20Sopenharmony_ci * so may overshoot/undershoot the transfer. 24208c2ecf20Sopenharmony_ci */ 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci size_done = hs_ep->size_loaded - size_left; 24238c2ecf20Sopenharmony_ci size_done += hs_ep->last_load; 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci req->actual = size_done; 24268c2ecf20Sopenharmony_ci } 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci /* if there is more request to do, schedule new transfer */ 24298c2ecf20Sopenharmony_ci if (req->actual < req->length && size_left == 0) { 24308c2ecf20Sopenharmony_ci dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 24318c2ecf20Sopenharmony_ci return; 24328c2ecf20Sopenharmony_ci } 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci if (req->actual < req->length && req->short_not_ok) { 24358c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", 24368c2ecf20Sopenharmony_ci __func__, req->actual, req->length); 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci /* 24398c2ecf20Sopenharmony_ci * todo - what should we return here? there's no one else 24408c2ecf20Sopenharmony_ci * even bothering to check the status. 24418c2ecf20Sopenharmony_ci */ 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci /* DDMA IN status phase will start from StsPhseRcvd interrupt */ 24458c2ecf20Sopenharmony_ci if (!using_desc_dma(hsotg) && epnum == 0 && 24468c2ecf20Sopenharmony_ci hsotg->ep0_state == DWC2_EP0_DATA_OUT) { 24478c2ecf20Sopenharmony_ci /* Move to STATUS IN */ 24488c2ecf20Sopenharmony_ci if (!hsotg->delayed_status) 24498c2ecf20Sopenharmony_ci dwc2_hsotg_ep0_zlp(hsotg, true); 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci /* Set actual frame number for completed transfers */ 24538c2ecf20Sopenharmony_ci if (!using_desc_dma(hsotg) && hs_ep->isochronous) { 24548c2ecf20Sopenharmony_ci req->frame_number = hs_ep->target_frame; 24558c2ecf20Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 24568c2ecf20Sopenharmony_ci } 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result); 24598c2ecf20Sopenharmony_ci} 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci/** 24628c2ecf20Sopenharmony_ci * dwc2_hsotg_handle_rx - RX FIFO has data 24638c2ecf20Sopenharmony_ci * @hsotg: The device instance 24648c2ecf20Sopenharmony_ci * 24658c2ecf20Sopenharmony_ci * The IRQ handler has detected that the RX FIFO has some data in it 24668c2ecf20Sopenharmony_ci * that requires processing, so find out what is in there and do the 24678c2ecf20Sopenharmony_ci * appropriate read. 24688c2ecf20Sopenharmony_ci * 24698c2ecf20Sopenharmony_ci * The RXFIFO is a true FIFO, the packets coming out are still in packet 24708c2ecf20Sopenharmony_ci * chunks, so if you have x packets received on an endpoint you'll get x 24718c2ecf20Sopenharmony_ci * FIFO events delivered, each with a packet's worth of data in it. 24728c2ecf20Sopenharmony_ci * 24738c2ecf20Sopenharmony_ci * When using DMA, we should not be processing events from the RXFIFO 24748c2ecf20Sopenharmony_ci * as the actual data should be sent to the memory directly and we turn 24758c2ecf20Sopenharmony_ci * on the completion interrupts to get notifications of transfer completion. 24768c2ecf20Sopenharmony_ci */ 24778c2ecf20Sopenharmony_cistatic void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg) 24788c2ecf20Sopenharmony_ci{ 24798c2ecf20Sopenharmony_ci u32 grxstsr = dwc2_readl(hsotg, GRXSTSP); 24808c2ecf20Sopenharmony_ci u32 epnum, status, size; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci WARN_ON(using_dma(hsotg)); 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci epnum = grxstsr & GRXSTS_EPNUM_MASK; 24858c2ecf20Sopenharmony_ci status = grxstsr & GRXSTS_PKTSTS_MASK; 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci size = grxstsr & GRXSTS_BYTECNT_MASK; 24888c2ecf20Sopenharmony_ci size >>= GRXSTS_BYTECNT_SHIFT; 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", 24918c2ecf20Sopenharmony_ci __func__, grxstsr, size, epnum); 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { 24948c2ecf20Sopenharmony_ci case GRXSTS_PKTSTS_GLOBALOUTNAK: 24958c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GLOBALOUTNAK\n"); 24968c2ecf20Sopenharmony_ci break; 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci case GRXSTS_PKTSTS_OUTDONE: 24998c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", 25008c2ecf20Sopenharmony_ci dwc2_hsotg_read_frameno(hsotg)); 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_ci if (!using_dma(hsotg)) 25038c2ecf20Sopenharmony_ci dwc2_hsotg_handle_outdone(hsotg, epnum); 25048c2ecf20Sopenharmony_ci break; 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci case GRXSTS_PKTSTS_SETUPDONE: 25078c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 25088c2ecf20Sopenharmony_ci "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 25098c2ecf20Sopenharmony_ci dwc2_hsotg_read_frameno(hsotg), 25108c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DOEPCTL(0))); 25118c2ecf20Sopenharmony_ci /* 25128c2ecf20Sopenharmony_ci * Call dwc2_hsotg_handle_outdone here if it was not called from 25138c2ecf20Sopenharmony_ci * GRXSTS_PKTSTS_OUTDONE. That is, if the core didn't 25148c2ecf20Sopenharmony_ci * generate GRXSTS_PKTSTS_OUTDONE for setup packet. 25158c2ecf20Sopenharmony_ci */ 25168c2ecf20Sopenharmony_ci if (hsotg->ep0_state == DWC2_EP0_SETUP) 25178c2ecf20Sopenharmony_ci dwc2_hsotg_handle_outdone(hsotg, epnum); 25188c2ecf20Sopenharmony_ci break; 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci case GRXSTS_PKTSTS_OUTRX: 25218c2ecf20Sopenharmony_ci dwc2_hsotg_rx_data(hsotg, epnum, size); 25228c2ecf20Sopenharmony_ci break; 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci case GRXSTS_PKTSTS_SETUPRX: 25258c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 25268c2ecf20Sopenharmony_ci "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 25278c2ecf20Sopenharmony_ci dwc2_hsotg_read_frameno(hsotg), 25288c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DOEPCTL(0))); 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci WARN_ON(hsotg->ep0_state != DWC2_EP0_SETUP); 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci dwc2_hsotg_rx_data(hsotg, epnum, size); 25338c2ecf20Sopenharmony_ci break; 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci default: 25368c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: unknown status %08x\n", 25378c2ecf20Sopenharmony_ci __func__, grxstsr); 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci dwc2_hsotg_dump(hsotg); 25408c2ecf20Sopenharmony_ci break; 25418c2ecf20Sopenharmony_ci } 25428c2ecf20Sopenharmony_ci} 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci/** 25458c2ecf20Sopenharmony_ci * dwc2_hsotg_ep0_mps - turn max packet size into register setting 25468c2ecf20Sopenharmony_ci * @mps: The maximum packet size in bytes. 25478c2ecf20Sopenharmony_ci */ 25488c2ecf20Sopenharmony_cistatic u32 dwc2_hsotg_ep0_mps(unsigned int mps) 25498c2ecf20Sopenharmony_ci{ 25508c2ecf20Sopenharmony_ci switch (mps) { 25518c2ecf20Sopenharmony_ci case 64: 25528c2ecf20Sopenharmony_ci return D0EPCTL_MPS_64; 25538c2ecf20Sopenharmony_ci case 32: 25548c2ecf20Sopenharmony_ci return D0EPCTL_MPS_32; 25558c2ecf20Sopenharmony_ci case 16: 25568c2ecf20Sopenharmony_ci return D0EPCTL_MPS_16; 25578c2ecf20Sopenharmony_ci case 8: 25588c2ecf20Sopenharmony_ci return D0EPCTL_MPS_8; 25598c2ecf20Sopenharmony_ci } 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci /* bad max packet size, warn and return invalid result */ 25628c2ecf20Sopenharmony_ci WARN_ON(1); 25638c2ecf20Sopenharmony_ci return (u32)-1; 25648c2ecf20Sopenharmony_ci} 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci/** 25678c2ecf20Sopenharmony_ci * dwc2_hsotg_set_ep_maxpacket - set endpoint's max-packet field 25688c2ecf20Sopenharmony_ci * @hsotg: The driver state. 25698c2ecf20Sopenharmony_ci * @ep: The index number of the endpoint 25708c2ecf20Sopenharmony_ci * @mps: The maximum packet size in bytes 25718c2ecf20Sopenharmony_ci * @mc: The multicount value 25728c2ecf20Sopenharmony_ci * @dir_in: True if direction is in. 25738c2ecf20Sopenharmony_ci * 25748c2ecf20Sopenharmony_ci * Configure the maximum packet size for the given endpoint, updating 25758c2ecf20Sopenharmony_ci * the hardware control registers to reflect this. 25768c2ecf20Sopenharmony_ci */ 25778c2ecf20Sopenharmony_cistatic void dwc2_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg, 25788c2ecf20Sopenharmony_ci unsigned int ep, unsigned int mps, 25798c2ecf20Sopenharmony_ci unsigned int mc, unsigned int dir_in) 25808c2ecf20Sopenharmony_ci{ 25818c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep; 25828c2ecf20Sopenharmony_ci u32 reg; 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci hs_ep = index_to_ep(hsotg, ep, dir_in); 25858c2ecf20Sopenharmony_ci if (!hs_ep) 25868c2ecf20Sopenharmony_ci return; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci if (ep == 0) { 25898c2ecf20Sopenharmony_ci u32 mps_bytes = mps; 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci /* EP0 is a special case */ 25928c2ecf20Sopenharmony_ci mps = dwc2_hsotg_ep0_mps(mps_bytes); 25938c2ecf20Sopenharmony_ci if (mps > 3) 25948c2ecf20Sopenharmony_ci goto bad_mps; 25958c2ecf20Sopenharmony_ci hs_ep->ep.maxpacket = mps_bytes; 25968c2ecf20Sopenharmony_ci hs_ep->mc = 1; 25978c2ecf20Sopenharmony_ci } else { 25988c2ecf20Sopenharmony_ci if (mps > 1024) 25998c2ecf20Sopenharmony_ci goto bad_mps; 26008c2ecf20Sopenharmony_ci hs_ep->mc = mc; 26018c2ecf20Sopenharmony_ci if (mc > 3) 26028c2ecf20Sopenharmony_ci goto bad_mps; 26038c2ecf20Sopenharmony_ci hs_ep->ep.maxpacket = mps; 26048c2ecf20Sopenharmony_ci } 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci if (dir_in) { 26078c2ecf20Sopenharmony_ci reg = dwc2_readl(hsotg, DIEPCTL(ep)); 26088c2ecf20Sopenharmony_ci reg &= ~DXEPCTL_MPS_MASK; 26098c2ecf20Sopenharmony_ci reg |= mps; 26108c2ecf20Sopenharmony_ci dwc2_writel(hsotg, reg, DIEPCTL(ep)); 26118c2ecf20Sopenharmony_ci } else { 26128c2ecf20Sopenharmony_ci reg = dwc2_readl(hsotg, DOEPCTL(ep)); 26138c2ecf20Sopenharmony_ci reg &= ~DXEPCTL_MPS_MASK; 26148c2ecf20Sopenharmony_ci reg |= mps; 26158c2ecf20Sopenharmony_ci dwc2_writel(hsotg, reg, DOEPCTL(ep)); 26168c2ecf20Sopenharmony_ci } 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci return; 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_cibad_mps: 26218c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); 26228c2ecf20Sopenharmony_ci} 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci/** 26258c2ecf20Sopenharmony_ci * dwc2_hsotg_txfifo_flush - flush Tx FIFO 26268c2ecf20Sopenharmony_ci * @hsotg: The driver state 26278c2ecf20Sopenharmony_ci * @idx: The index for the endpoint (0..15) 26288c2ecf20Sopenharmony_ci */ 26298c2ecf20Sopenharmony_cistatic void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx) 26308c2ecf20Sopenharmony_ci{ 26318c2ecf20Sopenharmony_ci dwc2_writel(hsotg, GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH, 26328c2ecf20Sopenharmony_ci GRSTCTL); 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_ci /* wait until the fifo is flushed */ 26358c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 100)) 26368c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: timeout flushing fifo GRSTCTL_TXFFLSH\n", 26378c2ecf20Sopenharmony_ci __func__); 26388c2ecf20Sopenharmony_ci} 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci/** 26418c2ecf20Sopenharmony_ci * dwc2_hsotg_trytx - check to see if anything needs transmitting 26428c2ecf20Sopenharmony_ci * @hsotg: The driver state 26438c2ecf20Sopenharmony_ci * @hs_ep: The driver endpoint to check. 26448c2ecf20Sopenharmony_ci * 26458c2ecf20Sopenharmony_ci * Check to see if there is a request that has data to send, and if so 26468c2ecf20Sopenharmony_ci * make an attempt to write data into the FIFO. 26478c2ecf20Sopenharmony_ci */ 26488c2ecf20Sopenharmony_cistatic int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, 26498c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep) 26508c2ecf20Sopenharmony_ci{ 26518c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req = hs_ep->req; 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci if (!hs_ep->dir_in || !hs_req) { 26548c2ecf20Sopenharmony_ci /** 26558c2ecf20Sopenharmony_ci * if request is not enqueued, we disable interrupts 26568c2ecf20Sopenharmony_ci * for endpoints, excepting ep0 26578c2ecf20Sopenharmony_ci */ 26588c2ecf20Sopenharmony_ci if (hs_ep->index != 0) 26598c2ecf20Sopenharmony_ci dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, 26608c2ecf20Sopenharmony_ci hs_ep->dir_in, 0); 26618c2ecf20Sopenharmony_ci return 0; 26628c2ecf20Sopenharmony_ci } 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci if (hs_req->req.actual < hs_req->req.length) { 26658c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "trying to write more for ep%d\n", 26668c2ecf20Sopenharmony_ci hs_ep->index); 26678c2ecf20Sopenharmony_ci return dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci return 0; 26718c2ecf20Sopenharmony_ci} 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci/** 26748c2ecf20Sopenharmony_ci * dwc2_hsotg_complete_in - complete IN transfer 26758c2ecf20Sopenharmony_ci * @hsotg: The device state. 26768c2ecf20Sopenharmony_ci * @hs_ep: The endpoint that has just completed. 26778c2ecf20Sopenharmony_ci * 26788c2ecf20Sopenharmony_ci * An IN transfer has been completed, update the transfer's state and then 26798c2ecf20Sopenharmony_ci * call the relevant completion routines. 26808c2ecf20Sopenharmony_ci */ 26818c2ecf20Sopenharmony_cistatic void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, 26828c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep) 26838c2ecf20Sopenharmony_ci{ 26848c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req = hs_ep->req; 26858c2ecf20Sopenharmony_ci u32 epsize = dwc2_readl(hsotg, DIEPTSIZ(hs_ep->index)); 26868c2ecf20Sopenharmony_ci int size_left, size_done; 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci if (!hs_req) { 26898c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "XferCompl but no req\n"); 26908c2ecf20Sopenharmony_ci return; 26918c2ecf20Sopenharmony_ci } 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_ci /* Finish ZLP handling for IN EP0 transactions */ 26948c2ecf20Sopenharmony_ci if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) { 26958c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "zlp packet sent\n"); 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci /* 26988c2ecf20Sopenharmony_ci * While send zlp for DWC2_EP0_STATUS_IN EP direction was 26998c2ecf20Sopenharmony_ci * changed to IN. Change back to complete OUT transfer request 27008c2ecf20Sopenharmony_ci */ 27018c2ecf20Sopenharmony_ci hs_ep->dir_in = 0; 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 27048c2ecf20Sopenharmony_ci if (hsotg->test_mode) { 27058c2ecf20Sopenharmony_ci int ret; 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci ret = dwc2_hsotg_set_test_mode(hsotg, hsotg->test_mode); 27088c2ecf20Sopenharmony_ci if (ret < 0) { 27098c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Invalid Test #%d\n", 27108c2ecf20Sopenharmony_ci hsotg->test_mode); 27118c2ecf20Sopenharmony_ci dwc2_hsotg_stall_ep0(hsotg); 27128c2ecf20Sopenharmony_ci return; 27138c2ecf20Sopenharmony_ci } 27148c2ecf20Sopenharmony_ci } 27158c2ecf20Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 27168c2ecf20Sopenharmony_ci return; 27178c2ecf20Sopenharmony_ci } 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci /* 27208c2ecf20Sopenharmony_ci * Calculate the size of the transfer by checking how much is left 27218c2ecf20Sopenharmony_ci * in the endpoint size register and then working it out from 27228c2ecf20Sopenharmony_ci * the amount we loaded for the transfer. 27238c2ecf20Sopenharmony_ci * 27248c2ecf20Sopenharmony_ci * We do this even for DMA, as the transfer may have incremented 27258c2ecf20Sopenharmony_ci * past the end of the buffer (DMA transfers are always 32bit 27268c2ecf20Sopenharmony_ci * aligned). 27278c2ecf20Sopenharmony_ci */ 27288c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg)) { 27298c2ecf20Sopenharmony_ci size_left = dwc2_gadget_get_xfersize_ddma(hs_ep); 27308c2ecf20Sopenharmony_ci if (size_left < 0) 27318c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "error parsing DDMA results %d\n", 27328c2ecf20Sopenharmony_ci size_left); 27338c2ecf20Sopenharmony_ci } else { 27348c2ecf20Sopenharmony_ci size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 27358c2ecf20Sopenharmony_ci } 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci size_done = hs_ep->size_loaded - size_left; 27388c2ecf20Sopenharmony_ci size_done += hs_ep->last_load; 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci if (hs_req->req.actual != size_done) 27418c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", 27428c2ecf20Sopenharmony_ci __func__, hs_req->req.actual, size_done); 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci hs_req->req.actual = size_done; 27458c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", 27468c2ecf20Sopenharmony_ci hs_req->req.length, hs_req->req.actual, hs_req->req.zero); 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_ci if (!size_left && hs_req->req.actual < hs_req->req.length) { 27498c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); 27508c2ecf20Sopenharmony_ci dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 27518c2ecf20Sopenharmony_ci return; 27528c2ecf20Sopenharmony_ci } 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci /* Zlp for all endpoints in non DDMA, for ep0 only in DATA IN stage */ 27558c2ecf20Sopenharmony_ci if (hs_ep->send_zlp) { 27568c2ecf20Sopenharmony_ci hs_ep->send_zlp = 0; 27578c2ecf20Sopenharmony_ci if (!using_desc_dma(hsotg)) { 27588c2ecf20Sopenharmony_ci dwc2_hsotg_program_zlp(hsotg, hs_ep); 27598c2ecf20Sopenharmony_ci /* transfer will be completed on next complete interrupt */ 27608c2ecf20Sopenharmony_ci return; 27618c2ecf20Sopenharmony_ci } 27628c2ecf20Sopenharmony_ci } 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_DATA_IN) { 27658c2ecf20Sopenharmony_ci /* Move to STATUS OUT */ 27668c2ecf20Sopenharmony_ci dwc2_hsotg_ep0_zlp(hsotg, false); 27678c2ecf20Sopenharmony_ci return; 27688c2ecf20Sopenharmony_ci } 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci /* Set actual frame number for completed transfers */ 27718c2ecf20Sopenharmony_ci if (!using_desc_dma(hsotg) && hs_ep->isochronous) { 27728c2ecf20Sopenharmony_ci hs_req->req.frame_number = hs_ep->target_frame; 27738c2ecf20Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 27748c2ecf20Sopenharmony_ci } 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 27778c2ecf20Sopenharmony_ci} 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci/** 27808c2ecf20Sopenharmony_ci * dwc2_gadget_read_ep_interrupts - reads interrupts for given ep 27818c2ecf20Sopenharmony_ci * @hsotg: The device state. 27828c2ecf20Sopenharmony_ci * @idx: Index of ep. 27838c2ecf20Sopenharmony_ci * @dir_in: Endpoint direction 1-in 0-out. 27848c2ecf20Sopenharmony_ci * 27858c2ecf20Sopenharmony_ci * Reads for endpoint with given index and direction, by masking 27868c2ecf20Sopenharmony_ci * epint_reg with coresponding mask. 27878c2ecf20Sopenharmony_ci */ 27888c2ecf20Sopenharmony_cistatic u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg, 27898c2ecf20Sopenharmony_ci unsigned int idx, int dir_in) 27908c2ecf20Sopenharmony_ci{ 27918c2ecf20Sopenharmony_ci u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; 27928c2ecf20Sopenharmony_ci u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 27938c2ecf20Sopenharmony_ci u32 ints; 27948c2ecf20Sopenharmony_ci u32 mask; 27958c2ecf20Sopenharmony_ci u32 diepempmsk; 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci mask = dwc2_readl(hsotg, epmsk_reg); 27988c2ecf20Sopenharmony_ci diepempmsk = dwc2_readl(hsotg, DIEPEMPMSK); 27998c2ecf20Sopenharmony_ci mask |= ((diepempmsk >> idx) & 0x1) ? DIEPMSK_TXFIFOEMPTY : 0; 28008c2ecf20Sopenharmony_ci mask |= DXEPINT_SETUP_RCVD; 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci ints = dwc2_readl(hsotg, epint_reg); 28038c2ecf20Sopenharmony_ci ints &= mask; 28048c2ecf20Sopenharmony_ci return ints; 28058c2ecf20Sopenharmony_ci} 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci/** 28088c2ecf20Sopenharmony_ci * dwc2_gadget_handle_ep_disabled - handle DXEPINT_EPDISBLD 28098c2ecf20Sopenharmony_ci * @hs_ep: The endpoint on which interrupt is asserted. 28108c2ecf20Sopenharmony_ci * 28118c2ecf20Sopenharmony_ci * This interrupt indicates that the endpoint has been disabled per the 28128c2ecf20Sopenharmony_ci * application's request. 28138c2ecf20Sopenharmony_ci * 28148c2ecf20Sopenharmony_ci * For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK, 28158c2ecf20Sopenharmony_ci * in case of ISOC completes current request. 28168c2ecf20Sopenharmony_ci * 28178c2ecf20Sopenharmony_ci * For ISOC-OUT endpoints completes expired requests. If there is remaining 28188c2ecf20Sopenharmony_ci * request starts it. 28198c2ecf20Sopenharmony_ci */ 28208c2ecf20Sopenharmony_cistatic void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) 28218c2ecf20Sopenharmony_ci{ 28228c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 28238c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req; 28248c2ecf20Sopenharmony_ci unsigned char idx = hs_ep->index; 28258c2ecf20Sopenharmony_ci int dir_in = hs_ep->dir_in; 28268c2ecf20Sopenharmony_ci u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 28278c2ecf20Sopenharmony_ci int dctl = dwc2_readl(hsotg, DCTL); 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci if (dir_in) { 28328c2ecf20Sopenharmony_ci int epctl = dwc2_readl(hsotg, epctl_reg); 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_ci dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) { 28378c2ecf20Sopenharmony_ci int dctl = dwc2_readl(hsotg, DCTL); 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci dctl |= DCTL_CGNPINNAK; 28408c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dctl, DCTL); 28418c2ecf20Sopenharmony_ci } 28428c2ecf20Sopenharmony_ci } else { 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci if (dctl & DCTL_GOUTNAKSTS) { 28458c2ecf20Sopenharmony_ci dctl |= DCTL_CGOUTNAK; 28468c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dctl, DCTL); 28478c2ecf20Sopenharmony_ci } 28488c2ecf20Sopenharmony_ci } 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci if (!hs_ep->isochronous) 28518c2ecf20Sopenharmony_ci return; 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci if (list_empty(&hs_ep->queue)) { 28548c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: complete_ep 0x%p, ep->queue empty!\n", 28558c2ecf20Sopenharmony_ci __func__, hs_ep); 28568c2ecf20Sopenharmony_ci return; 28578c2ecf20Sopenharmony_ci } 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci do { 28608c2ecf20Sopenharmony_ci hs_req = get_ep_head(hs_ep); 28618c2ecf20Sopenharmony_ci if (hs_req) { 28628c2ecf20Sopenharmony_ci hs_req->req.frame_number = hs_ep->target_frame; 28638c2ecf20Sopenharmony_ci hs_req->req.actual = 0; 28648c2ecf20Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 28658c2ecf20Sopenharmony_ci -ENODATA); 28668c2ecf20Sopenharmony_ci } 28678c2ecf20Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 28688c2ecf20Sopenharmony_ci /* Update current frame number value. */ 28698c2ecf20Sopenharmony_ci hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg); 28708c2ecf20Sopenharmony_ci } while (dwc2_gadget_target_frame_elapsed(hs_ep)); 28718c2ecf20Sopenharmony_ci} 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci/** 28748c2ecf20Sopenharmony_ci * dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS 28758c2ecf20Sopenharmony_ci * @ep: The endpoint on which interrupt is asserted. 28768c2ecf20Sopenharmony_ci * 28778c2ecf20Sopenharmony_ci * This is starting point for ISOC-OUT transfer, synchronization done with 28788c2ecf20Sopenharmony_ci * first out token received from host while corresponding EP is disabled. 28798c2ecf20Sopenharmony_ci * 28808c2ecf20Sopenharmony_ci * Device does not know initial frame in which out token will come. For this 28818c2ecf20Sopenharmony_ci * HW generates OUTTKNEPDIS - out token is received while EP is disabled. Upon 28828c2ecf20Sopenharmony_ci * getting this interrupt SW starts calculation for next transfer frame. 28838c2ecf20Sopenharmony_ci */ 28848c2ecf20Sopenharmony_cistatic void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) 28858c2ecf20Sopenharmony_ci{ 28868c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = ep->parent; 28878c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req; 28888c2ecf20Sopenharmony_ci int dir_in = ep->dir_in; 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci if (dir_in || !ep->isochronous) 28918c2ecf20Sopenharmony_ci return; 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg)) { 28948c2ecf20Sopenharmony_ci if (ep->target_frame == TARGET_FRAME_INITIAL) { 28958c2ecf20Sopenharmony_ci /* Start first ISO Out */ 28968c2ecf20Sopenharmony_ci ep->target_frame = hsotg->frame_number; 28978c2ecf20Sopenharmony_ci dwc2_gadget_start_isoc_ddma(ep); 28988c2ecf20Sopenharmony_ci } 28998c2ecf20Sopenharmony_ci return; 29008c2ecf20Sopenharmony_ci } 29018c2ecf20Sopenharmony_ci 29028c2ecf20Sopenharmony_ci if (ep->target_frame == TARGET_FRAME_INITIAL) { 29038c2ecf20Sopenharmony_ci u32 ctrl; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci ep->target_frame = hsotg->frame_number; 29068c2ecf20Sopenharmony_ci if (ep->interval > 1) { 29078c2ecf20Sopenharmony_ci ctrl = dwc2_readl(hsotg, DOEPCTL(ep->index)); 29088c2ecf20Sopenharmony_ci if (ep->target_frame & 0x1) 29098c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_SETODDFR; 29108c2ecf20Sopenharmony_ci else 29118c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_SETEVENFR; 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ctrl, DOEPCTL(ep->index)); 29148c2ecf20Sopenharmony_ci } 29158c2ecf20Sopenharmony_ci } 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci while (dwc2_gadget_target_frame_elapsed(ep)) { 29188c2ecf20Sopenharmony_ci hs_req = get_ep_head(ep); 29198c2ecf20Sopenharmony_ci if (hs_req) { 29208c2ecf20Sopenharmony_ci hs_req->req.frame_number = ep->target_frame; 29218c2ecf20Sopenharmony_ci hs_req->req.actual = 0; 29228c2ecf20Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, ep, hs_req, -ENODATA); 29238c2ecf20Sopenharmony_ci } 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci dwc2_gadget_incr_frame_num(ep); 29268c2ecf20Sopenharmony_ci /* Update current frame number value. */ 29278c2ecf20Sopenharmony_ci hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg); 29288c2ecf20Sopenharmony_ci } 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_ci if (!ep->req) 29318c2ecf20Sopenharmony_ci dwc2_gadget_start_next_request(ep); 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci} 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_cistatic void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, 29368c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep); 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci/** 29398c2ecf20Sopenharmony_ci * dwc2_gadget_handle_nak - handle NAK interrupt 29408c2ecf20Sopenharmony_ci * @hs_ep: The endpoint on which interrupt is asserted. 29418c2ecf20Sopenharmony_ci * 29428c2ecf20Sopenharmony_ci * This is starting point for ISOC-IN transfer, synchronization done with 29438c2ecf20Sopenharmony_ci * first IN token received from host while corresponding EP is disabled. 29448c2ecf20Sopenharmony_ci * 29458c2ecf20Sopenharmony_ci * Device does not know when first one token will arrive from host. On first 29468c2ecf20Sopenharmony_ci * token arrival HW generates 2 interrupts: 'in token received while FIFO empty' 29478c2ecf20Sopenharmony_ci * and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was 29488c2ecf20Sopenharmony_ci * sent in response to that as there was no data in FIFO. SW is basing on this 29498c2ecf20Sopenharmony_ci * interrupt to obtain frame in which token has come and then based on the 29508c2ecf20Sopenharmony_ci * interval calculates next frame for transfer. 29518c2ecf20Sopenharmony_ci */ 29528c2ecf20Sopenharmony_cistatic void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) 29538c2ecf20Sopenharmony_ci{ 29548c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 29558c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req; 29568c2ecf20Sopenharmony_ci int dir_in = hs_ep->dir_in; 29578c2ecf20Sopenharmony_ci u32 ctrl; 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_ci if (!dir_in || !hs_ep->isochronous) 29608c2ecf20Sopenharmony_ci return; 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci if (hs_ep->target_frame == TARGET_FRAME_INITIAL) { 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg)) { 29658c2ecf20Sopenharmony_ci hs_ep->target_frame = hsotg->frame_number; 29668c2ecf20Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci /* In service interval mode target_frame must 29698c2ecf20Sopenharmony_ci * be set to last (u)frame of the service interval. 29708c2ecf20Sopenharmony_ci */ 29718c2ecf20Sopenharmony_ci if (hsotg->params.service_interval) { 29728c2ecf20Sopenharmony_ci /* Set target_frame to the first (u)frame of 29738c2ecf20Sopenharmony_ci * the service interval 29748c2ecf20Sopenharmony_ci */ 29758c2ecf20Sopenharmony_ci hs_ep->target_frame &= ~hs_ep->interval + 1; 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_ci /* Set target_frame to the last (u)frame of 29788c2ecf20Sopenharmony_ci * the service interval 29798c2ecf20Sopenharmony_ci */ 29808c2ecf20Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 29818c2ecf20Sopenharmony_ci dwc2_gadget_dec_frame_num_by_one(hs_ep); 29828c2ecf20Sopenharmony_ci } 29838c2ecf20Sopenharmony_ci 29848c2ecf20Sopenharmony_ci dwc2_gadget_start_isoc_ddma(hs_ep); 29858c2ecf20Sopenharmony_ci return; 29868c2ecf20Sopenharmony_ci } 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci hs_ep->target_frame = hsotg->frame_number; 29898c2ecf20Sopenharmony_ci if (hs_ep->interval > 1) { 29908c2ecf20Sopenharmony_ci u32 ctrl = dwc2_readl(hsotg, 29918c2ecf20Sopenharmony_ci DIEPCTL(hs_ep->index)); 29928c2ecf20Sopenharmony_ci if (hs_ep->target_frame & 0x1) 29938c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_SETODDFR; 29948c2ecf20Sopenharmony_ci else 29958c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_SETEVENFR; 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ctrl, DIEPCTL(hs_ep->index)); 29988c2ecf20Sopenharmony_ci } 29998c2ecf20Sopenharmony_ci } 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg)) 30028c2ecf20Sopenharmony_ci return; 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci ctrl = dwc2_readl(hsotg, DIEPCTL(hs_ep->index)); 30058c2ecf20Sopenharmony_ci if (ctrl & DXEPCTL_EPENA) 30068c2ecf20Sopenharmony_ci dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep); 30078c2ecf20Sopenharmony_ci else 30088c2ecf20Sopenharmony_ci dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci while (dwc2_gadget_target_frame_elapsed(hs_ep)) { 30118c2ecf20Sopenharmony_ci hs_req = get_ep_head(hs_ep); 30128c2ecf20Sopenharmony_ci if (hs_req) { 30138c2ecf20Sopenharmony_ci hs_req->req.frame_number = hs_ep->target_frame; 30148c2ecf20Sopenharmony_ci hs_req->req.actual = 0; 30158c2ecf20Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ENODATA); 30168c2ecf20Sopenharmony_ci } 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 30198c2ecf20Sopenharmony_ci /* Update current frame number value. */ 30208c2ecf20Sopenharmony_ci hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg); 30218c2ecf20Sopenharmony_ci } 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci if (!hs_ep->req) 30248c2ecf20Sopenharmony_ci dwc2_gadget_start_next_request(hs_ep); 30258c2ecf20Sopenharmony_ci} 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci/** 30288c2ecf20Sopenharmony_ci * dwc2_hsotg_epint - handle an in/out endpoint interrupt 30298c2ecf20Sopenharmony_ci * @hsotg: The driver state 30308c2ecf20Sopenharmony_ci * @idx: The index for the endpoint (0..15) 30318c2ecf20Sopenharmony_ci * @dir_in: Set if this is an IN endpoint 30328c2ecf20Sopenharmony_ci * 30338c2ecf20Sopenharmony_ci * Process and clear any interrupt pending for an individual endpoint 30348c2ecf20Sopenharmony_ci */ 30358c2ecf20Sopenharmony_cistatic void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, 30368c2ecf20Sopenharmony_ci int dir_in) 30378c2ecf20Sopenharmony_ci{ 30388c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in); 30398c2ecf20Sopenharmony_ci u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 30408c2ecf20Sopenharmony_ci u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 30418c2ecf20Sopenharmony_ci u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); 30428c2ecf20Sopenharmony_ci u32 ints; 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_ci ints = dwc2_gadget_read_ep_interrupts(hsotg, idx, dir_in); 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci /* Clear endpoint interrupts */ 30478c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ints, epint_reg); 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci if (!hs_ep) { 30508c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n", 30518c2ecf20Sopenharmony_ci __func__, idx, dir_in ? "in" : "out"); 30528c2ecf20Sopenharmony_ci return; 30538c2ecf20Sopenharmony_ci } 30548c2ecf20Sopenharmony_ci 30558c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", 30568c2ecf20Sopenharmony_ci __func__, idx, dir_in ? "in" : "out", ints); 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci /* Don't process XferCompl interrupt if it is a setup packet */ 30598c2ecf20Sopenharmony_ci if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD))) 30608c2ecf20Sopenharmony_ci ints &= ~DXEPINT_XFERCOMPL; 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci /* 30638c2ecf20Sopenharmony_ci * Don't process XferCompl interrupt in DDMA if EP0 is still in SETUP 30648c2ecf20Sopenharmony_ci * stage and xfercomplete was generated without SETUP phase done 30658c2ecf20Sopenharmony_ci * interrupt. SW should parse received setup packet only after host's 30668c2ecf20Sopenharmony_ci * exit from setup phase of control transfer. 30678c2ecf20Sopenharmony_ci */ 30688c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg) && idx == 0 && !hs_ep->dir_in && 30698c2ecf20Sopenharmony_ci hsotg->ep0_state == DWC2_EP0_SETUP && !(ints & DXEPINT_SETUP)) 30708c2ecf20Sopenharmony_ci ints &= ~DXEPINT_XFERCOMPL; 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci if (ints & DXEPINT_XFERCOMPL) { 30738c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 30748c2ecf20Sopenharmony_ci "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", 30758c2ecf20Sopenharmony_ci __func__, dwc2_readl(hsotg, epctl_reg), 30768c2ecf20Sopenharmony_ci dwc2_readl(hsotg, epsiz_reg)); 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci /* In DDMA handle isochronous requests separately */ 30798c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg) && hs_ep->isochronous) { 30808c2ecf20Sopenharmony_ci dwc2_gadget_complete_isoc_request_ddma(hs_ep); 30818c2ecf20Sopenharmony_ci } else if (dir_in) { 30828c2ecf20Sopenharmony_ci /* 30838c2ecf20Sopenharmony_ci * We get OutDone from the FIFO, so we only 30848c2ecf20Sopenharmony_ci * need to look at completing IN requests here 30858c2ecf20Sopenharmony_ci * if operating slave mode 30868c2ecf20Sopenharmony_ci */ 30878c2ecf20Sopenharmony_ci if (!hs_ep->isochronous || !(ints & DXEPINT_NAKINTRPT)) 30888c2ecf20Sopenharmony_ci dwc2_hsotg_complete_in(hsotg, hs_ep); 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci if (idx == 0 && !hs_ep->req) 30918c2ecf20Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 30928c2ecf20Sopenharmony_ci } else if (using_dma(hsotg)) { 30938c2ecf20Sopenharmony_ci /* 30948c2ecf20Sopenharmony_ci * We're using DMA, we need to fire an OutDone here 30958c2ecf20Sopenharmony_ci * as we ignore the RXFIFO. 30968c2ecf20Sopenharmony_ci */ 30978c2ecf20Sopenharmony_ci if (!hs_ep->isochronous || !(ints & DXEPINT_OUTTKNEPDIS)) 30988c2ecf20Sopenharmony_ci dwc2_hsotg_handle_outdone(hsotg, idx); 30998c2ecf20Sopenharmony_ci } 31008c2ecf20Sopenharmony_ci } 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci if (ints & DXEPINT_EPDISBLD) 31038c2ecf20Sopenharmony_ci dwc2_gadget_handle_ep_disabled(hs_ep); 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci if (ints & DXEPINT_OUTTKNEPDIS) 31068c2ecf20Sopenharmony_ci dwc2_gadget_handle_out_token_ep_disabled(hs_ep); 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_ci if (ints & DXEPINT_NAKINTRPT) 31098c2ecf20Sopenharmony_ci dwc2_gadget_handle_nak(hs_ep); 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci if (ints & DXEPINT_AHBERR) 31128c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci if (ints & DXEPINT_SETUP) { /* Setup or Timeout */ 31158c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_ci if (using_dma(hsotg) && idx == 0) { 31188c2ecf20Sopenharmony_ci /* 31198c2ecf20Sopenharmony_ci * this is the notification we've received a 31208c2ecf20Sopenharmony_ci * setup packet. In non-DMA mode we'd get this 31218c2ecf20Sopenharmony_ci * from the RXFIFO, instead we need to process 31228c2ecf20Sopenharmony_ci * the setup here. 31238c2ecf20Sopenharmony_ci */ 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_ci if (dir_in) 31268c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 31278c2ecf20Sopenharmony_ci else 31288c2ecf20Sopenharmony_ci dwc2_hsotg_handle_outdone(hsotg, 0); 31298c2ecf20Sopenharmony_ci } 31308c2ecf20Sopenharmony_ci } 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ci if (ints & DXEPINT_STSPHSERCVD) { 31338c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: StsPhseRcvd\n", __func__); 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci /* Safety check EP0 state when STSPHSERCVD asserted */ 31368c2ecf20Sopenharmony_ci if (hsotg->ep0_state == DWC2_EP0_DATA_OUT) { 31378c2ecf20Sopenharmony_ci /* Move to STATUS IN for DDMA */ 31388c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg)) { 31398c2ecf20Sopenharmony_ci if (!hsotg->delayed_status) 31408c2ecf20Sopenharmony_ci dwc2_hsotg_ep0_zlp(hsotg, true); 31418c2ecf20Sopenharmony_ci else 31428c2ecf20Sopenharmony_ci /* In case of 3 stage Control Write with delayed 31438c2ecf20Sopenharmony_ci * status, when Status IN transfer started 31448c2ecf20Sopenharmony_ci * before STSPHSERCVD asserted, NAKSTS bit not 31458c2ecf20Sopenharmony_ci * cleared by CNAK in dwc2_hsotg_start_req() 31468c2ecf20Sopenharmony_ci * function. Clear now NAKSTS to allow complete 31478c2ecf20Sopenharmony_ci * transfer. 31488c2ecf20Sopenharmony_ci */ 31498c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DIEPCTL(0), 31508c2ecf20Sopenharmony_ci DXEPCTL_CNAK); 31518c2ecf20Sopenharmony_ci } 31528c2ecf20Sopenharmony_ci } 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci } 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci if (ints & DXEPINT_BACK2BACKSETUP) 31578c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ci if (ints & DXEPINT_BNAINTR) { 31608c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: BNA interrupt\n", __func__); 31618c2ecf20Sopenharmony_ci if (hs_ep->isochronous) 31628c2ecf20Sopenharmony_ci dwc2_gadget_handle_isoc_bna(hs_ep); 31638c2ecf20Sopenharmony_ci } 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci if (dir_in && !hs_ep->isochronous) { 31668c2ecf20Sopenharmony_ci /* not sure if this is important, but we'll clear it anyway */ 31678c2ecf20Sopenharmony_ci if (ints & DXEPINT_INTKNTXFEMP) { 31688c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", 31698c2ecf20Sopenharmony_ci __func__, idx); 31708c2ecf20Sopenharmony_ci } 31718c2ecf20Sopenharmony_ci 31728c2ecf20Sopenharmony_ci /* this probably means something bad is happening */ 31738c2ecf20Sopenharmony_ci if (ints & DXEPINT_INTKNEPMIS) { 31748c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", 31758c2ecf20Sopenharmony_ci __func__, idx); 31768c2ecf20Sopenharmony_ci } 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci /* FIFO has space or is empty (see GAHBCFG) */ 31798c2ecf20Sopenharmony_ci if (hsotg->dedicated_fifos && 31808c2ecf20Sopenharmony_ci ints & DXEPINT_TXFEMP) { 31818c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", 31828c2ecf20Sopenharmony_ci __func__, idx); 31838c2ecf20Sopenharmony_ci if (!using_dma(hsotg)) 31848c2ecf20Sopenharmony_ci dwc2_hsotg_trytx(hsotg, hs_ep); 31858c2ecf20Sopenharmony_ci } 31868c2ecf20Sopenharmony_ci } 31878c2ecf20Sopenharmony_ci} 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci/** 31908c2ecf20Sopenharmony_ci * dwc2_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) 31918c2ecf20Sopenharmony_ci * @hsotg: The device state. 31928c2ecf20Sopenharmony_ci * 31938c2ecf20Sopenharmony_ci * Handle updating the device settings after the enumeration phase has 31948c2ecf20Sopenharmony_ci * been completed. 31958c2ecf20Sopenharmony_ci */ 31968c2ecf20Sopenharmony_cistatic void dwc2_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg) 31978c2ecf20Sopenharmony_ci{ 31988c2ecf20Sopenharmony_ci u32 dsts = dwc2_readl(hsotg, DSTS); 31998c2ecf20Sopenharmony_ci int ep0_mps = 0, ep_mps = 8; 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci /* 32028c2ecf20Sopenharmony_ci * This should signal the finish of the enumeration phase 32038c2ecf20Sopenharmony_ci * of the USB handshaking, so we should now know what rate 32048c2ecf20Sopenharmony_ci * we connected at. 32058c2ecf20Sopenharmony_ci */ 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci /* 32108c2ecf20Sopenharmony_ci * note, since we're limited by the size of transfer on EP0, and 32118c2ecf20Sopenharmony_ci * it seems IN transfers must be a even number of packets we do 32128c2ecf20Sopenharmony_ci * not advertise a 64byte MPS on EP0. 32138c2ecf20Sopenharmony_ci */ 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci /* catch both EnumSpd_FS and EnumSpd_FS48 */ 32168c2ecf20Sopenharmony_ci switch ((dsts & DSTS_ENUMSPD_MASK) >> DSTS_ENUMSPD_SHIFT) { 32178c2ecf20Sopenharmony_ci case DSTS_ENUMSPD_FS: 32188c2ecf20Sopenharmony_ci case DSTS_ENUMSPD_FS48: 32198c2ecf20Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_FULL; 32208c2ecf20Sopenharmony_ci ep0_mps = EP0_MPS_LIMIT; 32218c2ecf20Sopenharmony_ci ep_mps = 1023; 32228c2ecf20Sopenharmony_ci break; 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_ci case DSTS_ENUMSPD_HS: 32258c2ecf20Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_HIGH; 32268c2ecf20Sopenharmony_ci ep0_mps = EP0_MPS_LIMIT; 32278c2ecf20Sopenharmony_ci ep_mps = 1024; 32288c2ecf20Sopenharmony_ci break; 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_ci case DSTS_ENUMSPD_LS: 32318c2ecf20Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_LOW; 32328c2ecf20Sopenharmony_ci ep0_mps = 8; 32338c2ecf20Sopenharmony_ci ep_mps = 8; 32348c2ecf20Sopenharmony_ci /* 32358c2ecf20Sopenharmony_ci * note, we don't actually support LS in this driver at the 32368c2ecf20Sopenharmony_ci * moment, and the documentation seems to imply that it isn't 32378c2ecf20Sopenharmony_ci * supported by the PHYs on some of the devices. 32388c2ecf20Sopenharmony_ci */ 32398c2ecf20Sopenharmony_ci break; 32408c2ecf20Sopenharmony_ci } 32418c2ecf20Sopenharmony_ci dev_info(hsotg->dev, "new device is %s\n", 32428c2ecf20Sopenharmony_ci usb_speed_string(hsotg->gadget.speed)); 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_ci /* 32458c2ecf20Sopenharmony_ci * we should now know the maximum packet size for an 32468c2ecf20Sopenharmony_ci * endpoint, so set the endpoints to a default value. 32478c2ecf20Sopenharmony_ci */ 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci if (ep0_mps) { 32508c2ecf20Sopenharmony_ci int i; 32518c2ecf20Sopenharmony_ci /* Initialize ep0 for both in and out directions */ 32528c2ecf20Sopenharmony_ci dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 1); 32538c2ecf20Sopenharmony_ci dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 0); 32548c2ecf20Sopenharmony_ci for (i = 1; i < hsotg->num_of_eps; i++) { 32558c2ecf20Sopenharmony_ci if (hsotg->eps_in[i]) 32568c2ecf20Sopenharmony_ci dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 32578c2ecf20Sopenharmony_ci 0, 1); 32588c2ecf20Sopenharmony_ci if (hsotg->eps_out[i]) 32598c2ecf20Sopenharmony_ci dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 32608c2ecf20Sopenharmony_ci 0, 0); 32618c2ecf20Sopenharmony_ci } 32628c2ecf20Sopenharmony_ci } 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci /* ensure after enumeration our EP0 is active */ 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 32698c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DIEPCTL0), 32708c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DOEPCTL0)); 32718c2ecf20Sopenharmony_ci} 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci/** 32748c2ecf20Sopenharmony_ci * kill_all_requests - remove all requests from the endpoint's queue 32758c2ecf20Sopenharmony_ci * @hsotg: The device state. 32768c2ecf20Sopenharmony_ci * @ep: The endpoint the requests may be on. 32778c2ecf20Sopenharmony_ci * @result: The result code to use. 32788c2ecf20Sopenharmony_ci * 32798c2ecf20Sopenharmony_ci * Go through the requests on the given endpoint and mark them 32808c2ecf20Sopenharmony_ci * completed with the given result code. 32818c2ecf20Sopenharmony_ci */ 32828c2ecf20Sopenharmony_cistatic void kill_all_requests(struct dwc2_hsotg *hsotg, 32838c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *ep, 32848c2ecf20Sopenharmony_ci int result) 32858c2ecf20Sopenharmony_ci{ 32868c2ecf20Sopenharmony_ci unsigned int size; 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci ep->req = NULL; 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_ci while (!list_empty(&ep->queue)) { 32918c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *req = get_ep_head(ep); 32928c2ecf20Sopenharmony_ci 32938c2ecf20Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, ep, req, result); 32948c2ecf20Sopenharmony_ci } 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci if (!hsotg->dedicated_fifos) 32978c2ecf20Sopenharmony_ci return; 32988c2ecf20Sopenharmony_ci size = (dwc2_readl(hsotg, DTXFSTS(ep->fifo_index)) & 0xffff) * 4; 32998c2ecf20Sopenharmony_ci if (size < ep->fifo_size) 33008c2ecf20Sopenharmony_ci dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); 33018c2ecf20Sopenharmony_ci} 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_ci/** 33048c2ecf20Sopenharmony_ci * dwc2_hsotg_disconnect - disconnect service 33058c2ecf20Sopenharmony_ci * @hsotg: The device state. 33068c2ecf20Sopenharmony_ci * 33078c2ecf20Sopenharmony_ci * The device has been disconnected. Remove all current 33088c2ecf20Sopenharmony_ci * transactions and signal the gadget driver that this 33098c2ecf20Sopenharmony_ci * has happened. 33108c2ecf20Sopenharmony_ci */ 33118c2ecf20Sopenharmony_civoid dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) 33128c2ecf20Sopenharmony_ci{ 33138c2ecf20Sopenharmony_ci unsigned int ep; 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci if (!hsotg->connected) 33168c2ecf20Sopenharmony_ci return; 33178c2ecf20Sopenharmony_ci 33188c2ecf20Sopenharmony_ci hsotg->connected = 0; 33198c2ecf20Sopenharmony_ci hsotg->test_mode = 0; 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci /* all endpoints should be shutdown */ 33228c2ecf20Sopenharmony_ci for (ep = 0; ep < hsotg->num_of_eps; ep++) { 33238c2ecf20Sopenharmony_ci if (hsotg->eps_in[ep]) 33248c2ecf20Sopenharmony_ci kill_all_requests(hsotg, hsotg->eps_in[ep], 33258c2ecf20Sopenharmony_ci -ESHUTDOWN); 33268c2ecf20Sopenharmony_ci if (hsotg->eps_out[ep]) 33278c2ecf20Sopenharmony_ci kill_all_requests(hsotg, hsotg->eps_out[ep], 33288c2ecf20Sopenharmony_ci -ESHUTDOWN); 33298c2ecf20Sopenharmony_ci } 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci call_gadget(hsotg, disconnect); 33328c2ecf20Sopenharmony_ci hsotg->lx_state = DWC2_L3; 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci usb_gadget_set_state(&hsotg->gadget, USB_STATE_NOTATTACHED); 33358c2ecf20Sopenharmony_ci} 33368c2ecf20Sopenharmony_ci 33378c2ecf20Sopenharmony_ci/** 33388c2ecf20Sopenharmony_ci * dwc2_hsotg_irq_fifoempty - TX FIFO empty interrupt handler 33398c2ecf20Sopenharmony_ci * @hsotg: The device state: 33408c2ecf20Sopenharmony_ci * @periodic: True if this is a periodic FIFO interrupt 33418c2ecf20Sopenharmony_ci */ 33428c2ecf20Sopenharmony_cistatic void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) 33438c2ecf20Sopenharmony_ci{ 33448c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *ep; 33458c2ecf20Sopenharmony_ci int epno, ret; 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ci /* look through for any more data to transmit */ 33488c2ecf20Sopenharmony_ci for (epno = 0; epno < hsotg->num_of_eps; epno++) { 33498c2ecf20Sopenharmony_ci ep = index_to_ep(hsotg, epno, 1); 33508c2ecf20Sopenharmony_ci 33518c2ecf20Sopenharmony_ci if (!ep) 33528c2ecf20Sopenharmony_ci continue; 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_ci if (!ep->dir_in) 33558c2ecf20Sopenharmony_ci continue; 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci if ((periodic && !ep->periodic) || 33588c2ecf20Sopenharmony_ci (!periodic && ep->periodic)) 33598c2ecf20Sopenharmony_ci continue; 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci ret = dwc2_hsotg_trytx(hsotg, ep); 33628c2ecf20Sopenharmony_ci if (ret < 0) 33638c2ecf20Sopenharmony_ci break; 33648c2ecf20Sopenharmony_ci } 33658c2ecf20Sopenharmony_ci} 33668c2ecf20Sopenharmony_ci 33678c2ecf20Sopenharmony_ci/* IRQ flags which will trigger a retry around the IRQ loop */ 33688c2ecf20Sopenharmony_ci#define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ 33698c2ecf20Sopenharmony_ci GINTSTS_PTXFEMP | \ 33708c2ecf20Sopenharmony_ci GINTSTS_RXFLVL) 33718c2ecf20Sopenharmony_ci 33728c2ecf20Sopenharmony_cistatic int dwc2_hsotg_ep_disable(struct usb_ep *ep); 33738c2ecf20Sopenharmony_ci/** 33748c2ecf20Sopenharmony_ci * dwc2_hsotg_core_init - issue softreset to the core 33758c2ecf20Sopenharmony_ci * @hsotg: The device state 33768c2ecf20Sopenharmony_ci * @is_usb_reset: Usb resetting flag 33778c2ecf20Sopenharmony_ci * 33788c2ecf20Sopenharmony_ci * Issue a soft reset to the core, and await the core finishing it. 33798c2ecf20Sopenharmony_ci */ 33808c2ecf20Sopenharmony_civoid dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, 33818c2ecf20Sopenharmony_ci bool is_usb_reset) 33828c2ecf20Sopenharmony_ci{ 33838c2ecf20Sopenharmony_ci u32 intmsk; 33848c2ecf20Sopenharmony_ci u32 val; 33858c2ecf20Sopenharmony_ci u32 usbcfg; 33868c2ecf20Sopenharmony_ci u32 dcfg = 0; 33878c2ecf20Sopenharmony_ci int ep; 33888c2ecf20Sopenharmony_ci 33898c2ecf20Sopenharmony_ci /* Kill any ep0 requests as controller will be reinitialized */ 33908c2ecf20Sopenharmony_ci kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci if (!is_usb_reset) { 33938c2ecf20Sopenharmony_ci if (dwc2_core_reset(hsotg, true)) 33948c2ecf20Sopenharmony_ci return; 33958c2ecf20Sopenharmony_ci } else { 33968c2ecf20Sopenharmony_ci /* all endpoints should be shutdown */ 33978c2ecf20Sopenharmony_ci for (ep = 1; ep < hsotg->num_of_eps; ep++) { 33988c2ecf20Sopenharmony_ci if (hsotg->eps_in[ep]) 33998c2ecf20Sopenharmony_ci dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 34008c2ecf20Sopenharmony_ci if (hsotg->eps_out[ep]) 34018c2ecf20Sopenharmony_ci dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 34028c2ecf20Sopenharmony_ci } 34038c2ecf20Sopenharmony_ci } 34048c2ecf20Sopenharmony_ci 34058c2ecf20Sopenharmony_ci /* 34068c2ecf20Sopenharmony_ci * we must now enable ep0 ready for host detection and then 34078c2ecf20Sopenharmony_ci * set configuration. 34088c2ecf20Sopenharmony_ci */ 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_ci /* keep other bits untouched (so e.g. forced modes are not lost) */ 34118c2ecf20Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 34128c2ecf20Sopenharmony_ci usbcfg &= ~GUSBCFG_TOUTCAL_MASK; 34138c2ecf20Sopenharmony_ci usbcfg |= GUSBCFG_TOUTCAL(7); 34148c2ecf20Sopenharmony_ci 34158c2ecf20Sopenharmony_ci /* remove the HNP/SRP and set the PHY */ 34168c2ecf20Sopenharmony_ci usbcfg &= ~(GUSBCFG_SRPCAP | GUSBCFG_HNPCAP); 34178c2ecf20Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 34188c2ecf20Sopenharmony_ci 34198c2ecf20Sopenharmony_ci dwc2_phy_init(hsotg, true); 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci dwc2_hsotg_init_fifo(hsotg); 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci if (!is_usb_reset) 34248c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci dcfg |= DCFG_EPMISCNT(1); 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ci switch (hsotg->params.speed) { 34298c2ecf20Sopenharmony_ci case DWC2_SPEED_PARAM_LOW: 34308c2ecf20Sopenharmony_ci dcfg |= DCFG_DEVSPD_LS; 34318c2ecf20Sopenharmony_ci break; 34328c2ecf20Sopenharmony_ci case DWC2_SPEED_PARAM_FULL: 34338c2ecf20Sopenharmony_ci if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) 34348c2ecf20Sopenharmony_ci dcfg |= DCFG_DEVSPD_FS48; 34358c2ecf20Sopenharmony_ci else 34368c2ecf20Sopenharmony_ci dcfg |= DCFG_DEVSPD_FS; 34378c2ecf20Sopenharmony_ci break; 34388c2ecf20Sopenharmony_ci default: 34398c2ecf20Sopenharmony_ci dcfg |= DCFG_DEVSPD_HS; 34408c2ecf20Sopenharmony_ci } 34418c2ecf20Sopenharmony_ci 34428c2ecf20Sopenharmony_ci if (hsotg->params.ipg_isoc_en) 34438c2ecf20Sopenharmony_ci dcfg |= DCFG_IPG_ISOC_SUPPORDED; 34448c2ecf20Sopenharmony_ci 34458c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dcfg, DCFG); 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ci /* Clear any pending OTG interrupts */ 34488c2ecf20Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GOTGINT); 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci /* Clear any pending interrupts */ 34518c2ecf20Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GINTSTS); 34528c2ecf20Sopenharmony_ci intmsk = GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT | 34538c2ecf20Sopenharmony_ci GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | 34548c2ecf20Sopenharmony_ci GINTSTS_USBRST | GINTSTS_RESETDET | 34558c2ecf20Sopenharmony_ci GINTSTS_ENUMDONE | GINTSTS_OTGINT | 34568c2ecf20Sopenharmony_ci GINTSTS_USBSUSP | GINTSTS_WKUPINT | 34578c2ecf20Sopenharmony_ci GINTSTS_LPMTRANRCVD; 34588c2ecf20Sopenharmony_ci 34598c2ecf20Sopenharmony_ci if (!using_desc_dma(hsotg)) 34608c2ecf20Sopenharmony_ci intmsk |= GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT; 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_ci if (!hsotg->params.external_id_pin_ctl) 34638c2ecf20Sopenharmony_ci intmsk |= GINTSTS_CONIDSTSCHNG; 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci dwc2_writel(hsotg, intmsk, GINTMSK); 34668c2ecf20Sopenharmony_ci 34678c2ecf20Sopenharmony_ci if (using_dma(hsotg)) { 34688c2ecf20Sopenharmony_ci dwc2_writel(hsotg, GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN | 34698c2ecf20Sopenharmony_ci hsotg->params.ahbcfg, 34708c2ecf20Sopenharmony_ci GAHBCFG); 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci /* Set DDMA mode support in the core if needed */ 34738c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg)) 34748c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCFG, DCFG_DESCDMA_EN); 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci } else { 34778c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ((hsotg->dedicated_fifos) ? 34788c2ecf20Sopenharmony_ci (GAHBCFG_NP_TXF_EMP_LVL | 34798c2ecf20Sopenharmony_ci GAHBCFG_P_TXF_EMP_LVL) : 0) | 34808c2ecf20Sopenharmony_ci GAHBCFG_GLBL_INTR_EN, GAHBCFG); 34818c2ecf20Sopenharmony_ci } 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_ci /* 34848c2ecf20Sopenharmony_ci * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts 34858c2ecf20Sopenharmony_ci * when we have no data to transfer. Otherwise we get being flooded by 34868c2ecf20Sopenharmony_ci * interrupts. 34878c2ecf20Sopenharmony_ci */ 34888c2ecf20Sopenharmony_ci 34898c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ((hsotg->dedicated_fifos && !using_dma(hsotg)) ? 34908c2ecf20Sopenharmony_ci DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) | 34918c2ecf20Sopenharmony_ci DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | 34928c2ecf20Sopenharmony_ci DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK, 34938c2ecf20Sopenharmony_ci DIEPMSK); 34948c2ecf20Sopenharmony_ci 34958c2ecf20Sopenharmony_ci /* 34968c2ecf20Sopenharmony_ci * don't need XferCompl, we get that from RXFIFO in slave mode. In 34978c2ecf20Sopenharmony_ci * DMA mode we may need this and StsPhseRcvd. 34988c2ecf20Sopenharmony_ci */ 34998c2ecf20Sopenharmony_ci dwc2_writel(hsotg, (using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK | 35008c2ecf20Sopenharmony_ci DOEPMSK_STSPHSERCVDMSK) : 0) | 35018c2ecf20Sopenharmony_ci DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | 35028c2ecf20Sopenharmony_ci DOEPMSK_SETUPMSK, 35038c2ecf20Sopenharmony_ci DOEPMSK); 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_ci /* Enable BNA interrupt for DDMA */ 35068c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg)) { 35078c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DOEPMSK, DOEPMSK_BNAMSK); 35088c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK); 35098c2ecf20Sopenharmony_ci } 35108c2ecf20Sopenharmony_ci 35118c2ecf20Sopenharmony_ci /* Enable Service Interval mode if supported */ 35128c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg) && hsotg->params.service_interval) 35138c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SERVICE_INTERVAL_SUPPORTED); 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_ci dwc2_writel(hsotg, 0, DAINTMSK); 35168c2ecf20Sopenharmony_ci 35178c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 35188c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DIEPCTL0), 35198c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DOEPCTL0)); 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci /* enable in and out endpoint interrupts */ 35228c2ecf20Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT); 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci /* 35258c2ecf20Sopenharmony_ci * Enable the RXFIFO when in slave mode, as this is how we collect 35268c2ecf20Sopenharmony_ci * the data. In DMA mode, we get events from the FIFO but also 35278c2ecf20Sopenharmony_ci * things we cannot process, so do not use it. 35288c2ecf20Sopenharmony_ci */ 35298c2ecf20Sopenharmony_ci if (!using_dma(hsotg)) 35308c2ecf20Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL); 35318c2ecf20Sopenharmony_ci 35328c2ecf20Sopenharmony_ci /* Enable interrupts for EP0 in and out */ 35338c2ecf20Sopenharmony_ci dwc2_hsotg_ctrl_epint(hsotg, 0, 0, 1); 35348c2ecf20Sopenharmony_ci dwc2_hsotg_ctrl_epint(hsotg, 0, 1, 1); 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci if (!is_usb_reset) { 35378c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_PWRONPRGDONE); 35388c2ecf20Sopenharmony_ci udelay(10); /* see openiboot */ 35398c2ecf20Sopenharmony_ci dwc2_clear_bit(hsotg, DCTL, DCTL_PWRONPRGDONE); 35408c2ecf20Sopenharmony_ci } 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "DCTL=0x%08x\n", dwc2_readl(hsotg, DCTL)); 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci /* 35458c2ecf20Sopenharmony_ci * DxEPCTL_USBActEp says RO in manual, but seems to be set by 35468c2ecf20Sopenharmony_ci * writing to the EPCTL register.. 35478c2ecf20Sopenharmony_ci */ 35488c2ecf20Sopenharmony_ci 35498c2ecf20Sopenharmony_ci /* set to read 1 8byte packet */ 35508c2ecf20Sopenharmony_ci dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 35518c2ecf20Sopenharmony_ci DXEPTSIZ_XFERSIZE(8), DOEPTSIZ0); 35528c2ecf20Sopenharmony_ci 35538c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 35548c2ecf20Sopenharmony_ci DXEPCTL_CNAK | DXEPCTL_EPENA | 35558c2ecf20Sopenharmony_ci DXEPCTL_USBACTEP, 35568c2ecf20Sopenharmony_ci DOEPCTL0); 35578c2ecf20Sopenharmony_ci 35588c2ecf20Sopenharmony_ci /* enable, but don't activate EP0in */ 35598c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 35608c2ecf20Sopenharmony_ci DXEPCTL_USBACTEP, DIEPCTL0); 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_ci /* clear global NAKs */ 35638c2ecf20Sopenharmony_ci val = DCTL_CGOUTNAK | DCTL_CGNPINNAK; 35648c2ecf20Sopenharmony_ci if (!is_usb_reset) 35658c2ecf20Sopenharmony_ci val |= DCTL_SFTDISCON; 35668c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, val); 35678c2ecf20Sopenharmony_ci 35688c2ecf20Sopenharmony_ci /* configure the core to support LPM */ 35698c2ecf20Sopenharmony_ci dwc2_gadget_init_lpm(hsotg); 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci /* program GREFCLK register if needed */ 35728c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg) && hsotg->params.service_interval) 35738c2ecf20Sopenharmony_ci dwc2_gadget_program_ref_clk(hsotg); 35748c2ecf20Sopenharmony_ci 35758c2ecf20Sopenharmony_ci /* must be at-least 3ms to allow bus to see disconnect */ 35768c2ecf20Sopenharmony_ci mdelay(3); 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci hsotg->lx_state = DWC2_L0; 35798c2ecf20Sopenharmony_ci 35808c2ecf20Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 35838c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DIEPCTL0), 35848c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DOEPCTL0)); 35858c2ecf20Sopenharmony_ci} 35868c2ecf20Sopenharmony_ci 35878c2ecf20Sopenharmony_civoid dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) 35888c2ecf20Sopenharmony_ci{ 35898c2ecf20Sopenharmony_ci /* set the soft-disconnect bit */ 35908c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); 35918c2ecf20Sopenharmony_ci} 35928c2ecf20Sopenharmony_ci 35938c2ecf20Sopenharmony_civoid dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) 35948c2ecf20Sopenharmony_ci{ 35958c2ecf20Sopenharmony_ci /* remove the soft-disconnect and let's go */ 35968c2ecf20Sopenharmony_ci if (!hsotg->role_sw || (dwc2_readl(hsotg, GOTGCTL) & GOTGCTL_BSESVLD)) 35978c2ecf20Sopenharmony_ci dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON); 35988c2ecf20Sopenharmony_ci} 35998c2ecf20Sopenharmony_ci 36008c2ecf20Sopenharmony_ci/** 36018c2ecf20Sopenharmony_ci * dwc2_gadget_handle_incomplete_isoc_in - handle incomplete ISO IN Interrupt. 36028c2ecf20Sopenharmony_ci * @hsotg: The device state: 36038c2ecf20Sopenharmony_ci * 36048c2ecf20Sopenharmony_ci * This interrupt indicates one of the following conditions occurred while 36058c2ecf20Sopenharmony_ci * transmitting an ISOC transaction. 36068c2ecf20Sopenharmony_ci * - Corrupted IN Token for ISOC EP. 36078c2ecf20Sopenharmony_ci * - Packet not complete in FIFO. 36088c2ecf20Sopenharmony_ci * 36098c2ecf20Sopenharmony_ci * The following actions will be taken: 36108c2ecf20Sopenharmony_ci * - Determine the EP 36118c2ecf20Sopenharmony_ci * - Disable EP; when 'Endpoint Disabled' interrupt is received Flush FIFO 36128c2ecf20Sopenharmony_ci */ 36138c2ecf20Sopenharmony_cistatic void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg) 36148c2ecf20Sopenharmony_ci{ 36158c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep; 36168c2ecf20Sopenharmony_ci u32 epctrl; 36178c2ecf20Sopenharmony_ci u32 daintmsk; 36188c2ecf20Sopenharmony_ci u32 idx; 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Incomplete isoc in interrupt received:\n"); 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ci daintmsk = dwc2_readl(hsotg, DAINTMSK); 36238c2ecf20Sopenharmony_ci 36248c2ecf20Sopenharmony_ci for (idx = 1; idx < hsotg->num_of_eps; idx++) { 36258c2ecf20Sopenharmony_ci hs_ep = hsotg->eps_in[idx]; 36268c2ecf20Sopenharmony_ci /* Proceed only unmasked ISOC EPs */ 36278c2ecf20Sopenharmony_ci if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous) 36288c2ecf20Sopenharmony_ci continue; 36298c2ecf20Sopenharmony_ci 36308c2ecf20Sopenharmony_ci epctrl = dwc2_readl(hsotg, DIEPCTL(idx)); 36318c2ecf20Sopenharmony_ci if ((epctrl & DXEPCTL_EPENA) && 36328c2ecf20Sopenharmony_ci dwc2_gadget_target_frame_elapsed(hs_ep)) { 36338c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_SNAK; 36348c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_EPDIS; 36358c2ecf20Sopenharmony_ci dwc2_writel(hsotg, epctrl, DIEPCTL(idx)); 36368c2ecf20Sopenharmony_ci } 36378c2ecf20Sopenharmony_ci } 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_ci /* Clear interrupt */ 36408c2ecf20Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_INCOMPL_SOIN, GINTSTS); 36418c2ecf20Sopenharmony_ci} 36428c2ecf20Sopenharmony_ci 36438c2ecf20Sopenharmony_ci/** 36448c2ecf20Sopenharmony_ci * dwc2_gadget_handle_incomplete_isoc_out - handle incomplete ISO OUT Interrupt 36458c2ecf20Sopenharmony_ci * @hsotg: The device state: 36468c2ecf20Sopenharmony_ci * 36478c2ecf20Sopenharmony_ci * This interrupt indicates one of the following conditions occurred while 36488c2ecf20Sopenharmony_ci * transmitting an ISOC transaction. 36498c2ecf20Sopenharmony_ci * - Corrupted OUT Token for ISOC EP. 36508c2ecf20Sopenharmony_ci * - Packet not complete in FIFO. 36518c2ecf20Sopenharmony_ci * 36528c2ecf20Sopenharmony_ci * The following actions will be taken: 36538c2ecf20Sopenharmony_ci * - Determine the EP 36548c2ecf20Sopenharmony_ci * - Set DCTL_SGOUTNAK and unmask GOUTNAKEFF if target frame elapsed. 36558c2ecf20Sopenharmony_ci */ 36568c2ecf20Sopenharmony_cistatic void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg) 36578c2ecf20Sopenharmony_ci{ 36588c2ecf20Sopenharmony_ci u32 gintsts; 36598c2ecf20Sopenharmony_ci u32 gintmsk; 36608c2ecf20Sopenharmony_ci u32 daintmsk; 36618c2ecf20Sopenharmony_ci u32 epctrl; 36628c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep; 36638c2ecf20Sopenharmony_ci int idx; 36648c2ecf20Sopenharmony_ci 36658c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__); 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci daintmsk = dwc2_readl(hsotg, DAINTMSK); 36688c2ecf20Sopenharmony_ci daintmsk >>= DAINT_OUTEP_SHIFT; 36698c2ecf20Sopenharmony_ci 36708c2ecf20Sopenharmony_ci for (idx = 1; idx < hsotg->num_of_eps; idx++) { 36718c2ecf20Sopenharmony_ci hs_ep = hsotg->eps_out[idx]; 36728c2ecf20Sopenharmony_ci /* Proceed only unmasked ISOC EPs */ 36738c2ecf20Sopenharmony_ci if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous) 36748c2ecf20Sopenharmony_ci continue; 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci epctrl = dwc2_readl(hsotg, DOEPCTL(idx)); 36778c2ecf20Sopenharmony_ci if ((epctrl & DXEPCTL_EPENA) && 36788c2ecf20Sopenharmony_ci dwc2_gadget_target_frame_elapsed(hs_ep)) { 36798c2ecf20Sopenharmony_ci /* Unmask GOUTNAKEFF interrupt */ 36808c2ecf20Sopenharmony_ci gintmsk = dwc2_readl(hsotg, GINTMSK); 36818c2ecf20Sopenharmony_ci gintmsk |= GINTSTS_GOUTNAKEFF; 36828c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gintmsk, GINTMSK); 36838c2ecf20Sopenharmony_ci 36848c2ecf20Sopenharmony_ci gintsts = dwc2_readl(hsotg, GINTSTS); 36858c2ecf20Sopenharmony_ci if (!(gintsts & GINTSTS_GOUTNAKEFF)) { 36868c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SGOUTNAK); 36878c2ecf20Sopenharmony_ci break; 36888c2ecf20Sopenharmony_ci } 36898c2ecf20Sopenharmony_ci } 36908c2ecf20Sopenharmony_ci } 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci /* Clear interrupt */ 36938c2ecf20Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_INCOMPL_SOOUT, GINTSTS); 36948c2ecf20Sopenharmony_ci} 36958c2ecf20Sopenharmony_ci 36968c2ecf20Sopenharmony_ci/** 36978c2ecf20Sopenharmony_ci * dwc2_hsotg_irq - handle device interrupt 36988c2ecf20Sopenharmony_ci * @irq: The IRQ number triggered 36998c2ecf20Sopenharmony_ci * @pw: The pw value when registered the handler. 37008c2ecf20Sopenharmony_ci */ 37018c2ecf20Sopenharmony_cistatic irqreturn_t dwc2_hsotg_irq(int irq, void *pw) 37028c2ecf20Sopenharmony_ci{ 37038c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = pw; 37048c2ecf20Sopenharmony_ci int retry_count = 8; 37058c2ecf20Sopenharmony_ci u32 gintsts; 37068c2ecf20Sopenharmony_ci u32 gintmsk; 37078c2ecf20Sopenharmony_ci 37088c2ecf20Sopenharmony_ci if (!dwc2_is_device_mode(hsotg)) 37098c2ecf20Sopenharmony_ci return IRQ_NONE; 37108c2ecf20Sopenharmony_ci 37118c2ecf20Sopenharmony_ci spin_lock(&hsotg->lock); 37128c2ecf20Sopenharmony_ciirq_retry: 37138c2ecf20Sopenharmony_ci gintsts = dwc2_readl(hsotg, GINTSTS); 37148c2ecf20Sopenharmony_ci gintmsk = dwc2_readl(hsotg, GINTMSK); 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", 37178c2ecf20Sopenharmony_ci __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_ci gintsts &= gintmsk; 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_RESETDET) { 37228c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: USBRstDet\n", __func__); 37238c2ecf20Sopenharmony_ci 37248c2ecf20Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_RESETDET, GINTSTS); 37258c2ecf20Sopenharmony_ci 37268c2ecf20Sopenharmony_ci /* This event must be used only if controller is suspended */ 37278c2ecf20Sopenharmony_ci if (hsotg->lx_state == DWC2_L2) { 37288c2ecf20Sopenharmony_ci dwc2_exit_partial_power_down(hsotg, true); 37298c2ecf20Sopenharmony_ci hsotg->lx_state = DWC2_L0; 37308c2ecf20Sopenharmony_ci } 37318c2ecf20Sopenharmony_ci } 37328c2ecf20Sopenharmony_ci 37338c2ecf20Sopenharmony_ci if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) { 37348c2ecf20Sopenharmony_ci u32 usb_status = dwc2_readl(hsotg, GOTGCTL); 37358c2ecf20Sopenharmony_ci u32 connected = hsotg->connected; 37368c2ecf20Sopenharmony_ci 37378c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: USBRst\n", __func__); 37388c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", 37398c2ecf20Sopenharmony_ci dwc2_readl(hsotg, GNPTXSTS)); 37408c2ecf20Sopenharmony_ci 37418c2ecf20Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_USBRST, GINTSTS); 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci /* Report disconnection if it is not already done. */ 37448c2ecf20Sopenharmony_ci dwc2_hsotg_disconnect(hsotg); 37458c2ecf20Sopenharmony_ci 37468c2ecf20Sopenharmony_ci /* Reset device address to zero */ 37478c2ecf20Sopenharmony_ci dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK); 37488c2ecf20Sopenharmony_ci 37498c2ecf20Sopenharmony_ci if (usb_status & GOTGCTL_BSESVLD && connected) 37508c2ecf20Sopenharmony_ci dwc2_hsotg_core_init_disconnected(hsotg, true); 37518c2ecf20Sopenharmony_ci } 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_ENUMDONE) { 37548c2ecf20Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_ENUMDONE, GINTSTS); 37558c2ecf20Sopenharmony_ci 37568c2ecf20Sopenharmony_ci dwc2_hsotg_irq_enumdone(hsotg); 37578c2ecf20Sopenharmony_ci } 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { 37608c2ecf20Sopenharmony_ci u32 daint = dwc2_readl(hsotg, DAINT); 37618c2ecf20Sopenharmony_ci u32 daintmsk = dwc2_readl(hsotg, DAINTMSK); 37628c2ecf20Sopenharmony_ci u32 daint_out, daint_in; 37638c2ecf20Sopenharmony_ci int ep; 37648c2ecf20Sopenharmony_ci 37658c2ecf20Sopenharmony_ci daint &= daintmsk; 37668c2ecf20Sopenharmony_ci daint_out = daint >> DAINT_OUTEP_SHIFT; 37678c2ecf20Sopenharmony_ci daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); 37688c2ecf20Sopenharmony_ci 37698c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); 37708c2ecf20Sopenharmony_ci 37718c2ecf20Sopenharmony_ci for (ep = 0; ep < hsotg->num_of_eps && daint_out; 37728c2ecf20Sopenharmony_ci ep++, daint_out >>= 1) { 37738c2ecf20Sopenharmony_ci if (daint_out & 1) 37748c2ecf20Sopenharmony_ci dwc2_hsotg_epint(hsotg, ep, 0); 37758c2ecf20Sopenharmony_ci } 37768c2ecf20Sopenharmony_ci 37778c2ecf20Sopenharmony_ci for (ep = 0; ep < hsotg->num_of_eps && daint_in; 37788c2ecf20Sopenharmony_ci ep++, daint_in >>= 1) { 37798c2ecf20Sopenharmony_ci if (daint_in & 1) 37808c2ecf20Sopenharmony_ci dwc2_hsotg_epint(hsotg, ep, 1); 37818c2ecf20Sopenharmony_ci } 37828c2ecf20Sopenharmony_ci } 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci /* check both FIFOs */ 37858c2ecf20Sopenharmony_ci 37868c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_NPTXFEMP) { 37878c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "NPTxFEmp\n"); 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ci /* 37908c2ecf20Sopenharmony_ci * Disable the interrupt to stop it happening again 37918c2ecf20Sopenharmony_ci * unless one of these endpoint routines decides that 37928c2ecf20Sopenharmony_ci * it needs re-enabling 37938c2ecf20Sopenharmony_ci */ 37948c2ecf20Sopenharmony_ci 37958c2ecf20Sopenharmony_ci dwc2_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); 37968c2ecf20Sopenharmony_ci dwc2_hsotg_irq_fifoempty(hsotg, false); 37978c2ecf20Sopenharmony_ci } 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_PTXFEMP) { 38008c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "PTxFEmp\n"); 38018c2ecf20Sopenharmony_ci 38028c2ecf20Sopenharmony_ci /* See note in GINTSTS_NPTxFEmp */ 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci dwc2_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); 38058c2ecf20Sopenharmony_ci dwc2_hsotg_irq_fifoempty(hsotg, true); 38068c2ecf20Sopenharmony_ci } 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_RXFLVL) { 38098c2ecf20Sopenharmony_ci /* 38108c2ecf20Sopenharmony_ci * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, 38118c2ecf20Sopenharmony_ci * we need to retry dwc2_hsotg_handle_rx if this is still 38128c2ecf20Sopenharmony_ci * set. 38138c2ecf20Sopenharmony_ci */ 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci dwc2_hsotg_handle_rx(hsotg); 38168c2ecf20Sopenharmony_ci } 38178c2ecf20Sopenharmony_ci 38188c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_ERLYSUSP) { 38198c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); 38208c2ecf20Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_ERLYSUSP, GINTSTS); 38218c2ecf20Sopenharmony_ci } 38228c2ecf20Sopenharmony_ci 38238c2ecf20Sopenharmony_ci /* 38248c2ecf20Sopenharmony_ci * these next two seem to crop-up occasionally causing the core 38258c2ecf20Sopenharmony_ci * to shutdown the USB transfer, so try clearing them and logging 38268c2ecf20Sopenharmony_ci * the occurrence. 38278c2ecf20Sopenharmony_ci */ 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_GOUTNAKEFF) { 38308c2ecf20Sopenharmony_ci u8 idx; 38318c2ecf20Sopenharmony_ci u32 epctrl; 38328c2ecf20Sopenharmony_ci u32 gintmsk; 38338c2ecf20Sopenharmony_ci u32 daintmsk; 38348c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep; 38358c2ecf20Sopenharmony_ci 38368c2ecf20Sopenharmony_ci daintmsk = dwc2_readl(hsotg, DAINTMSK); 38378c2ecf20Sopenharmony_ci daintmsk >>= DAINT_OUTEP_SHIFT; 38388c2ecf20Sopenharmony_ci /* Mask this interrupt */ 38398c2ecf20Sopenharmony_ci gintmsk = dwc2_readl(hsotg, GINTMSK); 38408c2ecf20Sopenharmony_ci gintmsk &= ~GINTSTS_GOUTNAKEFF; 38418c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gintmsk, GINTMSK); 38428c2ecf20Sopenharmony_ci 38438c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GOUTNakEff triggered\n"); 38448c2ecf20Sopenharmony_ci for (idx = 1; idx < hsotg->num_of_eps; idx++) { 38458c2ecf20Sopenharmony_ci hs_ep = hsotg->eps_out[idx]; 38468c2ecf20Sopenharmony_ci /* Proceed only unmasked ISOC EPs */ 38478c2ecf20Sopenharmony_ci if (BIT(idx) & ~daintmsk) 38488c2ecf20Sopenharmony_ci continue; 38498c2ecf20Sopenharmony_ci 38508c2ecf20Sopenharmony_ci epctrl = dwc2_readl(hsotg, DOEPCTL(idx)); 38518c2ecf20Sopenharmony_ci 38528c2ecf20Sopenharmony_ci //ISOC Ep's only 38538c2ecf20Sopenharmony_ci if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous) { 38548c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_SNAK; 38558c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_EPDIS; 38568c2ecf20Sopenharmony_ci dwc2_writel(hsotg, epctrl, DOEPCTL(idx)); 38578c2ecf20Sopenharmony_ci continue; 38588c2ecf20Sopenharmony_ci } 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_ci //Non-ISOC EP's 38618c2ecf20Sopenharmony_ci if (hs_ep->halted) { 38628c2ecf20Sopenharmony_ci if (!(epctrl & DXEPCTL_EPENA)) 38638c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_EPENA; 38648c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_EPDIS; 38658c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_STALL; 38668c2ecf20Sopenharmony_ci dwc2_writel(hsotg, epctrl, DOEPCTL(idx)); 38678c2ecf20Sopenharmony_ci } 38688c2ecf20Sopenharmony_ci } 38698c2ecf20Sopenharmony_ci 38708c2ecf20Sopenharmony_ci /* This interrupt bit is cleared in DXEPINT_EPDISBLD handler */ 38718c2ecf20Sopenharmony_ci } 38728c2ecf20Sopenharmony_ci 38738c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_GINNAKEFF) { 38748c2ecf20Sopenharmony_ci dev_info(hsotg->dev, "GINNakEff triggered\n"); 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_CGNPINNAK); 38778c2ecf20Sopenharmony_ci 38788c2ecf20Sopenharmony_ci dwc2_hsotg_dump(hsotg); 38798c2ecf20Sopenharmony_ci } 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_INCOMPL_SOIN) 38828c2ecf20Sopenharmony_ci dwc2_gadget_handle_incomplete_isoc_in(hsotg); 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_INCOMPL_SOOUT) 38858c2ecf20Sopenharmony_ci dwc2_gadget_handle_incomplete_isoc_out(hsotg); 38868c2ecf20Sopenharmony_ci 38878c2ecf20Sopenharmony_ci /* 38888c2ecf20Sopenharmony_ci * if we've had fifo events, we should try and go around the 38898c2ecf20Sopenharmony_ci * loop again to see if there's any point in returning yet. 38908c2ecf20Sopenharmony_ci */ 38918c2ecf20Sopenharmony_ci 38928c2ecf20Sopenharmony_ci if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) 38938c2ecf20Sopenharmony_ci goto irq_retry; 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci /* Check WKUP_ALERT interrupt*/ 38968c2ecf20Sopenharmony_ci if (hsotg->params.service_interval) 38978c2ecf20Sopenharmony_ci dwc2_gadget_wkup_alert_handler(hsotg); 38988c2ecf20Sopenharmony_ci 38998c2ecf20Sopenharmony_ci spin_unlock(&hsotg->lock); 39008c2ecf20Sopenharmony_ci 39018c2ecf20Sopenharmony_ci return IRQ_HANDLED; 39028c2ecf20Sopenharmony_ci} 39038c2ecf20Sopenharmony_ci 39048c2ecf20Sopenharmony_cistatic void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, 39058c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep) 39068c2ecf20Sopenharmony_ci{ 39078c2ecf20Sopenharmony_ci u32 epctrl_reg; 39088c2ecf20Sopenharmony_ci u32 epint_reg; 39098c2ecf20Sopenharmony_ci 39108c2ecf20Sopenharmony_ci epctrl_reg = hs_ep->dir_in ? DIEPCTL(hs_ep->index) : 39118c2ecf20Sopenharmony_ci DOEPCTL(hs_ep->index); 39128c2ecf20Sopenharmony_ci epint_reg = hs_ep->dir_in ? DIEPINT(hs_ep->index) : 39138c2ecf20Sopenharmony_ci DOEPINT(hs_ep->index); 39148c2ecf20Sopenharmony_ci 39158c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: stopping transfer on %s\n", __func__, 39168c2ecf20Sopenharmony_ci hs_ep->name); 39178c2ecf20Sopenharmony_ci 39188c2ecf20Sopenharmony_ci if (hs_ep->dir_in) { 39198c2ecf20Sopenharmony_ci if (hsotg->dedicated_fifos || hs_ep->periodic) { 39208c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, epctrl_reg, DXEPCTL_SNAK); 39218c2ecf20Sopenharmony_ci /* Wait for Nak effect */ 39228c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, 39238c2ecf20Sopenharmony_ci DXEPINT_INEPNAKEFF, 100)) 39248c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, 39258c2ecf20Sopenharmony_ci "%s: timeout DIEPINT.NAKEFF\n", 39268c2ecf20Sopenharmony_ci __func__); 39278c2ecf20Sopenharmony_ci } else { 39288c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SGNPINNAK); 39298c2ecf20Sopenharmony_ci /* Wait for Nak effect */ 39308c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 39318c2ecf20Sopenharmony_ci GINTSTS_GINNAKEFF, 100)) 39328c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, 39338c2ecf20Sopenharmony_ci "%s: timeout GINTSTS.GINNAKEFF\n", 39348c2ecf20Sopenharmony_ci __func__); 39358c2ecf20Sopenharmony_ci } 39368c2ecf20Sopenharmony_ci } else { 39378c2ecf20Sopenharmony_ci /* Mask GINTSTS_GOUTNAKEFF interrupt */ 39388c2ecf20Sopenharmony_ci dwc2_hsotg_disable_gsint(hsotg, GINTSTS_GOUTNAKEFF); 39398c2ecf20Sopenharmony_ci 39408c2ecf20Sopenharmony_ci if (!(dwc2_readl(hsotg, GINTSTS) & GINTSTS_GOUTNAKEFF)) 39418c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SGOUTNAK); 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_ci if (!using_dma(hsotg)) { 39448c2ecf20Sopenharmony_ci /* Wait for GINTSTS_RXFLVL interrupt */ 39458c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 39468c2ecf20Sopenharmony_ci GINTSTS_RXFLVL, 100)) { 39478c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: timeout GINTSTS.RXFLVL\n", 39488c2ecf20Sopenharmony_ci __func__); 39498c2ecf20Sopenharmony_ci } else { 39508c2ecf20Sopenharmony_ci /* 39518c2ecf20Sopenharmony_ci * Pop GLOBAL OUT NAK status packet from RxFIFO 39528c2ecf20Sopenharmony_ci * to assert GOUTNAKEFF interrupt 39538c2ecf20Sopenharmony_ci */ 39548c2ecf20Sopenharmony_ci dwc2_readl(hsotg, GRXSTSP); 39558c2ecf20Sopenharmony_ci } 39568c2ecf20Sopenharmony_ci } 39578c2ecf20Sopenharmony_ci 39588c2ecf20Sopenharmony_ci /* Wait for global nak to take effect */ 39598c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 39608c2ecf20Sopenharmony_ci GINTSTS_GOUTNAKEFF, 100)) 39618c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s: timeout GINTSTS.GOUTNAKEFF\n", 39628c2ecf20Sopenharmony_ci __func__); 39638c2ecf20Sopenharmony_ci } 39648c2ecf20Sopenharmony_ci 39658c2ecf20Sopenharmony_ci /* Disable ep */ 39668c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, epctrl_reg, DXEPCTL_EPDIS | DXEPCTL_SNAK); 39678c2ecf20Sopenharmony_ci 39688c2ecf20Sopenharmony_ci /* Wait for ep to be disabled */ 39698c2ecf20Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, DXEPINT_EPDISBLD, 100)) 39708c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, 39718c2ecf20Sopenharmony_ci "%s: timeout DOEPCTL.EPDisable\n", __func__); 39728c2ecf20Sopenharmony_ci 39738c2ecf20Sopenharmony_ci /* Clear EPDISBLD interrupt */ 39748c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, epint_reg, DXEPINT_EPDISBLD); 39758c2ecf20Sopenharmony_ci 39768c2ecf20Sopenharmony_ci if (hs_ep->dir_in) { 39778c2ecf20Sopenharmony_ci unsigned short fifo_index; 39788c2ecf20Sopenharmony_ci 39798c2ecf20Sopenharmony_ci if (hsotg->dedicated_fifos || hs_ep->periodic) 39808c2ecf20Sopenharmony_ci fifo_index = hs_ep->fifo_index; 39818c2ecf20Sopenharmony_ci else 39828c2ecf20Sopenharmony_ci fifo_index = 0; 39838c2ecf20Sopenharmony_ci 39848c2ecf20Sopenharmony_ci /* Flush TX FIFO */ 39858c2ecf20Sopenharmony_ci dwc2_flush_tx_fifo(hsotg, fifo_index); 39868c2ecf20Sopenharmony_ci 39878c2ecf20Sopenharmony_ci /* Clear Global In NP NAK in Shared FIFO for non periodic ep */ 39888c2ecf20Sopenharmony_ci if (!hsotg->dedicated_fifos && !hs_ep->periodic) 39898c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_CGNPINNAK); 39908c2ecf20Sopenharmony_ci 39918c2ecf20Sopenharmony_ci } else { 39928c2ecf20Sopenharmony_ci /* Remove global NAKs */ 39938c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_CGOUTNAK); 39948c2ecf20Sopenharmony_ci } 39958c2ecf20Sopenharmony_ci} 39968c2ecf20Sopenharmony_ci 39978c2ecf20Sopenharmony_ci/** 39988c2ecf20Sopenharmony_ci * dwc2_hsotg_ep_enable - enable the given endpoint 39998c2ecf20Sopenharmony_ci * @ep: The USB endpint to configure 40008c2ecf20Sopenharmony_ci * @desc: The USB endpoint descriptor to configure with. 40018c2ecf20Sopenharmony_ci * 40028c2ecf20Sopenharmony_ci * This is called from the USB gadget code's usb_ep_enable(). 40038c2ecf20Sopenharmony_ci */ 40048c2ecf20Sopenharmony_cistatic int dwc2_hsotg_ep_enable(struct usb_ep *ep, 40058c2ecf20Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 40068c2ecf20Sopenharmony_ci{ 40078c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 40088c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 40098c2ecf20Sopenharmony_ci unsigned long flags; 40108c2ecf20Sopenharmony_ci unsigned int index = hs_ep->index; 40118c2ecf20Sopenharmony_ci u32 epctrl_reg; 40128c2ecf20Sopenharmony_ci u32 epctrl; 40138c2ecf20Sopenharmony_ci u32 mps; 40148c2ecf20Sopenharmony_ci u32 mc; 40158c2ecf20Sopenharmony_ci u32 mask; 40168c2ecf20Sopenharmony_ci unsigned int dir_in; 40178c2ecf20Sopenharmony_ci unsigned int i, val, size; 40188c2ecf20Sopenharmony_ci int ret = 0; 40198c2ecf20Sopenharmony_ci unsigned char ep_type; 40208c2ecf20Sopenharmony_ci int desc_num; 40218c2ecf20Sopenharmony_ci 40228c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 40238c2ecf20Sopenharmony_ci "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", 40248c2ecf20Sopenharmony_ci __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, 40258c2ecf20Sopenharmony_ci desc->wMaxPacketSize, desc->bInterval); 40268c2ecf20Sopenharmony_ci 40278c2ecf20Sopenharmony_ci /* not to be called for EP0 */ 40288c2ecf20Sopenharmony_ci if (index == 0) { 40298c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: called for EP 0\n", __func__); 40308c2ecf20Sopenharmony_ci return -EINVAL; 40318c2ecf20Sopenharmony_ci } 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; 40348c2ecf20Sopenharmony_ci if (dir_in != hs_ep->dir_in) { 40358c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); 40368c2ecf20Sopenharmony_ci return -EINVAL; 40378c2ecf20Sopenharmony_ci } 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; 40408c2ecf20Sopenharmony_ci mps = usb_endpoint_maxp(desc); 40418c2ecf20Sopenharmony_ci mc = usb_endpoint_maxp_mult(desc); 40428c2ecf20Sopenharmony_ci 40438c2ecf20Sopenharmony_ci /* ISOC IN in DDMA supported bInterval up to 10 */ 40448c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC && 40458c2ecf20Sopenharmony_ci dir_in && desc->bInterval > 10) { 40468c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 40478c2ecf20Sopenharmony_ci "%s: ISOC IN, DDMA: bInterval>10 not supported!\n", __func__); 40488c2ecf20Sopenharmony_ci return -EINVAL; 40498c2ecf20Sopenharmony_ci } 40508c2ecf20Sopenharmony_ci 40518c2ecf20Sopenharmony_ci /* High bandwidth ISOC OUT in DDMA not supported */ 40528c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC && 40538c2ecf20Sopenharmony_ci !dir_in && mc > 1) { 40548c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 40558c2ecf20Sopenharmony_ci "%s: ISOC OUT, DDMA: HB not supported!\n", __func__); 40568c2ecf20Sopenharmony_ci return -EINVAL; 40578c2ecf20Sopenharmony_ci } 40588c2ecf20Sopenharmony_ci 40598c2ecf20Sopenharmony_ci /* note, we handle this here instead of dwc2_hsotg_set_ep_maxpacket */ 40608c2ecf20Sopenharmony_ci 40618c2ecf20Sopenharmony_ci epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 40628c2ecf20Sopenharmony_ci epctrl = dwc2_readl(hsotg, epctrl_reg); 40638c2ecf20Sopenharmony_ci 40648c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", 40658c2ecf20Sopenharmony_ci __func__, epctrl, epctrl_reg); 40668c2ecf20Sopenharmony_ci 40678c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC) 40688c2ecf20Sopenharmony_ci desc_num = MAX_DMA_DESC_NUM_HS_ISOC; 40698c2ecf20Sopenharmony_ci else 40708c2ecf20Sopenharmony_ci desc_num = MAX_DMA_DESC_NUM_GENERIC; 40718c2ecf20Sopenharmony_ci 40728c2ecf20Sopenharmony_ci /* Allocate DMA descriptor chain for non-ctrl endpoints */ 40738c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg) && !hs_ep->desc_list) { 40748c2ecf20Sopenharmony_ci hs_ep->desc_list = dmam_alloc_coherent(hsotg->dev, 40758c2ecf20Sopenharmony_ci desc_num * sizeof(struct dwc2_dma_desc), 40768c2ecf20Sopenharmony_ci &hs_ep->desc_list_dma, GFP_ATOMIC); 40778c2ecf20Sopenharmony_ci if (!hs_ep->desc_list) { 40788c2ecf20Sopenharmony_ci ret = -ENOMEM; 40798c2ecf20Sopenharmony_ci goto error2; 40808c2ecf20Sopenharmony_ci } 40818c2ecf20Sopenharmony_ci } 40828c2ecf20Sopenharmony_ci 40838c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 40848c2ecf20Sopenharmony_ci 40858c2ecf20Sopenharmony_ci epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK); 40868c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_MPS(mps); 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci /* 40898c2ecf20Sopenharmony_ci * mark the endpoint as active, otherwise the core may ignore 40908c2ecf20Sopenharmony_ci * transactions entirely for this endpoint 40918c2ecf20Sopenharmony_ci */ 40928c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_USBACTEP; 40938c2ecf20Sopenharmony_ci 40948c2ecf20Sopenharmony_ci /* update the endpoint state */ 40958c2ecf20Sopenharmony_ci dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, mc, dir_in); 40968c2ecf20Sopenharmony_ci 40978c2ecf20Sopenharmony_ci /* default, set to non-periodic */ 40988c2ecf20Sopenharmony_ci hs_ep->isochronous = 0; 40998c2ecf20Sopenharmony_ci hs_ep->periodic = 0; 41008c2ecf20Sopenharmony_ci hs_ep->halted = 0; 41018c2ecf20Sopenharmony_ci hs_ep->interval = desc->bInterval; 41028c2ecf20Sopenharmony_ci 41038c2ecf20Sopenharmony_ci switch (ep_type) { 41048c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 41058c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_EPTYPE_ISO; 41068c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_SETEVENFR; 41078c2ecf20Sopenharmony_ci hs_ep->isochronous = 1; 41088c2ecf20Sopenharmony_ci hs_ep->interval = 1 << (desc->bInterval - 1); 41098c2ecf20Sopenharmony_ci hs_ep->target_frame = TARGET_FRAME_INITIAL; 41108c2ecf20Sopenharmony_ci hs_ep->next_desc = 0; 41118c2ecf20Sopenharmony_ci hs_ep->compl_desc = 0; 41128c2ecf20Sopenharmony_ci if (dir_in) { 41138c2ecf20Sopenharmony_ci hs_ep->periodic = 1; 41148c2ecf20Sopenharmony_ci mask = dwc2_readl(hsotg, DIEPMSK); 41158c2ecf20Sopenharmony_ci mask |= DIEPMSK_NAKMSK; 41168c2ecf20Sopenharmony_ci dwc2_writel(hsotg, mask, DIEPMSK); 41178c2ecf20Sopenharmony_ci } else { 41188c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_SNAK; 41198c2ecf20Sopenharmony_ci mask = dwc2_readl(hsotg, DOEPMSK); 41208c2ecf20Sopenharmony_ci mask |= DOEPMSK_OUTTKNEPDISMSK; 41218c2ecf20Sopenharmony_ci dwc2_writel(hsotg, mask, DOEPMSK); 41228c2ecf20Sopenharmony_ci } 41238c2ecf20Sopenharmony_ci break; 41248c2ecf20Sopenharmony_ci 41258c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 41268c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_EPTYPE_BULK; 41278c2ecf20Sopenharmony_ci break; 41288c2ecf20Sopenharmony_ci 41298c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 41308c2ecf20Sopenharmony_ci if (dir_in) 41318c2ecf20Sopenharmony_ci hs_ep->periodic = 1; 41328c2ecf20Sopenharmony_ci 41338c2ecf20Sopenharmony_ci if (hsotg->gadget.speed == USB_SPEED_HIGH) 41348c2ecf20Sopenharmony_ci hs_ep->interval = 1 << (desc->bInterval - 1); 41358c2ecf20Sopenharmony_ci 41368c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_EPTYPE_INTERRUPT; 41378c2ecf20Sopenharmony_ci break; 41388c2ecf20Sopenharmony_ci 41398c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 41408c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_EPTYPE_CONTROL; 41418c2ecf20Sopenharmony_ci break; 41428c2ecf20Sopenharmony_ci } 41438c2ecf20Sopenharmony_ci 41448c2ecf20Sopenharmony_ci /* 41458c2ecf20Sopenharmony_ci * if the hardware has dedicated fifos, we must give each IN EP 41468c2ecf20Sopenharmony_ci * a unique tx-fifo even if it is non-periodic. 41478c2ecf20Sopenharmony_ci */ 41488c2ecf20Sopenharmony_ci if (dir_in && hsotg->dedicated_fifos) { 41498c2ecf20Sopenharmony_ci unsigned fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); 41508c2ecf20Sopenharmony_ci u32 fifo_index = 0; 41518c2ecf20Sopenharmony_ci u32 fifo_size = UINT_MAX; 41528c2ecf20Sopenharmony_ci 41538c2ecf20Sopenharmony_ci size = hs_ep->ep.maxpacket * hs_ep->mc; 41548c2ecf20Sopenharmony_ci for (i = 1; i <= fifo_count; ++i) { 41558c2ecf20Sopenharmony_ci if (hsotg->fifo_map & (1 << i)) 41568c2ecf20Sopenharmony_ci continue; 41578c2ecf20Sopenharmony_ci val = dwc2_readl(hsotg, DPTXFSIZN(i)); 41588c2ecf20Sopenharmony_ci val = (val >> FIFOSIZE_DEPTH_SHIFT) * 4; 41598c2ecf20Sopenharmony_ci if (val < size) 41608c2ecf20Sopenharmony_ci continue; 41618c2ecf20Sopenharmony_ci /* Search for smallest acceptable fifo */ 41628c2ecf20Sopenharmony_ci if (val < fifo_size) { 41638c2ecf20Sopenharmony_ci fifo_size = val; 41648c2ecf20Sopenharmony_ci fifo_index = i; 41658c2ecf20Sopenharmony_ci } 41668c2ecf20Sopenharmony_ci } 41678c2ecf20Sopenharmony_ci if (!fifo_index) { 41688c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 41698c2ecf20Sopenharmony_ci "%s: No suitable fifo found\n", __func__); 41708c2ecf20Sopenharmony_ci ret = -ENOMEM; 41718c2ecf20Sopenharmony_ci goto error1; 41728c2ecf20Sopenharmony_ci } 41738c2ecf20Sopenharmony_ci epctrl &= ~(DXEPCTL_TXFNUM_LIMIT << DXEPCTL_TXFNUM_SHIFT); 41748c2ecf20Sopenharmony_ci hsotg->fifo_map |= 1 << fifo_index; 41758c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_TXFNUM(fifo_index); 41768c2ecf20Sopenharmony_ci hs_ep->fifo_index = fifo_index; 41778c2ecf20Sopenharmony_ci hs_ep->fifo_size = fifo_size; 41788c2ecf20Sopenharmony_ci } 41798c2ecf20Sopenharmony_ci 41808c2ecf20Sopenharmony_ci /* for non control endpoints, set PID to D0 */ 41818c2ecf20Sopenharmony_ci if (index && !hs_ep->isochronous) 41828c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_SETD0PID; 41838c2ecf20Sopenharmony_ci 41848c2ecf20Sopenharmony_ci /* WA for Full speed ISOC IN in DDMA mode. 41858c2ecf20Sopenharmony_ci * By Clear NAK status of EP, core will send ZLP 41868c2ecf20Sopenharmony_ci * to IN token and assert NAK interrupt relying 41878c2ecf20Sopenharmony_ci * on TxFIFO status only 41888c2ecf20Sopenharmony_ci */ 41898c2ecf20Sopenharmony_ci 41908c2ecf20Sopenharmony_ci if (hsotg->gadget.speed == USB_SPEED_FULL && 41918c2ecf20Sopenharmony_ci hs_ep->isochronous && dir_in) { 41928c2ecf20Sopenharmony_ci /* The WA applies only to core versions from 2.72a 41938c2ecf20Sopenharmony_ci * to 4.00a (including both). Also for FS_IOT_1.00a 41948c2ecf20Sopenharmony_ci * and HS_IOT_1.00a. 41958c2ecf20Sopenharmony_ci */ 41968c2ecf20Sopenharmony_ci u32 gsnpsid = dwc2_readl(hsotg, GSNPSID); 41978c2ecf20Sopenharmony_ci 41988c2ecf20Sopenharmony_ci if ((gsnpsid >= DWC2_CORE_REV_2_72a && 41998c2ecf20Sopenharmony_ci gsnpsid <= DWC2_CORE_REV_4_00a) || 42008c2ecf20Sopenharmony_ci gsnpsid == DWC2_FS_IOT_REV_1_00a || 42018c2ecf20Sopenharmony_ci gsnpsid == DWC2_HS_IOT_REV_1_00a) 42028c2ecf20Sopenharmony_ci epctrl |= DXEPCTL_CNAK; 42038c2ecf20Sopenharmony_ci } 42048c2ecf20Sopenharmony_ci 42058c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", 42068c2ecf20Sopenharmony_ci __func__, epctrl); 42078c2ecf20Sopenharmony_ci 42088c2ecf20Sopenharmony_ci dwc2_writel(hsotg, epctrl, epctrl_reg); 42098c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", 42108c2ecf20Sopenharmony_ci __func__, dwc2_readl(hsotg, epctrl_reg)); 42118c2ecf20Sopenharmony_ci 42128c2ecf20Sopenharmony_ci /* enable the endpoint interrupt */ 42138c2ecf20Sopenharmony_ci dwc2_hsotg_ctrl_epint(hsotg, index, dir_in, 1); 42148c2ecf20Sopenharmony_ci 42158c2ecf20Sopenharmony_cierror1: 42168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 42178c2ecf20Sopenharmony_ci 42188c2ecf20Sopenharmony_cierror2: 42198c2ecf20Sopenharmony_ci if (ret && using_desc_dma(hsotg) && hs_ep->desc_list) { 42208c2ecf20Sopenharmony_ci dmam_free_coherent(hsotg->dev, desc_num * 42218c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 42228c2ecf20Sopenharmony_ci hs_ep->desc_list, hs_ep->desc_list_dma); 42238c2ecf20Sopenharmony_ci hs_ep->desc_list = NULL; 42248c2ecf20Sopenharmony_ci } 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ci return ret; 42278c2ecf20Sopenharmony_ci} 42288c2ecf20Sopenharmony_ci 42298c2ecf20Sopenharmony_ci/** 42308c2ecf20Sopenharmony_ci * dwc2_hsotg_ep_disable - disable given endpoint 42318c2ecf20Sopenharmony_ci * @ep: The endpoint to disable. 42328c2ecf20Sopenharmony_ci */ 42338c2ecf20Sopenharmony_cistatic int dwc2_hsotg_ep_disable(struct usb_ep *ep) 42348c2ecf20Sopenharmony_ci{ 42358c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 42368c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 42378c2ecf20Sopenharmony_ci int dir_in = hs_ep->dir_in; 42388c2ecf20Sopenharmony_ci int index = hs_ep->index; 42398c2ecf20Sopenharmony_ci u32 epctrl_reg; 42408c2ecf20Sopenharmony_ci u32 ctrl; 42418c2ecf20Sopenharmony_ci 42428c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); 42438c2ecf20Sopenharmony_ci 42448c2ecf20Sopenharmony_ci if (ep == &hsotg->eps_out[0]->ep) { 42458c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: called for ep0\n", __func__); 42468c2ecf20Sopenharmony_ci return -EINVAL; 42478c2ecf20Sopenharmony_ci } 42488c2ecf20Sopenharmony_ci 42498c2ecf20Sopenharmony_ci if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { 42508c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: called in host mode?\n", __func__); 42518c2ecf20Sopenharmony_ci return -EINVAL; 42528c2ecf20Sopenharmony_ci } 42538c2ecf20Sopenharmony_ci 42548c2ecf20Sopenharmony_ci epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 42558c2ecf20Sopenharmony_ci 42568c2ecf20Sopenharmony_ci ctrl = dwc2_readl(hsotg, epctrl_reg); 42578c2ecf20Sopenharmony_ci 42588c2ecf20Sopenharmony_ci if (ctrl & DXEPCTL_EPENA) 42598c2ecf20Sopenharmony_ci dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep); 42608c2ecf20Sopenharmony_ci 42618c2ecf20Sopenharmony_ci ctrl &= ~DXEPCTL_EPENA; 42628c2ecf20Sopenharmony_ci ctrl &= ~DXEPCTL_USBACTEP; 42638c2ecf20Sopenharmony_ci ctrl |= DXEPCTL_SNAK; 42648c2ecf20Sopenharmony_ci 42658c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 42668c2ecf20Sopenharmony_ci dwc2_writel(hsotg, ctrl, epctrl_reg); 42678c2ecf20Sopenharmony_ci 42688c2ecf20Sopenharmony_ci /* disable endpoint interrupts */ 42698c2ecf20Sopenharmony_ci dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); 42708c2ecf20Sopenharmony_ci 42718c2ecf20Sopenharmony_ci /* terminate all requests with shutdown */ 42728c2ecf20Sopenharmony_ci kill_all_requests(hsotg, hs_ep, -ESHUTDOWN); 42738c2ecf20Sopenharmony_ci 42748c2ecf20Sopenharmony_ci hsotg->fifo_map &= ~(1 << hs_ep->fifo_index); 42758c2ecf20Sopenharmony_ci hs_ep->fifo_index = 0; 42768c2ecf20Sopenharmony_ci hs_ep->fifo_size = 0; 42778c2ecf20Sopenharmony_ci 42788c2ecf20Sopenharmony_ci return 0; 42798c2ecf20Sopenharmony_ci} 42808c2ecf20Sopenharmony_ci 42818c2ecf20Sopenharmony_cistatic int dwc2_hsotg_ep_disable_lock(struct usb_ep *ep) 42828c2ecf20Sopenharmony_ci{ 42838c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 42848c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 42858c2ecf20Sopenharmony_ci unsigned long flags; 42868c2ecf20Sopenharmony_ci int ret; 42878c2ecf20Sopenharmony_ci 42888c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 42898c2ecf20Sopenharmony_ci ret = dwc2_hsotg_ep_disable(ep); 42908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 42918c2ecf20Sopenharmony_ci return ret; 42928c2ecf20Sopenharmony_ci} 42938c2ecf20Sopenharmony_ci 42948c2ecf20Sopenharmony_ci/** 42958c2ecf20Sopenharmony_ci * on_list - check request is on the given endpoint 42968c2ecf20Sopenharmony_ci * @ep: The endpoint to check. 42978c2ecf20Sopenharmony_ci * @test: The request to test if it is on the endpoint. 42988c2ecf20Sopenharmony_ci */ 42998c2ecf20Sopenharmony_cistatic bool on_list(struct dwc2_hsotg_ep *ep, struct dwc2_hsotg_req *test) 43008c2ecf20Sopenharmony_ci{ 43018c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *req, *treq; 43028c2ecf20Sopenharmony_ci 43038c2ecf20Sopenharmony_ci list_for_each_entry_safe(req, treq, &ep->queue, queue) { 43048c2ecf20Sopenharmony_ci if (req == test) 43058c2ecf20Sopenharmony_ci return true; 43068c2ecf20Sopenharmony_ci } 43078c2ecf20Sopenharmony_ci 43088c2ecf20Sopenharmony_ci return false; 43098c2ecf20Sopenharmony_ci} 43108c2ecf20Sopenharmony_ci 43118c2ecf20Sopenharmony_ci/** 43128c2ecf20Sopenharmony_ci * dwc2_hsotg_ep_dequeue - dequeue given endpoint 43138c2ecf20Sopenharmony_ci * @ep: The endpoint to dequeue. 43148c2ecf20Sopenharmony_ci * @req: The request to be removed from a queue. 43158c2ecf20Sopenharmony_ci */ 43168c2ecf20Sopenharmony_cistatic int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) 43178c2ecf20Sopenharmony_ci{ 43188c2ecf20Sopenharmony_ci struct dwc2_hsotg_req *hs_req = our_req(req); 43198c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 43208c2ecf20Sopenharmony_ci struct dwc2_hsotg *hs = hs_ep->parent; 43218c2ecf20Sopenharmony_ci unsigned long flags; 43228c2ecf20Sopenharmony_ci 43238c2ecf20Sopenharmony_ci dev_dbg(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); 43248c2ecf20Sopenharmony_ci 43258c2ecf20Sopenharmony_ci spin_lock_irqsave(&hs->lock, flags); 43268c2ecf20Sopenharmony_ci 43278c2ecf20Sopenharmony_ci if (!on_list(hs_ep, hs_req)) { 43288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hs->lock, flags); 43298c2ecf20Sopenharmony_ci return -EINVAL; 43308c2ecf20Sopenharmony_ci } 43318c2ecf20Sopenharmony_ci 43328c2ecf20Sopenharmony_ci /* Dequeue already started request */ 43338c2ecf20Sopenharmony_ci if (req == &hs_ep->req->req) 43348c2ecf20Sopenharmony_ci dwc2_hsotg_ep_stop_xfr(hs, hs_ep); 43358c2ecf20Sopenharmony_ci 43368c2ecf20Sopenharmony_ci dwc2_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); 43378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hs->lock, flags); 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci return 0; 43408c2ecf20Sopenharmony_ci} 43418c2ecf20Sopenharmony_ci 43428c2ecf20Sopenharmony_ci/** 43438c2ecf20Sopenharmony_ci * dwc2_hsotg_ep_sethalt - set halt on a given endpoint 43448c2ecf20Sopenharmony_ci * @ep: The endpoint to set halt. 43458c2ecf20Sopenharmony_ci * @value: Set or unset the halt. 43468c2ecf20Sopenharmony_ci * @now: If true, stall the endpoint now. Otherwise return -EAGAIN if 43478c2ecf20Sopenharmony_ci * the endpoint is busy processing requests. 43488c2ecf20Sopenharmony_ci * 43498c2ecf20Sopenharmony_ci * We need to stall the endpoint immediately if request comes from set_feature 43508c2ecf20Sopenharmony_ci * protocol command handler. 43518c2ecf20Sopenharmony_ci */ 43528c2ecf20Sopenharmony_cistatic int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now) 43538c2ecf20Sopenharmony_ci{ 43548c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 43558c2ecf20Sopenharmony_ci struct dwc2_hsotg *hs = hs_ep->parent; 43568c2ecf20Sopenharmony_ci int index = hs_ep->index; 43578c2ecf20Sopenharmony_ci u32 epreg; 43588c2ecf20Sopenharmony_ci u32 epctl; 43598c2ecf20Sopenharmony_ci u32 xfertype; 43608c2ecf20Sopenharmony_ci 43618c2ecf20Sopenharmony_ci dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); 43628c2ecf20Sopenharmony_ci 43638c2ecf20Sopenharmony_ci if (index == 0) { 43648c2ecf20Sopenharmony_ci if (value) 43658c2ecf20Sopenharmony_ci dwc2_hsotg_stall_ep0(hs); 43668c2ecf20Sopenharmony_ci else 43678c2ecf20Sopenharmony_ci dev_warn(hs->dev, 43688c2ecf20Sopenharmony_ci "%s: can't clear halt on ep0\n", __func__); 43698c2ecf20Sopenharmony_ci return 0; 43708c2ecf20Sopenharmony_ci } 43718c2ecf20Sopenharmony_ci 43728c2ecf20Sopenharmony_ci if (hs_ep->isochronous) { 43738c2ecf20Sopenharmony_ci dev_err(hs->dev, "%s is Isochronous Endpoint\n", ep->name); 43748c2ecf20Sopenharmony_ci return -EINVAL; 43758c2ecf20Sopenharmony_ci } 43768c2ecf20Sopenharmony_ci 43778c2ecf20Sopenharmony_ci if (!now && value && !list_empty(&hs_ep->queue)) { 43788c2ecf20Sopenharmony_ci dev_dbg(hs->dev, "%s request is pending, cannot halt\n", 43798c2ecf20Sopenharmony_ci ep->name); 43808c2ecf20Sopenharmony_ci return -EAGAIN; 43818c2ecf20Sopenharmony_ci } 43828c2ecf20Sopenharmony_ci 43838c2ecf20Sopenharmony_ci if (hs_ep->dir_in) { 43848c2ecf20Sopenharmony_ci epreg = DIEPCTL(index); 43858c2ecf20Sopenharmony_ci epctl = dwc2_readl(hs, epreg); 43868c2ecf20Sopenharmony_ci 43878c2ecf20Sopenharmony_ci if (value) { 43888c2ecf20Sopenharmony_ci epctl |= DXEPCTL_STALL | DXEPCTL_SNAK; 43898c2ecf20Sopenharmony_ci if (epctl & DXEPCTL_EPENA) 43908c2ecf20Sopenharmony_ci epctl |= DXEPCTL_EPDIS; 43918c2ecf20Sopenharmony_ci } else { 43928c2ecf20Sopenharmony_ci epctl &= ~DXEPCTL_STALL; 43938c2ecf20Sopenharmony_ci xfertype = epctl & DXEPCTL_EPTYPE_MASK; 43948c2ecf20Sopenharmony_ci if (xfertype == DXEPCTL_EPTYPE_BULK || 43958c2ecf20Sopenharmony_ci xfertype == DXEPCTL_EPTYPE_INTERRUPT) 43968c2ecf20Sopenharmony_ci epctl |= DXEPCTL_SETD0PID; 43978c2ecf20Sopenharmony_ci } 43988c2ecf20Sopenharmony_ci dwc2_writel(hs, epctl, epreg); 43998c2ecf20Sopenharmony_ci } else { 44008c2ecf20Sopenharmony_ci epreg = DOEPCTL(index); 44018c2ecf20Sopenharmony_ci epctl = dwc2_readl(hs, epreg); 44028c2ecf20Sopenharmony_ci 44038c2ecf20Sopenharmony_ci if (value) { 44048c2ecf20Sopenharmony_ci /* Unmask GOUTNAKEFF interrupt */ 44058c2ecf20Sopenharmony_ci dwc2_hsotg_en_gsint(hs, GINTSTS_GOUTNAKEFF); 44068c2ecf20Sopenharmony_ci 44078c2ecf20Sopenharmony_ci if (!(dwc2_readl(hs, GINTSTS) & GINTSTS_GOUTNAKEFF)) 44088c2ecf20Sopenharmony_ci dwc2_set_bit(hs, DCTL, DCTL_SGOUTNAK); 44098c2ecf20Sopenharmony_ci // STALL bit will be set in GOUTNAKEFF interrupt handler 44108c2ecf20Sopenharmony_ci } else { 44118c2ecf20Sopenharmony_ci epctl &= ~DXEPCTL_STALL; 44128c2ecf20Sopenharmony_ci xfertype = epctl & DXEPCTL_EPTYPE_MASK; 44138c2ecf20Sopenharmony_ci if (xfertype == DXEPCTL_EPTYPE_BULK || 44148c2ecf20Sopenharmony_ci xfertype == DXEPCTL_EPTYPE_INTERRUPT) 44158c2ecf20Sopenharmony_ci epctl |= DXEPCTL_SETD0PID; 44168c2ecf20Sopenharmony_ci dwc2_writel(hs, epctl, epreg); 44178c2ecf20Sopenharmony_ci } 44188c2ecf20Sopenharmony_ci } 44198c2ecf20Sopenharmony_ci 44208c2ecf20Sopenharmony_ci hs_ep->halted = value; 44218c2ecf20Sopenharmony_ci return 0; 44228c2ecf20Sopenharmony_ci} 44238c2ecf20Sopenharmony_ci 44248c2ecf20Sopenharmony_ci/** 44258c2ecf20Sopenharmony_ci * dwc2_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held 44268c2ecf20Sopenharmony_ci * @ep: The endpoint to set halt. 44278c2ecf20Sopenharmony_ci * @value: Set or unset the halt. 44288c2ecf20Sopenharmony_ci */ 44298c2ecf20Sopenharmony_cistatic int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) 44308c2ecf20Sopenharmony_ci{ 44318c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 44328c2ecf20Sopenharmony_ci struct dwc2_hsotg *hs = hs_ep->parent; 44338c2ecf20Sopenharmony_ci unsigned long flags = 0; 44348c2ecf20Sopenharmony_ci int ret = 0; 44358c2ecf20Sopenharmony_ci 44368c2ecf20Sopenharmony_ci spin_lock_irqsave(&hs->lock, flags); 44378c2ecf20Sopenharmony_ci ret = dwc2_hsotg_ep_sethalt(ep, value, false); 44388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hs->lock, flags); 44398c2ecf20Sopenharmony_ci 44408c2ecf20Sopenharmony_ci return ret; 44418c2ecf20Sopenharmony_ci} 44428c2ecf20Sopenharmony_ci 44438c2ecf20Sopenharmony_cistatic const struct usb_ep_ops dwc2_hsotg_ep_ops = { 44448c2ecf20Sopenharmony_ci .enable = dwc2_hsotg_ep_enable, 44458c2ecf20Sopenharmony_ci .disable = dwc2_hsotg_ep_disable_lock, 44468c2ecf20Sopenharmony_ci .alloc_request = dwc2_hsotg_ep_alloc_request, 44478c2ecf20Sopenharmony_ci .free_request = dwc2_hsotg_ep_free_request, 44488c2ecf20Sopenharmony_ci .queue = dwc2_hsotg_ep_queue_lock, 44498c2ecf20Sopenharmony_ci .dequeue = dwc2_hsotg_ep_dequeue, 44508c2ecf20Sopenharmony_ci .set_halt = dwc2_hsotg_ep_sethalt_lock, 44518c2ecf20Sopenharmony_ci /* note, don't believe we have any call for the fifo routines */ 44528c2ecf20Sopenharmony_ci}; 44538c2ecf20Sopenharmony_ci 44548c2ecf20Sopenharmony_ci/** 44558c2ecf20Sopenharmony_ci * dwc2_hsotg_init - initialize the usb core 44568c2ecf20Sopenharmony_ci * @hsotg: The driver state 44578c2ecf20Sopenharmony_ci */ 44588c2ecf20Sopenharmony_cistatic void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) 44598c2ecf20Sopenharmony_ci{ 44608c2ecf20Sopenharmony_ci /* unmask subset of endpoint interrupts */ 44618c2ecf20Sopenharmony_ci 44628c2ecf20Sopenharmony_ci dwc2_writel(hsotg, DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | 44638c2ecf20Sopenharmony_ci DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK, 44648c2ecf20Sopenharmony_ci DIEPMSK); 44658c2ecf20Sopenharmony_ci 44668c2ecf20Sopenharmony_ci dwc2_writel(hsotg, DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | 44678c2ecf20Sopenharmony_ci DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK, 44688c2ecf20Sopenharmony_ci DOEPMSK); 44698c2ecf20Sopenharmony_ci 44708c2ecf20Sopenharmony_ci dwc2_writel(hsotg, 0, DAINTMSK); 44718c2ecf20Sopenharmony_ci 44728c2ecf20Sopenharmony_ci /* Be in disconnected state until gadget is registered */ 44738c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); 44748c2ecf20Sopenharmony_ci 44758c2ecf20Sopenharmony_ci /* setup fifos */ 44768c2ecf20Sopenharmony_ci 44778c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 44788c2ecf20Sopenharmony_ci dwc2_readl(hsotg, GRXFSIZ), 44798c2ecf20Sopenharmony_ci dwc2_readl(hsotg, GNPTXFSIZ)); 44808c2ecf20Sopenharmony_ci 44818c2ecf20Sopenharmony_ci dwc2_hsotg_init_fifo(hsotg); 44828c2ecf20Sopenharmony_ci 44838c2ecf20Sopenharmony_ci if (using_dma(hsotg)) 44848c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, GAHBCFG, GAHBCFG_DMA_EN); 44858c2ecf20Sopenharmony_ci} 44868c2ecf20Sopenharmony_ci 44878c2ecf20Sopenharmony_ci/** 44888c2ecf20Sopenharmony_ci * dwc2_hsotg_udc_start - prepare the udc for work 44898c2ecf20Sopenharmony_ci * @gadget: The usb gadget state 44908c2ecf20Sopenharmony_ci * @driver: The usb gadget driver 44918c2ecf20Sopenharmony_ci * 44928c2ecf20Sopenharmony_ci * Perform initialization to prepare udc device and driver 44938c2ecf20Sopenharmony_ci * to work. 44948c2ecf20Sopenharmony_ci */ 44958c2ecf20Sopenharmony_cistatic int dwc2_hsotg_udc_start(struct usb_gadget *gadget, 44968c2ecf20Sopenharmony_ci struct usb_gadget_driver *driver) 44978c2ecf20Sopenharmony_ci{ 44988c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(gadget); 44998c2ecf20Sopenharmony_ci unsigned long flags; 45008c2ecf20Sopenharmony_ci int ret; 45018c2ecf20Sopenharmony_ci 45028c2ecf20Sopenharmony_ci if (!hsotg) { 45038c2ecf20Sopenharmony_ci pr_err("%s: called with no device\n", __func__); 45048c2ecf20Sopenharmony_ci return -ENODEV; 45058c2ecf20Sopenharmony_ci } 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci if (!driver) { 45088c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: no driver\n", __func__); 45098c2ecf20Sopenharmony_ci return -EINVAL; 45108c2ecf20Sopenharmony_ci } 45118c2ecf20Sopenharmony_ci 45128c2ecf20Sopenharmony_ci if (driver->max_speed < USB_SPEED_FULL) 45138c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: bad speed\n", __func__); 45148c2ecf20Sopenharmony_ci 45158c2ecf20Sopenharmony_ci if (!driver->setup) { 45168c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: missing entry points\n", __func__); 45178c2ecf20Sopenharmony_ci return -EINVAL; 45188c2ecf20Sopenharmony_ci } 45198c2ecf20Sopenharmony_ci 45208c2ecf20Sopenharmony_ci WARN_ON(hsotg->driver); 45218c2ecf20Sopenharmony_ci 45228c2ecf20Sopenharmony_ci hsotg->driver = driver; 45238c2ecf20Sopenharmony_ci hsotg->gadget.dev.of_node = hsotg->dev->of_node; 45248c2ecf20Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_UNKNOWN; 45258c2ecf20Sopenharmony_ci 45268c2ecf20Sopenharmony_ci if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) { 45278c2ecf20Sopenharmony_ci ret = dwc2_lowlevel_hw_enable(hsotg); 45288c2ecf20Sopenharmony_ci if (ret) 45298c2ecf20Sopenharmony_ci goto err; 45308c2ecf20Sopenharmony_ci } 45318c2ecf20Sopenharmony_ci 45328c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(hsotg->uphy)) 45338c2ecf20Sopenharmony_ci otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget); 45348c2ecf20Sopenharmony_ci 45358c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 45368c2ecf20Sopenharmony_ci if (dwc2_hw_is_device(hsotg)) { 45378c2ecf20Sopenharmony_ci dwc2_hsotg_init(hsotg); 45388c2ecf20Sopenharmony_ci dwc2_hsotg_core_init_disconnected(hsotg, false); 45398c2ecf20Sopenharmony_ci } 45408c2ecf20Sopenharmony_ci 45418c2ecf20Sopenharmony_ci hsotg->enabled = 0; 45428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 45438c2ecf20Sopenharmony_ci 45448c2ecf20Sopenharmony_ci gadget->sg_supported = using_desc_dma(hsotg); 45458c2ecf20Sopenharmony_ci dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); 45468c2ecf20Sopenharmony_ci 45478c2ecf20Sopenharmony_ci return 0; 45488c2ecf20Sopenharmony_ci 45498c2ecf20Sopenharmony_cierr: 45508c2ecf20Sopenharmony_ci hsotg->driver = NULL; 45518c2ecf20Sopenharmony_ci return ret; 45528c2ecf20Sopenharmony_ci} 45538c2ecf20Sopenharmony_ci 45548c2ecf20Sopenharmony_ci/** 45558c2ecf20Sopenharmony_ci * dwc2_hsotg_udc_stop - stop the udc 45568c2ecf20Sopenharmony_ci * @gadget: The usb gadget state 45578c2ecf20Sopenharmony_ci * 45588c2ecf20Sopenharmony_ci * Stop udc hw block and stay tunned for future transmissions 45598c2ecf20Sopenharmony_ci */ 45608c2ecf20Sopenharmony_cistatic int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) 45618c2ecf20Sopenharmony_ci{ 45628c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(gadget); 45638c2ecf20Sopenharmony_ci unsigned long flags = 0; 45648c2ecf20Sopenharmony_ci int ep; 45658c2ecf20Sopenharmony_ci 45668c2ecf20Sopenharmony_ci if (!hsotg) 45678c2ecf20Sopenharmony_ci return -ENODEV; 45688c2ecf20Sopenharmony_ci 45698c2ecf20Sopenharmony_ci /* all endpoints should be shutdown */ 45708c2ecf20Sopenharmony_ci for (ep = 1; ep < hsotg->num_of_eps; ep++) { 45718c2ecf20Sopenharmony_ci if (hsotg->eps_in[ep]) 45728c2ecf20Sopenharmony_ci dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); 45738c2ecf20Sopenharmony_ci if (hsotg->eps_out[ep]) 45748c2ecf20Sopenharmony_ci dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); 45758c2ecf20Sopenharmony_ci } 45768c2ecf20Sopenharmony_ci 45778c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 45788c2ecf20Sopenharmony_ci 45798c2ecf20Sopenharmony_ci hsotg->driver = NULL; 45808c2ecf20Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_UNKNOWN; 45818c2ecf20Sopenharmony_ci hsotg->enabled = 0; 45828c2ecf20Sopenharmony_ci 45838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 45848c2ecf20Sopenharmony_ci 45858c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(hsotg->uphy)) 45868c2ecf20Sopenharmony_ci otg_set_peripheral(hsotg->uphy->otg, NULL); 45878c2ecf20Sopenharmony_ci 45888c2ecf20Sopenharmony_ci if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 45898c2ecf20Sopenharmony_ci dwc2_lowlevel_hw_disable(hsotg); 45908c2ecf20Sopenharmony_ci 45918c2ecf20Sopenharmony_ci return 0; 45928c2ecf20Sopenharmony_ci} 45938c2ecf20Sopenharmony_ci 45948c2ecf20Sopenharmony_ci/** 45958c2ecf20Sopenharmony_ci * dwc2_hsotg_gadget_getframe - read the frame number 45968c2ecf20Sopenharmony_ci * @gadget: The usb gadget state 45978c2ecf20Sopenharmony_ci * 45988c2ecf20Sopenharmony_ci * Read the {micro} frame number 45998c2ecf20Sopenharmony_ci */ 46008c2ecf20Sopenharmony_cistatic int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget) 46018c2ecf20Sopenharmony_ci{ 46028c2ecf20Sopenharmony_ci return dwc2_hsotg_read_frameno(to_hsotg(gadget)); 46038c2ecf20Sopenharmony_ci} 46048c2ecf20Sopenharmony_ci 46058c2ecf20Sopenharmony_ci/** 46068c2ecf20Sopenharmony_ci * dwc2_hsotg_set_selfpowered - set if device is self/bus powered 46078c2ecf20Sopenharmony_ci * @gadget: The usb gadget state 46088c2ecf20Sopenharmony_ci * @is_selfpowered: Whether the device is self-powered 46098c2ecf20Sopenharmony_ci * 46108c2ecf20Sopenharmony_ci * Set if the device is self or bus powered. 46118c2ecf20Sopenharmony_ci */ 46128c2ecf20Sopenharmony_cistatic int dwc2_hsotg_set_selfpowered(struct usb_gadget *gadget, 46138c2ecf20Sopenharmony_ci int is_selfpowered) 46148c2ecf20Sopenharmony_ci{ 46158c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(gadget); 46168c2ecf20Sopenharmony_ci unsigned long flags; 46178c2ecf20Sopenharmony_ci 46188c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 46198c2ecf20Sopenharmony_ci gadget->is_selfpowered = !!is_selfpowered; 46208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 46218c2ecf20Sopenharmony_ci 46228c2ecf20Sopenharmony_ci return 0; 46238c2ecf20Sopenharmony_ci} 46248c2ecf20Sopenharmony_ci 46258c2ecf20Sopenharmony_ci/** 46268c2ecf20Sopenharmony_ci * dwc2_hsotg_pullup - connect/disconnect the USB PHY 46278c2ecf20Sopenharmony_ci * @gadget: The usb gadget state 46288c2ecf20Sopenharmony_ci * @is_on: Current state of the USB PHY 46298c2ecf20Sopenharmony_ci * 46308c2ecf20Sopenharmony_ci * Connect/Disconnect the USB PHY pullup 46318c2ecf20Sopenharmony_ci */ 46328c2ecf20Sopenharmony_cistatic int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) 46338c2ecf20Sopenharmony_ci{ 46348c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(gadget); 46358c2ecf20Sopenharmony_ci unsigned long flags = 0; 46368c2ecf20Sopenharmony_ci 46378c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on, 46388c2ecf20Sopenharmony_ci hsotg->op_state); 46398c2ecf20Sopenharmony_ci 46408c2ecf20Sopenharmony_ci /* Don't modify pullup state while in host mode */ 46418c2ecf20Sopenharmony_ci if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { 46428c2ecf20Sopenharmony_ci hsotg->enabled = is_on; 46438c2ecf20Sopenharmony_ci return 0; 46448c2ecf20Sopenharmony_ci } 46458c2ecf20Sopenharmony_ci 46468c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 46478c2ecf20Sopenharmony_ci if (is_on) { 46488c2ecf20Sopenharmony_ci hsotg->enabled = 1; 46498c2ecf20Sopenharmony_ci dwc2_hsotg_core_init_disconnected(hsotg, false); 46508c2ecf20Sopenharmony_ci /* Enable ACG feature in device mode,if supported */ 46518c2ecf20Sopenharmony_ci dwc2_enable_acg(hsotg); 46528c2ecf20Sopenharmony_ci dwc2_hsotg_core_connect(hsotg); 46538c2ecf20Sopenharmony_ci } else { 46548c2ecf20Sopenharmony_ci dwc2_hsotg_core_disconnect(hsotg); 46558c2ecf20Sopenharmony_ci dwc2_hsotg_disconnect(hsotg); 46568c2ecf20Sopenharmony_ci hsotg->enabled = 0; 46578c2ecf20Sopenharmony_ci } 46588c2ecf20Sopenharmony_ci 46598c2ecf20Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_UNKNOWN; 46608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 46618c2ecf20Sopenharmony_ci 46628c2ecf20Sopenharmony_ci return 0; 46638c2ecf20Sopenharmony_ci} 46648c2ecf20Sopenharmony_ci 46658c2ecf20Sopenharmony_cistatic int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) 46668c2ecf20Sopenharmony_ci{ 46678c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(gadget); 46688c2ecf20Sopenharmony_ci unsigned long flags; 46698c2ecf20Sopenharmony_ci 46708c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active); 46718c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 46728c2ecf20Sopenharmony_ci 46738c2ecf20Sopenharmony_ci /* 46748c2ecf20Sopenharmony_ci * If controller is hibernated, it must exit from power_down 46758c2ecf20Sopenharmony_ci * before being initialized / de-initialized 46768c2ecf20Sopenharmony_ci */ 46778c2ecf20Sopenharmony_ci if (hsotg->lx_state == DWC2_L2) 46788c2ecf20Sopenharmony_ci dwc2_exit_partial_power_down(hsotg, false); 46798c2ecf20Sopenharmony_ci 46808c2ecf20Sopenharmony_ci if (is_active) { 46818c2ecf20Sopenharmony_ci hsotg->op_state = OTG_STATE_B_PERIPHERAL; 46828c2ecf20Sopenharmony_ci 46838c2ecf20Sopenharmony_ci dwc2_hsotg_core_init_disconnected(hsotg, false); 46848c2ecf20Sopenharmony_ci if (hsotg->enabled) { 46858c2ecf20Sopenharmony_ci /* Enable ACG feature in device mode,if supported */ 46868c2ecf20Sopenharmony_ci dwc2_enable_acg(hsotg); 46878c2ecf20Sopenharmony_ci dwc2_hsotg_core_connect(hsotg); 46888c2ecf20Sopenharmony_ci } 46898c2ecf20Sopenharmony_ci } else { 46908c2ecf20Sopenharmony_ci dwc2_hsotg_core_disconnect(hsotg); 46918c2ecf20Sopenharmony_ci dwc2_hsotg_disconnect(hsotg); 46928c2ecf20Sopenharmony_ci } 46938c2ecf20Sopenharmony_ci 46948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 46958c2ecf20Sopenharmony_ci return 0; 46968c2ecf20Sopenharmony_ci} 46978c2ecf20Sopenharmony_ci 46988c2ecf20Sopenharmony_ci/** 46998c2ecf20Sopenharmony_ci * dwc2_hsotg_vbus_draw - report bMaxPower field 47008c2ecf20Sopenharmony_ci * @gadget: The usb gadget state 47018c2ecf20Sopenharmony_ci * @mA: Amount of current 47028c2ecf20Sopenharmony_ci * 47038c2ecf20Sopenharmony_ci * Report how much power the device may consume to the phy. 47048c2ecf20Sopenharmony_ci */ 47058c2ecf20Sopenharmony_cistatic int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA) 47068c2ecf20Sopenharmony_ci{ 47078c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(gadget); 47088c2ecf20Sopenharmony_ci 47098c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(hsotg->uphy)) 47108c2ecf20Sopenharmony_ci return -ENOTSUPP; 47118c2ecf20Sopenharmony_ci return usb_phy_set_power(hsotg->uphy, mA); 47128c2ecf20Sopenharmony_ci} 47138c2ecf20Sopenharmony_ci 47148c2ecf20Sopenharmony_cistatic const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { 47158c2ecf20Sopenharmony_ci .get_frame = dwc2_hsotg_gadget_getframe, 47168c2ecf20Sopenharmony_ci .set_selfpowered = dwc2_hsotg_set_selfpowered, 47178c2ecf20Sopenharmony_ci .udc_start = dwc2_hsotg_udc_start, 47188c2ecf20Sopenharmony_ci .udc_stop = dwc2_hsotg_udc_stop, 47198c2ecf20Sopenharmony_ci .pullup = dwc2_hsotg_pullup, 47208c2ecf20Sopenharmony_ci .vbus_session = dwc2_hsotg_vbus_session, 47218c2ecf20Sopenharmony_ci .vbus_draw = dwc2_hsotg_vbus_draw, 47228c2ecf20Sopenharmony_ci}; 47238c2ecf20Sopenharmony_ci 47248c2ecf20Sopenharmony_ci/** 47258c2ecf20Sopenharmony_ci * dwc2_hsotg_initep - initialise a single endpoint 47268c2ecf20Sopenharmony_ci * @hsotg: The device state. 47278c2ecf20Sopenharmony_ci * @hs_ep: The endpoint to be initialised. 47288c2ecf20Sopenharmony_ci * @epnum: The endpoint number 47298c2ecf20Sopenharmony_ci * @dir_in: True if direction is in. 47308c2ecf20Sopenharmony_ci * 47318c2ecf20Sopenharmony_ci * Initialise the given endpoint (as part of the probe and device state 47328c2ecf20Sopenharmony_ci * creation) to give to the gadget driver. Setup the endpoint name, any 47338c2ecf20Sopenharmony_ci * direction information and other state that may be required. 47348c2ecf20Sopenharmony_ci */ 47358c2ecf20Sopenharmony_cistatic void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, 47368c2ecf20Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 47378c2ecf20Sopenharmony_ci int epnum, 47388c2ecf20Sopenharmony_ci bool dir_in) 47398c2ecf20Sopenharmony_ci{ 47408c2ecf20Sopenharmony_ci char *dir; 47418c2ecf20Sopenharmony_ci 47428c2ecf20Sopenharmony_ci if (epnum == 0) 47438c2ecf20Sopenharmony_ci dir = ""; 47448c2ecf20Sopenharmony_ci else if (dir_in) 47458c2ecf20Sopenharmony_ci dir = "in"; 47468c2ecf20Sopenharmony_ci else 47478c2ecf20Sopenharmony_ci dir = "out"; 47488c2ecf20Sopenharmony_ci 47498c2ecf20Sopenharmony_ci hs_ep->dir_in = dir_in; 47508c2ecf20Sopenharmony_ci hs_ep->index = epnum; 47518c2ecf20Sopenharmony_ci 47528c2ecf20Sopenharmony_ci snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); 47538c2ecf20Sopenharmony_ci 47548c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hs_ep->queue); 47558c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hs_ep->ep.ep_list); 47568c2ecf20Sopenharmony_ci 47578c2ecf20Sopenharmony_ci /* add to the list of endpoints known by the gadget driver */ 47588c2ecf20Sopenharmony_ci if (epnum) 47598c2ecf20Sopenharmony_ci list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); 47608c2ecf20Sopenharmony_ci 47618c2ecf20Sopenharmony_ci hs_ep->parent = hsotg; 47628c2ecf20Sopenharmony_ci hs_ep->ep.name = hs_ep->name; 47638c2ecf20Sopenharmony_ci 47648c2ecf20Sopenharmony_ci if (hsotg->params.speed == DWC2_SPEED_PARAM_LOW) 47658c2ecf20Sopenharmony_ci usb_ep_set_maxpacket_limit(&hs_ep->ep, 8); 47668c2ecf20Sopenharmony_ci else 47678c2ecf20Sopenharmony_ci usb_ep_set_maxpacket_limit(&hs_ep->ep, 47688c2ecf20Sopenharmony_ci epnum ? 1024 : EP0_MPS_LIMIT); 47698c2ecf20Sopenharmony_ci hs_ep->ep.ops = &dwc2_hsotg_ep_ops; 47708c2ecf20Sopenharmony_ci 47718c2ecf20Sopenharmony_ci if (epnum == 0) { 47728c2ecf20Sopenharmony_ci hs_ep->ep.caps.type_control = true; 47738c2ecf20Sopenharmony_ci } else { 47748c2ecf20Sopenharmony_ci if (hsotg->params.speed != DWC2_SPEED_PARAM_LOW) { 47758c2ecf20Sopenharmony_ci hs_ep->ep.caps.type_iso = true; 47768c2ecf20Sopenharmony_ci hs_ep->ep.caps.type_bulk = true; 47778c2ecf20Sopenharmony_ci } 47788c2ecf20Sopenharmony_ci hs_ep->ep.caps.type_int = true; 47798c2ecf20Sopenharmony_ci } 47808c2ecf20Sopenharmony_ci 47818c2ecf20Sopenharmony_ci if (dir_in) 47828c2ecf20Sopenharmony_ci hs_ep->ep.caps.dir_in = true; 47838c2ecf20Sopenharmony_ci else 47848c2ecf20Sopenharmony_ci hs_ep->ep.caps.dir_out = true; 47858c2ecf20Sopenharmony_ci 47868c2ecf20Sopenharmony_ci /* 47878c2ecf20Sopenharmony_ci * if we're using dma, we need to set the next-endpoint pointer 47888c2ecf20Sopenharmony_ci * to be something valid. 47898c2ecf20Sopenharmony_ci */ 47908c2ecf20Sopenharmony_ci 47918c2ecf20Sopenharmony_ci if (using_dma(hsotg)) { 47928c2ecf20Sopenharmony_ci u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); 47938c2ecf20Sopenharmony_ci 47948c2ecf20Sopenharmony_ci if (dir_in) 47958c2ecf20Sopenharmony_ci dwc2_writel(hsotg, next, DIEPCTL(epnum)); 47968c2ecf20Sopenharmony_ci else 47978c2ecf20Sopenharmony_ci dwc2_writel(hsotg, next, DOEPCTL(epnum)); 47988c2ecf20Sopenharmony_ci } 47998c2ecf20Sopenharmony_ci} 48008c2ecf20Sopenharmony_ci 48018c2ecf20Sopenharmony_ci/** 48028c2ecf20Sopenharmony_ci * dwc2_hsotg_hw_cfg - read HW configuration registers 48038c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 48048c2ecf20Sopenharmony_ci * 48058c2ecf20Sopenharmony_ci * Read the USB core HW configuration registers 48068c2ecf20Sopenharmony_ci */ 48078c2ecf20Sopenharmony_cistatic int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) 48088c2ecf20Sopenharmony_ci{ 48098c2ecf20Sopenharmony_ci u32 cfg; 48108c2ecf20Sopenharmony_ci u32 ep_type; 48118c2ecf20Sopenharmony_ci u32 i; 48128c2ecf20Sopenharmony_ci 48138c2ecf20Sopenharmony_ci /* check hardware configuration */ 48148c2ecf20Sopenharmony_ci 48158c2ecf20Sopenharmony_ci hsotg->num_of_eps = hsotg->hw_params.num_dev_ep; 48168c2ecf20Sopenharmony_ci 48178c2ecf20Sopenharmony_ci /* Add ep0 */ 48188c2ecf20Sopenharmony_ci hsotg->num_of_eps++; 48198c2ecf20Sopenharmony_ci 48208c2ecf20Sopenharmony_ci hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, 48218c2ecf20Sopenharmony_ci sizeof(struct dwc2_hsotg_ep), 48228c2ecf20Sopenharmony_ci GFP_KERNEL); 48238c2ecf20Sopenharmony_ci if (!hsotg->eps_in[0]) 48248c2ecf20Sopenharmony_ci return -ENOMEM; 48258c2ecf20Sopenharmony_ci /* Same dwc2_hsotg_ep is used in both directions for ep0 */ 48268c2ecf20Sopenharmony_ci hsotg->eps_out[0] = hsotg->eps_in[0]; 48278c2ecf20Sopenharmony_ci 48288c2ecf20Sopenharmony_ci cfg = hsotg->hw_params.dev_ep_dirs; 48298c2ecf20Sopenharmony_ci for (i = 1, cfg >>= 2; i < hsotg->num_of_eps; i++, cfg >>= 2) { 48308c2ecf20Sopenharmony_ci ep_type = cfg & 3; 48318c2ecf20Sopenharmony_ci /* Direction in or both */ 48328c2ecf20Sopenharmony_ci if (!(ep_type & 2)) { 48338c2ecf20Sopenharmony_ci hsotg->eps_in[i] = devm_kzalloc(hsotg->dev, 48348c2ecf20Sopenharmony_ci sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 48358c2ecf20Sopenharmony_ci if (!hsotg->eps_in[i]) 48368c2ecf20Sopenharmony_ci return -ENOMEM; 48378c2ecf20Sopenharmony_ci } 48388c2ecf20Sopenharmony_ci /* Direction out or both */ 48398c2ecf20Sopenharmony_ci if (!(ep_type & 1)) { 48408c2ecf20Sopenharmony_ci hsotg->eps_out[i] = devm_kzalloc(hsotg->dev, 48418c2ecf20Sopenharmony_ci sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 48428c2ecf20Sopenharmony_ci if (!hsotg->eps_out[i]) 48438c2ecf20Sopenharmony_ci return -ENOMEM; 48448c2ecf20Sopenharmony_ci } 48458c2ecf20Sopenharmony_ci } 48468c2ecf20Sopenharmony_ci 48478c2ecf20Sopenharmony_ci hsotg->fifo_mem = hsotg->hw_params.total_fifo_size; 48488c2ecf20Sopenharmony_ci hsotg->dedicated_fifos = hsotg->hw_params.en_multiple_tx_fifo; 48498c2ecf20Sopenharmony_ci 48508c2ecf20Sopenharmony_ci dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n", 48518c2ecf20Sopenharmony_ci hsotg->num_of_eps, 48528c2ecf20Sopenharmony_ci hsotg->dedicated_fifos ? "dedicated" : "shared", 48538c2ecf20Sopenharmony_ci hsotg->fifo_mem); 48548c2ecf20Sopenharmony_ci return 0; 48558c2ecf20Sopenharmony_ci} 48568c2ecf20Sopenharmony_ci 48578c2ecf20Sopenharmony_ci/** 48588c2ecf20Sopenharmony_ci * dwc2_hsotg_dump - dump state of the udc 48598c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 48608c2ecf20Sopenharmony_ci * 48618c2ecf20Sopenharmony_ci */ 48628c2ecf20Sopenharmony_cistatic void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) 48638c2ecf20Sopenharmony_ci{ 48648c2ecf20Sopenharmony_ci#ifdef DEBUG 48658c2ecf20Sopenharmony_ci struct device *dev = hsotg->dev; 48668c2ecf20Sopenharmony_ci u32 val; 48678c2ecf20Sopenharmony_ci int idx; 48688c2ecf20Sopenharmony_ci 48698c2ecf20Sopenharmony_ci dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", 48708c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DCFG), dwc2_readl(hsotg, DCTL), 48718c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DIEPMSK)); 48728c2ecf20Sopenharmony_ci 48738c2ecf20Sopenharmony_ci dev_info(dev, "GAHBCFG=0x%08x, GHWCFG1=0x%08x\n", 48748c2ecf20Sopenharmony_ci dwc2_readl(hsotg, GAHBCFG), dwc2_readl(hsotg, GHWCFG1)); 48758c2ecf20Sopenharmony_ci 48768c2ecf20Sopenharmony_ci dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 48778c2ecf20Sopenharmony_ci dwc2_readl(hsotg, GRXFSIZ), dwc2_readl(hsotg, GNPTXFSIZ)); 48788c2ecf20Sopenharmony_ci 48798c2ecf20Sopenharmony_ci /* show periodic fifo settings */ 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ci for (idx = 1; idx < hsotg->num_of_eps; idx++) { 48828c2ecf20Sopenharmony_ci val = dwc2_readl(hsotg, DPTXFSIZN(idx)); 48838c2ecf20Sopenharmony_ci dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, 48848c2ecf20Sopenharmony_ci val >> FIFOSIZE_DEPTH_SHIFT, 48858c2ecf20Sopenharmony_ci val & FIFOSIZE_STARTADDR_MASK); 48868c2ecf20Sopenharmony_ci } 48878c2ecf20Sopenharmony_ci 48888c2ecf20Sopenharmony_ci for (idx = 0; idx < hsotg->num_of_eps; idx++) { 48898c2ecf20Sopenharmony_ci dev_info(dev, 48908c2ecf20Sopenharmony_ci "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, 48918c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DIEPCTL(idx)), 48928c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DIEPTSIZ(idx)), 48938c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DIEPDMA(idx))); 48948c2ecf20Sopenharmony_ci 48958c2ecf20Sopenharmony_ci val = dwc2_readl(hsotg, DOEPCTL(idx)); 48968c2ecf20Sopenharmony_ci dev_info(dev, 48978c2ecf20Sopenharmony_ci "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", 48988c2ecf20Sopenharmony_ci idx, dwc2_readl(hsotg, DOEPCTL(idx)), 48998c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DOEPTSIZ(idx)), 49008c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DOEPDMA(idx))); 49018c2ecf20Sopenharmony_ci } 49028c2ecf20Sopenharmony_ci 49038c2ecf20Sopenharmony_ci dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", 49048c2ecf20Sopenharmony_ci dwc2_readl(hsotg, DVBUSDIS), dwc2_readl(hsotg, DVBUSPULSE)); 49058c2ecf20Sopenharmony_ci#endif 49068c2ecf20Sopenharmony_ci} 49078c2ecf20Sopenharmony_ci 49088c2ecf20Sopenharmony_ci/** 49098c2ecf20Sopenharmony_ci * dwc2_gadget_init - init function for gadget 49108c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 49118c2ecf20Sopenharmony_ci * 49128c2ecf20Sopenharmony_ci */ 49138c2ecf20Sopenharmony_ciint dwc2_gadget_init(struct dwc2_hsotg *hsotg) 49148c2ecf20Sopenharmony_ci{ 49158c2ecf20Sopenharmony_ci struct device *dev = hsotg->dev; 49168c2ecf20Sopenharmony_ci int epnum; 49178c2ecf20Sopenharmony_ci int ret; 49188c2ecf20Sopenharmony_ci 49198c2ecf20Sopenharmony_ci /* Dump fifo information */ 49208c2ecf20Sopenharmony_ci dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n", 49218c2ecf20Sopenharmony_ci hsotg->params.g_np_tx_fifo_size); 49228c2ecf20Sopenharmony_ci dev_dbg(dev, "RXFIFO size: %d\n", hsotg->params.g_rx_fifo_size); 49238c2ecf20Sopenharmony_ci 49248c2ecf20Sopenharmony_ci hsotg->gadget.max_speed = USB_SPEED_HIGH; 49258c2ecf20Sopenharmony_ci hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; 49268c2ecf20Sopenharmony_ci hsotg->gadget.name = dev_name(dev); 49278c2ecf20Sopenharmony_ci hsotg->remote_wakeup_allowed = 0; 49288c2ecf20Sopenharmony_ci 49298c2ecf20Sopenharmony_ci if (hsotg->params.lpm) 49308c2ecf20Sopenharmony_ci hsotg->gadget.lpm_capable = true; 49318c2ecf20Sopenharmony_ci 49328c2ecf20Sopenharmony_ci if (hsotg->dr_mode == USB_DR_MODE_OTG) 49338c2ecf20Sopenharmony_ci hsotg->gadget.is_otg = 1; 49348c2ecf20Sopenharmony_ci else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 49358c2ecf20Sopenharmony_ci hsotg->op_state = OTG_STATE_B_PERIPHERAL; 49368c2ecf20Sopenharmony_ci 49378c2ecf20Sopenharmony_ci ret = dwc2_hsotg_hw_cfg(hsotg); 49388c2ecf20Sopenharmony_ci if (ret) { 49398c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret); 49408c2ecf20Sopenharmony_ci return ret; 49418c2ecf20Sopenharmony_ci } 49428c2ecf20Sopenharmony_ci 49438c2ecf20Sopenharmony_ci hsotg->ctrl_buff = devm_kzalloc(hsotg->dev, 49448c2ecf20Sopenharmony_ci DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 49458c2ecf20Sopenharmony_ci if (!hsotg->ctrl_buff) 49468c2ecf20Sopenharmony_ci return -ENOMEM; 49478c2ecf20Sopenharmony_ci 49488c2ecf20Sopenharmony_ci hsotg->ep0_buff = devm_kzalloc(hsotg->dev, 49498c2ecf20Sopenharmony_ci DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 49508c2ecf20Sopenharmony_ci if (!hsotg->ep0_buff) 49518c2ecf20Sopenharmony_ci return -ENOMEM; 49528c2ecf20Sopenharmony_ci 49538c2ecf20Sopenharmony_ci if (using_desc_dma(hsotg)) { 49548c2ecf20Sopenharmony_ci ret = dwc2_gadget_alloc_ctrl_desc_chains(hsotg); 49558c2ecf20Sopenharmony_ci if (ret < 0) 49568c2ecf20Sopenharmony_ci return ret; 49578c2ecf20Sopenharmony_ci } 49588c2ecf20Sopenharmony_ci 49598c2ecf20Sopenharmony_ci ret = devm_request_irq(hsotg->dev, hsotg->irq, dwc2_hsotg_irq, 49608c2ecf20Sopenharmony_ci IRQF_SHARED, dev_name(hsotg->dev), hsotg); 49618c2ecf20Sopenharmony_ci if (ret < 0) { 49628c2ecf20Sopenharmony_ci dev_err(dev, "cannot claim IRQ for gadget\n"); 49638c2ecf20Sopenharmony_ci return ret; 49648c2ecf20Sopenharmony_ci } 49658c2ecf20Sopenharmony_ci 49668c2ecf20Sopenharmony_ci /* hsotg->num_of_eps holds number of EPs other than ep0 */ 49678c2ecf20Sopenharmony_ci 49688c2ecf20Sopenharmony_ci if (hsotg->num_of_eps == 0) { 49698c2ecf20Sopenharmony_ci dev_err(dev, "wrong number of EPs (zero)\n"); 49708c2ecf20Sopenharmony_ci return -EINVAL; 49718c2ecf20Sopenharmony_ci } 49728c2ecf20Sopenharmony_ci 49738c2ecf20Sopenharmony_ci /* setup endpoint information */ 49748c2ecf20Sopenharmony_ci 49758c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hsotg->gadget.ep_list); 49768c2ecf20Sopenharmony_ci hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep; 49778c2ecf20Sopenharmony_ci 49788c2ecf20Sopenharmony_ci /* allocate EP0 request */ 49798c2ecf20Sopenharmony_ci 49808c2ecf20Sopenharmony_ci hsotg->ctrl_req = dwc2_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep, 49818c2ecf20Sopenharmony_ci GFP_KERNEL); 49828c2ecf20Sopenharmony_ci if (!hsotg->ctrl_req) { 49838c2ecf20Sopenharmony_ci dev_err(dev, "failed to allocate ctrl req\n"); 49848c2ecf20Sopenharmony_ci return -ENOMEM; 49858c2ecf20Sopenharmony_ci } 49868c2ecf20Sopenharmony_ci 49878c2ecf20Sopenharmony_ci /* initialise the endpoints now the core has been initialised */ 49888c2ecf20Sopenharmony_ci for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) { 49898c2ecf20Sopenharmony_ci if (hsotg->eps_in[epnum]) 49908c2ecf20Sopenharmony_ci dwc2_hsotg_initep(hsotg, hsotg->eps_in[epnum], 49918c2ecf20Sopenharmony_ci epnum, 1); 49928c2ecf20Sopenharmony_ci if (hsotg->eps_out[epnum]) 49938c2ecf20Sopenharmony_ci dwc2_hsotg_initep(hsotg, hsotg->eps_out[epnum], 49948c2ecf20Sopenharmony_ci epnum, 0); 49958c2ecf20Sopenharmony_ci } 49968c2ecf20Sopenharmony_ci 49978c2ecf20Sopenharmony_ci dwc2_hsotg_dump(hsotg); 49988c2ecf20Sopenharmony_ci 49998c2ecf20Sopenharmony_ci return 0; 50008c2ecf20Sopenharmony_ci} 50018c2ecf20Sopenharmony_ci 50028c2ecf20Sopenharmony_ci/** 50038c2ecf20Sopenharmony_ci * dwc2_hsotg_remove - remove function for hsotg driver 50048c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 50058c2ecf20Sopenharmony_ci * 50068c2ecf20Sopenharmony_ci */ 50078c2ecf20Sopenharmony_ciint dwc2_hsotg_remove(struct dwc2_hsotg *hsotg) 50088c2ecf20Sopenharmony_ci{ 50098c2ecf20Sopenharmony_ci usb_del_gadget_udc(&hsotg->gadget); 50108c2ecf20Sopenharmony_ci dwc2_hsotg_ep_free_request(&hsotg->eps_out[0]->ep, hsotg->ctrl_req); 50118c2ecf20Sopenharmony_ci 50128c2ecf20Sopenharmony_ci return 0; 50138c2ecf20Sopenharmony_ci} 50148c2ecf20Sopenharmony_ci 50158c2ecf20Sopenharmony_ciint dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) 50168c2ecf20Sopenharmony_ci{ 50178c2ecf20Sopenharmony_ci unsigned long flags; 50188c2ecf20Sopenharmony_ci 50198c2ecf20Sopenharmony_ci if (hsotg->lx_state != DWC2_L0) 50208c2ecf20Sopenharmony_ci return 0; 50218c2ecf20Sopenharmony_ci 50228c2ecf20Sopenharmony_ci if (hsotg->driver) { 50238c2ecf20Sopenharmony_ci int ep; 50248c2ecf20Sopenharmony_ci 50258c2ecf20Sopenharmony_ci dev_info(hsotg->dev, "suspending usb gadget %s\n", 50268c2ecf20Sopenharmony_ci hsotg->driver->driver.name); 50278c2ecf20Sopenharmony_ci 50288c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 50298c2ecf20Sopenharmony_ci if (hsotg->enabled) 50308c2ecf20Sopenharmony_ci dwc2_hsotg_core_disconnect(hsotg); 50318c2ecf20Sopenharmony_ci dwc2_hsotg_disconnect(hsotg); 50328c2ecf20Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_UNKNOWN; 50338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 50348c2ecf20Sopenharmony_ci 50358c2ecf20Sopenharmony_ci for (ep = 1; ep < hsotg->num_of_eps; ep++) { 50368c2ecf20Sopenharmony_ci if (hsotg->eps_in[ep]) 50378c2ecf20Sopenharmony_ci dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); 50388c2ecf20Sopenharmony_ci if (hsotg->eps_out[ep]) 50398c2ecf20Sopenharmony_ci dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); 50408c2ecf20Sopenharmony_ci } 50418c2ecf20Sopenharmony_ci } 50428c2ecf20Sopenharmony_ci 50438c2ecf20Sopenharmony_ci return 0; 50448c2ecf20Sopenharmony_ci} 50458c2ecf20Sopenharmony_ci 50468c2ecf20Sopenharmony_ciint dwc2_hsotg_resume(struct dwc2_hsotg *hsotg) 50478c2ecf20Sopenharmony_ci{ 50488c2ecf20Sopenharmony_ci unsigned long flags; 50498c2ecf20Sopenharmony_ci 50508c2ecf20Sopenharmony_ci if (hsotg->lx_state == DWC2_L2) 50518c2ecf20Sopenharmony_ci return 0; 50528c2ecf20Sopenharmony_ci 50538c2ecf20Sopenharmony_ci if (hsotg->driver) { 50548c2ecf20Sopenharmony_ci dev_info(hsotg->dev, "resuming usb gadget %s\n", 50558c2ecf20Sopenharmony_ci hsotg->driver->driver.name); 50568c2ecf20Sopenharmony_ci 50578c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 50588c2ecf20Sopenharmony_ci dwc2_hsotg_core_init_disconnected(hsotg, false); 50598c2ecf20Sopenharmony_ci if (hsotg->enabled) { 50608c2ecf20Sopenharmony_ci /* Enable ACG feature in device mode,if supported */ 50618c2ecf20Sopenharmony_ci dwc2_enable_acg(hsotg); 50628c2ecf20Sopenharmony_ci dwc2_hsotg_core_connect(hsotg); 50638c2ecf20Sopenharmony_ci } 50648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 50658c2ecf20Sopenharmony_ci } 50668c2ecf20Sopenharmony_ci 50678c2ecf20Sopenharmony_ci return 0; 50688c2ecf20Sopenharmony_ci} 50698c2ecf20Sopenharmony_ci 50708c2ecf20Sopenharmony_ci/** 50718c2ecf20Sopenharmony_ci * dwc2_backup_device_registers() - Backup controller device registers. 50728c2ecf20Sopenharmony_ci * When suspending usb bus, registers needs to be backuped 50738c2ecf20Sopenharmony_ci * if controller power is disabled once suspended. 50748c2ecf20Sopenharmony_ci * 50758c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 50768c2ecf20Sopenharmony_ci */ 50778c2ecf20Sopenharmony_ciint dwc2_backup_device_registers(struct dwc2_hsotg *hsotg) 50788c2ecf20Sopenharmony_ci{ 50798c2ecf20Sopenharmony_ci struct dwc2_dregs_backup *dr; 50808c2ecf20Sopenharmony_ci int i; 50818c2ecf20Sopenharmony_ci 50828c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s\n", __func__); 50838c2ecf20Sopenharmony_ci 50848c2ecf20Sopenharmony_ci /* Backup dev regs */ 50858c2ecf20Sopenharmony_ci dr = &hsotg->dr_backup; 50868c2ecf20Sopenharmony_ci 50878c2ecf20Sopenharmony_ci dr->dcfg = dwc2_readl(hsotg, DCFG); 50888c2ecf20Sopenharmony_ci dr->dctl = dwc2_readl(hsotg, DCTL); 50898c2ecf20Sopenharmony_ci dr->daintmsk = dwc2_readl(hsotg, DAINTMSK); 50908c2ecf20Sopenharmony_ci dr->diepmsk = dwc2_readl(hsotg, DIEPMSK); 50918c2ecf20Sopenharmony_ci dr->doepmsk = dwc2_readl(hsotg, DOEPMSK); 50928c2ecf20Sopenharmony_ci 50938c2ecf20Sopenharmony_ci for (i = 0; i < hsotg->num_of_eps; i++) { 50948c2ecf20Sopenharmony_ci /* Backup IN EPs */ 50958c2ecf20Sopenharmony_ci dr->diepctl[i] = dwc2_readl(hsotg, DIEPCTL(i)); 50968c2ecf20Sopenharmony_ci 50978c2ecf20Sopenharmony_ci /* Ensure DATA PID is correctly configured */ 50988c2ecf20Sopenharmony_ci if (dr->diepctl[i] & DXEPCTL_DPID) 50998c2ecf20Sopenharmony_ci dr->diepctl[i] |= DXEPCTL_SETD1PID; 51008c2ecf20Sopenharmony_ci else 51018c2ecf20Sopenharmony_ci dr->diepctl[i] |= DXEPCTL_SETD0PID; 51028c2ecf20Sopenharmony_ci 51038c2ecf20Sopenharmony_ci dr->dieptsiz[i] = dwc2_readl(hsotg, DIEPTSIZ(i)); 51048c2ecf20Sopenharmony_ci dr->diepdma[i] = dwc2_readl(hsotg, DIEPDMA(i)); 51058c2ecf20Sopenharmony_ci 51068c2ecf20Sopenharmony_ci /* Backup OUT EPs */ 51078c2ecf20Sopenharmony_ci dr->doepctl[i] = dwc2_readl(hsotg, DOEPCTL(i)); 51088c2ecf20Sopenharmony_ci 51098c2ecf20Sopenharmony_ci /* Ensure DATA PID is correctly configured */ 51108c2ecf20Sopenharmony_ci if (dr->doepctl[i] & DXEPCTL_DPID) 51118c2ecf20Sopenharmony_ci dr->doepctl[i] |= DXEPCTL_SETD1PID; 51128c2ecf20Sopenharmony_ci else 51138c2ecf20Sopenharmony_ci dr->doepctl[i] |= DXEPCTL_SETD0PID; 51148c2ecf20Sopenharmony_ci 51158c2ecf20Sopenharmony_ci dr->doeptsiz[i] = dwc2_readl(hsotg, DOEPTSIZ(i)); 51168c2ecf20Sopenharmony_ci dr->doepdma[i] = dwc2_readl(hsotg, DOEPDMA(i)); 51178c2ecf20Sopenharmony_ci dr->dtxfsiz[i] = dwc2_readl(hsotg, DPTXFSIZN(i)); 51188c2ecf20Sopenharmony_ci } 51198c2ecf20Sopenharmony_ci dr->valid = true; 51208c2ecf20Sopenharmony_ci return 0; 51218c2ecf20Sopenharmony_ci} 51228c2ecf20Sopenharmony_ci 51238c2ecf20Sopenharmony_ci/** 51248c2ecf20Sopenharmony_ci * dwc2_restore_device_registers() - Restore controller device registers. 51258c2ecf20Sopenharmony_ci * When resuming usb bus, device registers needs to be restored 51268c2ecf20Sopenharmony_ci * if controller power were disabled. 51278c2ecf20Sopenharmony_ci * 51288c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 51298c2ecf20Sopenharmony_ci * @remote_wakeup: Indicates whether resume is initiated by Device or Host. 51308c2ecf20Sopenharmony_ci * 51318c2ecf20Sopenharmony_ci * Return: 0 if successful, negative error code otherwise 51328c2ecf20Sopenharmony_ci */ 51338c2ecf20Sopenharmony_ciint dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup) 51348c2ecf20Sopenharmony_ci{ 51358c2ecf20Sopenharmony_ci struct dwc2_dregs_backup *dr; 51368c2ecf20Sopenharmony_ci int i; 51378c2ecf20Sopenharmony_ci 51388c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s\n", __func__); 51398c2ecf20Sopenharmony_ci 51408c2ecf20Sopenharmony_ci /* Restore dev regs */ 51418c2ecf20Sopenharmony_ci dr = &hsotg->dr_backup; 51428c2ecf20Sopenharmony_ci if (!dr->valid) { 51438c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: no device registers to restore\n", 51448c2ecf20Sopenharmony_ci __func__); 51458c2ecf20Sopenharmony_ci return -EINVAL; 51468c2ecf20Sopenharmony_ci } 51478c2ecf20Sopenharmony_ci dr->valid = false; 51488c2ecf20Sopenharmony_ci 51498c2ecf20Sopenharmony_ci if (!remote_wakeup) 51508c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->dctl, DCTL); 51518c2ecf20Sopenharmony_ci 51528c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->daintmsk, DAINTMSK); 51538c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->diepmsk, DIEPMSK); 51548c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->doepmsk, DOEPMSK); 51558c2ecf20Sopenharmony_ci 51568c2ecf20Sopenharmony_ci for (i = 0; i < hsotg->num_of_eps; i++) { 51578c2ecf20Sopenharmony_ci /* Restore IN EPs */ 51588c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->dieptsiz[i], DIEPTSIZ(i)); 51598c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->diepdma[i], DIEPDMA(i)); 51608c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->doeptsiz[i], DOEPTSIZ(i)); 51618c2ecf20Sopenharmony_ci /** WA for enabled EPx's IN in DDMA mode. On entering to 51628c2ecf20Sopenharmony_ci * hibernation wrong value read and saved from DIEPDMAx, 51638c2ecf20Sopenharmony_ci * as result BNA interrupt asserted on hibernation exit 51648c2ecf20Sopenharmony_ci * by restoring from saved area. 51658c2ecf20Sopenharmony_ci */ 51668c2ecf20Sopenharmony_ci if (hsotg->params.g_dma_desc && 51678c2ecf20Sopenharmony_ci (dr->diepctl[i] & DXEPCTL_EPENA)) 51688c2ecf20Sopenharmony_ci dr->diepdma[i] = hsotg->eps_in[i]->desc_list_dma; 51698c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->dtxfsiz[i], DPTXFSIZN(i)); 51708c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->diepctl[i], DIEPCTL(i)); 51718c2ecf20Sopenharmony_ci /* Restore OUT EPs */ 51728c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->doeptsiz[i], DOEPTSIZ(i)); 51738c2ecf20Sopenharmony_ci /* WA for enabled EPx's OUT in DDMA mode. On entering to 51748c2ecf20Sopenharmony_ci * hibernation wrong value read and saved from DOEPDMAx, 51758c2ecf20Sopenharmony_ci * as result BNA interrupt asserted on hibernation exit 51768c2ecf20Sopenharmony_ci * by restoring from saved area. 51778c2ecf20Sopenharmony_ci */ 51788c2ecf20Sopenharmony_ci if (hsotg->params.g_dma_desc && 51798c2ecf20Sopenharmony_ci (dr->doepctl[i] & DXEPCTL_EPENA)) 51808c2ecf20Sopenharmony_ci dr->doepdma[i] = hsotg->eps_out[i]->desc_list_dma; 51818c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->doepdma[i], DOEPDMA(i)); 51828c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->doepctl[i], DOEPCTL(i)); 51838c2ecf20Sopenharmony_ci } 51848c2ecf20Sopenharmony_ci 51858c2ecf20Sopenharmony_ci return 0; 51868c2ecf20Sopenharmony_ci} 51878c2ecf20Sopenharmony_ci 51888c2ecf20Sopenharmony_ci/** 51898c2ecf20Sopenharmony_ci * dwc2_gadget_init_lpm - Configure the core to support LPM in device mode 51908c2ecf20Sopenharmony_ci * 51918c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 51928c2ecf20Sopenharmony_ci * 51938c2ecf20Sopenharmony_ci */ 51948c2ecf20Sopenharmony_civoid dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) 51958c2ecf20Sopenharmony_ci{ 51968c2ecf20Sopenharmony_ci u32 val; 51978c2ecf20Sopenharmony_ci 51988c2ecf20Sopenharmony_ci if (!hsotg->params.lpm) 51998c2ecf20Sopenharmony_ci return; 52008c2ecf20Sopenharmony_ci 52018c2ecf20Sopenharmony_ci val = GLPMCFG_LPMCAP | GLPMCFG_APPL1RES; 52028c2ecf20Sopenharmony_ci val |= hsotg->params.hird_threshold_en ? GLPMCFG_HIRD_THRES_EN : 0; 52038c2ecf20Sopenharmony_ci val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0; 52048c2ecf20Sopenharmony_ci val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT; 52058c2ecf20Sopenharmony_ci val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; 52068c2ecf20Sopenharmony_ci val |= GLPMCFG_LPM_REJECT_CTRL_CONTROL; 52078c2ecf20Sopenharmony_ci val |= GLPMCFG_LPM_ACCEPT_CTRL_ISOC; 52088c2ecf20Sopenharmony_ci dwc2_writel(hsotg, val, GLPMCFG); 52098c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG)); 52108c2ecf20Sopenharmony_ci 52118c2ecf20Sopenharmony_ci /* Unmask WKUP_ALERT Interrupt */ 52128c2ecf20Sopenharmony_ci if (hsotg->params.service_interval) 52138c2ecf20Sopenharmony_ci dwc2_set_bit(hsotg, GINTMSK2, GINTMSK2_WKUP_ALERT_INT_MSK); 52148c2ecf20Sopenharmony_ci} 52158c2ecf20Sopenharmony_ci 52168c2ecf20Sopenharmony_ci/** 52178c2ecf20Sopenharmony_ci * dwc2_gadget_program_ref_clk - Program GREFCLK register in device mode 52188c2ecf20Sopenharmony_ci * 52198c2ecf20Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 52208c2ecf20Sopenharmony_ci * 52218c2ecf20Sopenharmony_ci */ 52228c2ecf20Sopenharmony_civoid dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) 52238c2ecf20Sopenharmony_ci{ 52248c2ecf20Sopenharmony_ci u32 val = 0; 52258c2ecf20Sopenharmony_ci 52268c2ecf20Sopenharmony_ci val |= GREFCLK_REF_CLK_MODE; 52278c2ecf20Sopenharmony_ci val |= hsotg->params.ref_clk_per << GREFCLK_REFCLKPER_SHIFT; 52288c2ecf20Sopenharmony_ci val |= hsotg->params.sof_cnt_wkup_alert << 52298c2ecf20Sopenharmony_ci GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT; 52308c2ecf20Sopenharmony_ci 52318c2ecf20Sopenharmony_ci dwc2_writel(hsotg, val, GREFCLK); 52328c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "GREFCLK=0x%08x\n", dwc2_readl(hsotg, GREFCLK)); 52338c2ecf20Sopenharmony_ci} 52348c2ecf20Sopenharmony_ci 52358c2ecf20Sopenharmony_ci/** 52368c2ecf20Sopenharmony_ci * dwc2_gadget_enter_hibernation() - Put controller in Hibernation. 52378c2ecf20Sopenharmony_ci * 52388c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 52398c2ecf20Sopenharmony_ci * 52408c2ecf20Sopenharmony_ci * Return non-zero if failed to enter to hibernation. 52418c2ecf20Sopenharmony_ci */ 52428c2ecf20Sopenharmony_ciint dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg) 52438c2ecf20Sopenharmony_ci{ 52448c2ecf20Sopenharmony_ci u32 gpwrdn; 52458c2ecf20Sopenharmony_ci int ret = 0; 52468c2ecf20Sopenharmony_ci 52478c2ecf20Sopenharmony_ci /* Change to L2(suspend) state */ 52488c2ecf20Sopenharmony_ci hsotg->lx_state = DWC2_L2; 52498c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Start of hibernation completed\n"); 52508c2ecf20Sopenharmony_ci ret = dwc2_backup_global_registers(hsotg); 52518c2ecf20Sopenharmony_ci if (ret) { 52528c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to backup global registers\n", 52538c2ecf20Sopenharmony_ci __func__); 52548c2ecf20Sopenharmony_ci return ret; 52558c2ecf20Sopenharmony_ci } 52568c2ecf20Sopenharmony_ci ret = dwc2_backup_device_registers(hsotg); 52578c2ecf20Sopenharmony_ci if (ret) { 52588c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to backup device registers\n", 52598c2ecf20Sopenharmony_ci __func__); 52608c2ecf20Sopenharmony_ci return ret; 52618c2ecf20Sopenharmony_ci } 52628c2ecf20Sopenharmony_ci 52638c2ecf20Sopenharmony_ci gpwrdn = GPWRDN_PWRDNRSTN; 52648c2ecf20Sopenharmony_ci gpwrdn |= GPWRDN_PMUACTV; 52658c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 52668c2ecf20Sopenharmony_ci udelay(10); 52678c2ecf20Sopenharmony_ci 52688c2ecf20Sopenharmony_ci /* Set flag to indicate that we are in hibernation */ 52698c2ecf20Sopenharmony_ci hsotg->hibernated = 1; 52708c2ecf20Sopenharmony_ci 52718c2ecf20Sopenharmony_ci /* Enable interrupts from wake up logic */ 52728c2ecf20Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 52738c2ecf20Sopenharmony_ci gpwrdn |= GPWRDN_PMUINTSEL; 52748c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 52758c2ecf20Sopenharmony_ci udelay(10); 52768c2ecf20Sopenharmony_ci 52778c2ecf20Sopenharmony_ci /* Unmask device mode interrupts in GPWRDN */ 52788c2ecf20Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 52798c2ecf20Sopenharmony_ci gpwrdn |= GPWRDN_RST_DET_MSK; 52808c2ecf20Sopenharmony_ci gpwrdn |= GPWRDN_LNSTSCHG_MSK; 52818c2ecf20Sopenharmony_ci gpwrdn |= GPWRDN_STS_CHGINT_MSK; 52828c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 52838c2ecf20Sopenharmony_ci udelay(10); 52848c2ecf20Sopenharmony_ci 52858c2ecf20Sopenharmony_ci /* Enable Power Down Clamp */ 52868c2ecf20Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 52878c2ecf20Sopenharmony_ci gpwrdn |= GPWRDN_PWRDNCLMP; 52888c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 52898c2ecf20Sopenharmony_ci udelay(10); 52908c2ecf20Sopenharmony_ci 52918c2ecf20Sopenharmony_ci /* Switch off VDD */ 52928c2ecf20Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 52938c2ecf20Sopenharmony_ci gpwrdn |= GPWRDN_PWRDNSWTCH; 52948c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 52958c2ecf20Sopenharmony_ci udelay(10); 52968c2ecf20Sopenharmony_ci 52978c2ecf20Sopenharmony_ci /* Save gpwrdn register for further usage if stschng interrupt */ 52988c2ecf20Sopenharmony_ci hsotg->gr_backup.gpwrdn = dwc2_readl(hsotg, GPWRDN); 52998c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Hibernation completed\n"); 53008c2ecf20Sopenharmony_ci 53018c2ecf20Sopenharmony_ci return ret; 53028c2ecf20Sopenharmony_ci} 53038c2ecf20Sopenharmony_ci 53048c2ecf20Sopenharmony_ci/** 53058c2ecf20Sopenharmony_ci * dwc2_gadget_exit_hibernation() 53068c2ecf20Sopenharmony_ci * This function is for exiting from Device mode hibernation by host initiated 53078c2ecf20Sopenharmony_ci * resume/reset and device initiated remote-wakeup. 53088c2ecf20Sopenharmony_ci * 53098c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 53108c2ecf20Sopenharmony_ci * @rem_wakeup: indicates whether resume is initiated by Device or Host. 53118c2ecf20Sopenharmony_ci * @reset: indicates whether resume is initiated by Reset. 53128c2ecf20Sopenharmony_ci * 53138c2ecf20Sopenharmony_ci * Return non-zero if failed to exit from hibernation. 53148c2ecf20Sopenharmony_ci */ 53158c2ecf20Sopenharmony_ciint dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, 53168c2ecf20Sopenharmony_ci int rem_wakeup, int reset) 53178c2ecf20Sopenharmony_ci{ 53188c2ecf20Sopenharmony_ci u32 pcgcctl; 53198c2ecf20Sopenharmony_ci u32 gpwrdn; 53208c2ecf20Sopenharmony_ci u32 dctl; 53218c2ecf20Sopenharmony_ci int ret = 0; 53228c2ecf20Sopenharmony_ci struct dwc2_gregs_backup *gr; 53238c2ecf20Sopenharmony_ci struct dwc2_dregs_backup *dr; 53248c2ecf20Sopenharmony_ci 53258c2ecf20Sopenharmony_ci gr = &hsotg->gr_backup; 53268c2ecf20Sopenharmony_ci dr = &hsotg->dr_backup; 53278c2ecf20Sopenharmony_ci 53288c2ecf20Sopenharmony_ci if (!hsotg->hibernated) { 53298c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Already exited from Hibernation\n"); 53308c2ecf20Sopenharmony_ci return 1; 53318c2ecf20Sopenharmony_ci } 53328c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 53338c2ecf20Sopenharmony_ci "%s: called with rem_wakeup = %d reset = %d\n", 53348c2ecf20Sopenharmony_ci __func__, rem_wakeup, reset); 53358c2ecf20Sopenharmony_ci 53368c2ecf20Sopenharmony_ci dwc2_hib_restore_common(hsotg, rem_wakeup, 0); 53378c2ecf20Sopenharmony_ci 53388c2ecf20Sopenharmony_ci if (!reset) { 53398c2ecf20Sopenharmony_ci /* Clear all pending interupts */ 53408c2ecf20Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GINTSTS); 53418c2ecf20Sopenharmony_ci } 53428c2ecf20Sopenharmony_ci 53438c2ecf20Sopenharmony_ci /* De-assert Restore */ 53448c2ecf20Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 53458c2ecf20Sopenharmony_ci gpwrdn &= ~GPWRDN_RESTORE; 53468c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 53478c2ecf20Sopenharmony_ci udelay(10); 53488c2ecf20Sopenharmony_ci 53498c2ecf20Sopenharmony_ci if (!rem_wakeup) { 53508c2ecf20Sopenharmony_ci pcgcctl = dwc2_readl(hsotg, PCGCTL); 53518c2ecf20Sopenharmony_ci pcgcctl &= ~PCGCTL_RSTPDWNMODULE; 53528c2ecf20Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 53538c2ecf20Sopenharmony_ci } 53548c2ecf20Sopenharmony_ci 53558c2ecf20Sopenharmony_ci /* Restore GUSBCFG, DCFG and DCTL */ 53568c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); 53578c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->dcfg, DCFG); 53588c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->dctl, DCTL); 53598c2ecf20Sopenharmony_ci 53608c2ecf20Sopenharmony_ci /* De-assert Wakeup Logic */ 53618c2ecf20Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 53628c2ecf20Sopenharmony_ci gpwrdn &= ~GPWRDN_PMUACTV; 53638c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 53648c2ecf20Sopenharmony_ci 53658c2ecf20Sopenharmony_ci if (rem_wakeup) { 53668c2ecf20Sopenharmony_ci udelay(10); 53678c2ecf20Sopenharmony_ci /* Start Remote Wakeup Signaling */ 53688c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dr->dctl | DCTL_RMTWKUPSIG, DCTL); 53698c2ecf20Sopenharmony_ci } else { 53708c2ecf20Sopenharmony_ci udelay(50); 53718c2ecf20Sopenharmony_ci /* Set Device programming done bit */ 53728c2ecf20Sopenharmony_ci dctl = dwc2_readl(hsotg, DCTL); 53738c2ecf20Sopenharmony_ci dctl |= DCTL_PWRONPRGDONE; 53748c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dctl, DCTL); 53758c2ecf20Sopenharmony_ci } 53768c2ecf20Sopenharmony_ci /* Wait for interrupts which must be cleared */ 53778c2ecf20Sopenharmony_ci mdelay(2); 53788c2ecf20Sopenharmony_ci /* Clear all pending interupts */ 53798c2ecf20Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GINTSTS); 53808c2ecf20Sopenharmony_ci 53818c2ecf20Sopenharmony_ci /* Restore global registers */ 53828c2ecf20Sopenharmony_ci ret = dwc2_restore_global_registers(hsotg); 53838c2ecf20Sopenharmony_ci if (ret) { 53848c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to restore registers\n", 53858c2ecf20Sopenharmony_ci __func__); 53868c2ecf20Sopenharmony_ci return ret; 53878c2ecf20Sopenharmony_ci } 53888c2ecf20Sopenharmony_ci 53898c2ecf20Sopenharmony_ci /* Restore device registers */ 53908c2ecf20Sopenharmony_ci ret = dwc2_restore_device_registers(hsotg, rem_wakeup); 53918c2ecf20Sopenharmony_ci if (ret) { 53928c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to restore device registers\n", 53938c2ecf20Sopenharmony_ci __func__); 53948c2ecf20Sopenharmony_ci return ret; 53958c2ecf20Sopenharmony_ci } 53968c2ecf20Sopenharmony_ci 53978c2ecf20Sopenharmony_ci if (rem_wakeup) { 53988c2ecf20Sopenharmony_ci mdelay(10); 53998c2ecf20Sopenharmony_ci dctl = dwc2_readl(hsotg, DCTL); 54008c2ecf20Sopenharmony_ci dctl &= ~DCTL_RMTWKUPSIG; 54018c2ecf20Sopenharmony_ci dwc2_writel(hsotg, dctl, DCTL); 54028c2ecf20Sopenharmony_ci } 54038c2ecf20Sopenharmony_ci 54048c2ecf20Sopenharmony_ci hsotg->hibernated = 0; 54058c2ecf20Sopenharmony_ci hsotg->lx_state = DWC2_L0; 54068c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "Hibernation recovery completes here\n"); 54078c2ecf20Sopenharmony_ci 54088c2ecf20Sopenharmony_ci return ret; 54098c2ecf20Sopenharmony_ci} 5410