15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 26fb914d7SGrigor Tovmasyan /* 347a1685fSDinh Nguyen * Copyright (c) 2011 Samsung Electronics Co., Ltd. 447a1685fSDinh Nguyen * http://www.samsung.com 547a1685fSDinh Nguyen * 647a1685fSDinh Nguyen * Copyright 2008 Openmoko, Inc. 747a1685fSDinh Nguyen * Copyright 2008 Simtec Electronics 847a1685fSDinh Nguyen * Ben Dooks <ben@simtec.co.uk> 947a1685fSDinh Nguyen * http://armlinux.simtec.co.uk/ 1047a1685fSDinh Nguyen * 1147a1685fSDinh Nguyen * S3C USB2.0 High-speed / OtG driver 1247a1685fSDinh Nguyen */ 1347a1685fSDinh Nguyen 1447a1685fSDinh Nguyen #include <linux/kernel.h> 1547a1685fSDinh Nguyen #include <linux/module.h> 1647a1685fSDinh Nguyen #include <linux/spinlock.h> 1747a1685fSDinh Nguyen #include <linux/interrupt.h> 1847a1685fSDinh Nguyen #include <linux/platform_device.h> 1947a1685fSDinh Nguyen #include <linux/dma-mapping.h> 207ad8096eSMarek Szyprowski #include <linux/mutex.h> 2147a1685fSDinh Nguyen #include <linux/seq_file.h> 2247a1685fSDinh Nguyen #include <linux/delay.h> 2347a1685fSDinh Nguyen #include <linux/io.h> 2447a1685fSDinh Nguyen #include <linux/slab.h> 2547a1685fSDinh Nguyen #include <linux/of_platform.h> 2647a1685fSDinh Nguyen 2747a1685fSDinh Nguyen #include <linux/usb/ch9.h> 2847a1685fSDinh Nguyen #include <linux/usb/gadget.h> 2947a1685fSDinh Nguyen #include <linux/usb/phy.h> 30b4c53b4aSMinas Harutyunyan #include <linux/usb/composite.h> 31b4c53b4aSMinas Harutyunyan 3247a1685fSDinh Nguyen 33f7c0b143SDinh Nguyen #include "core.h" 34941fcce4SDinh Nguyen #include "hw.h" 3547a1685fSDinh Nguyen 3647a1685fSDinh Nguyen /* conversion functions */ 371f91b4ccSFelipe Balbi static inline struct dwc2_hsotg_req *our_req(struct usb_request *req) 3847a1685fSDinh Nguyen { 391f91b4ccSFelipe Balbi return container_of(req, struct dwc2_hsotg_req, req); 4047a1685fSDinh Nguyen } 4147a1685fSDinh Nguyen 421f91b4ccSFelipe Balbi static inline struct dwc2_hsotg_ep *our_ep(struct usb_ep *ep) 4347a1685fSDinh Nguyen { 441f91b4ccSFelipe Balbi return container_of(ep, struct dwc2_hsotg_ep, ep); 4547a1685fSDinh Nguyen } 4647a1685fSDinh Nguyen 47941fcce4SDinh Nguyen static inline struct dwc2_hsotg *to_hsotg(struct usb_gadget *gadget) 4847a1685fSDinh Nguyen { 49941fcce4SDinh Nguyen return container_of(gadget, struct dwc2_hsotg, gadget); 5047a1685fSDinh Nguyen } 5147a1685fSDinh Nguyen 52f25c42b8SGevorg Sahakyan static inline void dwc2_set_bit(struct dwc2_hsotg *hsotg, u32 offset, u32 val) 5347a1685fSDinh Nguyen { 54f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dwc2_readl(hsotg, offset) | val, offset); 5547a1685fSDinh Nguyen } 5647a1685fSDinh Nguyen 57f25c42b8SGevorg Sahakyan static inline void dwc2_clear_bit(struct dwc2_hsotg *hsotg, u32 offset, u32 val) 5847a1685fSDinh Nguyen { 59f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dwc2_readl(hsotg, offset) & ~val, offset); 6047a1685fSDinh Nguyen } 6147a1685fSDinh Nguyen 621f91b4ccSFelipe Balbi static inline struct dwc2_hsotg_ep *index_to_ep(struct dwc2_hsotg *hsotg, 63c6f5c050SMian Yousaf Kaukab u32 ep_index, u32 dir_in) 64c6f5c050SMian Yousaf Kaukab { 65c6f5c050SMian Yousaf Kaukab if (dir_in) 66c6f5c050SMian Yousaf Kaukab return hsotg->eps_in[ep_index]; 67c6f5c050SMian Yousaf Kaukab else 68c6f5c050SMian Yousaf Kaukab return hsotg->eps_out[ep_index]; 69c6f5c050SMian Yousaf Kaukab } 70c6f5c050SMian Yousaf Kaukab 71997f4f81SMickael Maison /* forward declaration of functions */ 721f91b4ccSFelipe Balbi static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg); 7347a1685fSDinh Nguyen 7447a1685fSDinh Nguyen /** 7547a1685fSDinh Nguyen * using_dma - return the DMA status of the driver. 7647a1685fSDinh Nguyen * @hsotg: The driver state. 7747a1685fSDinh Nguyen * 7847a1685fSDinh Nguyen * Return true if we're using DMA. 7947a1685fSDinh Nguyen * 8047a1685fSDinh Nguyen * Currently, we have the DMA support code worked into everywhere 8147a1685fSDinh Nguyen * that needs it, but the AMBA DMA implementation in the hardware can 8247a1685fSDinh Nguyen * only DMA from 32bit aligned addresses. This means that gadgets such 8347a1685fSDinh Nguyen * as the CDC Ethernet cannot work as they often pass packets which are 8447a1685fSDinh Nguyen * not 32bit aligned. 8547a1685fSDinh Nguyen * 8647a1685fSDinh Nguyen * Unfortunately the choice to use DMA or not is global to the controller 8747a1685fSDinh Nguyen * and seems to be only settable when the controller is being put through 8847a1685fSDinh Nguyen * a core reset. This means we either need to fix the gadgets to take 8947a1685fSDinh Nguyen * account of DMA alignment, or add bounce buffers (yuerk). 9047a1685fSDinh Nguyen * 91edd74be8SGregory Herrero * g_using_dma is set depending on dts flag. 9247a1685fSDinh Nguyen */ 93941fcce4SDinh Nguyen static inline bool using_dma(struct dwc2_hsotg *hsotg) 9447a1685fSDinh Nguyen { 9505ee799fSJohn Youn return hsotg->params.g_dma; 9647a1685fSDinh Nguyen } 9747a1685fSDinh Nguyen 98dec4b556SVahram Aharonyan /* 99dec4b556SVahram Aharonyan * using_desc_dma - return the descriptor DMA status of the driver. 100dec4b556SVahram Aharonyan * @hsotg: The driver state. 101dec4b556SVahram Aharonyan * 102dec4b556SVahram Aharonyan * Return true if we're using descriptor DMA. 103dec4b556SVahram Aharonyan */ 104dec4b556SVahram Aharonyan static inline bool using_desc_dma(struct dwc2_hsotg *hsotg) 105dec4b556SVahram Aharonyan { 106dec4b556SVahram Aharonyan return hsotg->params.g_dma_desc; 107dec4b556SVahram Aharonyan } 108dec4b556SVahram Aharonyan 10947a1685fSDinh Nguyen /** 11092d1635dSVardan Mikayelyan * dwc2_gadget_incr_frame_num - Increments the targeted frame number. 11192d1635dSVardan Mikayelyan * @hs_ep: The endpoint 11292d1635dSVardan Mikayelyan * 11392d1635dSVardan Mikayelyan * This function will also check if the frame number overruns DSTS_SOFFN_LIMIT. 11492d1635dSVardan Mikayelyan * If an overrun occurs it will wrap the value and set the frame_overrun flag. 11592d1635dSVardan Mikayelyan */ 11692d1635dSVardan Mikayelyan static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep) 11792d1635dSVardan Mikayelyan { 11892d1635dSVardan Mikayelyan hs_ep->target_frame += hs_ep->interval; 11992d1635dSVardan Mikayelyan if (hs_ep->target_frame > DSTS_SOFFN_LIMIT) { 120c1d5df69SGustavo A. R. Silva hs_ep->frame_overrun = true; 12192d1635dSVardan Mikayelyan hs_ep->target_frame &= DSTS_SOFFN_LIMIT; 12292d1635dSVardan Mikayelyan } else { 123c1d5df69SGustavo A. R. Silva hs_ep->frame_overrun = false; 12492d1635dSVardan Mikayelyan } 12592d1635dSVardan Mikayelyan } 12692d1635dSVardan Mikayelyan 12792d1635dSVardan Mikayelyan /** 1289d630b9cSGrigor Tovmasyan * dwc2_gadget_dec_frame_num_by_one - Decrements the targeted frame number 1299d630b9cSGrigor Tovmasyan * by one. 1309d630b9cSGrigor Tovmasyan * @hs_ep: The endpoint. 1319d630b9cSGrigor Tovmasyan * 1329d630b9cSGrigor Tovmasyan * This function used in service interval based scheduling flow to calculate 1339d630b9cSGrigor Tovmasyan * descriptor frame number filed value. For service interval mode frame 1349d630b9cSGrigor Tovmasyan * number in descriptor should point to last (u)frame in the interval. 1359d630b9cSGrigor Tovmasyan * 1369d630b9cSGrigor Tovmasyan */ 1379d630b9cSGrigor Tovmasyan static inline void dwc2_gadget_dec_frame_num_by_one(struct dwc2_hsotg_ep *hs_ep) 1389d630b9cSGrigor Tovmasyan { 1399d630b9cSGrigor Tovmasyan if (hs_ep->target_frame) 1409d630b9cSGrigor Tovmasyan hs_ep->target_frame -= 1; 1419d630b9cSGrigor Tovmasyan else 1429d630b9cSGrigor Tovmasyan hs_ep->target_frame = DSTS_SOFFN_LIMIT; 1439d630b9cSGrigor Tovmasyan } 1449d630b9cSGrigor Tovmasyan 1459d630b9cSGrigor Tovmasyan /** 1461f91b4ccSFelipe Balbi * dwc2_hsotg_en_gsint - enable one or more of the general interrupt 14747a1685fSDinh Nguyen * @hsotg: The device state 14847a1685fSDinh Nguyen * @ints: A bitmask of the interrupts to enable 14947a1685fSDinh Nguyen */ 1501f91b4ccSFelipe Balbi static void dwc2_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints) 15147a1685fSDinh Nguyen { 152f25c42b8SGevorg Sahakyan u32 gsintmsk = dwc2_readl(hsotg, GINTMSK); 15347a1685fSDinh Nguyen u32 new_gsintmsk; 15447a1685fSDinh Nguyen 15547a1685fSDinh Nguyen new_gsintmsk = gsintmsk | ints; 15647a1685fSDinh Nguyen 15747a1685fSDinh Nguyen if (new_gsintmsk != gsintmsk) { 15847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); 159f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, new_gsintmsk, GINTMSK); 16047a1685fSDinh Nguyen } 16147a1685fSDinh Nguyen } 16247a1685fSDinh Nguyen 16347a1685fSDinh Nguyen /** 1641f91b4ccSFelipe Balbi * dwc2_hsotg_disable_gsint - disable one or more of the general interrupt 16547a1685fSDinh Nguyen * @hsotg: The device state 16647a1685fSDinh Nguyen * @ints: A bitmask of the interrupts to enable 16747a1685fSDinh Nguyen */ 1681f91b4ccSFelipe Balbi static void dwc2_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints) 16947a1685fSDinh Nguyen { 170f25c42b8SGevorg Sahakyan u32 gsintmsk = dwc2_readl(hsotg, GINTMSK); 17147a1685fSDinh Nguyen u32 new_gsintmsk; 17247a1685fSDinh Nguyen 17347a1685fSDinh Nguyen new_gsintmsk = gsintmsk & ~ints; 17447a1685fSDinh Nguyen 17547a1685fSDinh Nguyen if (new_gsintmsk != gsintmsk) 176f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, new_gsintmsk, GINTMSK); 17747a1685fSDinh Nguyen } 17847a1685fSDinh Nguyen 17947a1685fSDinh Nguyen /** 1801f91b4ccSFelipe Balbi * dwc2_hsotg_ctrl_epint - enable/disable an endpoint irq 18147a1685fSDinh Nguyen * @hsotg: The device state 18247a1685fSDinh Nguyen * @ep: The endpoint index 18347a1685fSDinh Nguyen * @dir_in: True if direction is in. 18447a1685fSDinh Nguyen * @en: The enable value, true to enable 18547a1685fSDinh Nguyen * 18647a1685fSDinh Nguyen * Set or clear the mask for an individual endpoint's interrupt 18747a1685fSDinh Nguyen * request. 18847a1685fSDinh Nguyen */ 1891f91b4ccSFelipe Balbi static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, 19047a1685fSDinh Nguyen unsigned int ep, unsigned int dir_in, 19147a1685fSDinh Nguyen unsigned int en) 19247a1685fSDinh Nguyen { 19347a1685fSDinh Nguyen unsigned long flags; 19447a1685fSDinh Nguyen u32 bit = 1 << ep; 19547a1685fSDinh Nguyen u32 daint; 19647a1685fSDinh Nguyen 19747a1685fSDinh Nguyen if (!dir_in) 19847a1685fSDinh Nguyen bit <<= 16; 19947a1685fSDinh Nguyen 20047a1685fSDinh Nguyen local_irq_save(flags); 201f25c42b8SGevorg Sahakyan daint = dwc2_readl(hsotg, DAINTMSK); 20247a1685fSDinh Nguyen if (en) 20347a1685fSDinh Nguyen daint |= bit; 20447a1685fSDinh Nguyen else 20547a1685fSDinh Nguyen daint &= ~bit; 206f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, daint, DAINTMSK); 20747a1685fSDinh Nguyen local_irq_restore(flags); 20847a1685fSDinh Nguyen } 20947a1685fSDinh Nguyen 21047a1685fSDinh Nguyen /** 211c138ecfaSSevak Arakelyan * dwc2_hsotg_tx_fifo_count - return count of TX FIFOs in device mode 2126fb914d7SGrigor Tovmasyan * 2136fb914d7SGrigor Tovmasyan * @hsotg: Programming view of the DWC_otg controller 214c138ecfaSSevak Arakelyan */ 215c138ecfaSSevak Arakelyan int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) 216c138ecfaSSevak Arakelyan { 217c138ecfaSSevak Arakelyan if (hsotg->hw_params.en_multiple_tx_fifo) 218c138ecfaSSevak Arakelyan /* In dedicated FIFO mode we need count of IN EPs */ 2199273083aSMinas Harutyunyan return hsotg->hw_params.num_dev_in_eps; 220c138ecfaSSevak Arakelyan else 221c138ecfaSSevak Arakelyan /* In shared FIFO mode we need count of Periodic IN EPs */ 222c138ecfaSSevak Arakelyan return hsotg->hw_params.num_dev_perio_in_ep; 223c138ecfaSSevak Arakelyan } 224c138ecfaSSevak Arakelyan 225c138ecfaSSevak Arakelyan /** 226c138ecfaSSevak Arakelyan * dwc2_hsotg_tx_fifo_total_depth - return total FIFO depth available for 227c138ecfaSSevak Arakelyan * device mode TX FIFOs 2286fb914d7SGrigor Tovmasyan * 2296fb914d7SGrigor Tovmasyan * @hsotg: Programming view of the DWC_otg controller 230c138ecfaSSevak Arakelyan */ 231c138ecfaSSevak Arakelyan int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) 232c138ecfaSSevak Arakelyan { 233c138ecfaSSevak Arakelyan int addr; 234c138ecfaSSevak Arakelyan int tx_addr_max; 235c138ecfaSSevak Arakelyan u32 np_tx_fifo_size; 236c138ecfaSSevak Arakelyan 237c138ecfaSSevak Arakelyan np_tx_fifo_size = min_t(u32, hsotg->hw_params.dev_nperio_tx_fifo_size, 238c138ecfaSSevak Arakelyan hsotg->params.g_np_tx_fifo_size); 239c138ecfaSSevak Arakelyan 240c138ecfaSSevak Arakelyan /* Get Endpoint Info Control block size in DWORDs. */ 2419273083aSMinas Harutyunyan tx_addr_max = hsotg->hw_params.total_fifo_size; 242c138ecfaSSevak Arakelyan 243c138ecfaSSevak Arakelyan addr = hsotg->params.g_rx_fifo_size + np_tx_fifo_size; 244c138ecfaSSevak Arakelyan if (tx_addr_max <= addr) 245c138ecfaSSevak Arakelyan return 0; 246c138ecfaSSevak Arakelyan 247c138ecfaSSevak Arakelyan return tx_addr_max - addr; 248c138ecfaSSevak Arakelyan } 249c138ecfaSSevak Arakelyan 250c138ecfaSSevak Arakelyan /** 251187c5298SGrigor Tovmasyan * dwc2_gadget_wkup_alert_handler - Handler for WKUP_ALERT interrupt 252187c5298SGrigor Tovmasyan * 253187c5298SGrigor Tovmasyan * @hsotg: Programming view of the DWC_otg controller 254187c5298SGrigor Tovmasyan * 255187c5298SGrigor Tovmasyan */ 256187c5298SGrigor Tovmasyan static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg) 257187c5298SGrigor Tovmasyan { 258187c5298SGrigor Tovmasyan u32 gintsts2; 259187c5298SGrigor Tovmasyan u32 gintmsk2; 260187c5298SGrigor Tovmasyan 261187c5298SGrigor Tovmasyan gintsts2 = dwc2_readl(hsotg, GINTSTS2); 262187c5298SGrigor Tovmasyan gintmsk2 = dwc2_readl(hsotg, GINTMSK2); 263187c5298SGrigor Tovmasyan 264187c5298SGrigor Tovmasyan if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) { 265187c5298SGrigor Tovmasyan dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__); 26687b6d2c5SMinas Harutyunyan dwc2_set_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT); 267d64bc8eeSArtur Petrosyan dwc2_set_bit(hsotg, DCTL, DCTL_RMTWKUPSIG); 268187c5298SGrigor Tovmasyan } 269187c5298SGrigor Tovmasyan } 270187c5298SGrigor Tovmasyan 271187c5298SGrigor Tovmasyan /** 272c138ecfaSSevak Arakelyan * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode 273c138ecfaSSevak Arakelyan * TX FIFOs 2746fb914d7SGrigor Tovmasyan * 2756fb914d7SGrigor Tovmasyan * @hsotg: Programming view of the DWC_otg controller 276c138ecfaSSevak Arakelyan */ 277c138ecfaSSevak Arakelyan int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) 278c138ecfaSSevak Arakelyan { 279c138ecfaSSevak Arakelyan int tx_fifo_count; 280c138ecfaSSevak Arakelyan int tx_fifo_depth; 281c138ecfaSSevak Arakelyan 282c138ecfaSSevak Arakelyan tx_fifo_depth = dwc2_hsotg_tx_fifo_total_depth(hsotg); 283c138ecfaSSevak Arakelyan 284c138ecfaSSevak Arakelyan tx_fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); 285c138ecfaSSevak Arakelyan 286c138ecfaSSevak Arakelyan if (!tx_fifo_count) 287c138ecfaSSevak Arakelyan return tx_fifo_depth; 288c138ecfaSSevak Arakelyan else 289c138ecfaSSevak Arakelyan return tx_fifo_depth / tx_fifo_count; 290c138ecfaSSevak Arakelyan } 291c138ecfaSSevak Arakelyan 292c138ecfaSSevak Arakelyan /** 2931f91b4ccSFelipe Balbi * dwc2_hsotg_init_fifo - initialise non-periodic FIFOs 29447a1685fSDinh Nguyen * @hsotg: The device instance. 29547a1685fSDinh Nguyen */ 2961f91b4ccSFelipe Balbi static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) 29747a1685fSDinh Nguyen { 2982317eacdSJohn Youn unsigned int ep; 29947a1685fSDinh Nguyen unsigned int addr; 30047a1685fSDinh Nguyen int timeout; 30179d6b8c5SSevak Arakelyan 30247a1685fSDinh Nguyen u32 val; 30305ee799fSJohn Youn u32 *txfsz = hsotg->params.g_tx_fifo_size; 30447a1685fSDinh Nguyen 3057fcbc95cSGregory Herrero /* Reset fifo map if not correctly cleared during previous session */ 3067fcbc95cSGregory Herrero WARN_ON(hsotg->fifo_map); 3077fcbc95cSGregory Herrero hsotg->fifo_map = 0; 3087fcbc95cSGregory Herrero 3090a176279SGregory Herrero /* set RX/NPTX FIFO sizes */ 310f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, hsotg->params.g_rx_fifo_size, GRXFSIZ); 311f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, (hsotg->params.g_rx_fifo_size << 312f25c42b8SGevorg Sahakyan FIFOSIZE_STARTADDR_SHIFT) | 31305ee799fSJohn Youn (hsotg->params.g_np_tx_fifo_size << FIFOSIZE_DEPTH_SHIFT), 314f25c42b8SGevorg Sahakyan GNPTXFSIZ); 31547a1685fSDinh Nguyen 31647a1685fSDinh Nguyen /* 31747a1685fSDinh Nguyen * arange all the rest of the TX FIFOs, as some versions of this 31847a1685fSDinh Nguyen * block have overlapping default addresses. This also ensures 31947a1685fSDinh Nguyen * that if the settings have been changed, then they are set to 32047a1685fSDinh Nguyen * known values. 32147a1685fSDinh Nguyen */ 32247a1685fSDinh Nguyen 32347a1685fSDinh Nguyen /* start at the end of the GNPTXFSIZ, rounded up */ 32405ee799fSJohn Youn addr = hsotg->params.g_rx_fifo_size + hsotg->params.g_np_tx_fifo_size; 32547a1685fSDinh Nguyen 32647a1685fSDinh Nguyen /* 3270a176279SGregory Herrero * Configure fifos sizes from provided configuration and assign 328b203d0a2SRobert Baldyga * them to endpoints dynamically according to maxpacket size value of 329b203d0a2SRobert Baldyga * given endpoint. 33047a1685fSDinh Nguyen */ 3312317eacdSJohn Youn for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) { 33205ee799fSJohn Youn if (!txfsz[ep]) 3333fa95385SJohn Youn continue; 3343fa95385SJohn Youn val = addr; 33505ee799fSJohn Youn val |= txfsz[ep] << FIFOSIZE_DEPTH_SHIFT; 33605ee799fSJohn Youn WARN_ONCE(addr + txfsz[ep] > hsotg->fifo_mem, 3373fa95385SJohn Youn "insufficient fifo memory"); 33805ee799fSJohn Youn addr += txfsz[ep]; 33947a1685fSDinh Nguyen 340f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, val, DPTXFSIZN(ep)); 341f25c42b8SGevorg Sahakyan val = dwc2_readl(hsotg, DPTXFSIZN(ep)); 34247a1685fSDinh Nguyen } 34347a1685fSDinh Nguyen 344f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, hsotg->hw_params.total_fifo_size | 345f87c842fSSevak Arakelyan addr << GDFIFOCFG_EPINFOBASE_SHIFT, 346f25c42b8SGevorg Sahakyan GDFIFOCFG); 34747a1685fSDinh Nguyen /* 34847a1685fSDinh Nguyen * according to p428 of the design guide, we need to ensure that 34947a1685fSDinh Nguyen * all fifos are flushed before continuing 35047a1685fSDinh Nguyen */ 35147a1685fSDinh Nguyen 352f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | 353f25c42b8SGevorg Sahakyan GRSTCTL_RXFFLSH, GRSTCTL); 35447a1685fSDinh Nguyen 35547a1685fSDinh Nguyen /* wait until the fifos are both flushed */ 35647a1685fSDinh Nguyen timeout = 100; 35747a1685fSDinh Nguyen while (1) { 358f25c42b8SGevorg Sahakyan val = dwc2_readl(hsotg, GRSTCTL); 35947a1685fSDinh Nguyen 36047a1685fSDinh Nguyen if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0) 36147a1685fSDinh Nguyen break; 36247a1685fSDinh Nguyen 36347a1685fSDinh Nguyen if (--timeout == 0) { 36447a1685fSDinh Nguyen dev_err(hsotg->dev, 36547a1685fSDinh Nguyen "%s: timeout flushing fifos (GRSTCTL=%08x)\n", 36647a1685fSDinh Nguyen __func__, val); 36748b20bcbSGregory Herrero break; 36847a1685fSDinh Nguyen } 36947a1685fSDinh Nguyen 37047a1685fSDinh Nguyen udelay(1); 37147a1685fSDinh Nguyen } 37247a1685fSDinh Nguyen 37347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); 37447a1685fSDinh Nguyen } 37547a1685fSDinh Nguyen 37647a1685fSDinh Nguyen /** 3776fb914d7SGrigor Tovmasyan * dwc2_hsotg_ep_alloc_request - allocate USB rerequest structure 37847a1685fSDinh Nguyen * @ep: USB endpoint to allocate request for. 37947a1685fSDinh Nguyen * @flags: Allocation flags 38047a1685fSDinh Nguyen * 38147a1685fSDinh Nguyen * Allocate a new USB request structure appropriate for the specified endpoint 38247a1685fSDinh Nguyen */ 3831f91b4ccSFelipe Balbi static struct usb_request *dwc2_hsotg_ep_alloc_request(struct usb_ep *ep, 38447a1685fSDinh Nguyen gfp_t flags) 38547a1685fSDinh Nguyen { 3861f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req; 38747a1685fSDinh Nguyen 388ec33efe2SJohn Youn req = kzalloc(sizeof(*req), flags); 38947a1685fSDinh Nguyen if (!req) 39047a1685fSDinh Nguyen return NULL; 39147a1685fSDinh Nguyen 39247a1685fSDinh Nguyen INIT_LIST_HEAD(&req->queue); 39347a1685fSDinh Nguyen 39447a1685fSDinh Nguyen return &req->req; 39547a1685fSDinh Nguyen } 39647a1685fSDinh Nguyen 39747a1685fSDinh Nguyen /** 39847a1685fSDinh Nguyen * is_ep_periodic - return true if the endpoint is in periodic mode. 39947a1685fSDinh Nguyen * @hs_ep: The endpoint to query. 40047a1685fSDinh Nguyen * 40147a1685fSDinh Nguyen * Returns true if the endpoint is in periodic mode, meaning it is being 40247a1685fSDinh Nguyen * used for an Interrupt or ISO transfer. 40347a1685fSDinh Nguyen */ 4041f91b4ccSFelipe Balbi static inline int is_ep_periodic(struct dwc2_hsotg_ep *hs_ep) 40547a1685fSDinh Nguyen { 40647a1685fSDinh Nguyen return hs_ep->periodic; 40747a1685fSDinh Nguyen } 40847a1685fSDinh Nguyen 40947a1685fSDinh Nguyen /** 4101f91b4ccSFelipe Balbi * dwc2_hsotg_unmap_dma - unmap the DMA memory being used for the request 41147a1685fSDinh Nguyen * @hsotg: The device state. 41247a1685fSDinh Nguyen * @hs_ep: The endpoint for the request 41347a1685fSDinh Nguyen * @hs_req: The request being processed. 41447a1685fSDinh Nguyen * 4151f91b4ccSFelipe Balbi * This is the reverse of dwc2_hsotg_map_dma(), called for the completion 41647a1685fSDinh Nguyen * of a request to ensure the buffer is ready for access by the caller. 41747a1685fSDinh Nguyen */ 4181f91b4ccSFelipe Balbi static void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg, 4191f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 4201f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req) 42147a1685fSDinh Nguyen { 42247a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 4239da51974SJohn Youn 42447a1685fSDinh Nguyen usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); 42547a1685fSDinh Nguyen } 42647a1685fSDinh Nguyen 4270f6b80c0SVahram Aharonyan /* 4280f6b80c0SVahram Aharonyan * dwc2_gadget_alloc_ctrl_desc_chains - allocate DMA descriptor chains 4290f6b80c0SVahram Aharonyan * for Control endpoint 4300f6b80c0SVahram Aharonyan * @hsotg: The device state. 4310f6b80c0SVahram Aharonyan * 4320f6b80c0SVahram Aharonyan * This function will allocate 4 descriptor chains for EP 0: 2 for 4330f6b80c0SVahram Aharonyan * Setup stage, per one for IN and OUT data/status transactions. 4340f6b80c0SVahram Aharonyan */ 4350f6b80c0SVahram Aharonyan static int dwc2_gadget_alloc_ctrl_desc_chains(struct dwc2_hsotg *hsotg) 4360f6b80c0SVahram Aharonyan { 4370f6b80c0SVahram Aharonyan hsotg->setup_desc[0] = 4380f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 4390f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 4400f6b80c0SVahram Aharonyan &hsotg->setup_desc_dma[0], 4410f6b80c0SVahram Aharonyan GFP_KERNEL); 4420f6b80c0SVahram Aharonyan if (!hsotg->setup_desc[0]) 4430f6b80c0SVahram Aharonyan goto fail; 4440f6b80c0SVahram Aharonyan 4450f6b80c0SVahram Aharonyan hsotg->setup_desc[1] = 4460f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 4470f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 4480f6b80c0SVahram Aharonyan &hsotg->setup_desc_dma[1], 4490f6b80c0SVahram Aharonyan GFP_KERNEL); 4500f6b80c0SVahram Aharonyan if (!hsotg->setup_desc[1]) 4510f6b80c0SVahram Aharonyan goto fail; 4520f6b80c0SVahram Aharonyan 4530f6b80c0SVahram Aharonyan hsotg->ctrl_in_desc = 4540f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 4550f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 4560f6b80c0SVahram Aharonyan &hsotg->ctrl_in_desc_dma, 4570f6b80c0SVahram Aharonyan GFP_KERNEL); 4580f6b80c0SVahram Aharonyan if (!hsotg->ctrl_in_desc) 4590f6b80c0SVahram Aharonyan goto fail; 4600f6b80c0SVahram Aharonyan 4610f6b80c0SVahram Aharonyan hsotg->ctrl_out_desc = 4620f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 4630f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 4640f6b80c0SVahram Aharonyan &hsotg->ctrl_out_desc_dma, 4650f6b80c0SVahram Aharonyan GFP_KERNEL); 4660f6b80c0SVahram Aharonyan if (!hsotg->ctrl_out_desc) 4670f6b80c0SVahram Aharonyan goto fail; 4680f6b80c0SVahram Aharonyan 4690f6b80c0SVahram Aharonyan return 0; 4700f6b80c0SVahram Aharonyan 4710f6b80c0SVahram Aharonyan fail: 4720f6b80c0SVahram Aharonyan return -ENOMEM; 4730f6b80c0SVahram Aharonyan } 4740f6b80c0SVahram Aharonyan 47547a1685fSDinh Nguyen /** 4761f91b4ccSFelipe Balbi * dwc2_hsotg_write_fifo - write packet Data to the TxFIFO 47747a1685fSDinh Nguyen * @hsotg: The controller state. 47847a1685fSDinh Nguyen * @hs_ep: The endpoint we're going to write for. 47947a1685fSDinh Nguyen * @hs_req: The request to write data for. 48047a1685fSDinh Nguyen * 48147a1685fSDinh Nguyen * This is called when the TxFIFO has some space in it to hold a new 48247a1685fSDinh Nguyen * transmission and we have something to give it. The actual setup of 48347a1685fSDinh Nguyen * the data size is done elsewhere, so all we have to do is to actually 48447a1685fSDinh Nguyen * write the data. 48547a1685fSDinh Nguyen * 48647a1685fSDinh Nguyen * The return value is zero if there is more space (or nothing was done) 48747a1685fSDinh Nguyen * otherwise -ENOSPC is returned if the FIFO space was used up. 48847a1685fSDinh Nguyen * 48947a1685fSDinh Nguyen * This routine is only needed for PIO 49047a1685fSDinh Nguyen */ 4911f91b4ccSFelipe Balbi static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, 4921f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 4931f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req) 49447a1685fSDinh Nguyen { 49547a1685fSDinh Nguyen bool periodic = is_ep_periodic(hs_ep); 496f25c42b8SGevorg Sahakyan u32 gnptxsts = dwc2_readl(hsotg, GNPTXSTS); 49747a1685fSDinh Nguyen int buf_pos = hs_req->req.actual; 49847a1685fSDinh Nguyen int to_write = hs_ep->size_loaded; 49947a1685fSDinh Nguyen void *data; 50047a1685fSDinh Nguyen int can_write; 50147a1685fSDinh Nguyen int pkt_round; 50247a1685fSDinh Nguyen int max_transfer; 50347a1685fSDinh Nguyen 50447a1685fSDinh Nguyen to_write -= (buf_pos - hs_ep->last_load); 50547a1685fSDinh Nguyen 50647a1685fSDinh Nguyen /* if there's nothing to write, get out early */ 50747a1685fSDinh Nguyen if (to_write == 0) 50847a1685fSDinh Nguyen return 0; 50947a1685fSDinh Nguyen 51047a1685fSDinh Nguyen if (periodic && !hsotg->dedicated_fifos) { 511f25c42b8SGevorg Sahakyan u32 epsize = dwc2_readl(hsotg, DIEPTSIZ(hs_ep->index)); 51247a1685fSDinh Nguyen int size_left; 51347a1685fSDinh Nguyen int size_done; 51447a1685fSDinh Nguyen 51547a1685fSDinh Nguyen /* 51647a1685fSDinh Nguyen * work out how much data was loaded so we can calculate 51747a1685fSDinh Nguyen * how much data is left in the fifo. 51847a1685fSDinh Nguyen */ 51947a1685fSDinh Nguyen 52047a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 52147a1685fSDinh Nguyen 52247a1685fSDinh Nguyen /* 52347a1685fSDinh Nguyen * if shared fifo, we cannot write anything until the 52447a1685fSDinh Nguyen * previous data has been completely sent. 52547a1685fSDinh Nguyen */ 52647a1685fSDinh Nguyen if (hs_ep->fifo_load != 0) { 5271f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 52847a1685fSDinh Nguyen return -ENOSPC; 52947a1685fSDinh Nguyen } 53047a1685fSDinh Nguyen 53147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", 53247a1685fSDinh Nguyen __func__, size_left, 53347a1685fSDinh Nguyen hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); 53447a1685fSDinh Nguyen 53547a1685fSDinh Nguyen /* how much of the data has moved */ 53647a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 53747a1685fSDinh Nguyen 53847a1685fSDinh Nguyen /* how much data is left in the fifo */ 53947a1685fSDinh Nguyen can_write = hs_ep->fifo_load - size_done; 54047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", 54147a1685fSDinh Nguyen __func__, can_write); 54247a1685fSDinh Nguyen 54347a1685fSDinh Nguyen can_write = hs_ep->fifo_size - can_write; 54447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", 54547a1685fSDinh Nguyen __func__, can_write); 54647a1685fSDinh Nguyen 54747a1685fSDinh Nguyen if (can_write <= 0) { 5481f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 54947a1685fSDinh Nguyen return -ENOSPC; 55047a1685fSDinh Nguyen } 55147a1685fSDinh Nguyen } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { 552f25c42b8SGevorg Sahakyan can_write = dwc2_readl(hsotg, 553ad674a15SRobert Baldyga DTXFSTS(hs_ep->fifo_index)); 55447a1685fSDinh Nguyen 55547a1685fSDinh Nguyen can_write &= 0xffff; 55647a1685fSDinh Nguyen can_write *= 4; 55747a1685fSDinh Nguyen } else { 55847a1685fSDinh Nguyen if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) { 55947a1685fSDinh Nguyen dev_dbg(hsotg->dev, 56047a1685fSDinh Nguyen "%s: no queue slots available (0x%08x)\n", 56147a1685fSDinh Nguyen __func__, gnptxsts); 56247a1685fSDinh Nguyen 5631f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP); 56447a1685fSDinh Nguyen return -ENOSPC; 56547a1685fSDinh Nguyen } 56647a1685fSDinh Nguyen 56747a1685fSDinh Nguyen can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts); 56847a1685fSDinh Nguyen can_write *= 4; /* fifo size is in 32bit quantities. */ 56947a1685fSDinh Nguyen } 57047a1685fSDinh Nguyen 57147a1685fSDinh Nguyen max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; 57247a1685fSDinh Nguyen 57347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", 57447a1685fSDinh Nguyen __func__, gnptxsts, can_write, to_write, max_transfer); 57547a1685fSDinh Nguyen 57647a1685fSDinh Nguyen /* 57747a1685fSDinh Nguyen * limit to 512 bytes of data, it seems at least on the non-periodic 57847a1685fSDinh Nguyen * FIFO, requests of >512 cause the endpoint to get stuck with a 57947a1685fSDinh Nguyen * fragment of the end of the transfer in it. 58047a1685fSDinh Nguyen */ 58147a1685fSDinh Nguyen if (can_write > 512 && !periodic) 58247a1685fSDinh Nguyen can_write = 512; 58347a1685fSDinh Nguyen 58447a1685fSDinh Nguyen /* 58547a1685fSDinh Nguyen * limit the write to one max-packet size worth of data, but allow 58647a1685fSDinh Nguyen * the transfer to return that it did not run out of fifo space 58747a1685fSDinh Nguyen * doing it. 58847a1685fSDinh Nguyen */ 58947a1685fSDinh Nguyen if (to_write > max_transfer) { 59047a1685fSDinh Nguyen to_write = max_transfer; 59147a1685fSDinh Nguyen 59247a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 59347a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 5941f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, 59547a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 59647a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 59747a1685fSDinh Nguyen } 59847a1685fSDinh Nguyen 59947a1685fSDinh Nguyen /* see if we can write data */ 60047a1685fSDinh Nguyen 60147a1685fSDinh Nguyen if (to_write > can_write) { 60247a1685fSDinh Nguyen to_write = can_write; 60347a1685fSDinh Nguyen pkt_round = to_write % max_transfer; 60447a1685fSDinh Nguyen 60547a1685fSDinh Nguyen /* 60647a1685fSDinh Nguyen * Round the write down to an 60747a1685fSDinh Nguyen * exact number of packets. 60847a1685fSDinh Nguyen * 60947a1685fSDinh Nguyen * Note, we do not currently check to see if we can ever 61047a1685fSDinh Nguyen * write a full packet or not to the FIFO. 61147a1685fSDinh Nguyen */ 61247a1685fSDinh Nguyen 61347a1685fSDinh Nguyen if (pkt_round) 61447a1685fSDinh Nguyen to_write -= pkt_round; 61547a1685fSDinh Nguyen 61647a1685fSDinh Nguyen /* 61747a1685fSDinh Nguyen * enable correct FIFO interrupt to alert us when there 61847a1685fSDinh Nguyen * is more room left. 61947a1685fSDinh Nguyen */ 62047a1685fSDinh Nguyen 62147a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 62247a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 6231f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, 62447a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 62547a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 62647a1685fSDinh Nguyen } 62747a1685fSDinh Nguyen 62847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", 62947a1685fSDinh Nguyen to_write, hs_req->req.length, can_write, buf_pos); 63047a1685fSDinh Nguyen 63147a1685fSDinh Nguyen if (to_write <= 0) 63247a1685fSDinh Nguyen return -ENOSPC; 63347a1685fSDinh Nguyen 63447a1685fSDinh Nguyen hs_req->req.actual = buf_pos + to_write; 63547a1685fSDinh Nguyen hs_ep->total_data += to_write; 63647a1685fSDinh Nguyen 63747a1685fSDinh Nguyen if (periodic) 63847a1685fSDinh Nguyen hs_ep->fifo_load += to_write; 63947a1685fSDinh Nguyen 64047a1685fSDinh Nguyen to_write = DIV_ROUND_UP(to_write, 4); 64147a1685fSDinh Nguyen data = hs_req->req.buf + buf_pos; 64247a1685fSDinh Nguyen 643342ccce1SGevorg Sahakyan dwc2_writel_rep(hsotg, EPFIFO(hs_ep->index), data, to_write); 64447a1685fSDinh Nguyen 64547a1685fSDinh Nguyen return (to_write >= can_write) ? -ENOSPC : 0; 64647a1685fSDinh Nguyen } 64747a1685fSDinh Nguyen 64847a1685fSDinh Nguyen /** 64947a1685fSDinh Nguyen * get_ep_limit - get the maximum data legnth for this endpoint 65047a1685fSDinh Nguyen * @hs_ep: The endpoint 65147a1685fSDinh Nguyen * 65247a1685fSDinh Nguyen * Return the maximum data that can be queued in one go on a given endpoint 65347a1685fSDinh Nguyen * so that transfers that are too long can be split. 65447a1685fSDinh Nguyen */ 6559da51974SJohn Youn static unsigned int get_ep_limit(struct dwc2_hsotg_ep *hs_ep) 65647a1685fSDinh Nguyen { 65747a1685fSDinh Nguyen int index = hs_ep->index; 6589da51974SJohn Youn unsigned int maxsize; 6599da51974SJohn Youn unsigned int maxpkt; 66047a1685fSDinh Nguyen 66147a1685fSDinh Nguyen if (index != 0) { 66247a1685fSDinh Nguyen maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; 66347a1685fSDinh Nguyen maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; 66447a1685fSDinh Nguyen } else { 66547a1685fSDinh Nguyen maxsize = 64 + 64; 66647a1685fSDinh Nguyen if (hs_ep->dir_in) 66747a1685fSDinh Nguyen maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; 66847a1685fSDinh Nguyen else 66947a1685fSDinh Nguyen maxpkt = 2; 67047a1685fSDinh Nguyen } 67147a1685fSDinh Nguyen 67247a1685fSDinh Nguyen /* we made the constant loading easier above by using +1 */ 67347a1685fSDinh Nguyen maxpkt--; 67447a1685fSDinh Nguyen maxsize--; 67547a1685fSDinh Nguyen 67647a1685fSDinh Nguyen /* 67747a1685fSDinh Nguyen * constrain by packet count if maxpkts*pktsize is greater 67847a1685fSDinh Nguyen * than the length register size. 67947a1685fSDinh Nguyen */ 68047a1685fSDinh Nguyen 68147a1685fSDinh Nguyen if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) 68247a1685fSDinh Nguyen maxsize = maxpkt * hs_ep->ep.maxpacket; 68347a1685fSDinh Nguyen 68447a1685fSDinh Nguyen return maxsize; 68547a1685fSDinh Nguyen } 68647a1685fSDinh Nguyen 68747a1685fSDinh Nguyen /** 688381fc8f8SVardan Mikayelyan * dwc2_hsotg_read_frameno - read current frame number 689381fc8f8SVardan Mikayelyan * @hsotg: The device instance 690381fc8f8SVardan Mikayelyan * 691381fc8f8SVardan Mikayelyan * Return the current frame number 692381fc8f8SVardan Mikayelyan */ 693381fc8f8SVardan Mikayelyan static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg) 694381fc8f8SVardan Mikayelyan { 695381fc8f8SVardan Mikayelyan u32 dsts; 696381fc8f8SVardan Mikayelyan 697f25c42b8SGevorg Sahakyan dsts = dwc2_readl(hsotg, DSTS); 698381fc8f8SVardan Mikayelyan dsts &= DSTS_SOFFN_MASK; 699381fc8f8SVardan Mikayelyan dsts >>= DSTS_SOFFN_SHIFT; 700381fc8f8SVardan Mikayelyan 701381fc8f8SVardan Mikayelyan return dsts; 702381fc8f8SVardan Mikayelyan } 703381fc8f8SVardan Mikayelyan 704381fc8f8SVardan Mikayelyan /** 705cf77b5fbSVahram Aharonyan * dwc2_gadget_get_chain_limit - get the maximum data payload value of the 706cf77b5fbSVahram Aharonyan * DMA descriptor chain prepared for specific endpoint 707cf77b5fbSVahram Aharonyan * @hs_ep: The endpoint 708cf77b5fbSVahram Aharonyan * 709cf77b5fbSVahram Aharonyan * Return the maximum data that can be queued in one go on a given endpoint 710cf77b5fbSVahram Aharonyan * depending on its descriptor chain capacity so that transfers that 711cf77b5fbSVahram Aharonyan * are too long can be split. 712cf77b5fbSVahram Aharonyan */ 713cf77b5fbSVahram Aharonyan static unsigned int dwc2_gadget_get_chain_limit(struct dwc2_hsotg_ep *hs_ep) 714cf77b5fbSVahram Aharonyan { 715cf77b5fbSVahram Aharonyan int is_isoc = hs_ep->isochronous; 716cf77b5fbSVahram Aharonyan unsigned int maxsize; 717cf77b5fbSVahram Aharonyan 718cf77b5fbSVahram Aharonyan if (is_isoc) 71954f37f56SMinas Harutyunyan maxsize = (hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_LIMIT : 72054f37f56SMinas Harutyunyan DEV_DMA_ISOC_RX_NBYTES_LIMIT) * 72154f37f56SMinas Harutyunyan MAX_DMA_DESC_NUM_HS_ISOC; 722cf77b5fbSVahram Aharonyan else 72354f37f56SMinas Harutyunyan maxsize = DEV_DMA_NBYTES_LIMIT * MAX_DMA_DESC_NUM_GENERIC; 724cf77b5fbSVahram Aharonyan 725cf77b5fbSVahram Aharonyan return maxsize; 726cf77b5fbSVahram Aharonyan } 727cf77b5fbSVahram Aharonyan 728e02f9aa6SVahram Aharonyan /* 729e02f9aa6SVahram Aharonyan * dwc2_gadget_get_desc_params - get DMA descriptor parameters. 730e02f9aa6SVahram Aharonyan * @hs_ep: The endpoint 731e02f9aa6SVahram Aharonyan * @mask: RX/TX bytes mask to be defined 732e02f9aa6SVahram Aharonyan * 733e02f9aa6SVahram Aharonyan * Returns maximum data payload for one descriptor after analyzing endpoint 734e02f9aa6SVahram Aharonyan * characteristics. 735e02f9aa6SVahram Aharonyan * DMA descriptor transfer bytes limit depends on EP type: 736e02f9aa6SVahram Aharonyan * Control out - MPS, 737e02f9aa6SVahram Aharonyan * Isochronous - descriptor rx/tx bytes bitfield limit, 738e02f9aa6SVahram Aharonyan * Control In/Bulk/Interrupt - multiple of mps. This will allow to not 739e02f9aa6SVahram Aharonyan * have concatenations from various descriptors within one packet. 740e02f9aa6SVahram Aharonyan * 741e02f9aa6SVahram Aharonyan * Selects corresponding mask for RX/TX bytes as well. 742e02f9aa6SVahram Aharonyan */ 743e02f9aa6SVahram Aharonyan static u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask) 744e02f9aa6SVahram Aharonyan { 745e02f9aa6SVahram Aharonyan u32 mps = hs_ep->ep.maxpacket; 746e02f9aa6SVahram Aharonyan int dir_in = hs_ep->dir_in; 747e02f9aa6SVahram Aharonyan u32 desc_size = 0; 748e02f9aa6SVahram Aharonyan 749e02f9aa6SVahram Aharonyan if (!hs_ep->index && !dir_in) { 750e02f9aa6SVahram Aharonyan desc_size = mps; 751e02f9aa6SVahram Aharonyan *mask = DEV_DMA_NBYTES_MASK; 752e02f9aa6SVahram Aharonyan } else if (hs_ep->isochronous) { 753e02f9aa6SVahram Aharonyan if (dir_in) { 754e02f9aa6SVahram Aharonyan desc_size = DEV_DMA_ISOC_TX_NBYTES_LIMIT; 755e02f9aa6SVahram Aharonyan *mask = DEV_DMA_ISOC_TX_NBYTES_MASK; 756e02f9aa6SVahram Aharonyan } else { 757e02f9aa6SVahram Aharonyan desc_size = DEV_DMA_ISOC_RX_NBYTES_LIMIT; 758e02f9aa6SVahram Aharonyan *mask = DEV_DMA_ISOC_RX_NBYTES_MASK; 759e02f9aa6SVahram Aharonyan } 760e02f9aa6SVahram Aharonyan } else { 761e02f9aa6SVahram Aharonyan desc_size = DEV_DMA_NBYTES_LIMIT; 762e02f9aa6SVahram Aharonyan *mask = DEV_DMA_NBYTES_MASK; 763e02f9aa6SVahram Aharonyan 764e02f9aa6SVahram Aharonyan /* Round down desc_size to be mps multiple */ 765e02f9aa6SVahram Aharonyan desc_size -= desc_size % mps; 766e02f9aa6SVahram Aharonyan } 767e02f9aa6SVahram Aharonyan 768e02f9aa6SVahram Aharonyan return desc_size; 769e02f9aa6SVahram Aharonyan } 770e02f9aa6SVahram Aharonyan 77110209abeSAndrzej Pietrasiewicz static void dwc2_gadget_fill_nonisoc_xfer_ddma_one(struct dwc2_hsotg_ep *hs_ep, 77210209abeSAndrzej Pietrasiewicz struct dwc2_dma_desc **desc, 773e02f9aa6SVahram Aharonyan dma_addr_t dma_buff, 77410209abeSAndrzej Pietrasiewicz unsigned int len, 77510209abeSAndrzej Pietrasiewicz bool true_last) 776e02f9aa6SVahram Aharonyan { 777e02f9aa6SVahram Aharonyan int dir_in = hs_ep->dir_in; 778e02f9aa6SVahram Aharonyan u32 mps = hs_ep->ep.maxpacket; 779e02f9aa6SVahram Aharonyan u32 maxsize = 0; 780e02f9aa6SVahram Aharonyan u32 offset = 0; 781e02f9aa6SVahram Aharonyan u32 mask = 0; 782e02f9aa6SVahram Aharonyan int i; 783e02f9aa6SVahram Aharonyan 784e02f9aa6SVahram Aharonyan maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); 785e02f9aa6SVahram Aharonyan 786e02f9aa6SVahram Aharonyan hs_ep->desc_count = (len / maxsize) + 787e02f9aa6SVahram Aharonyan ((len % maxsize) ? 1 : 0); 788e02f9aa6SVahram Aharonyan if (len == 0) 789e02f9aa6SVahram Aharonyan hs_ep->desc_count = 1; 790e02f9aa6SVahram Aharonyan 791e02f9aa6SVahram Aharonyan for (i = 0; i < hs_ep->desc_count; ++i) { 79210209abeSAndrzej Pietrasiewicz (*desc)->status = 0; 79310209abeSAndrzej Pietrasiewicz (*desc)->status |= (DEV_DMA_BUFF_STS_HBUSY 794e02f9aa6SVahram Aharonyan << DEV_DMA_BUFF_STS_SHIFT); 795e02f9aa6SVahram Aharonyan 796e02f9aa6SVahram Aharonyan if (len > maxsize) { 797e02f9aa6SVahram Aharonyan if (!hs_ep->index && !dir_in) 79810209abeSAndrzej Pietrasiewicz (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); 799e02f9aa6SVahram Aharonyan 80010209abeSAndrzej Pietrasiewicz (*desc)->status |= 80110209abeSAndrzej Pietrasiewicz maxsize << DEV_DMA_NBYTES_SHIFT & mask; 80210209abeSAndrzej Pietrasiewicz (*desc)->buf = dma_buff + offset; 803e02f9aa6SVahram Aharonyan 804e02f9aa6SVahram Aharonyan len -= maxsize; 805e02f9aa6SVahram Aharonyan offset += maxsize; 806e02f9aa6SVahram Aharonyan } else { 80710209abeSAndrzej Pietrasiewicz if (true_last) 80810209abeSAndrzej Pietrasiewicz (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); 809e02f9aa6SVahram Aharonyan 810e02f9aa6SVahram Aharonyan if (dir_in) 81110209abeSAndrzej Pietrasiewicz (*desc)->status |= (len % mps) ? DEV_DMA_SHORT : 81210209abeSAndrzej Pietrasiewicz ((hs_ep->send_zlp && true_last) ? 81310209abeSAndrzej Pietrasiewicz DEV_DMA_SHORT : 0); 814e02f9aa6SVahram Aharonyan 81510209abeSAndrzej Pietrasiewicz (*desc)->status |= 816e02f9aa6SVahram Aharonyan len << DEV_DMA_NBYTES_SHIFT & mask; 81710209abeSAndrzej Pietrasiewicz (*desc)->buf = dma_buff + offset; 818e02f9aa6SVahram Aharonyan } 819e02f9aa6SVahram Aharonyan 82010209abeSAndrzej Pietrasiewicz (*desc)->status &= ~DEV_DMA_BUFF_STS_MASK; 82110209abeSAndrzej Pietrasiewicz (*desc)->status |= (DEV_DMA_BUFF_STS_HREADY 822e02f9aa6SVahram Aharonyan << DEV_DMA_BUFF_STS_SHIFT); 82310209abeSAndrzej Pietrasiewicz (*desc)++; 824e02f9aa6SVahram Aharonyan } 825e02f9aa6SVahram Aharonyan } 826e02f9aa6SVahram Aharonyan 827540ccba0SVahram Aharonyan /* 82810209abeSAndrzej Pietrasiewicz * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. 82910209abeSAndrzej Pietrasiewicz * @hs_ep: The endpoint 83010209abeSAndrzej Pietrasiewicz * @ureq: Request to transfer 83110209abeSAndrzej Pietrasiewicz * @offset: offset in bytes 83210209abeSAndrzej Pietrasiewicz * @len: Length of the transfer 83310209abeSAndrzej Pietrasiewicz * 83410209abeSAndrzej Pietrasiewicz * This function will iterate over descriptor chain and fill its entries 83510209abeSAndrzej Pietrasiewicz * with corresponding information based on transfer data. 83610209abeSAndrzej Pietrasiewicz */ 83710209abeSAndrzej Pietrasiewicz static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, 83810209abeSAndrzej Pietrasiewicz struct usb_request *ureq, 83910209abeSAndrzej Pietrasiewicz unsigned int offset, 84010209abeSAndrzej Pietrasiewicz unsigned int len) 84110209abeSAndrzej Pietrasiewicz { 84210209abeSAndrzej Pietrasiewicz struct dwc2_dma_desc *desc = hs_ep->desc_list; 84310209abeSAndrzej Pietrasiewicz struct scatterlist *sg; 84410209abeSAndrzej Pietrasiewicz int i; 84510209abeSAndrzej Pietrasiewicz u8 desc_count = 0; 84610209abeSAndrzej Pietrasiewicz 84710209abeSAndrzej Pietrasiewicz /* non-DMA sg buffer */ 84810209abeSAndrzej Pietrasiewicz if (!ureq->num_sgs) { 84910209abeSAndrzej Pietrasiewicz dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc, 85010209abeSAndrzej Pietrasiewicz ureq->dma + offset, len, true); 85110209abeSAndrzej Pietrasiewicz return; 85210209abeSAndrzej Pietrasiewicz } 85310209abeSAndrzej Pietrasiewicz 85410209abeSAndrzej Pietrasiewicz /* DMA sg buffer */ 85510209abeSAndrzej Pietrasiewicz for_each_sg(ureq->sg, sg, ureq->num_sgs, i) { 85610209abeSAndrzej Pietrasiewicz dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc, 85710209abeSAndrzej Pietrasiewicz sg_dma_address(sg) + sg->offset, sg_dma_len(sg), 85810209abeSAndrzej Pietrasiewicz sg_is_last(sg)); 85910209abeSAndrzej Pietrasiewicz desc_count += hs_ep->desc_count; 86010209abeSAndrzej Pietrasiewicz } 86110209abeSAndrzej Pietrasiewicz 86210209abeSAndrzej Pietrasiewicz hs_ep->desc_count = desc_count; 86310209abeSAndrzej Pietrasiewicz } 86410209abeSAndrzej Pietrasiewicz 86510209abeSAndrzej Pietrasiewicz /* 866540ccba0SVahram Aharonyan * dwc2_gadget_fill_isoc_desc - fills next isochronous descriptor in chain. 867540ccba0SVahram Aharonyan * @hs_ep: The isochronous endpoint. 868540ccba0SVahram Aharonyan * @dma_buff: usb requests dma buffer. 869540ccba0SVahram Aharonyan * @len: usb request transfer length. 870540ccba0SVahram Aharonyan * 871729cac69SMinas Harutyunyan * Fills next free descriptor with the data of the arrived usb request, 872540ccba0SVahram Aharonyan * frame info, sets Last and IOC bits increments next_desc. If filled 873540ccba0SVahram Aharonyan * descriptor is not the first one, removes L bit from the previous descriptor 874540ccba0SVahram Aharonyan * status. 875540ccba0SVahram Aharonyan */ 876540ccba0SVahram Aharonyan static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, 877540ccba0SVahram Aharonyan dma_addr_t dma_buff, unsigned int len) 878540ccba0SVahram Aharonyan { 879540ccba0SVahram Aharonyan struct dwc2_dma_desc *desc; 880540ccba0SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 881540ccba0SVahram Aharonyan u32 index; 882540ccba0SVahram Aharonyan u32 maxsize = 0; 883540ccba0SVahram Aharonyan u32 mask = 0; 8841d8e5c00SMinas Harutyunyan u8 pid = 0; 885540ccba0SVahram Aharonyan 886540ccba0SVahram Aharonyan maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); 887540ccba0SVahram Aharonyan 888729cac69SMinas Harutyunyan index = hs_ep->next_desc; 889540ccba0SVahram Aharonyan desc = &hs_ep->desc_list[index]; 890540ccba0SVahram Aharonyan 891729cac69SMinas Harutyunyan /* Check if descriptor chain full */ 892729cac69SMinas Harutyunyan if ((desc->status >> DEV_DMA_BUFF_STS_SHIFT) == 893729cac69SMinas Harutyunyan DEV_DMA_BUFF_STS_HREADY) { 894729cac69SMinas Harutyunyan dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__); 895729cac69SMinas Harutyunyan return 1; 896729cac69SMinas Harutyunyan } 897729cac69SMinas Harutyunyan 898540ccba0SVahram Aharonyan /* Clear L bit of previous desc if more than one entries in the chain */ 899540ccba0SVahram Aharonyan if (hs_ep->next_desc) 900540ccba0SVahram Aharonyan hs_ep->desc_list[index - 1].status &= ~DEV_DMA_L; 901540ccba0SVahram Aharonyan 902540ccba0SVahram Aharonyan dev_dbg(hsotg->dev, "%s: Filling ep %d, dir %s isoc desc # %d\n", 903540ccba0SVahram Aharonyan __func__, hs_ep->index, hs_ep->dir_in ? "in" : "out", index); 904540ccba0SVahram Aharonyan 905540ccba0SVahram Aharonyan desc->status = 0; 906540ccba0SVahram Aharonyan desc->status |= (DEV_DMA_BUFF_STS_HBUSY << DEV_DMA_BUFF_STS_SHIFT); 907540ccba0SVahram Aharonyan 908540ccba0SVahram Aharonyan desc->buf = dma_buff; 909540ccba0SVahram Aharonyan desc->status |= (DEV_DMA_L | DEV_DMA_IOC | 910540ccba0SVahram Aharonyan ((len << DEV_DMA_NBYTES_SHIFT) & mask)); 911540ccba0SVahram Aharonyan 912540ccba0SVahram Aharonyan if (hs_ep->dir_in) { 9131d8e5c00SMinas Harutyunyan if (len) 9141d8e5c00SMinas Harutyunyan pid = DIV_ROUND_UP(len, hs_ep->ep.maxpacket); 9151d8e5c00SMinas Harutyunyan else 9161d8e5c00SMinas Harutyunyan pid = 1; 9171d8e5c00SMinas Harutyunyan desc->status |= ((pid << DEV_DMA_ISOC_PID_SHIFT) & 918540ccba0SVahram Aharonyan DEV_DMA_ISOC_PID_MASK) | 919540ccba0SVahram Aharonyan ((len % hs_ep->ep.maxpacket) ? 920540ccba0SVahram Aharonyan DEV_DMA_SHORT : 0) | 921540ccba0SVahram Aharonyan ((hs_ep->target_frame << 922540ccba0SVahram Aharonyan DEV_DMA_ISOC_FRNUM_SHIFT) & 923540ccba0SVahram Aharonyan DEV_DMA_ISOC_FRNUM_MASK); 924540ccba0SVahram Aharonyan } 925540ccba0SVahram Aharonyan 926540ccba0SVahram Aharonyan desc->status &= ~DEV_DMA_BUFF_STS_MASK; 927540ccba0SVahram Aharonyan desc->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT); 928540ccba0SVahram Aharonyan 929729cac69SMinas Harutyunyan /* Increment frame number by interval for IN */ 930729cac69SMinas Harutyunyan if (hs_ep->dir_in) 931729cac69SMinas Harutyunyan dwc2_gadget_incr_frame_num(hs_ep); 932729cac69SMinas Harutyunyan 933540ccba0SVahram Aharonyan /* Update index of last configured entry in the chain */ 934540ccba0SVahram Aharonyan hs_ep->next_desc++; 93554f37f56SMinas Harutyunyan if (hs_ep->next_desc >= MAX_DMA_DESC_NUM_HS_ISOC) 936729cac69SMinas Harutyunyan hs_ep->next_desc = 0; 937540ccba0SVahram Aharonyan 938540ccba0SVahram Aharonyan return 0; 939540ccba0SVahram Aharonyan } 940540ccba0SVahram Aharonyan 941540ccba0SVahram Aharonyan /* 942540ccba0SVahram Aharonyan * dwc2_gadget_start_isoc_ddma - start isochronous transfer in DDMA 943540ccba0SVahram Aharonyan * @hs_ep: The isochronous endpoint. 944540ccba0SVahram Aharonyan * 945729cac69SMinas Harutyunyan * Prepare descriptor chain for isochronous endpoints. Afterwards 946540ccba0SVahram Aharonyan * write DMA address to HW and enable the endpoint. 947540ccba0SVahram Aharonyan */ 948540ccba0SVahram Aharonyan static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) 949540ccba0SVahram Aharonyan { 950540ccba0SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 951540ccba0SVahram Aharonyan struct dwc2_hsotg_req *hs_req, *treq; 952540ccba0SVahram Aharonyan int index = hs_ep->index; 953540ccba0SVahram Aharonyan int ret; 954729cac69SMinas Harutyunyan int i; 955540ccba0SVahram Aharonyan u32 dma_reg; 956540ccba0SVahram Aharonyan u32 depctl; 957540ccba0SVahram Aharonyan u32 ctrl; 958729cac69SMinas Harutyunyan struct dwc2_dma_desc *desc; 959540ccba0SVahram Aharonyan 960540ccba0SVahram Aharonyan if (list_empty(&hs_ep->queue)) { 9611ffba905SMinas Harutyunyan hs_ep->target_frame = TARGET_FRAME_INITIAL; 962540ccba0SVahram Aharonyan dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__); 963540ccba0SVahram Aharonyan return; 964540ccba0SVahram Aharonyan } 965540ccba0SVahram Aharonyan 966729cac69SMinas Harutyunyan /* Initialize descriptor chain by Host Busy status */ 96754f37f56SMinas Harutyunyan for (i = 0; i < MAX_DMA_DESC_NUM_HS_ISOC; i++) { 968729cac69SMinas Harutyunyan desc = &hs_ep->desc_list[i]; 969729cac69SMinas Harutyunyan desc->status = 0; 970729cac69SMinas Harutyunyan desc->status |= (DEV_DMA_BUFF_STS_HBUSY 971729cac69SMinas Harutyunyan << DEV_DMA_BUFF_STS_SHIFT); 972729cac69SMinas Harutyunyan } 973729cac69SMinas Harutyunyan 974729cac69SMinas Harutyunyan hs_ep->next_desc = 0; 975540ccba0SVahram Aharonyan list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) { 97610209abeSAndrzej Pietrasiewicz dma_addr_t dma_addr = hs_req->req.dma; 97710209abeSAndrzej Pietrasiewicz 97810209abeSAndrzej Pietrasiewicz if (hs_req->req.num_sgs) { 97910209abeSAndrzej Pietrasiewicz WARN_ON(hs_req->req.num_sgs > 1); 98010209abeSAndrzej Pietrasiewicz dma_addr = sg_dma_address(hs_req->req.sg); 98110209abeSAndrzej Pietrasiewicz } 98210209abeSAndrzej Pietrasiewicz ret = dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, 983540ccba0SVahram Aharonyan hs_req->req.length); 984729cac69SMinas Harutyunyan if (ret) 985540ccba0SVahram Aharonyan break; 986540ccba0SVahram Aharonyan } 987540ccba0SVahram Aharonyan 988729cac69SMinas Harutyunyan hs_ep->compl_desc = 0; 989540ccba0SVahram Aharonyan depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 990540ccba0SVahram Aharonyan dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index); 991540ccba0SVahram Aharonyan 992540ccba0SVahram Aharonyan /* write descriptor chain address to control register */ 993f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, hs_ep->desc_list_dma, dma_reg); 994540ccba0SVahram Aharonyan 995f25c42b8SGevorg Sahakyan ctrl = dwc2_readl(hsotg, depctl); 996540ccba0SVahram Aharonyan ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK; 997f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ctrl, depctl); 998540ccba0SVahram Aharonyan } 999540ccba0SVahram Aharonyan 1000cf77b5fbSVahram Aharonyan /** 10011f91b4ccSFelipe Balbi * dwc2_hsotg_start_req - start a USB request from an endpoint's queue 100247a1685fSDinh Nguyen * @hsotg: The controller state. 100347a1685fSDinh Nguyen * @hs_ep: The endpoint to process a request for 100447a1685fSDinh Nguyen * @hs_req: The request to start. 100547a1685fSDinh Nguyen * @continuing: True if we are doing more for the current request. 100647a1685fSDinh Nguyen * 100747a1685fSDinh Nguyen * Start the given request running by setting the endpoint registers 100847a1685fSDinh Nguyen * appropriately, and writing any data to the FIFOs. 100947a1685fSDinh Nguyen */ 10101f91b4ccSFelipe Balbi static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, 10111f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 10121f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req, 101347a1685fSDinh Nguyen bool continuing) 101447a1685fSDinh Nguyen { 101547a1685fSDinh Nguyen struct usb_request *ureq = &hs_req->req; 101647a1685fSDinh Nguyen int index = hs_ep->index; 101747a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 101847a1685fSDinh Nguyen u32 epctrl_reg; 101947a1685fSDinh Nguyen u32 epsize_reg; 102047a1685fSDinh Nguyen u32 epsize; 102147a1685fSDinh Nguyen u32 ctrl; 10229da51974SJohn Youn unsigned int length; 10239da51974SJohn Youn unsigned int packets; 10249da51974SJohn Youn unsigned int maxreq; 1025aa3e8bc8SVahram Aharonyan unsigned int dma_reg; 102647a1685fSDinh Nguyen 102747a1685fSDinh Nguyen if (index != 0) { 102847a1685fSDinh Nguyen if (hs_ep->req && !continuing) { 102947a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: active request\n", __func__); 103047a1685fSDinh Nguyen WARN_ON(1); 103147a1685fSDinh Nguyen return; 103247a1685fSDinh Nguyen } else if (hs_ep->req != hs_req && continuing) { 103347a1685fSDinh Nguyen dev_err(hsotg->dev, 103447a1685fSDinh Nguyen "%s: continue different req\n", __func__); 103547a1685fSDinh Nguyen WARN_ON(1); 103647a1685fSDinh Nguyen return; 103747a1685fSDinh Nguyen } 103847a1685fSDinh Nguyen } 103947a1685fSDinh Nguyen 1040aa3e8bc8SVahram Aharonyan dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); 104147a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 104247a1685fSDinh Nguyen epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 104347a1685fSDinh Nguyen 104447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", 1045f25c42b8SGevorg Sahakyan __func__, dwc2_readl(hsotg, epctrl_reg), index, 104647a1685fSDinh Nguyen hs_ep->dir_in ? "in" : "out"); 104747a1685fSDinh Nguyen 104847a1685fSDinh Nguyen /* If endpoint is stalled, we will restart request later */ 1049f25c42b8SGevorg Sahakyan ctrl = dwc2_readl(hsotg, epctrl_reg); 105047a1685fSDinh Nguyen 1051b2d4c54eSMian Yousaf Kaukab if (index && ctrl & DXEPCTL_STALL) { 105247a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); 105347a1685fSDinh Nguyen return; 105447a1685fSDinh Nguyen } 105547a1685fSDinh Nguyen 105647a1685fSDinh Nguyen length = ureq->length - ureq->actual; 105747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", 105847a1685fSDinh Nguyen ureq->length, ureq->actual); 105947a1685fSDinh Nguyen 1060cf77b5fbSVahram Aharonyan if (!using_desc_dma(hsotg)) 106147a1685fSDinh Nguyen maxreq = get_ep_limit(hs_ep); 1062cf77b5fbSVahram Aharonyan else 1063cf77b5fbSVahram Aharonyan maxreq = dwc2_gadget_get_chain_limit(hs_ep); 1064cf77b5fbSVahram Aharonyan 106547a1685fSDinh Nguyen if (length > maxreq) { 106647a1685fSDinh Nguyen int round = maxreq % hs_ep->ep.maxpacket; 106747a1685fSDinh Nguyen 106847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", 106947a1685fSDinh Nguyen __func__, length, maxreq, round); 107047a1685fSDinh Nguyen 107147a1685fSDinh Nguyen /* round down to multiple of packets */ 107247a1685fSDinh Nguyen if (round) 107347a1685fSDinh Nguyen maxreq -= round; 107447a1685fSDinh Nguyen 107547a1685fSDinh Nguyen length = maxreq; 107647a1685fSDinh Nguyen } 107747a1685fSDinh Nguyen 107847a1685fSDinh Nguyen if (length) 107947a1685fSDinh Nguyen packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); 108047a1685fSDinh Nguyen else 108147a1685fSDinh Nguyen packets = 1; /* send one packet if length is zero. */ 108247a1685fSDinh Nguyen 108347a1685fSDinh Nguyen if (hs_ep->isochronous && length > (hs_ep->mc * hs_ep->ep.maxpacket)) { 108447a1685fSDinh Nguyen dev_err(hsotg->dev, "req length > maxpacket*mc\n"); 108547a1685fSDinh Nguyen return; 108647a1685fSDinh Nguyen } 108747a1685fSDinh Nguyen 108847a1685fSDinh Nguyen if (dir_in && index != 0) 108947a1685fSDinh Nguyen if (hs_ep->isochronous) 109047a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(packets); 109147a1685fSDinh Nguyen else 109247a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(1); 109347a1685fSDinh Nguyen else 109447a1685fSDinh Nguyen epsize = 0; 109547a1685fSDinh Nguyen 109647a1685fSDinh Nguyen /* 1097f71b5e25SMian Yousaf Kaukab * zero length packet should be programmed on its own and should not 1098f71b5e25SMian Yousaf Kaukab * be counted in DIEPTSIZ.PktCnt with other packets. 109947a1685fSDinh Nguyen */ 1100f71b5e25SMian Yousaf Kaukab if (dir_in && ureq->zero && !continuing) { 1101f71b5e25SMian Yousaf Kaukab /* Test if zlp is actually required. */ 1102f71b5e25SMian Yousaf Kaukab if ((ureq->length >= hs_ep->ep.maxpacket) && 1103f71b5e25SMian Yousaf Kaukab !(ureq->length % hs_ep->ep.maxpacket)) 11048a20fa45SMian Yousaf Kaukab hs_ep->send_zlp = 1; 110547a1685fSDinh Nguyen } 110647a1685fSDinh Nguyen 110747a1685fSDinh Nguyen epsize |= DXEPTSIZ_PKTCNT(packets); 110847a1685fSDinh Nguyen epsize |= DXEPTSIZ_XFERSIZE(length); 110947a1685fSDinh Nguyen 111047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", 111147a1685fSDinh Nguyen __func__, packets, length, ureq->length, epsize, epsize_reg); 111247a1685fSDinh Nguyen 111347a1685fSDinh Nguyen /* store the request as the current one we're doing */ 111447a1685fSDinh Nguyen hs_ep->req = hs_req; 111547a1685fSDinh Nguyen 1116aa3e8bc8SVahram Aharonyan if (using_desc_dma(hsotg)) { 1117aa3e8bc8SVahram Aharonyan u32 offset = 0; 1118aa3e8bc8SVahram Aharonyan u32 mps = hs_ep->ep.maxpacket; 1119aa3e8bc8SVahram Aharonyan 1120aa3e8bc8SVahram Aharonyan /* Adjust length: EP0 - MPS, other OUT EPs - multiple of MPS */ 1121aa3e8bc8SVahram Aharonyan if (!dir_in) { 1122aa3e8bc8SVahram Aharonyan if (!index) 1123aa3e8bc8SVahram Aharonyan length = mps; 1124aa3e8bc8SVahram Aharonyan else if (length % mps) 1125aa3e8bc8SVahram Aharonyan length += (mps - (length % mps)); 1126aa3e8bc8SVahram Aharonyan } 1127aa3e8bc8SVahram Aharonyan 1128aa3e8bc8SVahram Aharonyan /* 1129aa3e8bc8SVahram Aharonyan * If more data to send, adjust DMA for EP0 out data stage. 1130aa3e8bc8SVahram Aharonyan * ureq->dma stays unchanged, hence increment it by already 1131aa3e8bc8SVahram Aharonyan * passed passed data count before starting new transaction. 1132aa3e8bc8SVahram Aharonyan */ 1133aa3e8bc8SVahram Aharonyan if (!index && hsotg->ep0_state == DWC2_EP0_DATA_OUT && 1134aa3e8bc8SVahram Aharonyan continuing) 1135aa3e8bc8SVahram Aharonyan offset = ureq->actual; 1136aa3e8bc8SVahram Aharonyan 1137aa3e8bc8SVahram Aharonyan /* Fill DDMA chain entries */ 113810209abeSAndrzej Pietrasiewicz dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq, offset, 1139aa3e8bc8SVahram Aharonyan length); 1140aa3e8bc8SVahram Aharonyan 1141aa3e8bc8SVahram Aharonyan /* write descriptor chain address to control register */ 1142f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, hs_ep->desc_list_dma, dma_reg); 1143aa3e8bc8SVahram Aharonyan 1144aa3e8bc8SVahram Aharonyan dev_dbg(hsotg->dev, "%s: %08x pad => 0x%08x\n", 1145aa3e8bc8SVahram Aharonyan __func__, (u32)hs_ep->desc_list_dma, dma_reg); 1146aa3e8bc8SVahram Aharonyan } else { 114747a1685fSDinh Nguyen /* write size / packets */ 1148f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, epsize, epsize_reg); 114947a1685fSDinh Nguyen 1150729e6574SRazmik Karapetyan if (using_dma(hsotg) && !continuing && (length != 0)) { 115147a1685fSDinh Nguyen /* 1152aa3e8bc8SVahram Aharonyan * write DMA address to control register, buffer 1153aa3e8bc8SVahram Aharonyan * already synced by dwc2_hsotg_ep_queue(). 115447a1685fSDinh Nguyen */ 115547a1685fSDinh Nguyen 1156f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ureq->dma, dma_reg); 115747a1685fSDinh Nguyen 11580cc4cf6fSFabio Estevam dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n", 115947a1685fSDinh Nguyen __func__, &ureq->dma, dma_reg); 116047a1685fSDinh Nguyen } 1161aa3e8bc8SVahram Aharonyan } 116247a1685fSDinh Nguyen 1163837e9f00SVardan Mikayelyan if (hs_ep->isochronous && hs_ep->interval == 1) { 1164837e9f00SVardan Mikayelyan hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg); 1165837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 1166837e9f00SVardan Mikayelyan 1167837e9f00SVardan Mikayelyan if (hs_ep->target_frame & 0x1) 1168837e9f00SVardan Mikayelyan ctrl |= DXEPCTL_SETODDFR; 1169837e9f00SVardan Mikayelyan else 1170837e9f00SVardan Mikayelyan ctrl |= DXEPCTL_SETEVENFR; 1171837e9f00SVardan Mikayelyan } 1172837e9f00SVardan Mikayelyan 117347a1685fSDinh Nguyen ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 117447a1685fSDinh Nguyen 1175fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state); 117647a1685fSDinh Nguyen 117747a1685fSDinh Nguyen /* For Setup request do not clear NAK */ 1178fe0b94abSMian Yousaf Kaukab if (!(index == 0 && hsotg->ep0_state == DWC2_EP0_SETUP)) 117947a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 118047a1685fSDinh Nguyen 118147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 1182f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ctrl, epctrl_reg); 118347a1685fSDinh Nguyen 118447a1685fSDinh Nguyen /* 118547a1685fSDinh Nguyen * set these, it seems that DMA support increments past the end 118647a1685fSDinh Nguyen * of the packet buffer so we need to calculate the length from 118747a1685fSDinh Nguyen * this information. 118847a1685fSDinh Nguyen */ 118947a1685fSDinh Nguyen hs_ep->size_loaded = length; 119047a1685fSDinh Nguyen hs_ep->last_load = ureq->actual; 119147a1685fSDinh Nguyen 119247a1685fSDinh Nguyen if (dir_in && !using_dma(hsotg)) { 119347a1685fSDinh Nguyen /* set these anyway, we may need them for non-periodic in */ 119447a1685fSDinh Nguyen hs_ep->fifo_load = 0; 119547a1685fSDinh Nguyen 11961f91b4ccSFelipe Balbi dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 119747a1685fSDinh Nguyen } 119847a1685fSDinh Nguyen 119947a1685fSDinh Nguyen /* 120047a1685fSDinh Nguyen * Note, trying to clear the NAK here causes problems with transmit 120147a1685fSDinh Nguyen * on the S3C6400 ending up with the TXFIFO becoming full. 120247a1685fSDinh Nguyen */ 120347a1685fSDinh Nguyen 120447a1685fSDinh Nguyen /* check ep is enabled */ 1205f25c42b8SGevorg Sahakyan if (!(dwc2_readl(hsotg, epctrl_reg) & DXEPCTL_EPENA)) 12061a0ed863SMian Yousaf Kaukab dev_dbg(hsotg->dev, 120747a1685fSDinh Nguyen "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", 1208f25c42b8SGevorg Sahakyan index, dwc2_readl(hsotg, epctrl_reg)); 120947a1685fSDinh Nguyen 121047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", 1211f25c42b8SGevorg Sahakyan __func__, dwc2_readl(hsotg, epctrl_reg)); 121247a1685fSDinh Nguyen 121347a1685fSDinh Nguyen /* enable ep interrupts */ 12141f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1); 121547a1685fSDinh Nguyen } 121647a1685fSDinh Nguyen 121747a1685fSDinh Nguyen /** 12181f91b4ccSFelipe Balbi * dwc2_hsotg_map_dma - map the DMA memory being used for the request 121947a1685fSDinh Nguyen * @hsotg: The device state. 122047a1685fSDinh Nguyen * @hs_ep: The endpoint the request is on. 122147a1685fSDinh Nguyen * @req: The request being processed. 122247a1685fSDinh Nguyen * 122347a1685fSDinh Nguyen * We've been asked to queue a request, so ensure that the memory buffer 122447a1685fSDinh Nguyen * is correctly setup for DMA. If we've been passed an extant DMA address 122547a1685fSDinh Nguyen * then ensure the buffer has been synced to memory. If our buffer has no 122647a1685fSDinh Nguyen * DMA memory, then we map the memory and mark our request to allow us to 122747a1685fSDinh Nguyen * cleanup on completion. 122847a1685fSDinh Nguyen */ 12291f91b4ccSFelipe Balbi static int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg, 12301f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 123147a1685fSDinh Nguyen struct usb_request *req) 123247a1685fSDinh Nguyen { 123347a1685fSDinh Nguyen int ret; 123447a1685fSDinh Nguyen 123547a1685fSDinh Nguyen ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); 123647a1685fSDinh Nguyen if (ret) 123747a1685fSDinh Nguyen goto dma_error; 123847a1685fSDinh Nguyen 123947a1685fSDinh Nguyen return 0; 124047a1685fSDinh Nguyen 124147a1685fSDinh Nguyen dma_error: 124247a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", 124347a1685fSDinh Nguyen __func__, req->buf, req->length); 124447a1685fSDinh Nguyen 124547a1685fSDinh Nguyen return -EIO; 124647a1685fSDinh Nguyen } 124747a1685fSDinh Nguyen 12481f91b4ccSFelipe Balbi static int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, 1249b98866c2SJohn Youn struct dwc2_hsotg_ep *hs_ep, 1250b98866c2SJohn Youn struct dwc2_hsotg_req *hs_req) 12517d24c1b5SMian Yousaf Kaukab { 12527d24c1b5SMian Yousaf Kaukab void *req_buf = hs_req->req.buf; 12537d24c1b5SMian Yousaf Kaukab 12547d24c1b5SMian Yousaf Kaukab /* If dma is not being used or buffer is aligned */ 12557d24c1b5SMian Yousaf Kaukab if (!using_dma(hsotg) || !((long)req_buf & 3)) 12567d24c1b5SMian Yousaf Kaukab return 0; 12577d24c1b5SMian Yousaf Kaukab 12587d24c1b5SMian Yousaf Kaukab WARN_ON(hs_req->saved_req_buf); 12597d24c1b5SMian Yousaf Kaukab 12607d24c1b5SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__, 12617d24c1b5SMian Yousaf Kaukab hs_ep->ep.name, req_buf, hs_req->req.length); 12627d24c1b5SMian Yousaf Kaukab 12637d24c1b5SMian Yousaf Kaukab hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC); 12647d24c1b5SMian Yousaf Kaukab if (!hs_req->req.buf) { 12657d24c1b5SMian Yousaf Kaukab hs_req->req.buf = req_buf; 12667d24c1b5SMian Yousaf Kaukab dev_err(hsotg->dev, 12677d24c1b5SMian Yousaf Kaukab "%s: unable to allocate memory for bounce buffer\n", 12687d24c1b5SMian Yousaf Kaukab __func__); 12697d24c1b5SMian Yousaf Kaukab return -ENOMEM; 12707d24c1b5SMian Yousaf Kaukab } 12717d24c1b5SMian Yousaf Kaukab 12727d24c1b5SMian Yousaf Kaukab /* Save actual buffer */ 12737d24c1b5SMian Yousaf Kaukab hs_req->saved_req_buf = req_buf; 12747d24c1b5SMian Yousaf Kaukab 12757d24c1b5SMian Yousaf Kaukab if (hs_ep->dir_in) 12767d24c1b5SMian Yousaf Kaukab memcpy(hs_req->req.buf, req_buf, hs_req->req.length); 12777d24c1b5SMian Yousaf Kaukab return 0; 12787d24c1b5SMian Yousaf Kaukab } 12797d24c1b5SMian Yousaf Kaukab 1280b98866c2SJohn Youn static void 1281b98866c2SJohn Youn dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, 1282b98866c2SJohn Youn struct dwc2_hsotg_ep *hs_ep, 1283b98866c2SJohn Youn struct dwc2_hsotg_req *hs_req) 12847d24c1b5SMian Yousaf Kaukab { 12857d24c1b5SMian Yousaf Kaukab /* If dma is not being used or buffer was aligned */ 12867d24c1b5SMian Yousaf Kaukab if (!using_dma(hsotg) || !hs_req->saved_req_buf) 12877d24c1b5SMian Yousaf Kaukab return; 12887d24c1b5SMian Yousaf Kaukab 12897d24c1b5SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: %s: status=%d actual-length=%d\n", __func__, 12907d24c1b5SMian Yousaf Kaukab hs_ep->ep.name, hs_req->req.status, hs_req->req.actual); 12917d24c1b5SMian Yousaf Kaukab 12927d24c1b5SMian Yousaf Kaukab /* Copy data from bounce buffer on successful out transfer */ 12937d24c1b5SMian Yousaf Kaukab if (!hs_ep->dir_in && !hs_req->req.status) 12947d24c1b5SMian Yousaf Kaukab memcpy(hs_req->saved_req_buf, hs_req->req.buf, 12957d24c1b5SMian Yousaf Kaukab hs_req->req.actual); 12967d24c1b5SMian Yousaf Kaukab 12977d24c1b5SMian Yousaf Kaukab /* Free bounce buffer */ 12987d24c1b5SMian Yousaf Kaukab kfree(hs_req->req.buf); 12997d24c1b5SMian Yousaf Kaukab 13007d24c1b5SMian Yousaf Kaukab hs_req->req.buf = hs_req->saved_req_buf; 13017d24c1b5SMian Yousaf Kaukab hs_req->saved_req_buf = NULL; 13027d24c1b5SMian Yousaf Kaukab } 13037d24c1b5SMian Yousaf Kaukab 1304381fc8f8SVardan Mikayelyan /** 1305381fc8f8SVardan Mikayelyan * dwc2_gadget_target_frame_elapsed - Checks target frame 1306381fc8f8SVardan Mikayelyan * @hs_ep: The driver endpoint to check 1307381fc8f8SVardan Mikayelyan * 1308381fc8f8SVardan Mikayelyan * Returns 1 if targeted frame elapsed. If returned 1 then we need to drop 1309381fc8f8SVardan Mikayelyan * corresponding transfer. 1310381fc8f8SVardan Mikayelyan */ 1311381fc8f8SVardan Mikayelyan static bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep) 1312381fc8f8SVardan Mikayelyan { 1313381fc8f8SVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 1314381fc8f8SVardan Mikayelyan u32 target_frame = hs_ep->target_frame; 1315c7c24e7aSArtur Petrosyan u32 current_frame = hsotg->frame_number; 1316381fc8f8SVardan Mikayelyan bool frame_overrun = hs_ep->frame_overrun; 1317381fc8f8SVardan Mikayelyan 1318381fc8f8SVardan Mikayelyan if (!frame_overrun && current_frame >= target_frame) 1319381fc8f8SVardan Mikayelyan return true; 1320381fc8f8SVardan Mikayelyan 1321381fc8f8SVardan Mikayelyan if (frame_overrun && current_frame >= target_frame && 1322381fc8f8SVardan Mikayelyan ((current_frame - target_frame) < DSTS_SOFFN_LIMIT / 2)) 1323381fc8f8SVardan Mikayelyan return true; 1324381fc8f8SVardan Mikayelyan 1325381fc8f8SVardan Mikayelyan return false; 1326381fc8f8SVardan Mikayelyan } 1327381fc8f8SVardan Mikayelyan 1328e02f9aa6SVahram Aharonyan /* 1329e02f9aa6SVahram Aharonyan * dwc2_gadget_set_ep0_desc_chain - Set EP's desc chain pointers 1330e02f9aa6SVahram Aharonyan * @hsotg: The driver state 1331e02f9aa6SVahram Aharonyan * @hs_ep: the ep descriptor chain is for 1332e02f9aa6SVahram Aharonyan * 1333e02f9aa6SVahram Aharonyan * Called to update EP0 structure's pointers depend on stage of 1334e02f9aa6SVahram Aharonyan * control transfer. 1335e02f9aa6SVahram Aharonyan */ 1336e02f9aa6SVahram Aharonyan static int dwc2_gadget_set_ep0_desc_chain(struct dwc2_hsotg *hsotg, 1337e02f9aa6SVahram Aharonyan struct dwc2_hsotg_ep *hs_ep) 1338e02f9aa6SVahram Aharonyan { 1339e02f9aa6SVahram Aharonyan switch (hsotg->ep0_state) { 1340e02f9aa6SVahram Aharonyan case DWC2_EP0_SETUP: 1341e02f9aa6SVahram Aharonyan case DWC2_EP0_STATUS_OUT: 1342e02f9aa6SVahram Aharonyan hs_ep->desc_list = hsotg->setup_desc[0]; 1343e02f9aa6SVahram Aharonyan hs_ep->desc_list_dma = hsotg->setup_desc_dma[0]; 1344e02f9aa6SVahram Aharonyan break; 1345e02f9aa6SVahram Aharonyan case DWC2_EP0_DATA_IN: 1346e02f9aa6SVahram Aharonyan case DWC2_EP0_STATUS_IN: 1347e02f9aa6SVahram Aharonyan hs_ep->desc_list = hsotg->ctrl_in_desc; 1348e02f9aa6SVahram Aharonyan hs_ep->desc_list_dma = hsotg->ctrl_in_desc_dma; 1349e02f9aa6SVahram Aharonyan break; 1350e02f9aa6SVahram Aharonyan case DWC2_EP0_DATA_OUT: 1351e02f9aa6SVahram Aharonyan hs_ep->desc_list = hsotg->ctrl_out_desc; 1352e02f9aa6SVahram Aharonyan hs_ep->desc_list_dma = hsotg->ctrl_out_desc_dma; 1353e02f9aa6SVahram Aharonyan break; 1354e02f9aa6SVahram Aharonyan default: 1355e02f9aa6SVahram Aharonyan dev_err(hsotg->dev, "invalid EP 0 state in queue %d\n", 1356e02f9aa6SVahram Aharonyan hsotg->ep0_state); 1357e02f9aa6SVahram Aharonyan return -EINVAL; 1358e02f9aa6SVahram Aharonyan } 1359e02f9aa6SVahram Aharonyan 1360e02f9aa6SVahram Aharonyan return 0; 1361e02f9aa6SVahram Aharonyan } 1362e02f9aa6SVahram Aharonyan 13631f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, 136447a1685fSDinh Nguyen gfp_t gfp_flags) 136547a1685fSDinh Nguyen { 13661f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 13671f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1368941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 136947a1685fSDinh Nguyen bool first; 13707d24c1b5SMian Yousaf Kaukab int ret; 1371729cac69SMinas Harutyunyan u32 maxsize = 0; 1372729cac69SMinas Harutyunyan u32 mask = 0; 1373729cac69SMinas Harutyunyan 137447a1685fSDinh Nguyen 137547a1685fSDinh Nguyen dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", 137647a1685fSDinh Nguyen ep->name, req, req->length, req->buf, req->no_interrupt, 137747a1685fSDinh Nguyen req->zero, req->short_not_ok); 137847a1685fSDinh Nguyen 13797ababa92SGregory Herrero /* Prevent new request submission when controller is suspended */ 138088b02f2cSGrigor Tovmasyan if (hs->lx_state != DWC2_L0) { 138188b02f2cSGrigor Tovmasyan dev_dbg(hs->dev, "%s: submit request only in active state\n", 13827ababa92SGregory Herrero __func__); 13837ababa92SGregory Herrero return -EAGAIN; 13847ababa92SGregory Herrero } 13857ababa92SGregory Herrero 138647a1685fSDinh Nguyen /* initialise status of the request */ 138747a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_req->queue); 138847a1685fSDinh Nguyen req->actual = 0; 138947a1685fSDinh Nguyen req->status = -EINPROGRESS; 139047a1685fSDinh Nguyen 1391729cac69SMinas Harutyunyan /* In DDMA mode for ISOC's don't queue request if length greater 1392729cac69SMinas Harutyunyan * than descriptor limits. 1393729cac69SMinas Harutyunyan */ 1394729cac69SMinas Harutyunyan if (using_desc_dma(hs) && hs_ep->isochronous) { 1395729cac69SMinas Harutyunyan maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); 1396729cac69SMinas Harutyunyan if (hs_ep->dir_in && req->length > maxsize) { 1397729cac69SMinas Harutyunyan dev_err(hs->dev, "wrong length %d (maxsize=%d)\n", 1398729cac69SMinas Harutyunyan req->length, maxsize); 1399729cac69SMinas Harutyunyan return -EINVAL; 1400729cac69SMinas Harutyunyan } 1401729cac69SMinas Harutyunyan 1402729cac69SMinas Harutyunyan if (!hs_ep->dir_in && req->length > hs_ep->ep.maxpacket) { 1403729cac69SMinas Harutyunyan dev_err(hs->dev, "ISOC OUT: wrong length %d (mps=%d)\n", 1404729cac69SMinas Harutyunyan req->length, hs_ep->ep.maxpacket); 1405729cac69SMinas Harutyunyan return -EINVAL; 1406729cac69SMinas Harutyunyan } 1407729cac69SMinas Harutyunyan } 1408729cac69SMinas Harutyunyan 14091f91b4ccSFelipe Balbi ret = dwc2_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req); 14107d24c1b5SMian Yousaf Kaukab if (ret) 14117d24c1b5SMian Yousaf Kaukab return ret; 14127d24c1b5SMian Yousaf Kaukab 141347a1685fSDinh Nguyen /* if we're using DMA, sync the buffers as necessary */ 141447a1685fSDinh Nguyen if (using_dma(hs)) { 14151f91b4ccSFelipe Balbi ret = dwc2_hsotg_map_dma(hs, hs_ep, req); 141647a1685fSDinh Nguyen if (ret) 141747a1685fSDinh Nguyen return ret; 141847a1685fSDinh Nguyen } 1419e02f9aa6SVahram Aharonyan /* If using descriptor DMA configure EP0 descriptor chain pointers */ 1420e02f9aa6SVahram Aharonyan if (using_desc_dma(hs) && !hs_ep->index) { 1421e02f9aa6SVahram Aharonyan ret = dwc2_gadget_set_ep0_desc_chain(hs, hs_ep); 1422e02f9aa6SVahram Aharonyan if (ret) 1423e02f9aa6SVahram Aharonyan return ret; 1424e02f9aa6SVahram Aharonyan } 142547a1685fSDinh Nguyen 142647a1685fSDinh Nguyen first = list_empty(&hs_ep->queue); 142747a1685fSDinh Nguyen list_add_tail(&hs_req->queue, &hs_ep->queue); 142847a1685fSDinh Nguyen 1429540ccba0SVahram Aharonyan /* 1430540ccba0SVahram Aharonyan * Handle DDMA isochronous transfers separately - just add new entry 1431729cac69SMinas Harutyunyan * to the descriptor chain. 1432540ccba0SVahram Aharonyan * Transfer will be started once SW gets either one of NAK or 1433540ccba0SVahram Aharonyan * OutTknEpDis interrupts. 1434540ccba0SVahram Aharonyan */ 1435729cac69SMinas Harutyunyan if (using_desc_dma(hs) && hs_ep->isochronous) { 1436729cac69SMinas Harutyunyan if (hs_ep->target_frame != TARGET_FRAME_INITIAL) { 143710209abeSAndrzej Pietrasiewicz dma_addr_t dma_addr = hs_req->req.dma; 143810209abeSAndrzej Pietrasiewicz 143910209abeSAndrzej Pietrasiewicz if (hs_req->req.num_sgs) { 144010209abeSAndrzej Pietrasiewicz WARN_ON(hs_req->req.num_sgs > 1); 144110209abeSAndrzej Pietrasiewicz dma_addr = sg_dma_address(hs_req->req.sg); 144210209abeSAndrzej Pietrasiewicz } 144310209abeSAndrzej Pietrasiewicz dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, 1444540ccba0SVahram Aharonyan hs_req->req.length); 1445729cac69SMinas Harutyunyan } 1446540ccba0SVahram Aharonyan return 0; 1447540ccba0SVahram Aharonyan } 1448540ccba0SVahram Aharonyan 1449b4c53b4aSMinas Harutyunyan /* Change EP direction if status phase request is after data out */ 1450b4c53b4aSMinas Harutyunyan if (!hs_ep->index && !req->length && !hs_ep->dir_in && 1451b4c53b4aSMinas Harutyunyan hs->ep0_state == DWC2_EP0_DATA_OUT) 1452b4c53b4aSMinas Harutyunyan hs_ep->dir_in = 1; 1453b4c53b4aSMinas Harutyunyan 1454837e9f00SVardan Mikayelyan if (first) { 1455837e9f00SVardan Mikayelyan if (!hs_ep->isochronous) { 14561f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 1457837e9f00SVardan Mikayelyan return 0; 1458837e9f00SVardan Mikayelyan } 145947a1685fSDinh Nguyen 1460c7c24e7aSArtur Petrosyan /* Update current frame number value. */ 1461c7c24e7aSArtur Petrosyan hs->frame_number = dwc2_hsotg_read_frameno(hs); 1462c7c24e7aSArtur Petrosyan while (dwc2_gadget_target_frame_elapsed(hs_ep)) { 1463837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 1464c7c24e7aSArtur Petrosyan /* Update current frame number value once more as it 1465c7c24e7aSArtur Petrosyan * changes here. 1466c7c24e7aSArtur Petrosyan */ 1467c7c24e7aSArtur Petrosyan hs->frame_number = dwc2_hsotg_read_frameno(hs); 1468c7c24e7aSArtur Petrosyan } 1469837e9f00SVardan Mikayelyan 1470837e9f00SVardan Mikayelyan if (hs_ep->target_frame != TARGET_FRAME_INITIAL) 1471837e9f00SVardan Mikayelyan dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 1472837e9f00SVardan Mikayelyan } 147347a1685fSDinh Nguyen return 0; 147447a1685fSDinh Nguyen } 147547a1685fSDinh Nguyen 14761f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, 147747a1685fSDinh Nguyen gfp_t gfp_flags) 147847a1685fSDinh Nguyen { 14791f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1480941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 148147a1685fSDinh Nguyen unsigned long flags = 0; 148247a1685fSDinh Nguyen int ret = 0; 148347a1685fSDinh Nguyen 148447a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 14851f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(ep, req, gfp_flags); 148647a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 148747a1685fSDinh Nguyen 148847a1685fSDinh Nguyen return ret; 148947a1685fSDinh Nguyen } 149047a1685fSDinh Nguyen 14911f91b4ccSFelipe Balbi static void dwc2_hsotg_ep_free_request(struct usb_ep *ep, 149247a1685fSDinh Nguyen struct usb_request *req) 149347a1685fSDinh Nguyen { 14941f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 149547a1685fSDinh Nguyen 149647a1685fSDinh Nguyen kfree(hs_req); 149747a1685fSDinh Nguyen } 149847a1685fSDinh Nguyen 149947a1685fSDinh Nguyen /** 15001f91b4ccSFelipe Balbi * dwc2_hsotg_complete_oursetup - setup completion callback 150147a1685fSDinh Nguyen * @ep: The endpoint the request was on. 150247a1685fSDinh Nguyen * @req: The request completed. 150347a1685fSDinh Nguyen * 150447a1685fSDinh Nguyen * Called on completion of any requests the driver itself 150547a1685fSDinh Nguyen * submitted that need cleaning up. 150647a1685fSDinh Nguyen */ 15071f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_oursetup(struct usb_ep *ep, 150847a1685fSDinh Nguyen struct usb_request *req) 150947a1685fSDinh Nguyen { 15101f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1511941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 151247a1685fSDinh Nguyen 151347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); 151447a1685fSDinh Nguyen 15151f91b4ccSFelipe Balbi dwc2_hsotg_ep_free_request(ep, req); 151647a1685fSDinh Nguyen } 151747a1685fSDinh Nguyen 151847a1685fSDinh Nguyen /** 151947a1685fSDinh Nguyen * ep_from_windex - convert control wIndex value to endpoint 152047a1685fSDinh Nguyen * @hsotg: The driver state. 152147a1685fSDinh Nguyen * @windex: The control request wIndex field (in host order). 152247a1685fSDinh Nguyen * 152347a1685fSDinh Nguyen * Convert the given wIndex into a pointer to an driver endpoint 152447a1685fSDinh Nguyen * structure, or return NULL if it is not a valid endpoint. 152547a1685fSDinh Nguyen */ 15261f91b4ccSFelipe Balbi static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, 152747a1685fSDinh Nguyen u32 windex) 152847a1685fSDinh Nguyen { 15291f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 153047a1685fSDinh Nguyen int dir = (windex & USB_DIR_IN) ? 1 : 0; 153147a1685fSDinh Nguyen int idx = windex & 0x7F; 153247a1685fSDinh Nguyen 153347a1685fSDinh Nguyen if (windex >= 0x100) 153447a1685fSDinh Nguyen return NULL; 153547a1685fSDinh Nguyen 153647a1685fSDinh Nguyen if (idx > hsotg->num_of_eps) 153747a1685fSDinh Nguyen return NULL; 153847a1685fSDinh Nguyen 1539c6f5c050SMian Yousaf Kaukab ep = index_to_ep(hsotg, idx, dir); 1540c6f5c050SMian Yousaf Kaukab 154147a1685fSDinh Nguyen if (idx && ep->dir_in != dir) 154247a1685fSDinh Nguyen return NULL; 154347a1685fSDinh Nguyen 154447a1685fSDinh Nguyen return ep; 154547a1685fSDinh Nguyen } 154647a1685fSDinh Nguyen 154747a1685fSDinh Nguyen /** 15481f91b4ccSFelipe Balbi * dwc2_hsotg_set_test_mode - Enable usb Test Modes 15499e14d0a5SGregory Herrero * @hsotg: The driver state. 15509e14d0a5SGregory Herrero * @testmode: requested usb test mode 15519e14d0a5SGregory Herrero * Enable usb Test Mode requested by the Host. 15529e14d0a5SGregory Herrero */ 15531f91b4ccSFelipe Balbi int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode) 15549e14d0a5SGregory Herrero { 1555f25c42b8SGevorg Sahakyan int dctl = dwc2_readl(hsotg, DCTL); 15569e14d0a5SGregory Herrero 15579e14d0a5SGregory Herrero dctl &= ~DCTL_TSTCTL_MASK; 15589e14d0a5SGregory Herrero switch (testmode) { 15599e14d0a5SGregory Herrero case TEST_J: 15609e14d0a5SGregory Herrero case TEST_K: 15619e14d0a5SGregory Herrero case TEST_SE0_NAK: 15629e14d0a5SGregory Herrero case TEST_PACKET: 15639e14d0a5SGregory Herrero case TEST_FORCE_EN: 15649e14d0a5SGregory Herrero dctl |= testmode << DCTL_TSTCTL_SHIFT; 15659e14d0a5SGregory Herrero break; 15669e14d0a5SGregory Herrero default: 15679e14d0a5SGregory Herrero return -EINVAL; 15689e14d0a5SGregory Herrero } 1569f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dctl, DCTL); 15709e14d0a5SGregory Herrero return 0; 15719e14d0a5SGregory Herrero } 15729e14d0a5SGregory Herrero 15739e14d0a5SGregory Herrero /** 15741f91b4ccSFelipe Balbi * dwc2_hsotg_send_reply - send reply to control request 157547a1685fSDinh Nguyen * @hsotg: The device state 157647a1685fSDinh Nguyen * @ep: Endpoint 0 157747a1685fSDinh Nguyen * @buff: Buffer for request 157847a1685fSDinh Nguyen * @length: Length of reply. 157947a1685fSDinh Nguyen * 158047a1685fSDinh Nguyen * Create a request and queue it on the given endpoint. This is useful as 158147a1685fSDinh Nguyen * an internal method of sending replies to certain control requests, etc. 158247a1685fSDinh Nguyen */ 15831f91b4ccSFelipe Balbi static int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg, 15841f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep, 158547a1685fSDinh Nguyen void *buff, 158647a1685fSDinh Nguyen int length) 158747a1685fSDinh Nguyen { 158847a1685fSDinh Nguyen struct usb_request *req; 158947a1685fSDinh Nguyen int ret; 159047a1685fSDinh Nguyen 159147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); 159247a1685fSDinh Nguyen 15931f91b4ccSFelipe Balbi req = dwc2_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); 159447a1685fSDinh Nguyen hsotg->ep0_reply = req; 159547a1685fSDinh Nguyen if (!req) { 159647a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); 159747a1685fSDinh Nguyen return -ENOMEM; 159847a1685fSDinh Nguyen } 159947a1685fSDinh Nguyen 160047a1685fSDinh Nguyen req->buf = hsotg->ep0_buff; 160147a1685fSDinh Nguyen req->length = length; 1602f71b5e25SMian Yousaf Kaukab /* 1603f71b5e25SMian Yousaf Kaukab * zero flag is for sending zlp in DATA IN stage. It has no impact on 1604f71b5e25SMian Yousaf Kaukab * STATUS stage. 1605f71b5e25SMian Yousaf Kaukab */ 1606f71b5e25SMian Yousaf Kaukab req->zero = 0; 16071f91b4ccSFelipe Balbi req->complete = dwc2_hsotg_complete_oursetup; 160847a1685fSDinh Nguyen 160947a1685fSDinh Nguyen if (length) 161047a1685fSDinh Nguyen memcpy(req->buf, buff, length); 161147a1685fSDinh Nguyen 16121f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); 161347a1685fSDinh Nguyen if (ret) { 161447a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); 161547a1685fSDinh Nguyen return ret; 161647a1685fSDinh Nguyen } 161747a1685fSDinh Nguyen 161847a1685fSDinh Nguyen return 0; 161947a1685fSDinh Nguyen } 162047a1685fSDinh Nguyen 162147a1685fSDinh Nguyen /** 16221f91b4ccSFelipe Balbi * dwc2_hsotg_process_req_status - process request GET_STATUS 162347a1685fSDinh Nguyen * @hsotg: The device state 162447a1685fSDinh Nguyen * @ctrl: USB control request 162547a1685fSDinh Nguyen */ 16261f91b4ccSFelipe Balbi static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, 162747a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 162847a1685fSDinh Nguyen { 16291f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 16301f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 163147a1685fSDinh Nguyen __le16 reply; 163247a1685fSDinh Nguyen int ret; 163347a1685fSDinh Nguyen 163447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); 163547a1685fSDinh Nguyen 163647a1685fSDinh Nguyen if (!ep0->dir_in) { 163747a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: direction out?\n", __func__); 163847a1685fSDinh Nguyen return -EINVAL; 163947a1685fSDinh Nguyen } 164047a1685fSDinh Nguyen 164147a1685fSDinh Nguyen switch (ctrl->bRequestType & USB_RECIP_MASK) { 164247a1685fSDinh Nguyen case USB_RECIP_DEVICE: 164338beaec6SJohn Youn /* 164438beaec6SJohn Youn * bit 0 => self powered 164538beaec6SJohn Youn * bit 1 => remote wakeup 164638beaec6SJohn Youn */ 164738beaec6SJohn Youn reply = cpu_to_le16(0); 164847a1685fSDinh Nguyen break; 164947a1685fSDinh Nguyen 165047a1685fSDinh Nguyen case USB_RECIP_INTERFACE: 165147a1685fSDinh Nguyen /* currently, the data result should be zero */ 165247a1685fSDinh Nguyen reply = cpu_to_le16(0); 165347a1685fSDinh Nguyen break; 165447a1685fSDinh Nguyen 165547a1685fSDinh Nguyen case USB_RECIP_ENDPOINT: 165647a1685fSDinh Nguyen ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); 165747a1685fSDinh Nguyen if (!ep) 165847a1685fSDinh Nguyen return -ENOENT; 165947a1685fSDinh Nguyen 166047a1685fSDinh Nguyen reply = cpu_to_le16(ep->halted ? 1 : 0); 166147a1685fSDinh Nguyen break; 166247a1685fSDinh Nguyen 166347a1685fSDinh Nguyen default: 166447a1685fSDinh Nguyen return 0; 166547a1685fSDinh Nguyen } 166647a1685fSDinh Nguyen 166747a1685fSDinh Nguyen if (le16_to_cpu(ctrl->wLength) != 2) 166847a1685fSDinh Nguyen return -EINVAL; 166947a1685fSDinh Nguyen 16701f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, &reply, 2); 167147a1685fSDinh Nguyen if (ret) { 167247a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); 167347a1685fSDinh Nguyen return ret; 167447a1685fSDinh Nguyen } 167547a1685fSDinh Nguyen 167647a1685fSDinh Nguyen return 1; 167747a1685fSDinh Nguyen } 167847a1685fSDinh Nguyen 167951da43b5SVahram Aharonyan static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now); 168047a1685fSDinh Nguyen 168147a1685fSDinh Nguyen /** 168247a1685fSDinh Nguyen * get_ep_head - return the first request on the endpoint 168347a1685fSDinh Nguyen * @hs_ep: The controller endpoint to get 168447a1685fSDinh Nguyen * 168547a1685fSDinh Nguyen * Get the first request on the endpoint. 168647a1685fSDinh Nguyen */ 16871f91b4ccSFelipe Balbi static struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep) 168847a1685fSDinh Nguyen { 1689ffc4b406SMasahiro Yamada return list_first_entry_or_null(&hs_ep->queue, struct dwc2_hsotg_req, 1690ffc4b406SMasahiro Yamada queue); 169147a1685fSDinh Nguyen } 169247a1685fSDinh Nguyen 169347a1685fSDinh Nguyen /** 169441cc4cd2SVardan Mikayelyan * dwc2_gadget_start_next_request - Starts next request from ep queue 169541cc4cd2SVardan Mikayelyan * @hs_ep: Endpoint structure 169641cc4cd2SVardan Mikayelyan * 169741cc4cd2SVardan Mikayelyan * If queue is empty and EP is ISOC-OUT - unmasks OUTTKNEPDIS which is masked 169841cc4cd2SVardan Mikayelyan * in its handler. Hence we need to unmask it here to be able to do 169941cc4cd2SVardan Mikayelyan * resynchronization. 170041cc4cd2SVardan Mikayelyan */ 170141cc4cd2SVardan Mikayelyan static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep) 170241cc4cd2SVardan Mikayelyan { 170341cc4cd2SVardan Mikayelyan u32 mask; 170441cc4cd2SVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 170541cc4cd2SVardan Mikayelyan int dir_in = hs_ep->dir_in; 170641cc4cd2SVardan Mikayelyan struct dwc2_hsotg_req *hs_req; 170741cc4cd2SVardan Mikayelyan u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; 170841cc4cd2SVardan Mikayelyan 170941cc4cd2SVardan Mikayelyan if (!list_empty(&hs_ep->queue)) { 171041cc4cd2SVardan Mikayelyan hs_req = get_ep_head(hs_ep); 171141cc4cd2SVardan Mikayelyan dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false); 171241cc4cd2SVardan Mikayelyan return; 171341cc4cd2SVardan Mikayelyan } 171441cc4cd2SVardan Mikayelyan if (!hs_ep->isochronous) 171541cc4cd2SVardan Mikayelyan return; 171641cc4cd2SVardan Mikayelyan 171741cc4cd2SVardan Mikayelyan if (dir_in) { 171841cc4cd2SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: No more ISOC-IN requests\n", 171941cc4cd2SVardan Mikayelyan __func__); 172041cc4cd2SVardan Mikayelyan } else { 172141cc4cd2SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: No more ISOC-OUT requests\n", 172241cc4cd2SVardan Mikayelyan __func__); 1723f25c42b8SGevorg Sahakyan mask = dwc2_readl(hsotg, epmsk_reg); 172441cc4cd2SVardan Mikayelyan mask |= DOEPMSK_OUTTKNEPDISMSK; 1725f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, mask, epmsk_reg); 172641cc4cd2SVardan Mikayelyan } 172741cc4cd2SVardan Mikayelyan } 172841cc4cd2SVardan Mikayelyan 172941cc4cd2SVardan Mikayelyan /** 17301f91b4ccSFelipe Balbi * dwc2_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE 173147a1685fSDinh Nguyen * @hsotg: The device state 173247a1685fSDinh Nguyen * @ctrl: USB control request 173347a1685fSDinh Nguyen */ 17341f91b4ccSFelipe Balbi static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, 173547a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 173647a1685fSDinh Nguyen { 17371f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 17381f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req; 173947a1685fSDinh Nguyen bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); 17401f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 174147a1685fSDinh Nguyen int ret; 174247a1685fSDinh Nguyen bool halted; 17439e14d0a5SGregory Herrero u32 recip; 17449e14d0a5SGregory Herrero u32 wValue; 17459e14d0a5SGregory Herrero u32 wIndex; 174647a1685fSDinh Nguyen 174747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", 174847a1685fSDinh Nguyen __func__, set ? "SET" : "CLEAR"); 174947a1685fSDinh Nguyen 17509e14d0a5SGregory Herrero wValue = le16_to_cpu(ctrl->wValue); 17519e14d0a5SGregory Herrero wIndex = le16_to_cpu(ctrl->wIndex); 17529e14d0a5SGregory Herrero recip = ctrl->bRequestType & USB_RECIP_MASK; 17539e14d0a5SGregory Herrero 17549e14d0a5SGregory Herrero switch (recip) { 17559e14d0a5SGregory Herrero case USB_RECIP_DEVICE: 17569e14d0a5SGregory Herrero switch (wValue) { 1757fa389a6dSVardan Mikayelyan case USB_DEVICE_REMOTE_WAKEUP: 1758fa389a6dSVardan Mikayelyan hsotg->remote_wakeup_allowed = 1; 1759fa389a6dSVardan Mikayelyan break; 1760fa389a6dSVardan Mikayelyan 17619e14d0a5SGregory Herrero case USB_DEVICE_TEST_MODE: 17629e14d0a5SGregory Herrero if ((wIndex & 0xff) != 0) 17639e14d0a5SGregory Herrero return -EINVAL; 17649e14d0a5SGregory Herrero if (!set) 17659e14d0a5SGregory Herrero return -EINVAL; 17669e14d0a5SGregory Herrero 17679e14d0a5SGregory Herrero hsotg->test_mode = wIndex >> 8; 17681f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 17699e14d0a5SGregory Herrero if (ret) { 17709e14d0a5SGregory Herrero dev_err(hsotg->dev, 17719e14d0a5SGregory Herrero "%s: failed to send reply\n", __func__); 17729e14d0a5SGregory Herrero return ret; 17739e14d0a5SGregory Herrero } 17749e14d0a5SGregory Herrero break; 17759e14d0a5SGregory Herrero default: 17769e14d0a5SGregory Herrero return -ENOENT; 17779e14d0a5SGregory Herrero } 17789e14d0a5SGregory Herrero break; 17799e14d0a5SGregory Herrero 17809e14d0a5SGregory Herrero case USB_RECIP_ENDPOINT: 17819e14d0a5SGregory Herrero ep = ep_from_windex(hsotg, wIndex); 178247a1685fSDinh Nguyen if (!ep) { 178347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", 17849e14d0a5SGregory Herrero __func__, wIndex); 178547a1685fSDinh Nguyen return -ENOENT; 178647a1685fSDinh Nguyen } 178747a1685fSDinh Nguyen 17889e14d0a5SGregory Herrero switch (wValue) { 178947a1685fSDinh Nguyen case USB_ENDPOINT_HALT: 179047a1685fSDinh Nguyen halted = ep->halted; 179147a1685fSDinh Nguyen 179251da43b5SVahram Aharonyan dwc2_hsotg_ep_sethalt(&ep->ep, set, true); 179347a1685fSDinh Nguyen 17941f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 179547a1685fSDinh Nguyen if (ret) { 179647a1685fSDinh Nguyen dev_err(hsotg->dev, 179747a1685fSDinh Nguyen "%s: failed to send reply\n", __func__); 179847a1685fSDinh Nguyen return ret; 179947a1685fSDinh Nguyen } 180047a1685fSDinh Nguyen 180147a1685fSDinh Nguyen /* 180247a1685fSDinh Nguyen * we have to complete all requests for ep if it was 180347a1685fSDinh Nguyen * halted, and the halt was cleared by CLEAR_FEATURE 180447a1685fSDinh Nguyen */ 180547a1685fSDinh Nguyen 180647a1685fSDinh Nguyen if (!set && halted) { 180747a1685fSDinh Nguyen /* 180847a1685fSDinh Nguyen * If we have request in progress, 180947a1685fSDinh Nguyen * then complete it 181047a1685fSDinh Nguyen */ 181147a1685fSDinh Nguyen if (ep->req) { 181247a1685fSDinh Nguyen hs_req = ep->req; 181347a1685fSDinh Nguyen ep->req = NULL; 181447a1685fSDinh Nguyen list_del_init(&hs_req->queue); 1815c00dd4a6SGregory Herrero if (hs_req->req.complete) { 1816c00dd4a6SGregory Herrero spin_unlock(&hsotg->lock); 1817c00dd4a6SGregory Herrero usb_gadget_giveback_request( 1818c00dd4a6SGregory Herrero &ep->ep, &hs_req->req); 1819c00dd4a6SGregory Herrero spin_lock(&hsotg->lock); 1820c00dd4a6SGregory Herrero } 182147a1685fSDinh Nguyen } 182247a1685fSDinh Nguyen 182347a1685fSDinh Nguyen /* If we have pending request, then start it */ 182434c0887fSJohn Youn if (!ep->req) 182541cc4cd2SVardan Mikayelyan dwc2_gadget_start_next_request(ep); 182647a1685fSDinh Nguyen } 182747a1685fSDinh Nguyen 182847a1685fSDinh Nguyen break; 182947a1685fSDinh Nguyen 183047a1685fSDinh Nguyen default: 183147a1685fSDinh Nguyen return -ENOENT; 183247a1685fSDinh Nguyen } 18339e14d0a5SGregory Herrero break; 18349e14d0a5SGregory Herrero default: 18359e14d0a5SGregory Herrero return -ENOENT; 18369e14d0a5SGregory Herrero } 183747a1685fSDinh Nguyen return 1; 183847a1685fSDinh Nguyen } 183947a1685fSDinh Nguyen 18401f91b4ccSFelipe Balbi static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg); 184147a1685fSDinh Nguyen 184247a1685fSDinh Nguyen /** 18431f91b4ccSFelipe Balbi * dwc2_hsotg_stall_ep0 - stall ep0 184447a1685fSDinh Nguyen * @hsotg: The device state 184547a1685fSDinh Nguyen * 184647a1685fSDinh Nguyen * Set stall for ep0 as response for setup request. 184747a1685fSDinh Nguyen */ 18481f91b4ccSFelipe Balbi static void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg) 1849e9ebe7c3SJingoo Han { 18501f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 185147a1685fSDinh Nguyen u32 reg; 185247a1685fSDinh Nguyen u32 ctrl; 185347a1685fSDinh Nguyen 185447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); 185547a1685fSDinh Nguyen reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; 185647a1685fSDinh Nguyen 185747a1685fSDinh Nguyen /* 185847a1685fSDinh Nguyen * DxEPCTL_Stall will be cleared by EP once it has 185947a1685fSDinh Nguyen * taken effect, so no need to clear later. 186047a1685fSDinh Nguyen */ 186147a1685fSDinh Nguyen 1862f25c42b8SGevorg Sahakyan ctrl = dwc2_readl(hsotg, reg); 186347a1685fSDinh Nguyen ctrl |= DXEPCTL_STALL; 186447a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; 1865f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ctrl, reg); 186647a1685fSDinh Nguyen 186747a1685fSDinh Nguyen dev_dbg(hsotg->dev, 186847a1685fSDinh Nguyen "written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n", 1869f25c42b8SGevorg Sahakyan ctrl, reg, dwc2_readl(hsotg, reg)); 187047a1685fSDinh Nguyen 187147a1685fSDinh Nguyen /* 187247a1685fSDinh Nguyen * complete won't be called, so we enqueue 187347a1685fSDinh Nguyen * setup request here 187447a1685fSDinh Nguyen */ 18751f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 187647a1685fSDinh Nguyen } 187747a1685fSDinh Nguyen 187847a1685fSDinh Nguyen /** 18791f91b4ccSFelipe Balbi * dwc2_hsotg_process_control - process a control request 188047a1685fSDinh Nguyen * @hsotg: The device state 188147a1685fSDinh Nguyen * @ctrl: The control request received 188247a1685fSDinh Nguyen * 188347a1685fSDinh Nguyen * The controller has received the SETUP phase of a control request, and 188447a1685fSDinh Nguyen * needs to work out what to do next (and whether to pass it on to the 188547a1685fSDinh Nguyen * gadget driver). 188647a1685fSDinh Nguyen */ 18871f91b4ccSFelipe Balbi static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, 188847a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 188947a1685fSDinh Nguyen { 18901f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 189147a1685fSDinh Nguyen int ret = 0; 189247a1685fSDinh Nguyen u32 dcfg; 189347a1685fSDinh Nguyen 1894e525e743SMian Yousaf Kaukab dev_dbg(hsotg->dev, 1895e525e743SMian Yousaf Kaukab "ctrl Type=%02x, Req=%02x, V=%04x, I=%04x, L=%04x\n", 1896e525e743SMian Yousaf Kaukab ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, 1897e525e743SMian Yousaf Kaukab ctrl->wIndex, ctrl->wLength); 189847a1685fSDinh Nguyen 1899fe0b94abSMian Yousaf Kaukab if (ctrl->wLength == 0) { 190047a1685fSDinh Nguyen ep0->dir_in = 1; 1901fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_STATUS_IN; 1902fe0b94abSMian Yousaf Kaukab } else if (ctrl->bRequestType & USB_DIR_IN) { 1903fe0b94abSMian Yousaf Kaukab ep0->dir_in = 1; 1904fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_DATA_IN; 1905fe0b94abSMian Yousaf Kaukab } else { 1906fe0b94abSMian Yousaf Kaukab ep0->dir_in = 0; 1907fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_DATA_OUT; 1908fe0b94abSMian Yousaf Kaukab } 190947a1685fSDinh Nguyen 191047a1685fSDinh Nguyen if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 191147a1685fSDinh Nguyen switch (ctrl->bRequest) { 191247a1685fSDinh Nguyen case USB_REQ_SET_ADDRESS: 19136d713c15SMian Yousaf Kaukab hsotg->connected = 1; 1914f25c42b8SGevorg Sahakyan dcfg = dwc2_readl(hsotg, DCFG); 191547a1685fSDinh Nguyen dcfg &= ~DCFG_DEVADDR_MASK; 1916d5dbd3f7SPaul Zimmerman dcfg |= (le16_to_cpu(ctrl->wValue) << 1917d5dbd3f7SPaul Zimmerman DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK; 1918f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dcfg, DCFG); 191947a1685fSDinh Nguyen 192047a1685fSDinh Nguyen dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); 192147a1685fSDinh Nguyen 19221f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 192347a1685fSDinh Nguyen return; 192447a1685fSDinh Nguyen 192547a1685fSDinh Nguyen case USB_REQ_GET_STATUS: 19261f91b4ccSFelipe Balbi ret = dwc2_hsotg_process_req_status(hsotg, ctrl); 192747a1685fSDinh Nguyen break; 192847a1685fSDinh Nguyen 192947a1685fSDinh Nguyen case USB_REQ_CLEAR_FEATURE: 193047a1685fSDinh Nguyen case USB_REQ_SET_FEATURE: 19311f91b4ccSFelipe Balbi ret = dwc2_hsotg_process_req_feature(hsotg, ctrl); 193247a1685fSDinh Nguyen break; 193347a1685fSDinh Nguyen } 193447a1685fSDinh Nguyen } 193547a1685fSDinh Nguyen 193647a1685fSDinh Nguyen /* as a fallback, try delivering it to the driver to deal with */ 193747a1685fSDinh Nguyen 193847a1685fSDinh Nguyen if (ret == 0 && hsotg->driver) { 193947a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 194047a1685fSDinh Nguyen ret = hsotg->driver->setup(&hsotg->gadget, ctrl); 194147a1685fSDinh Nguyen spin_lock(&hsotg->lock); 194247a1685fSDinh Nguyen if (ret < 0) 194347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); 194447a1685fSDinh Nguyen } 194547a1685fSDinh Nguyen 1946b4c53b4aSMinas Harutyunyan hsotg->delayed_status = false; 1947b4c53b4aSMinas Harutyunyan if (ret == USB_GADGET_DELAYED_STATUS) 1948b4c53b4aSMinas Harutyunyan hsotg->delayed_status = true; 1949b4c53b4aSMinas Harutyunyan 195047a1685fSDinh Nguyen /* 195147a1685fSDinh Nguyen * the request is either unhandlable, or is not formatted correctly 195247a1685fSDinh Nguyen * so respond with a STALL for the status stage to indicate failure. 195347a1685fSDinh Nguyen */ 195447a1685fSDinh Nguyen 195547a1685fSDinh Nguyen if (ret < 0) 19561f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hsotg); 195747a1685fSDinh Nguyen } 195847a1685fSDinh Nguyen 195947a1685fSDinh Nguyen /** 19601f91b4ccSFelipe Balbi * dwc2_hsotg_complete_setup - completion of a setup transfer 196147a1685fSDinh Nguyen * @ep: The endpoint the request was on. 196247a1685fSDinh Nguyen * @req: The request completed. 196347a1685fSDinh Nguyen * 196447a1685fSDinh Nguyen * Called on completion of any requests the driver itself submitted for 196547a1685fSDinh Nguyen * EP0 setup packets 196647a1685fSDinh Nguyen */ 19671f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_setup(struct usb_ep *ep, 196847a1685fSDinh Nguyen struct usb_request *req) 196947a1685fSDinh Nguyen { 19701f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1971941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 197247a1685fSDinh Nguyen 197347a1685fSDinh Nguyen if (req->status < 0) { 197447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); 197547a1685fSDinh Nguyen return; 197647a1685fSDinh Nguyen } 197747a1685fSDinh Nguyen 197847a1685fSDinh Nguyen spin_lock(&hsotg->lock); 197947a1685fSDinh Nguyen if (req->actual == 0) 19801f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 198147a1685fSDinh Nguyen else 19821f91b4ccSFelipe Balbi dwc2_hsotg_process_control(hsotg, req->buf); 198347a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 198447a1685fSDinh Nguyen } 198547a1685fSDinh Nguyen 198647a1685fSDinh Nguyen /** 19871f91b4ccSFelipe Balbi * dwc2_hsotg_enqueue_setup - start a request for EP0 packets 198847a1685fSDinh Nguyen * @hsotg: The device state. 198947a1685fSDinh Nguyen * 199047a1685fSDinh Nguyen * Enqueue a request on EP0 if necessary to received any SETUP packets 199147a1685fSDinh Nguyen * received from the host. 199247a1685fSDinh Nguyen */ 19931f91b4ccSFelipe Balbi static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg) 199447a1685fSDinh Nguyen { 199547a1685fSDinh Nguyen struct usb_request *req = hsotg->ctrl_req; 19961f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 199747a1685fSDinh Nguyen int ret; 199847a1685fSDinh Nguyen 199947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); 200047a1685fSDinh Nguyen 200147a1685fSDinh Nguyen req->zero = 0; 200247a1685fSDinh Nguyen req->length = 8; 200347a1685fSDinh Nguyen req->buf = hsotg->ctrl_buff; 20041f91b4ccSFelipe Balbi req->complete = dwc2_hsotg_complete_setup; 200547a1685fSDinh Nguyen 200647a1685fSDinh Nguyen if (!list_empty(&hs_req->queue)) { 200747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s already queued???\n", __func__); 200847a1685fSDinh Nguyen return; 200947a1685fSDinh Nguyen } 201047a1685fSDinh Nguyen 2011c6f5c050SMian Yousaf Kaukab hsotg->eps_out[0]->dir_in = 0; 20128a20fa45SMian Yousaf Kaukab hsotg->eps_out[0]->send_zlp = 0; 2013fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_SETUP; 201447a1685fSDinh Nguyen 20151f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(&hsotg->eps_out[0]->ep, req, GFP_ATOMIC); 201647a1685fSDinh Nguyen if (ret < 0) { 201747a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); 201847a1685fSDinh Nguyen /* 201947a1685fSDinh Nguyen * Don't think there's much we can do other than watch the 202047a1685fSDinh Nguyen * driver fail. 202147a1685fSDinh Nguyen */ 202247a1685fSDinh Nguyen } 202347a1685fSDinh Nguyen } 202447a1685fSDinh Nguyen 20251f91b4ccSFelipe Balbi static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, 20261f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 2027fe0b94abSMian Yousaf Kaukab { 2028fe0b94abSMian Yousaf Kaukab u32 ctrl; 2029fe0b94abSMian Yousaf Kaukab u8 index = hs_ep->index; 2030fe0b94abSMian Yousaf Kaukab u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 2031fe0b94abSMian Yousaf Kaukab u32 epsiz_reg = hs_ep->dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 2032fe0b94abSMian Yousaf Kaukab 2033ccb34a91SMian Yousaf Kaukab if (hs_ep->dir_in) 2034ccb34a91SMian Yousaf Kaukab dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n", 2035ccb34a91SMian Yousaf Kaukab index); 2036ccb34a91SMian Yousaf Kaukab else 2037ccb34a91SMian Yousaf Kaukab dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n", 2038ccb34a91SMian Yousaf Kaukab index); 2039e02f9aa6SVahram Aharonyan if (using_desc_dma(hsotg)) { 2040201ec568SMinas Harutyunyan if (!index) 2041e02f9aa6SVahram Aharonyan dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep); 2042201ec568SMinas Harutyunyan 204310209abeSAndrzej Pietrasiewicz /* Not specific buffer needed for ep0 ZLP */ 204410209abeSAndrzej Pietrasiewicz dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &hs_ep->desc_list, 204510209abeSAndrzej Pietrasiewicz hs_ep->desc_list_dma, 0, true); 2046e02f9aa6SVahram Aharonyan } else { 2047f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 2048f25c42b8SGevorg Sahakyan DXEPTSIZ_XFERSIZE(0), 2049fe0b94abSMian Yousaf Kaukab epsiz_reg); 2050e02f9aa6SVahram Aharonyan } 2051fe0b94abSMian Yousaf Kaukab 2052f25c42b8SGevorg Sahakyan ctrl = dwc2_readl(hsotg, epctl_reg); 2053fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 2054fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 2055fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_USBACTEP; 2056f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ctrl, epctl_reg); 2057fe0b94abSMian Yousaf Kaukab } 2058fe0b94abSMian Yousaf Kaukab 205947a1685fSDinh Nguyen /** 20601f91b4ccSFelipe Balbi * dwc2_hsotg_complete_request - complete a request given to us 206147a1685fSDinh Nguyen * @hsotg: The device state. 206247a1685fSDinh Nguyen * @hs_ep: The endpoint the request was on. 206347a1685fSDinh Nguyen * @hs_req: The request to complete. 206447a1685fSDinh Nguyen * @result: The result code (0 => Ok, otherwise errno) 206547a1685fSDinh Nguyen * 206647a1685fSDinh Nguyen * The given request has finished, so call the necessary completion 206747a1685fSDinh Nguyen * if it has one and then look to see if we can start a new request 206847a1685fSDinh Nguyen * on the endpoint. 206947a1685fSDinh Nguyen * 207047a1685fSDinh Nguyen * Note, expects the ep to already be locked as appropriate. 207147a1685fSDinh Nguyen */ 20721f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, 20731f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 20741f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req, 207547a1685fSDinh Nguyen int result) 207647a1685fSDinh Nguyen { 207747a1685fSDinh Nguyen if (!hs_req) { 207847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); 207947a1685fSDinh Nguyen return; 208047a1685fSDinh Nguyen } 208147a1685fSDinh Nguyen 208247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", 208347a1685fSDinh Nguyen hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); 208447a1685fSDinh Nguyen 208547a1685fSDinh Nguyen /* 208647a1685fSDinh Nguyen * only replace the status if we've not already set an error 208747a1685fSDinh Nguyen * from a previous transaction 208847a1685fSDinh Nguyen */ 208947a1685fSDinh Nguyen 209047a1685fSDinh Nguyen if (hs_req->req.status == -EINPROGRESS) 209147a1685fSDinh Nguyen hs_req->req.status = result; 209247a1685fSDinh Nguyen 209344583fecSYunzhi Li if (using_dma(hsotg)) 209444583fecSYunzhi Li dwc2_hsotg_unmap_dma(hsotg, hs_ep, hs_req); 209544583fecSYunzhi Li 20961f91b4ccSFelipe Balbi dwc2_hsotg_handle_unaligned_buf_complete(hsotg, hs_ep, hs_req); 20977d24c1b5SMian Yousaf Kaukab 209847a1685fSDinh Nguyen hs_ep->req = NULL; 209947a1685fSDinh Nguyen list_del_init(&hs_req->queue); 210047a1685fSDinh Nguyen 210147a1685fSDinh Nguyen /* 210247a1685fSDinh Nguyen * call the complete request with the locks off, just in case the 210347a1685fSDinh Nguyen * request tries to queue more work for this endpoint. 210447a1685fSDinh Nguyen */ 210547a1685fSDinh Nguyen 210647a1685fSDinh Nguyen if (hs_req->req.complete) { 210747a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 2108304f7e5eSMichal Sojka usb_gadget_giveback_request(&hs_ep->ep, &hs_req->req); 210947a1685fSDinh Nguyen spin_lock(&hsotg->lock); 211047a1685fSDinh Nguyen } 211147a1685fSDinh Nguyen 2112540ccba0SVahram Aharonyan /* In DDMA don't need to proceed to starting of next ISOC request */ 2113540ccba0SVahram Aharonyan if (using_desc_dma(hsotg) && hs_ep->isochronous) 2114540ccba0SVahram Aharonyan return; 2115540ccba0SVahram Aharonyan 211647a1685fSDinh Nguyen /* 211747a1685fSDinh Nguyen * Look to see if there is anything else to do. Note, the completion 211847a1685fSDinh Nguyen * of the previous request may have caused a new request to be started 211947a1685fSDinh Nguyen * so be careful when doing this. 212047a1685fSDinh Nguyen */ 212147a1685fSDinh Nguyen 212234c0887fSJohn Youn if (!hs_ep->req && result >= 0) 212341cc4cd2SVardan Mikayelyan dwc2_gadget_start_next_request(hs_ep); 212447a1685fSDinh Nguyen } 212547a1685fSDinh Nguyen 2126540ccba0SVahram Aharonyan /* 2127540ccba0SVahram Aharonyan * dwc2_gadget_complete_isoc_request_ddma - complete an isoc request in DDMA 2128540ccba0SVahram Aharonyan * @hs_ep: The endpoint the request was on. 2129540ccba0SVahram Aharonyan * 2130540ccba0SVahram Aharonyan * Get first request from the ep queue, determine descriptor on which complete 2131729cac69SMinas Harutyunyan * happened. SW discovers which descriptor currently in use by HW, adjusts 2132729cac69SMinas Harutyunyan * dma_address and calculates index of completed descriptor based on the value 2133729cac69SMinas Harutyunyan * of DEPDMA register. Update actual length of request, giveback to gadget. 2134540ccba0SVahram Aharonyan */ 2135540ccba0SVahram Aharonyan static void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep) 2136540ccba0SVahram Aharonyan { 2137540ccba0SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 2138540ccba0SVahram Aharonyan struct dwc2_hsotg_req *hs_req; 2139540ccba0SVahram Aharonyan struct usb_request *ureq; 2140540ccba0SVahram Aharonyan u32 desc_sts; 2141540ccba0SVahram Aharonyan u32 mask; 2142540ccba0SVahram Aharonyan 2143729cac69SMinas Harutyunyan desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status; 2144729cac69SMinas Harutyunyan 2145729cac69SMinas Harutyunyan /* Process only descriptors with buffer status set to DMA done */ 2146729cac69SMinas Harutyunyan while ((desc_sts & DEV_DMA_BUFF_STS_MASK) >> 2147729cac69SMinas Harutyunyan DEV_DMA_BUFF_STS_SHIFT == DEV_DMA_BUFF_STS_DMADONE) { 2148729cac69SMinas Harutyunyan 2149540ccba0SVahram Aharonyan hs_req = get_ep_head(hs_ep); 2150540ccba0SVahram Aharonyan if (!hs_req) { 2151540ccba0SVahram Aharonyan dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n", __func__); 2152540ccba0SVahram Aharonyan return; 2153540ccba0SVahram Aharonyan } 2154540ccba0SVahram Aharonyan ureq = &hs_req->req; 2155540ccba0SVahram Aharonyan 2156729cac69SMinas Harutyunyan /* Check completion status */ 2157729cac69SMinas Harutyunyan if ((desc_sts & DEV_DMA_STS_MASK) >> DEV_DMA_STS_SHIFT == 2158729cac69SMinas Harutyunyan DEV_DMA_STS_SUCC) { 2159540ccba0SVahram Aharonyan mask = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_MASK : 2160540ccba0SVahram Aharonyan DEV_DMA_ISOC_RX_NBYTES_MASK; 2161729cac69SMinas Harutyunyan ureq->actual = ureq->length - ((desc_sts & mask) >> 2162729cac69SMinas Harutyunyan DEV_DMA_ISOC_NBYTES_SHIFT); 2163540ccba0SVahram Aharonyan 2164729cac69SMinas Harutyunyan /* Adjust actual len for ISOC Out if len is 2165729cac69SMinas Harutyunyan * not align of 4 2166729cac69SMinas Harutyunyan */ 216795d2b037SVahram Aharonyan if (!hs_ep->dir_in && ureq->length & 0x3) 216895d2b037SVahram Aharonyan ureq->actual += 4 - (ureq->length & 0x3); 2169c8006f67SMinas Harutyunyan 2170c8006f67SMinas Harutyunyan /* Set actual frame number for completed transfers */ 2171c8006f67SMinas Harutyunyan ureq->frame_number = 2172c8006f67SMinas Harutyunyan (desc_sts & DEV_DMA_ISOC_FRNUM_MASK) >> 2173c8006f67SMinas Harutyunyan DEV_DMA_ISOC_FRNUM_SHIFT; 2174729cac69SMinas Harutyunyan } 217595d2b037SVahram Aharonyan 2176540ccba0SVahram Aharonyan dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 2177729cac69SMinas Harutyunyan 2178729cac69SMinas Harutyunyan hs_ep->compl_desc++; 217954f37f56SMinas Harutyunyan if (hs_ep->compl_desc > (MAX_DMA_DESC_NUM_HS_ISOC - 1)) 2180729cac69SMinas Harutyunyan hs_ep->compl_desc = 0; 2181729cac69SMinas Harutyunyan desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status; 2182729cac69SMinas Harutyunyan } 2183540ccba0SVahram Aharonyan } 2184540ccba0SVahram Aharonyan 2185540ccba0SVahram Aharonyan /* 2186729cac69SMinas Harutyunyan * dwc2_gadget_handle_isoc_bna - handle BNA interrupt for ISOC. 2187729cac69SMinas Harutyunyan * @hs_ep: The isochronous endpoint. 2188540ccba0SVahram Aharonyan * 2189729cac69SMinas Harutyunyan * If EP ISOC OUT then need to flush RX FIFO to remove source of BNA 2190729cac69SMinas Harutyunyan * interrupt. Reset target frame and next_desc to allow to start 2191729cac69SMinas Harutyunyan * ISOC's on NAK interrupt for IN direction or on OUTTKNEPDIS 2192729cac69SMinas Harutyunyan * interrupt for OUT direction. 2193540ccba0SVahram Aharonyan */ 2194729cac69SMinas Harutyunyan static void dwc2_gadget_handle_isoc_bna(struct dwc2_hsotg_ep *hs_ep) 2195540ccba0SVahram Aharonyan { 2196540ccba0SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 2197540ccba0SVahram Aharonyan 2198729cac69SMinas Harutyunyan if (!hs_ep->dir_in) 2199729cac69SMinas Harutyunyan dwc2_flush_rx_fifo(hsotg); 2200729cac69SMinas Harutyunyan dwc2_hsotg_complete_request(hsotg, hs_ep, get_ep_head(hs_ep), 0); 2201540ccba0SVahram Aharonyan 2202729cac69SMinas Harutyunyan hs_ep->target_frame = TARGET_FRAME_INITIAL; 2203540ccba0SVahram Aharonyan hs_ep->next_desc = 0; 2204729cac69SMinas Harutyunyan hs_ep->compl_desc = 0; 2205540ccba0SVahram Aharonyan } 2206540ccba0SVahram Aharonyan 220747a1685fSDinh Nguyen /** 22081f91b4ccSFelipe Balbi * dwc2_hsotg_rx_data - receive data from the FIFO for an endpoint 220947a1685fSDinh Nguyen * @hsotg: The device state. 221047a1685fSDinh Nguyen * @ep_idx: The endpoint index for the data 221147a1685fSDinh Nguyen * @size: The size of data in the fifo, in bytes 221247a1685fSDinh Nguyen * 221347a1685fSDinh Nguyen * The FIFO status shows there is data to read from the FIFO for a given 221447a1685fSDinh Nguyen * endpoint, so sort out whether we need to read the data into a request 221547a1685fSDinh Nguyen * that has been made for that endpoint. 221647a1685fSDinh Nguyen */ 22171f91b4ccSFelipe Balbi static void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size) 221847a1685fSDinh Nguyen { 22191f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[ep_idx]; 22201f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 222147a1685fSDinh Nguyen int to_read; 222247a1685fSDinh Nguyen int max_req; 222347a1685fSDinh Nguyen int read_ptr; 222447a1685fSDinh Nguyen 222547a1685fSDinh Nguyen if (!hs_req) { 2226f25c42b8SGevorg Sahakyan u32 epctl = dwc2_readl(hsotg, DOEPCTL(ep_idx)); 222747a1685fSDinh Nguyen int ptr; 222847a1685fSDinh Nguyen 22296b448af4SRobert Baldyga dev_dbg(hsotg->dev, 223047a1685fSDinh Nguyen "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", 223147a1685fSDinh Nguyen __func__, size, ep_idx, epctl); 223247a1685fSDinh Nguyen 223347a1685fSDinh Nguyen /* dump the data from the FIFO, we've nothing we can do */ 223447a1685fSDinh Nguyen for (ptr = 0; ptr < size; ptr += 4) 2235f25c42b8SGevorg Sahakyan (void)dwc2_readl(hsotg, EPFIFO(ep_idx)); 223647a1685fSDinh Nguyen 223747a1685fSDinh Nguyen return; 223847a1685fSDinh Nguyen } 223947a1685fSDinh Nguyen 224047a1685fSDinh Nguyen to_read = size; 224147a1685fSDinh Nguyen read_ptr = hs_req->req.actual; 224247a1685fSDinh Nguyen max_req = hs_req->req.length - read_ptr; 224347a1685fSDinh Nguyen 224447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", 224547a1685fSDinh Nguyen __func__, to_read, max_req, read_ptr, hs_req->req.length); 224647a1685fSDinh Nguyen 224747a1685fSDinh Nguyen if (to_read > max_req) { 224847a1685fSDinh Nguyen /* 224947a1685fSDinh Nguyen * more data appeared than we where willing 225047a1685fSDinh Nguyen * to deal with in this request. 225147a1685fSDinh Nguyen */ 225247a1685fSDinh Nguyen 225347a1685fSDinh Nguyen /* currently we don't deal this */ 225447a1685fSDinh Nguyen WARN_ON_ONCE(1); 225547a1685fSDinh Nguyen } 225647a1685fSDinh Nguyen 225747a1685fSDinh Nguyen hs_ep->total_data += to_read; 225847a1685fSDinh Nguyen hs_req->req.actual += to_read; 225947a1685fSDinh Nguyen to_read = DIV_ROUND_UP(to_read, 4); 226047a1685fSDinh Nguyen 226147a1685fSDinh Nguyen /* 226247a1685fSDinh Nguyen * note, we might over-write the buffer end by 3 bytes depending on 226347a1685fSDinh Nguyen * alignment of the data. 226447a1685fSDinh Nguyen */ 2265342ccce1SGevorg Sahakyan dwc2_readl_rep(hsotg, EPFIFO(ep_idx), 2266f25c42b8SGevorg Sahakyan hs_req->req.buf + read_ptr, to_read); 226747a1685fSDinh Nguyen } 226847a1685fSDinh Nguyen 226947a1685fSDinh Nguyen /** 22701f91b4ccSFelipe Balbi * dwc2_hsotg_ep0_zlp - send/receive zero-length packet on control endpoint 227147a1685fSDinh Nguyen * @hsotg: The device instance 2272fe0b94abSMian Yousaf Kaukab * @dir_in: If IN zlp 227347a1685fSDinh Nguyen * 227447a1685fSDinh Nguyen * Generate a zero-length IN packet request for terminating a SETUP 227547a1685fSDinh Nguyen * transaction. 227647a1685fSDinh Nguyen * 227747a1685fSDinh Nguyen * Note, since we don't write any data to the TxFIFO, then it is 227847a1685fSDinh Nguyen * currently believed that we do not need to wait for any space in 227947a1685fSDinh Nguyen * the TxFIFO. 228047a1685fSDinh Nguyen */ 22811f91b4ccSFelipe Balbi static void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in) 228247a1685fSDinh Nguyen { 2283c6f5c050SMian Yousaf Kaukab /* eps_out[0] is used in both directions */ 2284fe0b94abSMian Yousaf Kaukab hsotg->eps_out[0]->dir_in = dir_in; 2285fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = dir_in ? DWC2_EP0_STATUS_IN : DWC2_EP0_STATUS_OUT; 228647a1685fSDinh Nguyen 22871f91b4ccSFelipe Balbi dwc2_hsotg_program_zlp(hsotg, hsotg->eps_out[0]); 228847a1685fSDinh Nguyen } 228947a1685fSDinh Nguyen 2290ec1f9d9fSRoman Bacik static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg, 2291ec1f9d9fSRoman Bacik u32 epctl_reg) 2292ec1f9d9fSRoman Bacik { 2293ec1f9d9fSRoman Bacik u32 ctrl; 2294ec1f9d9fSRoman Bacik 2295f25c42b8SGevorg Sahakyan ctrl = dwc2_readl(hsotg, epctl_reg); 2296ec1f9d9fSRoman Bacik if (ctrl & DXEPCTL_EOFRNUM) 2297ec1f9d9fSRoman Bacik ctrl |= DXEPCTL_SETEVENFR; 2298ec1f9d9fSRoman Bacik else 2299ec1f9d9fSRoman Bacik ctrl |= DXEPCTL_SETODDFR; 2300f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ctrl, epctl_reg); 2301ec1f9d9fSRoman Bacik } 2302ec1f9d9fSRoman Bacik 2303aa3e8bc8SVahram Aharonyan /* 2304aa3e8bc8SVahram Aharonyan * dwc2_gadget_get_xfersize_ddma - get transferred bytes amount from desc 2305aa3e8bc8SVahram Aharonyan * @hs_ep - The endpoint on which transfer went 2306aa3e8bc8SVahram Aharonyan * 2307aa3e8bc8SVahram Aharonyan * Iterate over endpoints descriptor chain and get info on bytes remained 2308aa3e8bc8SVahram Aharonyan * in DMA descriptors after transfer has completed. Used for non isoc EPs. 2309aa3e8bc8SVahram Aharonyan */ 2310aa3e8bc8SVahram Aharonyan static unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep) 2311aa3e8bc8SVahram Aharonyan { 2312aa3e8bc8SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 2313aa3e8bc8SVahram Aharonyan unsigned int bytes_rem = 0; 2314aa3e8bc8SVahram Aharonyan struct dwc2_dma_desc *desc = hs_ep->desc_list; 2315aa3e8bc8SVahram Aharonyan int i; 2316aa3e8bc8SVahram Aharonyan u32 status; 2317aa3e8bc8SVahram Aharonyan 2318aa3e8bc8SVahram Aharonyan if (!desc) 2319aa3e8bc8SVahram Aharonyan return -EINVAL; 2320aa3e8bc8SVahram Aharonyan 2321aa3e8bc8SVahram Aharonyan for (i = 0; i < hs_ep->desc_count; ++i) { 2322aa3e8bc8SVahram Aharonyan status = desc->status; 2323aa3e8bc8SVahram Aharonyan bytes_rem += status & DEV_DMA_NBYTES_MASK; 2324aa3e8bc8SVahram Aharonyan 2325aa3e8bc8SVahram Aharonyan if (status & DEV_DMA_STS_MASK) 2326aa3e8bc8SVahram Aharonyan dev_err(hsotg->dev, "descriptor %d closed with %x\n", 2327aa3e8bc8SVahram Aharonyan i, status & DEV_DMA_STS_MASK); 23285acb4b97SMinas Harutyunyan desc++; 2329aa3e8bc8SVahram Aharonyan } 2330aa3e8bc8SVahram Aharonyan 2331aa3e8bc8SVahram Aharonyan return bytes_rem; 2332aa3e8bc8SVahram Aharonyan } 2333aa3e8bc8SVahram Aharonyan 233447a1685fSDinh Nguyen /** 23351f91b4ccSFelipe Balbi * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO 233647a1685fSDinh Nguyen * @hsotg: The device instance 233747a1685fSDinh Nguyen * @epnum: The endpoint received from 233847a1685fSDinh Nguyen * 233947a1685fSDinh Nguyen * The RXFIFO has delivered an OutDone event, which means that the data 234047a1685fSDinh Nguyen * transfer for an OUT endpoint has been completed, either by a short 234147a1685fSDinh Nguyen * packet or by the finish of a transfer. 234247a1685fSDinh Nguyen */ 23431f91b4ccSFelipe Balbi static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) 234447a1685fSDinh Nguyen { 2345f25c42b8SGevorg Sahakyan u32 epsize = dwc2_readl(hsotg, DOEPTSIZ(epnum)); 23461f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[epnum]; 23471f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 234847a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 23499da51974SJohn Youn unsigned int size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 235047a1685fSDinh Nguyen int result = 0; 235147a1685fSDinh Nguyen 235247a1685fSDinh Nguyen if (!hs_req) { 235347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no request active\n", __func__); 235447a1685fSDinh Nguyen return; 235547a1685fSDinh Nguyen } 235647a1685fSDinh Nguyen 2357fe0b94abSMian Yousaf Kaukab if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_OUT) { 2358fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "zlp packet received\n"); 23591f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 23601f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 2361fe0b94abSMian Yousaf Kaukab return; 2362fe0b94abSMian Yousaf Kaukab } 2363fe0b94abSMian Yousaf Kaukab 2364aa3e8bc8SVahram Aharonyan if (using_desc_dma(hsotg)) 2365aa3e8bc8SVahram Aharonyan size_left = dwc2_gadget_get_xfersize_ddma(hs_ep); 2366aa3e8bc8SVahram Aharonyan 236747a1685fSDinh Nguyen if (using_dma(hsotg)) { 23689da51974SJohn Youn unsigned int size_done; 236947a1685fSDinh Nguyen 237047a1685fSDinh Nguyen /* 237147a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much 237247a1685fSDinh Nguyen * is left in the endpoint size register and then working it 237347a1685fSDinh Nguyen * out from the amount we loaded for the transfer. 237447a1685fSDinh Nguyen * 237547a1685fSDinh Nguyen * We need to do this as DMA pointers are always 32bit aligned 237647a1685fSDinh Nguyen * so may overshoot/undershoot the transfer. 237747a1685fSDinh Nguyen */ 237847a1685fSDinh Nguyen 237947a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 238047a1685fSDinh Nguyen size_done += hs_ep->last_load; 238147a1685fSDinh Nguyen 238247a1685fSDinh Nguyen req->actual = size_done; 238347a1685fSDinh Nguyen } 238447a1685fSDinh Nguyen 238547a1685fSDinh Nguyen /* if there is more request to do, schedule new transfer */ 238647a1685fSDinh Nguyen if (req->actual < req->length && size_left == 0) { 23871f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 238847a1685fSDinh Nguyen return; 238947a1685fSDinh Nguyen } 239047a1685fSDinh Nguyen 239147a1685fSDinh Nguyen if (req->actual < req->length && req->short_not_ok) { 239247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", 239347a1685fSDinh Nguyen __func__, req->actual, req->length); 239447a1685fSDinh Nguyen 239547a1685fSDinh Nguyen /* 239647a1685fSDinh Nguyen * todo - what should we return here? there's no one else 239747a1685fSDinh Nguyen * even bothering to check the status. 239847a1685fSDinh Nguyen */ 239947a1685fSDinh Nguyen } 240047a1685fSDinh Nguyen 2401ef750c71SVahram Aharonyan /* DDMA IN status phase will start from StsPhseRcvd interrupt */ 2402ef750c71SVahram Aharonyan if (!using_desc_dma(hsotg) && epnum == 0 && 2403ef750c71SVahram Aharonyan hsotg->ep0_state == DWC2_EP0_DATA_OUT) { 2404fe0b94abSMian Yousaf Kaukab /* Move to STATUS IN */ 2405b4c53b4aSMinas Harutyunyan if (!hsotg->delayed_status) 24061f91b4ccSFelipe Balbi dwc2_hsotg_ep0_zlp(hsotg, true); 240747a1685fSDinh Nguyen } 240847a1685fSDinh Nguyen 2409ec1f9d9fSRoman Bacik /* 2410ec1f9d9fSRoman Bacik * Slave mode OUT transfers do not go through XferComplete so 2411ec1f9d9fSRoman Bacik * adjust the ISOC parity here. 2412ec1f9d9fSRoman Bacik */ 2413ec1f9d9fSRoman Bacik if (!using_dma(hsotg)) { 2414ec1f9d9fSRoman Bacik if (hs_ep->isochronous && hs_ep->interval == 1) 2415ec1f9d9fSRoman Bacik dwc2_hsotg_change_ep_iso_parity(hsotg, DOEPCTL(epnum)); 2416837e9f00SVardan Mikayelyan else if (hs_ep->isochronous && hs_ep->interval > 1) 2417837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 2418ec1f9d9fSRoman Bacik } 2419ec1f9d9fSRoman Bacik 2420*4faf3b36SMinas Harutyunyan /* Set actual frame number for completed transfers */ 2421*4faf3b36SMinas Harutyunyan if (!using_desc_dma(hsotg) && hs_ep->isochronous) 2422*4faf3b36SMinas Harutyunyan req->frame_number = hsotg->frame_number; 2423*4faf3b36SMinas Harutyunyan 24241f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result); 242547a1685fSDinh Nguyen } 242647a1685fSDinh Nguyen 242747a1685fSDinh Nguyen /** 24281f91b4ccSFelipe Balbi * dwc2_hsotg_handle_rx - RX FIFO has data 242947a1685fSDinh Nguyen * @hsotg: The device instance 243047a1685fSDinh Nguyen * 243147a1685fSDinh Nguyen * The IRQ handler has detected that the RX FIFO has some data in it 243247a1685fSDinh Nguyen * that requires processing, so find out what is in there and do the 243347a1685fSDinh Nguyen * appropriate read. 243447a1685fSDinh Nguyen * 243547a1685fSDinh Nguyen * The RXFIFO is a true FIFO, the packets coming out are still in packet 243647a1685fSDinh Nguyen * chunks, so if you have x packets received on an endpoint you'll get x 243747a1685fSDinh Nguyen * FIFO events delivered, each with a packet's worth of data in it. 243847a1685fSDinh Nguyen * 243947a1685fSDinh Nguyen * When using DMA, we should not be processing events from the RXFIFO 244047a1685fSDinh Nguyen * as the actual data should be sent to the memory directly and we turn 244147a1685fSDinh Nguyen * on the completion interrupts to get notifications of transfer completion. 244247a1685fSDinh Nguyen */ 24431f91b4ccSFelipe Balbi static void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg) 244447a1685fSDinh Nguyen { 2445f25c42b8SGevorg Sahakyan u32 grxstsr = dwc2_readl(hsotg, GRXSTSP); 244647a1685fSDinh Nguyen u32 epnum, status, size; 244747a1685fSDinh Nguyen 244847a1685fSDinh Nguyen WARN_ON(using_dma(hsotg)); 244947a1685fSDinh Nguyen 245047a1685fSDinh Nguyen epnum = grxstsr & GRXSTS_EPNUM_MASK; 245147a1685fSDinh Nguyen status = grxstsr & GRXSTS_PKTSTS_MASK; 245247a1685fSDinh Nguyen 245347a1685fSDinh Nguyen size = grxstsr & GRXSTS_BYTECNT_MASK; 245447a1685fSDinh Nguyen size >>= GRXSTS_BYTECNT_SHIFT; 245547a1685fSDinh Nguyen 245647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", 245747a1685fSDinh Nguyen __func__, grxstsr, size, epnum); 245847a1685fSDinh Nguyen 245947a1685fSDinh Nguyen switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { 246047a1685fSDinh Nguyen case GRXSTS_PKTSTS_GLOBALOUTNAK: 246147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GLOBALOUTNAK\n"); 246247a1685fSDinh Nguyen break; 246347a1685fSDinh Nguyen 246447a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTDONE: 246547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", 24661f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg)); 246747a1685fSDinh Nguyen 246847a1685fSDinh Nguyen if (!using_dma(hsotg)) 24691f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, epnum); 247047a1685fSDinh Nguyen break; 247147a1685fSDinh Nguyen 247247a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPDONE: 247347a1685fSDinh Nguyen dev_dbg(hsotg->dev, 247447a1685fSDinh Nguyen "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 24751f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg), 2476f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DOEPCTL(0))); 2477fe0b94abSMian Yousaf Kaukab /* 24781f91b4ccSFelipe Balbi * Call dwc2_hsotg_handle_outdone here if it was not called from 2479fe0b94abSMian Yousaf Kaukab * GRXSTS_PKTSTS_OUTDONE. That is, if the core didn't 2480fe0b94abSMian Yousaf Kaukab * generate GRXSTS_PKTSTS_OUTDONE for setup packet. 2481fe0b94abSMian Yousaf Kaukab */ 2482fe0b94abSMian Yousaf Kaukab if (hsotg->ep0_state == DWC2_EP0_SETUP) 24831f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, epnum); 248447a1685fSDinh Nguyen break; 248547a1685fSDinh Nguyen 248647a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTRX: 24871f91b4ccSFelipe Balbi dwc2_hsotg_rx_data(hsotg, epnum, size); 248847a1685fSDinh Nguyen break; 248947a1685fSDinh Nguyen 249047a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPRX: 249147a1685fSDinh Nguyen dev_dbg(hsotg->dev, 249247a1685fSDinh Nguyen "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 24931f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg), 2494f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DOEPCTL(0))); 249547a1685fSDinh Nguyen 2496fe0b94abSMian Yousaf Kaukab WARN_ON(hsotg->ep0_state != DWC2_EP0_SETUP); 2497fe0b94abSMian Yousaf Kaukab 24981f91b4ccSFelipe Balbi dwc2_hsotg_rx_data(hsotg, epnum, size); 249947a1685fSDinh Nguyen break; 250047a1685fSDinh Nguyen 250147a1685fSDinh Nguyen default: 250247a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: unknown status %08x\n", 250347a1685fSDinh Nguyen __func__, grxstsr); 250447a1685fSDinh Nguyen 25051f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 250647a1685fSDinh Nguyen break; 250747a1685fSDinh Nguyen } 250847a1685fSDinh Nguyen } 250947a1685fSDinh Nguyen 251047a1685fSDinh Nguyen /** 25111f91b4ccSFelipe Balbi * dwc2_hsotg_ep0_mps - turn max packet size into register setting 251247a1685fSDinh Nguyen * @mps: The maximum packet size in bytes. 251347a1685fSDinh Nguyen */ 25141f91b4ccSFelipe Balbi static u32 dwc2_hsotg_ep0_mps(unsigned int mps) 251547a1685fSDinh Nguyen { 251647a1685fSDinh Nguyen switch (mps) { 251747a1685fSDinh Nguyen case 64: 251847a1685fSDinh Nguyen return D0EPCTL_MPS_64; 251947a1685fSDinh Nguyen case 32: 252047a1685fSDinh Nguyen return D0EPCTL_MPS_32; 252147a1685fSDinh Nguyen case 16: 252247a1685fSDinh Nguyen return D0EPCTL_MPS_16; 252347a1685fSDinh Nguyen case 8: 252447a1685fSDinh Nguyen return D0EPCTL_MPS_8; 252547a1685fSDinh Nguyen } 252647a1685fSDinh Nguyen 252747a1685fSDinh Nguyen /* bad max packet size, warn and return invalid result */ 252847a1685fSDinh Nguyen WARN_ON(1); 252947a1685fSDinh Nguyen return (u32)-1; 253047a1685fSDinh Nguyen } 253147a1685fSDinh Nguyen 253247a1685fSDinh Nguyen /** 25331f91b4ccSFelipe Balbi * dwc2_hsotg_set_ep_maxpacket - set endpoint's max-packet field 253447a1685fSDinh Nguyen * @hsotg: The driver state. 253547a1685fSDinh Nguyen * @ep: The index number of the endpoint 253647a1685fSDinh Nguyen * @mps: The maximum packet size in bytes 2537ee2c40deSVardan Mikayelyan * @mc: The multicount value 25386fb914d7SGrigor Tovmasyan * @dir_in: True if direction is in. 253947a1685fSDinh Nguyen * 254047a1685fSDinh Nguyen * Configure the maximum packet size for the given endpoint, updating 254147a1685fSDinh Nguyen * the hardware control registers to reflect this. 254247a1685fSDinh Nguyen */ 25431f91b4ccSFelipe Balbi static void dwc2_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg, 2544ee2c40deSVardan Mikayelyan unsigned int ep, unsigned int mps, 2545ee2c40deSVardan Mikayelyan unsigned int mc, unsigned int dir_in) 254647a1685fSDinh Nguyen { 25471f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep; 254847a1685fSDinh Nguyen u32 reg; 254947a1685fSDinh Nguyen 2550c6f5c050SMian Yousaf Kaukab hs_ep = index_to_ep(hsotg, ep, dir_in); 2551c6f5c050SMian Yousaf Kaukab if (!hs_ep) 2552c6f5c050SMian Yousaf Kaukab return; 2553c6f5c050SMian Yousaf Kaukab 255447a1685fSDinh Nguyen if (ep == 0) { 2555ee2c40deSVardan Mikayelyan u32 mps_bytes = mps; 2556ee2c40deSVardan Mikayelyan 255747a1685fSDinh Nguyen /* EP0 is a special case */ 2558ee2c40deSVardan Mikayelyan mps = dwc2_hsotg_ep0_mps(mps_bytes); 2559ee2c40deSVardan Mikayelyan if (mps > 3) 256047a1685fSDinh Nguyen goto bad_mps; 2561ee2c40deSVardan Mikayelyan hs_ep->ep.maxpacket = mps_bytes; 256247a1685fSDinh Nguyen hs_ep->mc = 1; 256347a1685fSDinh Nguyen } else { 2564ee2c40deSVardan Mikayelyan if (mps > 1024) 256547a1685fSDinh Nguyen goto bad_mps; 2566ee2c40deSVardan Mikayelyan hs_ep->mc = mc; 2567ee2c40deSVardan Mikayelyan if (mc > 3) 256847a1685fSDinh Nguyen goto bad_mps; 2569ee2c40deSVardan Mikayelyan hs_ep->ep.maxpacket = mps; 257047a1685fSDinh Nguyen } 257147a1685fSDinh Nguyen 2572c6f5c050SMian Yousaf Kaukab if (dir_in) { 2573f25c42b8SGevorg Sahakyan reg = dwc2_readl(hsotg, DIEPCTL(ep)); 257447a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 2575ee2c40deSVardan Mikayelyan reg |= mps; 2576f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, reg, DIEPCTL(ep)); 2577c6f5c050SMian Yousaf Kaukab } else { 2578f25c42b8SGevorg Sahakyan reg = dwc2_readl(hsotg, DOEPCTL(ep)); 257947a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 2580ee2c40deSVardan Mikayelyan reg |= mps; 2581f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, reg, DOEPCTL(ep)); 258247a1685fSDinh Nguyen } 258347a1685fSDinh Nguyen 258447a1685fSDinh Nguyen return; 258547a1685fSDinh Nguyen 258647a1685fSDinh Nguyen bad_mps: 258747a1685fSDinh Nguyen dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); 258847a1685fSDinh Nguyen } 258947a1685fSDinh Nguyen 259047a1685fSDinh Nguyen /** 25911f91b4ccSFelipe Balbi * dwc2_hsotg_txfifo_flush - flush Tx FIFO 259247a1685fSDinh Nguyen * @hsotg: The driver state 259347a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 259447a1685fSDinh Nguyen */ 25951f91b4ccSFelipe Balbi static void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx) 259647a1685fSDinh Nguyen { 2597f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH, 2598f25c42b8SGevorg Sahakyan GRSTCTL); 259947a1685fSDinh Nguyen 260047a1685fSDinh Nguyen /* wait until the fifo is flushed */ 260179d6b8c5SSevak Arakelyan if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 100)) 260279d6b8c5SSevak Arakelyan dev_warn(hsotg->dev, "%s: timeout flushing fifo GRSTCTL_TXFFLSH\n", 260379d6b8c5SSevak Arakelyan __func__); 260447a1685fSDinh Nguyen } 260547a1685fSDinh Nguyen 260647a1685fSDinh Nguyen /** 26071f91b4ccSFelipe Balbi * dwc2_hsotg_trytx - check to see if anything needs transmitting 260847a1685fSDinh Nguyen * @hsotg: The driver state 260947a1685fSDinh Nguyen * @hs_ep: The driver endpoint to check. 261047a1685fSDinh Nguyen * 261147a1685fSDinh Nguyen * Check to see if there is a request that has data to send, and if so 261247a1685fSDinh Nguyen * make an attempt to write data into the FIFO. 261347a1685fSDinh Nguyen */ 26141f91b4ccSFelipe Balbi static int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, 26151f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 261647a1685fSDinh Nguyen { 26171f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 261847a1685fSDinh Nguyen 261947a1685fSDinh Nguyen if (!hs_ep->dir_in || !hs_req) { 262047a1685fSDinh Nguyen /** 262147a1685fSDinh Nguyen * if request is not enqueued, we disable interrupts 262247a1685fSDinh Nguyen * for endpoints, excepting ep0 262347a1685fSDinh Nguyen */ 262447a1685fSDinh Nguyen if (hs_ep->index != 0) 26251f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, 262647a1685fSDinh Nguyen hs_ep->dir_in, 0); 262747a1685fSDinh Nguyen return 0; 262847a1685fSDinh Nguyen } 262947a1685fSDinh Nguyen 263047a1685fSDinh Nguyen if (hs_req->req.actual < hs_req->req.length) { 263147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "trying to write more for ep%d\n", 263247a1685fSDinh Nguyen hs_ep->index); 26331f91b4ccSFelipe Balbi return dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 263447a1685fSDinh Nguyen } 263547a1685fSDinh Nguyen 263647a1685fSDinh Nguyen return 0; 263747a1685fSDinh Nguyen } 263847a1685fSDinh Nguyen 263947a1685fSDinh Nguyen /** 26401f91b4ccSFelipe Balbi * dwc2_hsotg_complete_in - complete IN transfer 264147a1685fSDinh Nguyen * @hsotg: The device state. 264247a1685fSDinh Nguyen * @hs_ep: The endpoint that has just completed. 264347a1685fSDinh Nguyen * 264447a1685fSDinh Nguyen * An IN transfer has been completed, update the transfer's state and then 264547a1685fSDinh Nguyen * call the relevant completion routines. 264647a1685fSDinh Nguyen */ 26471f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, 26481f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 264947a1685fSDinh Nguyen { 26501f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 2651f25c42b8SGevorg Sahakyan u32 epsize = dwc2_readl(hsotg, DIEPTSIZ(hs_ep->index)); 265247a1685fSDinh Nguyen int size_left, size_done; 265347a1685fSDinh Nguyen 265447a1685fSDinh Nguyen if (!hs_req) { 265547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "XferCompl but no req\n"); 265647a1685fSDinh Nguyen return; 265747a1685fSDinh Nguyen } 265847a1685fSDinh Nguyen 265947a1685fSDinh Nguyen /* Finish ZLP handling for IN EP0 transactions */ 2660fe0b94abSMian Yousaf Kaukab if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) { 2661fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "zlp packet sent\n"); 2662c3b22fe2SRazmik Karapetyan 2663c3b22fe2SRazmik Karapetyan /* 2664c3b22fe2SRazmik Karapetyan * While send zlp for DWC2_EP0_STATUS_IN EP direction was 2665c3b22fe2SRazmik Karapetyan * changed to IN. Change back to complete OUT transfer request 2666c3b22fe2SRazmik Karapetyan */ 2667c3b22fe2SRazmik Karapetyan hs_ep->dir_in = 0; 2668c3b22fe2SRazmik Karapetyan 26691f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 26709e14d0a5SGregory Herrero if (hsotg->test_mode) { 26719e14d0a5SGregory Herrero int ret; 26729e14d0a5SGregory Herrero 26731f91b4ccSFelipe Balbi ret = dwc2_hsotg_set_test_mode(hsotg, hsotg->test_mode); 26749e14d0a5SGregory Herrero if (ret < 0) { 26759e14d0a5SGregory Herrero dev_dbg(hsotg->dev, "Invalid Test #%d\n", 26769e14d0a5SGregory Herrero hsotg->test_mode); 26771f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hsotg); 26789e14d0a5SGregory Herrero return; 26799e14d0a5SGregory Herrero } 26809e14d0a5SGregory Herrero } 26811f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 268247a1685fSDinh Nguyen return; 268347a1685fSDinh Nguyen } 268447a1685fSDinh Nguyen 268547a1685fSDinh Nguyen /* 268647a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much is left 268747a1685fSDinh Nguyen * in the endpoint size register and then working it out from 268847a1685fSDinh Nguyen * the amount we loaded for the transfer. 268947a1685fSDinh Nguyen * 269047a1685fSDinh Nguyen * We do this even for DMA, as the transfer may have incremented 269147a1685fSDinh Nguyen * past the end of the buffer (DMA transfers are always 32bit 269247a1685fSDinh Nguyen * aligned). 269347a1685fSDinh Nguyen */ 2694aa3e8bc8SVahram Aharonyan if (using_desc_dma(hsotg)) { 2695aa3e8bc8SVahram Aharonyan size_left = dwc2_gadget_get_xfersize_ddma(hs_ep); 2696aa3e8bc8SVahram Aharonyan if (size_left < 0) 2697aa3e8bc8SVahram Aharonyan dev_err(hsotg->dev, "error parsing DDMA results %d\n", 2698aa3e8bc8SVahram Aharonyan size_left); 2699aa3e8bc8SVahram Aharonyan } else { 270047a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 2701aa3e8bc8SVahram Aharonyan } 270247a1685fSDinh Nguyen 270347a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 270447a1685fSDinh Nguyen size_done += hs_ep->last_load; 270547a1685fSDinh Nguyen 270647a1685fSDinh Nguyen if (hs_req->req.actual != size_done) 270747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", 270847a1685fSDinh Nguyen __func__, hs_req->req.actual, size_done); 270947a1685fSDinh Nguyen 271047a1685fSDinh Nguyen hs_req->req.actual = size_done; 271147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", 271247a1685fSDinh Nguyen hs_req->req.length, hs_req->req.actual, hs_req->req.zero); 271347a1685fSDinh Nguyen 271447a1685fSDinh Nguyen if (!size_left && hs_req->req.actual < hs_req->req.length) { 271547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); 27161f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 2717fe0b94abSMian Yousaf Kaukab return; 2718fe0b94abSMian Yousaf Kaukab } 2719fe0b94abSMian Yousaf Kaukab 2720f71b5e25SMian Yousaf Kaukab /* Zlp for all endpoints, for ep0 only in DATA IN stage */ 27218a20fa45SMian Yousaf Kaukab if (hs_ep->send_zlp) { 27221f91b4ccSFelipe Balbi dwc2_hsotg_program_zlp(hsotg, hs_ep); 27238a20fa45SMian Yousaf Kaukab hs_ep->send_zlp = 0; 2724f71b5e25SMian Yousaf Kaukab /* transfer will be completed on next complete interrupt */ 2725f71b5e25SMian Yousaf Kaukab return; 2726f71b5e25SMian Yousaf Kaukab } 2727f71b5e25SMian Yousaf Kaukab 2728fe0b94abSMian Yousaf Kaukab if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_DATA_IN) { 2729fe0b94abSMian Yousaf Kaukab /* Move to STATUS OUT */ 27301f91b4ccSFelipe Balbi dwc2_hsotg_ep0_zlp(hsotg, false); 2731fe0b94abSMian Yousaf Kaukab return; 2732fe0b94abSMian Yousaf Kaukab } 2733fe0b94abSMian Yousaf Kaukab 27341f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 273547a1685fSDinh Nguyen } 273647a1685fSDinh Nguyen 273747a1685fSDinh Nguyen /** 273832601588SVardan Mikayelyan * dwc2_gadget_read_ep_interrupts - reads interrupts for given ep 273932601588SVardan Mikayelyan * @hsotg: The device state. 274032601588SVardan Mikayelyan * @idx: Index of ep. 274132601588SVardan Mikayelyan * @dir_in: Endpoint direction 1-in 0-out. 274232601588SVardan Mikayelyan * 274332601588SVardan Mikayelyan * Reads for endpoint with given index and direction, by masking 274432601588SVardan Mikayelyan * epint_reg with coresponding mask. 274532601588SVardan Mikayelyan */ 274632601588SVardan Mikayelyan static u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg, 274732601588SVardan Mikayelyan unsigned int idx, int dir_in) 274832601588SVardan Mikayelyan { 274932601588SVardan Mikayelyan u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; 275032601588SVardan Mikayelyan u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 275132601588SVardan Mikayelyan u32 ints; 275232601588SVardan Mikayelyan u32 mask; 275332601588SVardan Mikayelyan u32 diepempmsk; 275432601588SVardan Mikayelyan 2755f25c42b8SGevorg Sahakyan mask = dwc2_readl(hsotg, epmsk_reg); 2756f25c42b8SGevorg Sahakyan diepempmsk = dwc2_readl(hsotg, DIEPEMPMSK); 275732601588SVardan Mikayelyan mask |= ((diepempmsk >> idx) & 0x1) ? DIEPMSK_TXFIFOEMPTY : 0; 275832601588SVardan Mikayelyan mask |= DXEPINT_SETUP_RCVD; 275932601588SVardan Mikayelyan 2760f25c42b8SGevorg Sahakyan ints = dwc2_readl(hsotg, epint_reg); 276132601588SVardan Mikayelyan ints &= mask; 276232601588SVardan Mikayelyan return ints; 276332601588SVardan Mikayelyan } 276432601588SVardan Mikayelyan 276532601588SVardan Mikayelyan /** 2766bd9971f0SVardan Mikayelyan * dwc2_gadget_handle_ep_disabled - handle DXEPINT_EPDISBLD 2767bd9971f0SVardan Mikayelyan * @hs_ep: The endpoint on which interrupt is asserted. 2768bd9971f0SVardan Mikayelyan * 2769bd9971f0SVardan Mikayelyan * This interrupt indicates that the endpoint has been disabled per the 2770bd9971f0SVardan Mikayelyan * application's request. 2771bd9971f0SVardan Mikayelyan * 2772bd9971f0SVardan Mikayelyan * For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK, 2773bd9971f0SVardan Mikayelyan * in case of ISOC completes current request. 2774bd9971f0SVardan Mikayelyan * 2775bd9971f0SVardan Mikayelyan * For ISOC-OUT endpoints completes expired requests. If there is remaining 2776bd9971f0SVardan Mikayelyan * request starts it. 2777bd9971f0SVardan Mikayelyan */ 2778bd9971f0SVardan Mikayelyan static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) 2779bd9971f0SVardan Mikayelyan { 2780bd9971f0SVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 2781bd9971f0SVardan Mikayelyan struct dwc2_hsotg_req *hs_req; 2782bd9971f0SVardan Mikayelyan unsigned char idx = hs_ep->index; 2783bd9971f0SVardan Mikayelyan int dir_in = hs_ep->dir_in; 2784bd9971f0SVardan Mikayelyan u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 2785f25c42b8SGevorg Sahakyan int dctl = dwc2_readl(hsotg, DCTL); 2786bd9971f0SVardan Mikayelyan 2787bd9971f0SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); 2788bd9971f0SVardan Mikayelyan 2789bd9971f0SVardan Mikayelyan if (dir_in) { 2790f25c42b8SGevorg Sahakyan int epctl = dwc2_readl(hsotg, epctl_reg); 2791bd9971f0SVardan Mikayelyan 2792bd9971f0SVardan Mikayelyan dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); 2793bd9971f0SVardan Mikayelyan 2794bd9971f0SVardan Mikayelyan if (hs_ep->isochronous) { 2795bd9971f0SVardan Mikayelyan dwc2_hsotg_complete_in(hsotg, hs_ep); 2796bd9971f0SVardan Mikayelyan return; 2797bd9971f0SVardan Mikayelyan } 2798bd9971f0SVardan Mikayelyan 2799bd9971f0SVardan Mikayelyan if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) { 2800f25c42b8SGevorg Sahakyan int dctl = dwc2_readl(hsotg, DCTL); 2801bd9971f0SVardan Mikayelyan 2802bd9971f0SVardan Mikayelyan dctl |= DCTL_CGNPINNAK; 2803f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dctl, DCTL); 2804bd9971f0SVardan Mikayelyan } 2805bd9971f0SVardan Mikayelyan return; 2806bd9971f0SVardan Mikayelyan } 2807bd9971f0SVardan Mikayelyan 2808bd9971f0SVardan Mikayelyan if (dctl & DCTL_GOUTNAKSTS) { 2809bd9971f0SVardan Mikayelyan dctl |= DCTL_CGOUTNAK; 2810f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dctl, DCTL); 2811bd9971f0SVardan Mikayelyan } 2812bd9971f0SVardan Mikayelyan 2813bd9971f0SVardan Mikayelyan if (!hs_ep->isochronous) 2814bd9971f0SVardan Mikayelyan return; 2815bd9971f0SVardan Mikayelyan 2816bd9971f0SVardan Mikayelyan if (list_empty(&hs_ep->queue)) { 2817bd9971f0SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: complete_ep 0x%p, ep->queue empty!\n", 2818bd9971f0SVardan Mikayelyan __func__, hs_ep); 2819bd9971f0SVardan Mikayelyan return; 2820bd9971f0SVardan Mikayelyan } 2821bd9971f0SVardan Mikayelyan 2822bd9971f0SVardan Mikayelyan do { 2823bd9971f0SVardan Mikayelyan hs_req = get_ep_head(hs_ep); 2824bd9971f0SVardan Mikayelyan if (hs_req) 2825bd9971f0SVardan Mikayelyan dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 2826bd9971f0SVardan Mikayelyan -ENODATA); 2827bd9971f0SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 2828c7c24e7aSArtur Petrosyan /* Update current frame number value. */ 2829c7c24e7aSArtur Petrosyan hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg); 2830bd9971f0SVardan Mikayelyan } while (dwc2_gadget_target_frame_elapsed(hs_ep)); 2831bd9971f0SVardan Mikayelyan 2832bd9971f0SVardan Mikayelyan dwc2_gadget_start_next_request(hs_ep); 2833bd9971f0SVardan Mikayelyan } 2834bd9971f0SVardan Mikayelyan 2835bd9971f0SVardan Mikayelyan /** 28365321922cSVardan Mikayelyan * dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS 28376fb914d7SGrigor Tovmasyan * @ep: The endpoint on which interrupt is asserted. 28385321922cSVardan Mikayelyan * 28395321922cSVardan Mikayelyan * This is starting point for ISOC-OUT transfer, synchronization done with 28405321922cSVardan Mikayelyan * first out token received from host while corresponding EP is disabled. 28415321922cSVardan Mikayelyan * 28425321922cSVardan Mikayelyan * Device does not know initial frame in which out token will come. For this 28435321922cSVardan Mikayelyan * HW generates OUTTKNEPDIS - out token is received while EP is disabled. Upon 28445321922cSVardan Mikayelyan * getting this interrupt SW starts calculation for next transfer frame. 28455321922cSVardan Mikayelyan */ 28465321922cSVardan Mikayelyan static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) 28475321922cSVardan Mikayelyan { 28485321922cSVardan Mikayelyan struct dwc2_hsotg *hsotg = ep->parent; 28495321922cSVardan Mikayelyan int dir_in = ep->dir_in; 28505321922cSVardan Mikayelyan u32 doepmsk; 28515321922cSVardan Mikayelyan 28525321922cSVardan Mikayelyan if (dir_in || !ep->isochronous) 28535321922cSVardan Mikayelyan return; 28545321922cSVardan Mikayelyan 2855540ccba0SVahram Aharonyan if (using_desc_dma(hsotg)) { 2856540ccba0SVahram Aharonyan if (ep->target_frame == TARGET_FRAME_INITIAL) { 2857540ccba0SVahram Aharonyan /* Start first ISO Out */ 28584d4f1e79SMinas Harutyunyan ep->target_frame = hsotg->frame_number; 2859540ccba0SVahram Aharonyan dwc2_gadget_start_isoc_ddma(ep); 2860540ccba0SVahram Aharonyan } 2861540ccba0SVahram Aharonyan return; 2862540ccba0SVahram Aharonyan } 2863540ccba0SVahram Aharonyan 28645321922cSVardan Mikayelyan if (ep->interval > 1 && 28655321922cSVardan Mikayelyan ep->target_frame == TARGET_FRAME_INITIAL) { 28665321922cSVardan Mikayelyan u32 ctrl; 28675321922cSVardan Mikayelyan 28684d4f1e79SMinas Harutyunyan ep->target_frame = hsotg->frame_number; 28695321922cSVardan Mikayelyan dwc2_gadget_incr_frame_num(ep); 28705321922cSVardan Mikayelyan 2871f25c42b8SGevorg Sahakyan ctrl = dwc2_readl(hsotg, DOEPCTL(ep->index)); 28725321922cSVardan Mikayelyan if (ep->target_frame & 0x1) 28735321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETODDFR; 28745321922cSVardan Mikayelyan else 28755321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETEVENFR; 28765321922cSVardan Mikayelyan 2877f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ctrl, DOEPCTL(ep->index)); 28785321922cSVardan Mikayelyan } 28795321922cSVardan Mikayelyan 28805321922cSVardan Mikayelyan dwc2_gadget_start_next_request(ep); 2881f25c42b8SGevorg Sahakyan doepmsk = dwc2_readl(hsotg, DOEPMSK); 28825321922cSVardan Mikayelyan doepmsk &= ~DOEPMSK_OUTTKNEPDISMSK; 2883f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, doepmsk, DOEPMSK); 28845321922cSVardan Mikayelyan } 28855321922cSVardan Mikayelyan 28865321922cSVardan Mikayelyan /** 28875321922cSVardan Mikayelyan * dwc2_gadget_handle_nak - handle NAK interrupt 28885321922cSVardan Mikayelyan * @hs_ep: The endpoint on which interrupt is asserted. 28895321922cSVardan Mikayelyan * 28905321922cSVardan Mikayelyan * This is starting point for ISOC-IN transfer, synchronization done with 28915321922cSVardan Mikayelyan * first IN token received from host while corresponding EP is disabled. 28925321922cSVardan Mikayelyan * 28935321922cSVardan Mikayelyan * Device does not know when first one token will arrive from host. On first 28945321922cSVardan Mikayelyan * token arrival HW generates 2 interrupts: 'in token received while FIFO empty' 28955321922cSVardan Mikayelyan * and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was 28965321922cSVardan Mikayelyan * sent in response to that as there was no data in FIFO. SW is basing on this 28975321922cSVardan Mikayelyan * interrupt to obtain frame in which token has come and then based on the 28985321922cSVardan Mikayelyan * interval calculates next frame for transfer. 28995321922cSVardan Mikayelyan */ 29005321922cSVardan Mikayelyan static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) 29015321922cSVardan Mikayelyan { 29025321922cSVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 29035321922cSVardan Mikayelyan int dir_in = hs_ep->dir_in; 29045321922cSVardan Mikayelyan 29055321922cSVardan Mikayelyan if (!dir_in || !hs_ep->isochronous) 29065321922cSVardan Mikayelyan return; 29075321922cSVardan Mikayelyan 29085321922cSVardan Mikayelyan if (hs_ep->target_frame == TARGET_FRAME_INITIAL) { 2909540ccba0SVahram Aharonyan 2910540ccba0SVahram Aharonyan if (using_desc_dma(hsotg)) { 29114d4f1e79SMinas Harutyunyan hs_ep->target_frame = hsotg->frame_number; 2912729cac69SMinas Harutyunyan dwc2_gadget_incr_frame_num(hs_ep); 291348dac4e4SGrigor Tovmasyan 291448dac4e4SGrigor Tovmasyan /* In service interval mode target_frame must 291548dac4e4SGrigor Tovmasyan * be set to last (u)frame of the service interval. 291648dac4e4SGrigor Tovmasyan */ 291748dac4e4SGrigor Tovmasyan if (hsotg->params.service_interval) { 291848dac4e4SGrigor Tovmasyan /* Set target_frame to the first (u)frame of 291948dac4e4SGrigor Tovmasyan * the service interval 292048dac4e4SGrigor Tovmasyan */ 292148dac4e4SGrigor Tovmasyan hs_ep->target_frame &= ~hs_ep->interval + 1; 292248dac4e4SGrigor Tovmasyan 292348dac4e4SGrigor Tovmasyan /* Set target_frame to the last (u)frame of 292448dac4e4SGrigor Tovmasyan * the service interval 292548dac4e4SGrigor Tovmasyan */ 292648dac4e4SGrigor Tovmasyan dwc2_gadget_incr_frame_num(hs_ep); 292748dac4e4SGrigor Tovmasyan dwc2_gadget_dec_frame_num_by_one(hs_ep); 292848dac4e4SGrigor Tovmasyan } 292948dac4e4SGrigor Tovmasyan 2930540ccba0SVahram Aharonyan dwc2_gadget_start_isoc_ddma(hs_ep); 2931540ccba0SVahram Aharonyan return; 2932540ccba0SVahram Aharonyan } 2933540ccba0SVahram Aharonyan 29344d4f1e79SMinas Harutyunyan hs_ep->target_frame = hsotg->frame_number; 29355321922cSVardan Mikayelyan if (hs_ep->interval > 1) { 2936f25c42b8SGevorg Sahakyan u32 ctrl = dwc2_readl(hsotg, 29375321922cSVardan Mikayelyan DIEPCTL(hs_ep->index)); 29385321922cSVardan Mikayelyan if (hs_ep->target_frame & 0x1) 29395321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETODDFR; 29405321922cSVardan Mikayelyan else 29415321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETEVENFR; 29425321922cSVardan Mikayelyan 2943f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ctrl, DIEPCTL(hs_ep->index)); 29445321922cSVardan Mikayelyan } 29455321922cSVardan Mikayelyan 29465321922cSVardan Mikayelyan dwc2_hsotg_complete_request(hsotg, hs_ep, 29475321922cSVardan Mikayelyan get_ep_head(hs_ep), 0); 29485321922cSVardan Mikayelyan } 29495321922cSVardan Mikayelyan 2950729cac69SMinas Harutyunyan if (!using_desc_dma(hsotg)) 29515321922cSVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 29525321922cSVardan Mikayelyan } 29535321922cSVardan Mikayelyan 29545321922cSVardan Mikayelyan /** 29551f91b4ccSFelipe Balbi * dwc2_hsotg_epint - handle an in/out endpoint interrupt 295647a1685fSDinh Nguyen * @hsotg: The driver state 295747a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 295847a1685fSDinh Nguyen * @dir_in: Set if this is an IN endpoint 295947a1685fSDinh Nguyen * 296047a1685fSDinh Nguyen * Process and clear any interrupt pending for an individual endpoint 296147a1685fSDinh Nguyen */ 29621f91b4ccSFelipe Balbi static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, 296347a1685fSDinh Nguyen int dir_in) 296447a1685fSDinh Nguyen { 29651f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in); 296647a1685fSDinh Nguyen u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 296747a1685fSDinh Nguyen u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 296847a1685fSDinh Nguyen u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); 296947a1685fSDinh Nguyen u32 ints; 297047a1685fSDinh Nguyen u32 ctrl; 297147a1685fSDinh Nguyen 297232601588SVardan Mikayelyan ints = dwc2_gadget_read_ep_interrupts(hsotg, idx, dir_in); 2973f25c42b8SGevorg Sahakyan ctrl = dwc2_readl(hsotg, epctl_reg); 297447a1685fSDinh Nguyen 297547a1685fSDinh Nguyen /* Clear endpoint interrupts */ 2976f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ints, epint_reg); 297747a1685fSDinh Nguyen 2978c6f5c050SMian Yousaf Kaukab if (!hs_ep) { 2979c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n", 2980c6f5c050SMian Yousaf Kaukab __func__, idx, dir_in ? "in" : "out"); 2981c6f5c050SMian Yousaf Kaukab return; 2982c6f5c050SMian Yousaf Kaukab } 2983c6f5c050SMian Yousaf Kaukab 298447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", 298547a1685fSDinh Nguyen __func__, idx, dir_in ? "in" : "out", ints); 298647a1685fSDinh Nguyen 2987b787d755SMian Yousaf Kaukab /* Don't process XferCompl interrupt if it is a setup packet */ 2988b787d755SMian Yousaf Kaukab if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD))) 2989b787d755SMian Yousaf Kaukab ints &= ~DXEPINT_XFERCOMPL; 2990b787d755SMian Yousaf Kaukab 2991f0afdb42SVahram Aharonyan /* 2992f0afdb42SVahram Aharonyan * Don't process XferCompl interrupt in DDMA if EP0 is still in SETUP 2993f0afdb42SVahram Aharonyan * stage and xfercomplete was generated without SETUP phase done 2994f0afdb42SVahram Aharonyan * interrupt. SW should parse received setup packet only after host's 2995f0afdb42SVahram Aharonyan * exit from setup phase of control transfer. 2996f0afdb42SVahram Aharonyan */ 2997f0afdb42SVahram Aharonyan if (using_desc_dma(hsotg) && idx == 0 && !hs_ep->dir_in && 2998f0afdb42SVahram Aharonyan hsotg->ep0_state == DWC2_EP0_SETUP && !(ints & DXEPINT_SETUP)) 2999f0afdb42SVahram Aharonyan ints &= ~DXEPINT_XFERCOMPL; 3000f0afdb42SVahram Aharonyan 3001837e9f00SVardan Mikayelyan if (ints & DXEPINT_XFERCOMPL) { 300247a1685fSDinh Nguyen dev_dbg(hsotg->dev, 300347a1685fSDinh Nguyen "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", 3004f25c42b8SGevorg Sahakyan __func__, dwc2_readl(hsotg, epctl_reg), 3005f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, epsiz_reg)); 300647a1685fSDinh Nguyen 3007540ccba0SVahram Aharonyan /* In DDMA handle isochronous requests separately */ 3008540ccba0SVahram Aharonyan if (using_desc_dma(hsotg) && hs_ep->isochronous) { 3009729cac69SMinas Harutyunyan /* XferCompl set along with BNA */ 3010729cac69SMinas Harutyunyan if (!(ints & DXEPINT_BNAINTR)) 3011540ccba0SVahram Aharonyan dwc2_gadget_complete_isoc_request_ddma(hs_ep); 3012540ccba0SVahram Aharonyan } else if (dir_in) { 301347a1685fSDinh Nguyen /* 3014540ccba0SVahram Aharonyan * We get OutDone from the FIFO, so we only 3015540ccba0SVahram Aharonyan * need to look at completing IN requests here 3016540ccba0SVahram Aharonyan * if operating slave mode 301747a1685fSDinh Nguyen */ 3018837e9f00SVardan Mikayelyan if (hs_ep->isochronous && hs_ep->interval > 1) 3019837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 3020837e9f00SVardan Mikayelyan 30211f91b4ccSFelipe Balbi dwc2_hsotg_complete_in(hsotg, hs_ep); 3022837e9f00SVardan Mikayelyan if (ints & DXEPINT_NAKINTRPT) 3023837e9f00SVardan Mikayelyan ints &= ~DXEPINT_NAKINTRPT; 302447a1685fSDinh Nguyen 302547a1685fSDinh Nguyen if (idx == 0 && !hs_ep->req) 30261f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 302747a1685fSDinh Nguyen } else if (using_dma(hsotg)) { 302847a1685fSDinh Nguyen /* 302947a1685fSDinh Nguyen * We're using DMA, we need to fire an OutDone here 303047a1685fSDinh Nguyen * as we ignore the RXFIFO. 303147a1685fSDinh Nguyen */ 3032837e9f00SVardan Mikayelyan if (hs_ep->isochronous && hs_ep->interval > 1) 3033837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 303447a1685fSDinh Nguyen 30351f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, idx); 303647a1685fSDinh Nguyen } 303747a1685fSDinh Nguyen } 303847a1685fSDinh Nguyen 3039bd9971f0SVardan Mikayelyan if (ints & DXEPINT_EPDISBLD) 3040bd9971f0SVardan Mikayelyan dwc2_gadget_handle_ep_disabled(hs_ep); 304147a1685fSDinh Nguyen 30425321922cSVardan Mikayelyan if (ints & DXEPINT_OUTTKNEPDIS) 30435321922cSVardan Mikayelyan dwc2_gadget_handle_out_token_ep_disabled(hs_ep); 30445321922cSVardan Mikayelyan 30455321922cSVardan Mikayelyan if (ints & DXEPINT_NAKINTRPT) 30465321922cSVardan Mikayelyan dwc2_gadget_handle_nak(hs_ep); 30475321922cSVardan Mikayelyan 304847a1685fSDinh Nguyen if (ints & DXEPINT_AHBERR) 304947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); 305047a1685fSDinh Nguyen 305147a1685fSDinh Nguyen if (ints & DXEPINT_SETUP) { /* Setup or Timeout */ 305247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); 305347a1685fSDinh Nguyen 305447a1685fSDinh Nguyen if (using_dma(hsotg) && idx == 0) { 305547a1685fSDinh Nguyen /* 305647a1685fSDinh Nguyen * this is the notification we've received a 305747a1685fSDinh Nguyen * setup packet. In non-DMA mode we'd get this 305847a1685fSDinh Nguyen * from the RXFIFO, instead we need to process 305947a1685fSDinh Nguyen * the setup here. 306047a1685fSDinh Nguyen */ 306147a1685fSDinh Nguyen 306247a1685fSDinh Nguyen if (dir_in) 306347a1685fSDinh Nguyen WARN_ON_ONCE(1); 306447a1685fSDinh Nguyen else 30651f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, 0); 306647a1685fSDinh Nguyen } 306747a1685fSDinh Nguyen } 306847a1685fSDinh Nguyen 3069ef750c71SVahram Aharonyan if (ints & DXEPINT_STSPHSERCVD) { 30709d9a6b07SVahram Aharonyan dev_dbg(hsotg->dev, "%s: StsPhseRcvd\n", __func__); 30719d9a6b07SVahram Aharonyan 30729e95a66cSMinas Harutyunyan /* Safety check EP0 state when STSPHSERCVD asserted */ 30739e95a66cSMinas Harutyunyan if (hsotg->ep0_state == DWC2_EP0_DATA_OUT) { 3074ef750c71SVahram Aharonyan /* Move to STATUS IN for DDMA */ 3075b4c53b4aSMinas Harutyunyan if (using_desc_dma(hsotg)) { 3076b4c53b4aSMinas Harutyunyan if (!hsotg->delayed_status) 3077ef750c71SVahram Aharonyan dwc2_hsotg_ep0_zlp(hsotg, true); 3078b4c53b4aSMinas Harutyunyan else 3079b4c53b4aSMinas Harutyunyan /* In case of 3 stage Control Write with delayed 3080b4c53b4aSMinas Harutyunyan * status, when Status IN transfer started 3081b4c53b4aSMinas Harutyunyan * before STSPHSERCVD asserted, NAKSTS bit not 3082b4c53b4aSMinas Harutyunyan * cleared by CNAK in dwc2_hsotg_start_req() 3083b4c53b4aSMinas Harutyunyan * function. Clear now NAKSTS to allow complete 3084b4c53b4aSMinas Harutyunyan * transfer. 3085b4c53b4aSMinas Harutyunyan */ 3086b4c53b4aSMinas Harutyunyan dwc2_set_bit(hsotg, DIEPCTL(0), 3087b4c53b4aSMinas Harutyunyan DXEPCTL_CNAK); 3088b4c53b4aSMinas Harutyunyan } 3089ef750c71SVahram Aharonyan } 3090ef750c71SVahram Aharonyan 30919e95a66cSMinas Harutyunyan } 30929e95a66cSMinas Harutyunyan 309347a1685fSDinh Nguyen if (ints & DXEPINT_BACK2BACKSETUP) 309447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); 309547a1685fSDinh Nguyen 3096540ccba0SVahram Aharonyan if (ints & DXEPINT_BNAINTR) { 3097540ccba0SVahram Aharonyan dev_dbg(hsotg->dev, "%s: BNA interrupt\n", __func__); 3098540ccba0SVahram Aharonyan if (hs_ep->isochronous) 3099729cac69SMinas Harutyunyan dwc2_gadget_handle_isoc_bna(hs_ep); 3100540ccba0SVahram Aharonyan } 3101540ccba0SVahram Aharonyan 310247a1685fSDinh Nguyen if (dir_in && !hs_ep->isochronous) { 310347a1685fSDinh Nguyen /* not sure if this is important, but we'll clear it anyway */ 310426ddef5dSVardan Mikayelyan if (ints & DXEPINT_INTKNTXFEMP) { 310547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", 310647a1685fSDinh Nguyen __func__, idx); 310747a1685fSDinh Nguyen } 310847a1685fSDinh Nguyen 310947a1685fSDinh Nguyen /* this probably means something bad is happening */ 311026ddef5dSVardan Mikayelyan if (ints & DXEPINT_INTKNEPMIS) { 311147a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", 311247a1685fSDinh Nguyen __func__, idx); 311347a1685fSDinh Nguyen } 311447a1685fSDinh Nguyen 311547a1685fSDinh Nguyen /* FIFO has space or is empty (see GAHBCFG) */ 311647a1685fSDinh Nguyen if (hsotg->dedicated_fifos && 311726ddef5dSVardan Mikayelyan ints & DXEPINT_TXFEMP) { 311847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", 311947a1685fSDinh Nguyen __func__, idx); 312047a1685fSDinh Nguyen if (!using_dma(hsotg)) 31211f91b4ccSFelipe Balbi dwc2_hsotg_trytx(hsotg, hs_ep); 312247a1685fSDinh Nguyen } 312347a1685fSDinh Nguyen } 312447a1685fSDinh Nguyen } 312547a1685fSDinh Nguyen 312647a1685fSDinh Nguyen /** 31271f91b4ccSFelipe Balbi * dwc2_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) 312847a1685fSDinh Nguyen * @hsotg: The device state. 312947a1685fSDinh Nguyen * 313047a1685fSDinh Nguyen * Handle updating the device settings after the enumeration phase has 313147a1685fSDinh Nguyen * been completed. 313247a1685fSDinh Nguyen */ 31331f91b4ccSFelipe Balbi static void dwc2_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg) 313447a1685fSDinh Nguyen { 3135f25c42b8SGevorg Sahakyan u32 dsts = dwc2_readl(hsotg, DSTS); 31369b2667f1SJingoo Han int ep0_mps = 0, ep_mps = 8; 313747a1685fSDinh Nguyen 313847a1685fSDinh Nguyen /* 313947a1685fSDinh Nguyen * This should signal the finish of the enumeration phase 314047a1685fSDinh Nguyen * of the USB handshaking, so we should now know what rate 314147a1685fSDinh Nguyen * we connected at. 314247a1685fSDinh Nguyen */ 314347a1685fSDinh Nguyen 314447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); 314547a1685fSDinh Nguyen 314647a1685fSDinh Nguyen /* 314747a1685fSDinh Nguyen * note, since we're limited by the size of transfer on EP0, and 314847a1685fSDinh Nguyen * it seems IN transfers must be a even number of packets we do 314947a1685fSDinh Nguyen * not advertise a 64byte MPS on EP0. 315047a1685fSDinh Nguyen */ 315147a1685fSDinh Nguyen 315247a1685fSDinh Nguyen /* catch both EnumSpd_FS and EnumSpd_FS48 */ 31536d76c92cSMarek Vasut switch ((dsts & DSTS_ENUMSPD_MASK) >> DSTS_ENUMSPD_SHIFT) { 315447a1685fSDinh Nguyen case DSTS_ENUMSPD_FS: 315547a1685fSDinh Nguyen case DSTS_ENUMSPD_FS48: 315647a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_FULL; 315747a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 315847a1685fSDinh Nguyen ep_mps = 1023; 315947a1685fSDinh Nguyen break; 316047a1685fSDinh Nguyen 316147a1685fSDinh Nguyen case DSTS_ENUMSPD_HS: 316247a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_HIGH; 316347a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 316447a1685fSDinh Nguyen ep_mps = 1024; 316547a1685fSDinh Nguyen break; 316647a1685fSDinh Nguyen 316747a1685fSDinh Nguyen case DSTS_ENUMSPD_LS: 316847a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_LOW; 3169552d940fSVardan Mikayelyan ep0_mps = 8; 3170552d940fSVardan Mikayelyan ep_mps = 8; 317147a1685fSDinh Nguyen /* 317247a1685fSDinh Nguyen * note, we don't actually support LS in this driver at the 317347a1685fSDinh Nguyen * moment, and the documentation seems to imply that it isn't 317447a1685fSDinh Nguyen * supported by the PHYs on some of the devices. 317547a1685fSDinh Nguyen */ 317647a1685fSDinh Nguyen break; 317747a1685fSDinh Nguyen } 317847a1685fSDinh Nguyen dev_info(hsotg->dev, "new device is %s\n", 317947a1685fSDinh Nguyen usb_speed_string(hsotg->gadget.speed)); 318047a1685fSDinh Nguyen 318147a1685fSDinh Nguyen /* 318247a1685fSDinh Nguyen * we should now know the maximum packet size for an 318347a1685fSDinh Nguyen * endpoint, so set the endpoints to a default value. 318447a1685fSDinh Nguyen */ 318547a1685fSDinh Nguyen 318647a1685fSDinh Nguyen if (ep0_mps) { 318747a1685fSDinh Nguyen int i; 3188c6f5c050SMian Yousaf Kaukab /* Initialize ep0 for both in and out directions */ 3189ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 1); 3190ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 0); 3191c6f5c050SMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; i++) { 3192c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[i]) 3193ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 3194ee2c40deSVardan Mikayelyan 0, 1); 3195c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[i]) 3196ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 3197ee2c40deSVardan Mikayelyan 0, 0); 3198c6f5c050SMian Yousaf Kaukab } 319947a1685fSDinh Nguyen } 320047a1685fSDinh Nguyen 320147a1685fSDinh Nguyen /* ensure after enumeration our EP0 is active */ 320247a1685fSDinh Nguyen 32031f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 320447a1685fSDinh Nguyen 320547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 3206f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DIEPCTL0), 3207f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DOEPCTL0)); 320847a1685fSDinh Nguyen } 320947a1685fSDinh Nguyen 321047a1685fSDinh Nguyen /** 321147a1685fSDinh Nguyen * kill_all_requests - remove all requests from the endpoint's queue 321247a1685fSDinh Nguyen * @hsotg: The device state. 321347a1685fSDinh Nguyen * @ep: The endpoint the requests may be on. 321447a1685fSDinh Nguyen * @result: The result code to use. 321547a1685fSDinh Nguyen * 321647a1685fSDinh Nguyen * Go through the requests on the given endpoint and mark them 321747a1685fSDinh Nguyen * completed with the given result code. 321847a1685fSDinh Nguyen */ 3219941fcce4SDinh Nguyen static void kill_all_requests(struct dwc2_hsotg *hsotg, 32201f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep, 32216b448af4SRobert Baldyga int result) 322247a1685fSDinh Nguyen { 32231f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req, *treq; 32249da51974SJohn Youn unsigned int size; 322547a1685fSDinh Nguyen 32266b448af4SRobert Baldyga ep->req = NULL; 322747a1685fSDinh Nguyen 32286b448af4SRobert Baldyga list_for_each_entry_safe(req, treq, &ep->queue, queue) 32291f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, ep, req, 323047a1685fSDinh Nguyen result); 32316b448af4SRobert Baldyga 3232b203d0a2SRobert Baldyga if (!hsotg->dedicated_fifos) 3233b203d0a2SRobert Baldyga return; 3234f25c42b8SGevorg Sahakyan size = (dwc2_readl(hsotg, DTXFSTS(ep->fifo_index)) & 0xffff) * 4; 3235b203d0a2SRobert Baldyga if (size < ep->fifo_size) 32361f91b4ccSFelipe Balbi dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); 323747a1685fSDinh Nguyen } 323847a1685fSDinh Nguyen 323947a1685fSDinh Nguyen /** 32401f91b4ccSFelipe Balbi * dwc2_hsotg_disconnect - disconnect service 324147a1685fSDinh Nguyen * @hsotg: The device state. 324247a1685fSDinh Nguyen * 324347a1685fSDinh Nguyen * The device has been disconnected. Remove all current 324447a1685fSDinh Nguyen * transactions and signal the gadget driver that this 324547a1685fSDinh Nguyen * has happened. 324647a1685fSDinh Nguyen */ 32471f91b4ccSFelipe Balbi void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) 324847a1685fSDinh Nguyen { 32499da51974SJohn Youn unsigned int ep; 325047a1685fSDinh Nguyen 32514ace06e8SMarek Szyprowski if (!hsotg->connected) 32524ace06e8SMarek Szyprowski return; 32534ace06e8SMarek Szyprowski 32544ace06e8SMarek Szyprowski hsotg->connected = 0; 32559e14d0a5SGregory Herrero hsotg->test_mode = 0; 3256c6f5c050SMian Yousaf Kaukab 3257dccf1badSMinas Harutyunyan /* all endpoints should be shutdown */ 3258c6f5c050SMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps; ep++) { 3259c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 32604fe4f9feSMinas Harutyunyan kill_all_requests(hsotg, hsotg->eps_in[ep], 32614fe4f9feSMinas Harutyunyan -ESHUTDOWN); 3262c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 32634fe4f9feSMinas Harutyunyan kill_all_requests(hsotg, hsotg->eps_out[ep], 32644fe4f9feSMinas Harutyunyan -ESHUTDOWN); 3265c6f5c050SMian Yousaf Kaukab } 326647a1685fSDinh Nguyen 326747a1685fSDinh Nguyen call_gadget(hsotg, disconnect); 3268065d3931SGregory Herrero hsotg->lx_state = DWC2_L3; 3269ce2b21a4SJohn Stultz 3270ce2b21a4SJohn Stultz usb_gadget_set_state(&hsotg->gadget, USB_STATE_NOTATTACHED); 327147a1685fSDinh Nguyen } 327247a1685fSDinh Nguyen 327347a1685fSDinh Nguyen /** 32741f91b4ccSFelipe Balbi * dwc2_hsotg_irq_fifoempty - TX FIFO empty interrupt handler 327547a1685fSDinh Nguyen * @hsotg: The device state: 327647a1685fSDinh Nguyen * @periodic: True if this is a periodic FIFO interrupt 327747a1685fSDinh Nguyen */ 32781f91b4ccSFelipe Balbi static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) 327947a1685fSDinh Nguyen { 32801f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 328147a1685fSDinh Nguyen int epno, ret; 328247a1685fSDinh Nguyen 328347a1685fSDinh Nguyen /* look through for any more data to transmit */ 328447a1685fSDinh Nguyen for (epno = 0; epno < hsotg->num_of_eps; epno++) { 3285c6f5c050SMian Yousaf Kaukab ep = index_to_ep(hsotg, epno, 1); 3286c6f5c050SMian Yousaf Kaukab 3287c6f5c050SMian Yousaf Kaukab if (!ep) 3288c6f5c050SMian Yousaf Kaukab continue; 328947a1685fSDinh Nguyen 329047a1685fSDinh Nguyen if (!ep->dir_in) 329147a1685fSDinh Nguyen continue; 329247a1685fSDinh Nguyen 329347a1685fSDinh Nguyen if ((periodic && !ep->periodic) || 329447a1685fSDinh Nguyen (!periodic && ep->periodic)) 329547a1685fSDinh Nguyen continue; 329647a1685fSDinh Nguyen 32971f91b4ccSFelipe Balbi ret = dwc2_hsotg_trytx(hsotg, ep); 329847a1685fSDinh Nguyen if (ret < 0) 329947a1685fSDinh Nguyen break; 330047a1685fSDinh Nguyen } 330147a1685fSDinh Nguyen } 330247a1685fSDinh Nguyen 330347a1685fSDinh Nguyen /* IRQ flags which will trigger a retry around the IRQ loop */ 330447a1685fSDinh Nguyen #define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ 330547a1685fSDinh Nguyen GINTSTS_PTXFEMP | \ 330647a1685fSDinh Nguyen GINTSTS_RXFLVL) 330747a1685fSDinh Nguyen 33084fe4f9feSMinas Harutyunyan static int dwc2_hsotg_ep_disable(struct usb_ep *ep); 330947a1685fSDinh Nguyen /** 33101f91b4ccSFelipe Balbi * dwc2_hsotg_core_init - issue softreset to the core 331147a1685fSDinh Nguyen * @hsotg: The device state 33126fb914d7SGrigor Tovmasyan * @is_usb_reset: Usb resetting flag 331347a1685fSDinh Nguyen * 331447a1685fSDinh Nguyen * Issue a soft reset to the core, and await the core finishing it. 331547a1685fSDinh Nguyen */ 33161f91b4ccSFelipe Balbi void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, 3317643cc4deSGregory Herrero bool is_usb_reset) 331847a1685fSDinh Nguyen { 33191ee6903bSGregory Herrero u32 intmsk; 3320643cc4deSGregory Herrero u32 val; 3321ecd9a7adSPrzemek Rudy u32 usbcfg; 332279c3b5bbSVahram Aharonyan u32 dcfg = 0; 3323dccf1badSMinas Harutyunyan int ep; 3324643cc4deSGregory Herrero 33255390d438SMian Yousaf Kaukab /* Kill any ep0 requests as controller will be reinitialized */ 33265390d438SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); 33275390d438SMian Yousaf Kaukab 3328dccf1badSMinas Harutyunyan if (!is_usb_reset) { 33296e6360b6SJohn Stultz if (dwc2_core_reset(hsotg, true)) 333086de4895SGregory Herrero return; 3331dccf1badSMinas Harutyunyan } else { 3332dccf1badSMinas Harutyunyan /* all endpoints should be shutdown */ 3333dccf1badSMinas Harutyunyan for (ep = 1; ep < hsotg->num_of_eps; ep++) { 3334dccf1badSMinas Harutyunyan if (hsotg->eps_in[ep]) 3335dccf1badSMinas Harutyunyan dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 3336dccf1badSMinas Harutyunyan if (hsotg->eps_out[ep]) 3337dccf1badSMinas Harutyunyan dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 3338dccf1badSMinas Harutyunyan } 3339dccf1badSMinas Harutyunyan } 334047a1685fSDinh Nguyen 334147a1685fSDinh Nguyen /* 334247a1685fSDinh Nguyen * we must now enable ep0 ready for host detection and then 334347a1685fSDinh Nguyen * set configuration. 334447a1685fSDinh Nguyen */ 334547a1685fSDinh Nguyen 3346ecd9a7adSPrzemek Rudy /* keep other bits untouched (so e.g. forced modes are not lost) */ 3347f25c42b8SGevorg Sahakyan usbcfg = dwc2_readl(hsotg, GUSBCFG); 33481e868545SJules Maselbas usbcfg &= ~GUSBCFG_TOUTCAL_MASK; 3349707d80f0SJules Maselbas usbcfg |= GUSBCFG_TOUTCAL(7); 3350ecd9a7adSPrzemek Rudy 33511e868545SJules Maselbas /* remove the HNP/SRP and set the PHY */ 33521e868545SJules Maselbas usbcfg &= ~(GUSBCFG_SRPCAP | GUSBCFG_HNPCAP); 3353f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, usbcfg, GUSBCFG); 335447a1685fSDinh Nguyen 33551e868545SJules Maselbas dwc2_phy_init(hsotg, true); 33561e868545SJules Maselbas 33571f91b4ccSFelipe Balbi dwc2_hsotg_init_fifo(hsotg); 335847a1685fSDinh Nguyen 3359643cc4deSGregory Herrero if (!is_usb_reset) 3360f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); 336147a1685fSDinh Nguyen 336279c3b5bbSVahram Aharonyan dcfg |= DCFG_EPMISCNT(1); 336338e9002bSVardan Mikayelyan 336438e9002bSVardan Mikayelyan switch (hsotg->params.speed) { 336538e9002bSVardan Mikayelyan case DWC2_SPEED_PARAM_LOW: 336638e9002bSVardan Mikayelyan dcfg |= DCFG_DEVSPD_LS; 336738e9002bSVardan Mikayelyan break; 336838e9002bSVardan Mikayelyan case DWC2_SPEED_PARAM_FULL: 336979c3b5bbSVahram Aharonyan if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) 337079c3b5bbSVahram Aharonyan dcfg |= DCFG_DEVSPD_FS48; 337179c3b5bbSVahram Aharonyan else 337279c3b5bbSVahram Aharonyan dcfg |= DCFG_DEVSPD_FS; 337338e9002bSVardan Mikayelyan break; 337438e9002bSVardan Mikayelyan default: 337579c3b5bbSVahram Aharonyan dcfg |= DCFG_DEVSPD_HS; 337679c3b5bbSVahram Aharonyan } 337738e9002bSVardan Mikayelyan 3378b43ebc96SGrigor Tovmasyan if (hsotg->params.ipg_isoc_en) 3379b43ebc96SGrigor Tovmasyan dcfg |= DCFG_IPG_ISOC_SUPPORDED; 3380b43ebc96SGrigor Tovmasyan 3381f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dcfg, DCFG); 338247a1685fSDinh Nguyen 338347a1685fSDinh Nguyen /* Clear any pending OTG interrupts */ 3384f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, 0xffffffff, GOTGINT); 338547a1685fSDinh Nguyen 338647a1685fSDinh Nguyen /* Clear any pending interrupts */ 3387f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, 0xffffffff, GINTSTS); 33881ee6903bSGregory Herrero intmsk = GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT | 338947a1685fSDinh Nguyen GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | 33901ee6903bSGregory Herrero GINTSTS_USBRST | GINTSTS_RESETDET | 33911ee6903bSGregory Herrero GINTSTS_ENUMDONE | GINTSTS_OTGINT | 3392376f0401SSevak Arakelyan GINTSTS_USBSUSP | GINTSTS_WKUPINT | 3393376f0401SSevak Arakelyan GINTSTS_LPMTRANRCVD; 3394f4736701SVahram Aharonyan 3395f4736701SVahram Aharonyan if (!using_desc_dma(hsotg)) 3396f4736701SVahram Aharonyan intmsk |= GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT; 33971ee6903bSGregory Herrero 339895832c00SJohn Youn if (!hsotg->params.external_id_pin_ctl) 33991ee6903bSGregory Herrero intmsk |= GINTSTS_CONIDSTSCHNG; 34001ee6903bSGregory Herrero 3401f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, intmsk, GINTMSK); 340247a1685fSDinh Nguyen 3403a5c18f11SVahram Aharonyan if (using_dma(hsotg)) { 3404f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN | 3405d1ac8c80SRazmik Karapetyan hsotg->params.ahbcfg, 3406f25c42b8SGevorg Sahakyan GAHBCFG); 3407a5c18f11SVahram Aharonyan 3408a5c18f11SVahram Aharonyan /* Set DDMA mode support in the core if needed */ 3409a5c18f11SVahram Aharonyan if (using_desc_dma(hsotg)) 3410f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DCFG, DCFG_DESCDMA_EN); 3411a5c18f11SVahram Aharonyan 3412a5c18f11SVahram Aharonyan } else { 3413f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ((hsotg->dedicated_fifos) ? 341495c8bc36SAntti Seppälä (GAHBCFG_NP_TXF_EMP_LVL | 341547a1685fSDinh Nguyen GAHBCFG_P_TXF_EMP_LVL) : 0) | 3416f25c42b8SGevorg Sahakyan GAHBCFG_GLBL_INTR_EN, GAHBCFG); 3417a5c18f11SVahram Aharonyan } 341847a1685fSDinh Nguyen 341947a1685fSDinh Nguyen /* 342047a1685fSDinh Nguyen * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts 342147a1685fSDinh Nguyen * when we have no data to transfer. Otherwise we get being flooded by 342247a1685fSDinh Nguyen * interrupts. 342347a1685fSDinh Nguyen */ 342447a1685fSDinh Nguyen 3425f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ((hsotg->dedicated_fifos && !using_dma(hsotg)) ? 34266ff2e832SMian Yousaf Kaukab DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) | 342747a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | 3428837e9f00SVardan Mikayelyan DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK, 3429f25c42b8SGevorg Sahakyan DIEPMSK); 343047a1685fSDinh Nguyen 343147a1685fSDinh Nguyen /* 343247a1685fSDinh Nguyen * don't need XferCompl, we get that from RXFIFO in slave mode. In 34339d9a6b07SVahram Aharonyan * DMA mode we may need this and StsPhseRcvd. 343447a1685fSDinh Nguyen */ 3435f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, (using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK | 34369d9a6b07SVahram Aharonyan DOEPMSK_STSPHSERCVDMSK) : 0) | 343747a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | 34389d9a6b07SVahram Aharonyan DOEPMSK_SETUPMSK, 3439f25c42b8SGevorg Sahakyan DOEPMSK); 344047a1685fSDinh Nguyen 3441ec01f0b2SVahram Aharonyan /* Enable BNA interrupt for DDMA */ 344237981e00SMinas Harutyunyan if (using_desc_dma(hsotg)) { 3443f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DOEPMSK, DOEPMSK_BNAMSK); 3444f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK); 344537981e00SMinas Harutyunyan } 3446ec01f0b2SVahram Aharonyan 3447ca531bc2SGrigor Tovmasyan /* Enable Service Interval mode if supported */ 3448ca531bc2SGrigor Tovmasyan if (using_desc_dma(hsotg) && hsotg->params.service_interval) 3449ca531bc2SGrigor Tovmasyan dwc2_set_bit(hsotg, DCTL, DCTL_SERVICE_INTERVAL_SUPPORTED); 3450ca531bc2SGrigor Tovmasyan 3451f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, 0, DAINTMSK); 345247a1685fSDinh Nguyen 345347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 3454f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DIEPCTL0), 3455f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DOEPCTL0)); 345647a1685fSDinh Nguyen 345747a1685fSDinh Nguyen /* enable in and out endpoint interrupts */ 34581f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT); 345947a1685fSDinh Nguyen 346047a1685fSDinh Nguyen /* 346147a1685fSDinh Nguyen * Enable the RXFIFO when in slave mode, as this is how we collect 346247a1685fSDinh Nguyen * the data. In DMA mode, we get events from the FIFO but also 346347a1685fSDinh Nguyen * things we cannot process, so do not use it. 346447a1685fSDinh Nguyen */ 346547a1685fSDinh Nguyen if (!using_dma(hsotg)) 34661f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL); 346747a1685fSDinh Nguyen 346847a1685fSDinh Nguyen /* Enable interrupts for EP0 in and out */ 34691f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, 0, 0, 1); 34701f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, 0, 1, 1); 347147a1685fSDinh Nguyen 3472643cc4deSGregory Herrero if (!is_usb_reset) { 3473f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DCTL, DCTL_PWRONPRGDONE); 347447a1685fSDinh Nguyen udelay(10); /* see openiboot */ 3475f25c42b8SGevorg Sahakyan dwc2_clear_bit(hsotg, DCTL, DCTL_PWRONPRGDONE); 3476643cc4deSGregory Herrero } 347747a1685fSDinh Nguyen 3478f25c42b8SGevorg Sahakyan dev_dbg(hsotg->dev, "DCTL=0x%08x\n", dwc2_readl(hsotg, DCTL)); 347947a1685fSDinh Nguyen 348047a1685fSDinh Nguyen /* 348147a1685fSDinh Nguyen * DxEPCTL_USBActEp says RO in manual, but seems to be set by 348247a1685fSDinh Nguyen * writing to the EPCTL register.. 348347a1685fSDinh Nguyen */ 348447a1685fSDinh Nguyen 348547a1685fSDinh Nguyen /* set to read 1 8byte packet */ 3486f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 3487f25c42b8SGevorg Sahakyan DXEPTSIZ_XFERSIZE(8), DOEPTSIZ0); 348847a1685fSDinh Nguyen 3489f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 349047a1685fSDinh Nguyen DXEPCTL_CNAK | DXEPCTL_EPENA | 349147a1685fSDinh Nguyen DXEPCTL_USBACTEP, 3492f25c42b8SGevorg Sahakyan DOEPCTL0); 349347a1685fSDinh Nguyen 349447a1685fSDinh Nguyen /* enable, but don't activate EP0in */ 3495f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 3496f25c42b8SGevorg Sahakyan DXEPCTL_USBACTEP, DIEPCTL0); 349747a1685fSDinh Nguyen 349847a1685fSDinh Nguyen /* clear global NAKs */ 3499643cc4deSGregory Herrero val = DCTL_CGOUTNAK | DCTL_CGNPINNAK; 3500643cc4deSGregory Herrero if (!is_usb_reset) 3501643cc4deSGregory Herrero val |= DCTL_SFTDISCON; 3502f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DCTL, val); 350347a1685fSDinh Nguyen 350421b03405SSevak Arakelyan /* configure the core to support LPM */ 350521b03405SSevak Arakelyan dwc2_gadget_init_lpm(hsotg); 350621b03405SSevak Arakelyan 350715d9dbf8SGrigor Tovmasyan /* program GREFCLK register if needed */ 350815d9dbf8SGrigor Tovmasyan if (using_desc_dma(hsotg) && hsotg->params.service_interval) 350915d9dbf8SGrigor Tovmasyan dwc2_gadget_program_ref_clk(hsotg); 351015d9dbf8SGrigor Tovmasyan 351147a1685fSDinh Nguyen /* must be at-least 3ms to allow bus to see disconnect */ 351247a1685fSDinh Nguyen mdelay(3); 351347a1685fSDinh Nguyen 3514065d3931SGregory Herrero hsotg->lx_state = DWC2_L0; 3515755d7395SVardan Mikayelyan 3516755d7395SVardan Mikayelyan dwc2_hsotg_enqueue_setup(hsotg); 3517755d7395SVardan Mikayelyan 3518755d7395SVardan Mikayelyan dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 3519f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DIEPCTL0), 3520f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DOEPCTL0)); 3521ad38dc5dSMarek Szyprowski } 3522ac3c81f3SMarek Szyprowski 35231f91b4ccSFelipe Balbi static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) 3524ad38dc5dSMarek Szyprowski { 3525ad38dc5dSMarek Szyprowski /* set the soft-disconnect bit */ 3526f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); 3527ad38dc5dSMarek Szyprowski } 3528ad38dc5dSMarek Szyprowski 35291f91b4ccSFelipe Balbi void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) 3530ad38dc5dSMarek Szyprowski { 353147a1685fSDinh Nguyen /* remove the soft-disconnect and let's go */ 3532f25c42b8SGevorg Sahakyan dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON); 353347a1685fSDinh Nguyen } 353447a1685fSDinh Nguyen 353547a1685fSDinh Nguyen /** 3536381fc8f8SVardan Mikayelyan * dwc2_gadget_handle_incomplete_isoc_in - handle incomplete ISO IN Interrupt. 3537381fc8f8SVardan Mikayelyan * @hsotg: The device state: 3538381fc8f8SVardan Mikayelyan * 3539381fc8f8SVardan Mikayelyan * This interrupt indicates one of the following conditions occurred while 3540381fc8f8SVardan Mikayelyan * transmitting an ISOC transaction. 3541381fc8f8SVardan Mikayelyan * - Corrupted IN Token for ISOC EP. 3542381fc8f8SVardan Mikayelyan * - Packet not complete in FIFO. 3543381fc8f8SVardan Mikayelyan * 3544381fc8f8SVardan Mikayelyan * The following actions will be taken: 3545381fc8f8SVardan Mikayelyan * - Determine the EP 3546381fc8f8SVardan Mikayelyan * - Disable EP; when 'Endpoint Disabled' interrupt is received Flush FIFO 3547381fc8f8SVardan Mikayelyan */ 3548381fc8f8SVardan Mikayelyan static void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg) 3549381fc8f8SVardan Mikayelyan { 3550381fc8f8SVardan Mikayelyan struct dwc2_hsotg_ep *hs_ep; 3551381fc8f8SVardan Mikayelyan u32 epctrl; 35521b4977c7SRazmik Karapetyan u32 daintmsk; 3553381fc8f8SVardan Mikayelyan u32 idx; 3554381fc8f8SVardan Mikayelyan 3555381fc8f8SVardan Mikayelyan dev_dbg(hsotg->dev, "Incomplete isoc in interrupt received:\n"); 3556381fc8f8SVardan Mikayelyan 3557f25c42b8SGevorg Sahakyan daintmsk = dwc2_readl(hsotg, DAINTMSK); 35581b4977c7SRazmik Karapetyan 3559d5d5f079SArtur Petrosyan for (idx = 1; idx < hsotg->num_of_eps; idx++) { 3560381fc8f8SVardan Mikayelyan hs_ep = hsotg->eps_in[idx]; 35611b4977c7SRazmik Karapetyan /* Proceed only unmasked ISOC EPs */ 356289066b36SJohn Keeping if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous) 35631b4977c7SRazmik Karapetyan continue; 35641b4977c7SRazmik Karapetyan 3565f25c42b8SGevorg Sahakyan epctrl = dwc2_readl(hsotg, DIEPCTL(idx)); 35661b4977c7SRazmik Karapetyan if ((epctrl & DXEPCTL_EPENA) && 3567381fc8f8SVardan Mikayelyan dwc2_gadget_target_frame_elapsed(hs_ep)) { 3568381fc8f8SVardan Mikayelyan epctrl |= DXEPCTL_SNAK; 3569381fc8f8SVardan Mikayelyan epctrl |= DXEPCTL_EPDIS; 3570f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, epctrl, DIEPCTL(idx)); 3571381fc8f8SVardan Mikayelyan } 3572381fc8f8SVardan Mikayelyan } 3573381fc8f8SVardan Mikayelyan 3574381fc8f8SVardan Mikayelyan /* Clear interrupt */ 3575f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, GINTSTS_INCOMPL_SOIN, GINTSTS); 3576381fc8f8SVardan Mikayelyan } 3577381fc8f8SVardan Mikayelyan 3578381fc8f8SVardan Mikayelyan /** 3579381fc8f8SVardan Mikayelyan * dwc2_gadget_handle_incomplete_isoc_out - handle incomplete ISO OUT Interrupt 3580381fc8f8SVardan Mikayelyan * @hsotg: The device state: 3581381fc8f8SVardan Mikayelyan * 3582381fc8f8SVardan Mikayelyan * This interrupt indicates one of the following conditions occurred while 3583381fc8f8SVardan Mikayelyan * transmitting an ISOC transaction. 3584381fc8f8SVardan Mikayelyan * - Corrupted OUT Token for ISOC EP. 3585381fc8f8SVardan Mikayelyan * - Packet not complete in FIFO. 3586381fc8f8SVardan Mikayelyan * 3587381fc8f8SVardan Mikayelyan * The following actions will be taken: 3588381fc8f8SVardan Mikayelyan * - Determine the EP 3589381fc8f8SVardan Mikayelyan * - Set DCTL_SGOUTNAK and unmask GOUTNAKEFF if target frame elapsed. 3590381fc8f8SVardan Mikayelyan */ 3591381fc8f8SVardan Mikayelyan static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg) 3592381fc8f8SVardan Mikayelyan { 3593381fc8f8SVardan Mikayelyan u32 gintsts; 3594381fc8f8SVardan Mikayelyan u32 gintmsk; 3595689efb26SRazmik Karapetyan u32 daintmsk; 3596381fc8f8SVardan Mikayelyan u32 epctrl; 3597381fc8f8SVardan Mikayelyan struct dwc2_hsotg_ep *hs_ep; 3598381fc8f8SVardan Mikayelyan int idx; 3599381fc8f8SVardan Mikayelyan 3600381fc8f8SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__); 3601381fc8f8SVardan Mikayelyan 3602f25c42b8SGevorg Sahakyan daintmsk = dwc2_readl(hsotg, DAINTMSK); 3603689efb26SRazmik Karapetyan daintmsk >>= DAINT_OUTEP_SHIFT; 3604689efb26SRazmik Karapetyan 3605d5d5f079SArtur Petrosyan for (idx = 1; idx < hsotg->num_of_eps; idx++) { 3606381fc8f8SVardan Mikayelyan hs_ep = hsotg->eps_out[idx]; 3607689efb26SRazmik Karapetyan /* Proceed only unmasked ISOC EPs */ 360889066b36SJohn Keeping if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous) 3609689efb26SRazmik Karapetyan continue; 3610689efb26SRazmik Karapetyan 3611f25c42b8SGevorg Sahakyan epctrl = dwc2_readl(hsotg, DOEPCTL(idx)); 3612689efb26SRazmik Karapetyan if ((epctrl & DXEPCTL_EPENA) && 3613381fc8f8SVardan Mikayelyan dwc2_gadget_target_frame_elapsed(hs_ep)) { 3614381fc8f8SVardan Mikayelyan /* Unmask GOUTNAKEFF interrupt */ 3615f25c42b8SGevorg Sahakyan gintmsk = dwc2_readl(hsotg, GINTMSK); 3616381fc8f8SVardan Mikayelyan gintmsk |= GINTSTS_GOUTNAKEFF; 3617f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gintmsk, GINTMSK); 3618381fc8f8SVardan Mikayelyan 3619f25c42b8SGevorg Sahakyan gintsts = dwc2_readl(hsotg, GINTSTS); 3620689efb26SRazmik Karapetyan if (!(gintsts & GINTSTS_GOUTNAKEFF)) { 3621f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DCTL, DCTL_SGOUTNAK); 3622689efb26SRazmik Karapetyan break; 3623689efb26SRazmik Karapetyan } 3624381fc8f8SVardan Mikayelyan } 3625381fc8f8SVardan Mikayelyan } 3626381fc8f8SVardan Mikayelyan 3627381fc8f8SVardan Mikayelyan /* Clear interrupt */ 3628f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, GINTSTS_INCOMPL_SOOUT, GINTSTS); 3629381fc8f8SVardan Mikayelyan } 3630381fc8f8SVardan Mikayelyan 3631381fc8f8SVardan Mikayelyan /** 36321f91b4ccSFelipe Balbi * dwc2_hsotg_irq - handle device interrupt 363347a1685fSDinh Nguyen * @irq: The IRQ number triggered 363447a1685fSDinh Nguyen * @pw: The pw value when registered the handler. 363547a1685fSDinh Nguyen */ 36361f91b4ccSFelipe Balbi static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) 363747a1685fSDinh Nguyen { 3638941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = pw; 363947a1685fSDinh Nguyen int retry_count = 8; 364047a1685fSDinh Nguyen u32 gintsts; 364147a1685fSDinh Nguyen u32 gintmsk; 364247a1685fSDinh Nguyen 3643ee3de8d7SVardan Mikayelyan if (!dwc2_is_device_mode(hsotg)) 3644ee3de8d7SVardan Mikayelyan return IRQ_NONE; 3645ee3de8d7SVardan Mikayelyan 364647a1685fSDinh Nguyen spin_lock(&hsotg->lock); 364747a1685fSDinh Nguyen irq_retry: 3648f25c42b8SGevorg Sahakyan gintsts = dwc2_readl(hsotg, GINTSTS); 3649f25c42b8SGevorg Sahakyan gintmsk = dwc2_readl(hsotg, GINTMSK); 365047a1685fSDinh Nguyen 365147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", 365247a1685fSDinh Nguyen __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); 365347a1685fSDinh Nguyen 365447a1685fSDinh Nguyen gintsts &= gintmsk; 365547a1685fSDinh Nguyen 36568fc37b82SMian Yousaf Kaukab if (gintsts & GINTSTS_RESETDET) { 36578fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: USBRstDet\n", __func__); 36588fc37b82SMian Yousaf Kaukab 3659f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, GINTSTS_RESETDET, GINTSTS); 36608fc37b82SMian Yousaf Kaukab 36618fc37b82SMian Yousaf Kaukab /* This event must be used only if controller is suspended */ 36628fc37b82SMian Yousaf Kaukab if (hsotg->lx_state == DWC2_L2) { 366341ba9b9bSVardan Mikayelyan dwc2_exit_partial_power_down(hsotg, true); 36648fc37b82SMian Yousaf Kaukab hsotg->lx_state = DWC2_L0; 36658fc37b82SMian Yousaf Kaukab } 36668fc37b82SMian Yousaf Kaukab } 36678fc37b82SMian Yousaf Kaukab 36688fc37b82SMian Yousaf Kaukab if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) { 3669f25c42b8SGevorg Sahakyan u32 usb_status = dwc2_readl(hsotg, GOTGCTL); 36708fc37b82SMian Yousaf Kaukab u32 connected = hsotg->connected; 36718fc37b82SMian Yousaf Kaukab 36728fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: USBRst\n", __func__); 36738fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", 3674f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, GNPTXSTS)); 36758fc37b82SMian Yousaf Kaukab 3676f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, GINTSTS_USBRST, GINTSTS); 36778fc37b82SMian Yousaf Kaukab 36788fc37b82SMian Yousaf Kaukab /* Report disconnection if it is not already done. */ 36798fc37b82SMian Yousaf Kaukab dwc2_hsotg_disconnect(hsotg); 36808fc37b82SMian Yousaf Kaukab 3681307bc11fSMinas Harutyunyan /* Reset device address to zero */ 3682f25c42b8SGevorg Sahakyan dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK); 3683307bc11fSMinas Harutyunyan 36848fc37b82SMian Yousaf Kaukab if (usb_status & GOTGCTL_BSESVLD && connected) 36858fc37b82SMian Yousaf Kaukab dwc2_hsotg_core_init_disconnected(hsotg, true); 36868fc37b82SMian Yousaf Kaukab } 36878fc37b82SMian Yousaf Kaukab 368847a1685fSDinh Nguyen if (gintsts & GINTSTS_ENUMDONE) { 3689f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, GINTSTS_ENUMDONE, GINTSTS); 369047a1685fSDinh Nguyen 36911f91b4ccSFelipe Balbi dwc2_hsotg_irq_enumdone(hsotg); 369247a1685fSDinh Nguyen } 369347a1685fSDinh Nguyen 369447a1685fSDinh Nguyen if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { 3695f25c42b8SGevorg Sahakyan u32 daint = dwc2_readl(hsotg, DAINT); 3696f25c42b8SGevorg Sahakyan u32 daintmsk = dwc2_readl(hsotg, DAINTMSK); 369747a1685fSDinh Nguyen u32 daint_out, daint_in; 369847a1685fSDinh Nguyen int ep; 369947a1685fSDinh Nguyen 370047a1685fSDinh Nguyen daint &= daintmsk; 370147a1685fSDinh Nguyen daint_out = daint >> DAINT_OUTEP_SHIFT; 370247a1685fSDinh Nguyen daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); 370347a1685fSDinh Nguyen 370447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); 370547a1685fSDinh Nguyen 3706cec87f1dSMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps && daint_out; 3707cec87f1dSMian Yousaf Kaukab ep++, daint_out >>= 1) { 370847a1685fSDinh Nguyen if (daint_out & 1) 37091f91b4ccSFelipe Balbi dwc2_hsotg_epint(hsotg, ep, 0); 371047a1685fSDinh Nguyen } 371147a1685fSDinh Nguyen 3712cec87f1dSMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps && daint_in; 3713cec87f1dSMian Yousaf Kaukab ep++, daint_in >>= 1) { 371447a1685fSDinh Nguyen if (daint_in & 1) 37151f91b4ccSFelipe Balbi dwc2_hsotg_epint(hsotg, ep, 1); 371647a1685fSDinh Nguyen } 371747a1685fSDinh Nguyen } 371847a1685fSDinh Nguyen 371947a1685fSDinh Nguyen /* check both FIFOs */ 372047a1685fSDinh Nguyen 372147a1685fSDinh Nguyen if (gintsts & GINTSTS_NPTXFEMP) { 372247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "NPTxFEmp\n"); 372347a1685fSDinh Nguyen 372447a1685fSDinh Nguyen /* 372547a1685fSDinh Nguyen * Disable the interrupt to stop it happening again 372647a1685fSDinh Nguyen * unless one of these endpoint routines decides that 372747a1685fSDinh Nguyen * it needs re-enabling 372847a1685fSDinh Nguyen */ 372947a1685fSDinh Nguyen 37301f91b4ccSFelipe Balbi dwc2_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); 37311f91b4ccSFelipe Balbi dwc2_hsotg_irq_fifoempty(hsotg, false); 373247a1685fSDinh Nguyen } 373347a1685fSDinh Nguyen 373447a1685fSDinh Nguyen if (gintsts & GINTSTS_PTXFEMP) { 373547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "PTxFEmp\n"); 373647a1685fSDinh Nguyen 373747a1685fSDinh Nguyen /* See note in GINTSTS_NPTxFEmp */ 373847a1685fSDinh Nguyen 37391f91b4ccSFelipe Balbi dwc2_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); 37401f91b4ccSFelipe Balbi dwc2_hsotg_irq_fifoempty(hsotg, true); 374147a1685fSDinh Nguyen } 374247a1685fSDinh Nguyen 374347a1685fSDinh Nguyen if (gintsts & GINTSTS_RXFLVL) { 374447a1685fSDinh Nguyen /* 374547a1685fSDinh Nguyen * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, 37461f91b4ccSFelipe Balbi * we need to retry dwc2_hsotg_handle_rx if this is still 374747a1685fSDinh Nguyen * set. 374847a1685fSDinh Nguyen */ 374947a1685fSDinh Nguyen 37501f91b4ccSFelipe Balbi dwc2_hsotg_handle_rx(hsotg); 375147a1685fSDinh Nguyen } 375247a1685fSDinh Nguyen 375347a1685fSDinh Nguyen if (gintsts & GINTSTS_ERLYSUSP) { 375447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); 3755f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, GINTSTS_ERLYSUSP, GINTSTS); 375647a1685fSDinh Nguyen } 375747a1685fSDinh Nguyen 375847a1685fSDinh Nguyen /* 375947a1685fSDinh Nguyen * these next two seem to crop-up occasionally causing the core 376047a1685fSDinh Nguyen * to shutdown the USB transfer, so try clearing them and logging 376147a1685fSDinh Nguyen * the occurrence. 376247a1685fSDinh Nguyen */ 376347a1685fSDinh Nguyen 376447a1685fSDinh Nguyen if (gintsts & GINTSTS_GOUTNAKEFF) { 3765837e9f00SVardan Mikayelyan u8 idx; 3766837e9f00SVardan Mikayelyan u32 epctrl; 3767837e9f00SVardan Mikayelyan u32 gintmsk; 3768d8484552SRazmik Karapetyan u32 daintmsk; 3769837e9f00SVardan Mikayelyan struct dwc2_hsotg_ep *hs_ep; 377047a1685fSDinh Nguyen 3771f25c42b8SGevorg Sahakyan daintmsk = dwc2_readl(hsotg, DAINTMSK); 3772d8484552SRazmik Karapetyan daintmsk >>= DAINT_OUTEP_SHIFT; 3773837e9f00SVardan Mikayelyan /* Mask this interrupt */ 3774f25c42b8SGevorg Sahakyan gintmsk = dwc2_readl(hsotg, GINTMSK); 3775837e9f00SVardan Mikayelyan gintmsk &= ~GINTSTS_GOUTNAKEFF; 3776f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gintmsk, GINTMSK); 377747a1685fSDinh Nguyen 3778837e9f00SVardan Mikayelyan dev_dbg(hsotg->dev, "GOUTNakEff triggered\n"); 3779d5d5f079SArtur Petrosyan for (idx = 1; idx < hsotg->num_of_eps; idx++) { 3780837e9f00SVardan Mikayelyan hs_ep = hsotg->eps_out[idx]; 3781d8484552SRazmik Karapetyan /* Proceed only unmasked ISOC EPs */ 378289066b36SJohn Keeping if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous) 3783d8484552SRazmik Karapetyan continue; 3784d8484552SRazmik Karapetyan 3785f25c42b8SGevorg Sahakyan epctrl = dwc2_readl(hsotg, DOEPCTL(idx)); 3786837e9f00SVardan Mikayelyan 3787d8484552SRazmik Karapetyan if (epctrl & DXEPCTL_EPENA) { 3788837e9f00SVardan Mikayelyan epctrl |= DXEPCTL_SNAK; 3789837e9f00SVardan Mikayelyan epctrl |= DXEPCTL_EPDIS; 3790f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, epctrl, DOEPCTL(idx)); 3791837e9f00SVardan Mikayelyan } 3792837e9f00SVardan Mikayelyan } 3793837e9f00SVardan Mikayelyan 3794837e9f00SVardan Mikayelyan /* This interrupt bit is cleared in DXEPINT_EPDISBLD handler */ 379547a1685fSDinh Nguyen } 379647a1685fSDinh Nguyen 379747a1685fSDinh Nguyen if (gintsts & GINTSTS_GINNAKEFF) { 379847a1685fSDinh Nguyen dev_info(hsotg->dev, "GINNakEff triggered\n"); 379947a1685fSDinh Nguyen 3800f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DCTL, DCTL_CGNPINNAK); 380147a1685fSDinh Nguyen 38021f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 380347a1685fSDinh Nguyen } 380447a1685fSDinh Nguyen 3805381fc8f8SVardan Mikayelyan if (gintsts & GINTSTS_INCOMPL_SOIN) 3806381fc8f8SVardan Mikayelyan dwc2_gadget_handle_incomplete_isoc_in(hsotg); 3807ec1f9d9fSRoman Bacik 3808381fc8f8SVardan Mikayelyan if (gintsts & GINTSTS_INCOMPL_SOOUT) 3809381fc8f8SVardan Mikayelyan dwc2_gadget_handle_incomplete_isoc_out(hsotg); 3810ec1f9d9fSRoman Bacik 381147a1685fSDinh Nguyen /* 381247a1685fSDinh Nguyen * if we've had fifo events, we should try and go around the 381347a1685fSDinh Nguyen * loop again to see if there's any point in returning yet. 381447a1685fSDinh Nguyen */ 381547a1685fSDinh Nguyen 381647a1685fSDinh Nguyen if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) 381747a1685fSDinh Nguyen goto irq_retry; 381847a1685fSDinh Nguyen 3819187c5298SGrigor Tovmasyan /* Check WKUP_ALERT interrupt*/ 3820187c5298SGrigor Tovmasyan if (hsotg->params.service_interval) 3821187c5298SGrigor Tovmasyan dwc2_gadget_wkup_alert_handler(hsotg); 3822187c5298SGrigor Tovmasyan 382347a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 382447a1685fSDinh Nguyen 382547a1685fSDinh Nguyen return IRQ_HANDLED; 382647a1685fSDinh Nguyen } 382747a1685fSDinh Nguyen 3828a4f82771SVahram Aharonyan static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, 3829a4f82771SVahram Aharonyan struct dwc2_hsotg_ep *hs_ep) 3830a4f82771SVahram Aharonyan { 3831a4f82771SVahram Aharonyan u32 epctrl_reg; 3832a4f82771SVahram Aharonyan u32 epint_reg; 3833a4f82771SVahram Aharonyan 3834a4f82771SVahram Aharonyan epctrl_reg = hs_ep->dir_in ? DIEPCTL(hs_ep->index) : 3835a4f82771SVahram Aharonyan DOEPCTL(hs_ep->index); 3836a4f82771SVahram Aharonyan epint_reg = hs_ep->dir_in ? DIEPINT(hs_ep->index) : 3837a4f82771SVahram Aharonyan DOEPINT(hs_ep->index); 3838a4f82771SVahram Aharonyan 3839a4f82771SVahram Aharonyan dev_dbg(hsotg->dev, "%s: stopping transfer on %s\n", __func__, 3840a4f82771SVahram Aharonyan hs_ep->name); 3841a4f82771SVahram Aharonyan 3842a4f82771SVahram Aharonyan if (hs_ep->dir_in) { 3843a4f82771SVahram Aharonyan if (hsotg->dedicated_fifos || hs_ep->periodic) { 3844f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, epctrl_reg, DXEPCTL_SNAK); 3845a4f82771SVahram Aharonyan /* Wait for Nak effect */ 3846a4f82771SVahram Aharonyan if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, 3847a4f82771SVahram Aharonyan DXEPINT_INEPNAKEFF, 100)) 3848a4f82771SVahram Aharonyan dev_warn(hsotg->dev, 3849a4f82771SVahram Aharonyan "%s: timeout DIEPINT.NAKEFF\n", 3850a4f82771SVahram Aharonyan __func__); 3851a4f82771SVahram Aharonyan } else { 3852f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DCTL, DCTL_SGNPINNAK); 3853a4f82771SVahram Aharonyan /* Wait for Nak effect */ 3854a4f82771SVahram Aharonyan if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 3855a4f82771SVahram Aharonyan GINTSTS_GINNAKEFF, 100)) 3856a4f82771SVahram Aharonyan dev_warn(hsotg->dev, 3857a4f82771SVahram Aharonyan "%s: timeout GINTSTS.GINNAKEFF\n", 3858a4f82771SVahram Aharonyan __func__); 3859a4f82771SVahram Aharonyan } 3860a4f82771SVahram Aharonyan } else { 3861f25c42b8SGevorg Sahakyan if (!(dwc2_readl(hsotg, GINTSTS) & GINTSTS_GOUTNAKEFF)) 3862f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DCTL, DCTL_SGOUTNAK); 3863a4f82771SVahram Aharonyan 3864a4f82771SVahram Aharonyan /* Wait for global nak to take effect */ 3865a4f82771SVahram Aharonyan if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 3866a4f82771SVahram Aharonyan GINTSTS_GOUTNAKEFF, 100)) 3867a4f82771SVahram Aharonyan dev_warn(hsotg->dev, "%s: timeout GINTSTS.GOUTNAKEFF\n", 3868a4f82771SVahram Aharonyan __func__); 3869a4f82771SVahram Aharonyan } 3870a4f82771SVahram Aharonyan 3871a4f82771SVahram Aharonyan /* Disable ep */ 3872f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, epctrl_reg, DXEPCTL_EPDIS | DXEPCTL_SNAK); 3873a4f82771SVahram Aharonyan 3874a4f82771SVahram Aharonyan /* Wait for ep to be disabled */ 3875a4f82771SVahram Aharonyan if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, DXEPINT_EPDISBLD, 100)) 3876a4f82771SVahram Aharonyan dev_warn(hsotg->dev, 3877a4f82771SVahram Aharonyan "%s: timeout DOEPCTL.EPDisable\n", __func__); 3878a4f82771SVahram Aharonyan 3879a4f82771SVahram Aharonyan /* Clear EPDISBLD interrupt */ 3880f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, epint_reg, DXEPINT_EPDISBLD); 3881a4f82771SVahram Aharonyan 3882a4f82771SVahram Aharonyan if (hs_ep->dir_in) { 3883a4f82771SVahram Aharonyan unsigned short fifo_index; 3884a4f82771SVahram Aharonyan 3885a4f82771SVahram Aharonyan if (hsotg->dedicated_fifos || hs_ep->periodic) 3886a4f82771SVahram Aharonyan fifo_index = hs_ep->fifo_index; 3887a4f82771SVahram Aharonyan else 3888a4f82771SVahram Aharonyan fifo_index = 0; 3889a4f82771SVahram Aharonyan 3890a4f82771SVahram Aharonyan /* Flush TX FIFO */ 3891a4f82771SVahram Aharonyan dwc2_flush_tx_fifo(hsotg, fifo_index); 3892a4f82771SVahram Aharonyan 3893a4f82771SVahram Aharonyan /* Clear Global In NP NAK in Shared FIFO for non periodic ep */ 3894a4f82771SVahram Aharonyan if (!hsotg->dedicated_fifos && !hs_ep->periodic) 3895f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DCTL, DCTL_CGNPINNAK); 3896a4f82771SVahram Aharonyan 3897a4f82771SVahram Aharonyan } else { 3898a4f82771SVahram Aharonyan /* Remove global NAKs */ 3899f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DCTL, DCTL_CGOUTNAK); 3900a4f82771SVahram Aharonyan } 3901a4f82771SVahram Aharonyan } 3902a4f82771SVahram Aharonyan 390347a1685fSDinh Nguyen /** 39041f91b4ccSFelipe Balbi * dwc2_hsotg_ep_enable - enable the given endpoint 390547a1685fSDinh Nguyen * @ep: The USB endpint to configure 390647a1685fSDinh Nguyen * @desc: The USB endpoint descriptor to configure with. 390747a1685fSDinh Nguyen * 390847a1685fSDinh Nguyen * This is called from the USB gadget code's usb_ep_enable(). 390947a1685fSDinh Nguyen */ 39101f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_enable(struct usb_ep *ep, 391147a1685fSDinh Nguyen const struct usb_endpoint_descriptor *desc) 391247a1685fSDinh Nguyen { 39131f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 3914941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 391547a1685fSDinh Nguyen unsigned long flags; 3916ca4c55adSMian Yousaf Kaukab unsigned int index = hs_ep->index; 391747a1685fSDinh Nguyen u32 epctrl_reg; 391847a1685fSDinh Nguyen u32 epctrl; 391947a1685fSDinh Nguyen u32 mps; 3920ee2c40deSVardan Mikayelyan u32 mc; 3921837e9f00SVardan Mikayelyan u32 mask; 3922ca4c55adSMian Yousaf Kaukab unsigned int dir_in; 3923ca4c55adSMian Yousaf Kaukab unsigned int i, val, size; 392447a1685fSDinh Nguyen int ret = 0; 3925729cac69SMinas Harutyunyan unsigned char ep_type; 392654f37f56SMinas Harutyunyan int desc_num; 392747a1685fSDinh Nguyen 392847a1685fSDinh Nguyen dev_dbg(hsotg->dev, 392947a1685fSDinh Nguyen "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", 393047a1685fSDinh Nguyen __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, 393147a1685fSDinh Nguyen desc->wMaxPacketSize, desc->bInterval); 393247a1685fSDinh Nguyen 393347a1685fSDinh Nguyen /* not to be called for EP0 */ 39348c3d6092SVahram Aharonyan if (index == 0) { 39358c3d6092SVahram Aharonyan dev_err(hsotg->dev, "%s: called for EP 0\n", __func__); 39368c3d6092SVahram Aharonyan return -EINVAL; 39378c3d6092SVahram Aharonyan } 393847a1685fSDinh Nguyen 393947a1685fSDinh Nguyen dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; 394047a1685fSDinh Nguyen if (dir_in != hs_ep->dir_in) { 394147a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); 394247a1685fSDinh Nguyen return -EINVAL; 394347a1685fSDinh Nguyen } 394447a1685fSDinh Nguyen 3945729cac69SMinas Harutyunyan ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; 394647a1685fSDinh Nguyen mps = usb_endpoint_maxp(desc); 3947ee2c40deSVardan Mikayelyan mc = usb_endpoint_maxp_mult(desc); 394847a1685fSDinh Nguyen 3949729cac69SMinas Harutyunyan /* ISOC IN in DDMA supported bInterval up to 10 */ 3950729cac69SMinas Harutyunyan if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC && 3951729cac69SMinas Harutyunyan dir_in && desc->bInterval > 10) { 3952729cac69SMinas Harutyunyan dev_err(hsotg->dev, 3953729cac69SMinas Harutyunyan "%s: ISOC IN, DDMA: bInterval>10 not supported!\n", __func__); 3954729cac69SMinas Harutyunyan return -EINVAL; 3955729cac69SMinas Harutyunyan } 3956729cac69SMinas Harutyunyan 3957729cac69SMinas Harutyunyan /* High bandwidth ISOC OUT in DDMA not supported */ 3958729cac69SMinas Harutyunyan if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC && 3959729cac69SMinas Harutyunyan !dir_in && mc > 1) { 3960729cac69SMinas Harutyunyan dev_err(hsotg->dev, 3961729cac69SMinas Harutyunyan "%s: ISOC OUT, DDMA: HB not supported!\n", __func__); 3962729cac69SMinas Harutyunyan return -EINVAL; 3963729cac69SMinas Harutyunyan } 3964729cac69SMinas Harutyunyan 39651f91b4ccSFelipe Balbi /* note, we handle this here instead of dwc2_hsotg_set_ep_maxpacket */ 396647a1685fSDinh Nguyen 396747a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 3968f25c42b8SGevorg Sahakyan epctrl = dwc2_readl(hsotg, epctrl_reg); 396947a1685fSDinh Nguyen 397047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", 397147a1685fSDinh Nguyen __func__, epctrl, epctrl_reg); 397247a1685fSDinh Nguyen 397354f37f56SMinas Harutyunyan if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC) 397454f37f56SMinas Harutyunyan desc_num = MAX_DMA_DESC_NUM_HS_ISOC; 397554f37f56SMinas Harutyunyan else 397654f37f56SMinas Harutyunyan desc_num = MAX_DMA_DESC_NUM_GENERIC; 397754f37f56SMinas Harutyunyan 39785f54c54bSVahram Aharonyan /* Allocate DMA descriptor chain for non-ctrl endpoints */ 39799383e084SVardan Mikayelyan if (using_desc_dma(hsotg) && !hs_ep->desc_list) { 39809383e084SVardan Mikayelyan hs_ep->desc_list = dmam_alloc_coherent(hsotg->dev, 398154f37f56SMinas Harutyunyan desc_num * sizeof(struct dwc2_dma_desc), 398286e881e7SMarek Szyprowski &hs_ep->desc_list_dma, GFP_ATOMIC); 39835f54c54bSVahram Aharonyan if (!hs_ep->desc_list) { 39845f54c54bSVahram Aharonyan ret = -ENOMEM; 39855f54c54bSVahram Aharonyan goto error2; 39865f54c54bSVahram Aharonyan } 39875f54c54bSVahram Aharonyan } 39885f54c54bSVahram Aharonyan 398947a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 399047a1685fSDinh Nguyen 399147a1685fSDinh Nguyen epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK); 399247a1685fSDinh Nguyen epctrl |= DXEPCTL_MPS(mps); 399347a1685fSDinh Nguyen 399447a1685fSDinh Nguyen /* 399547a1685fSDinh Nguyen * mark the endpoint as active, otherwise the core may ignore 399647a1685fSDinh Nguyen * transactions entirely for this endpoint 399747a1685fSDinh Nguyen */ 399847a1685fSDinh Nguyen epctrl |= DXEPCTL_USBACTEP; 399947a1685fSDinh Nguyen 400047a1685fSDinh Nguyen /* update the endpoint state */ 4001ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, mc, dir_in); 400247a1685fSDinh Nguyen 400347a1685fSDinh Nguyen /* default, set to non-periodic */ 400447a1685fSDinh Nguyen hs_ep->isochronous = 0; 400547a1685fSDinh Nguyen hs_ep->periodic = 0; 400647a1685fSDinh Nguyen hs_ep->halted = 0; 400747a1685fSDinh Nguyen hs_ep->interval = desc->bInterval; 400847a1685fSDinh Nguyen 4009729cac69SMinas Harutyunyan switch (ep_type) { 401047a1685fSDinh Nguyen case USB_ENDPOINT_XFER_ISOC: 401147a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_ISO; 401247a1685fSDinh Nguyen epctrl |= DXEPCTL_SETEVENFR; 401347a1685fSDinh Nguyen hs_ep->isochronous = 1; 4014142bd33fSVardan Mikayelyan hs_ep->interval = 1 << (desc->bInterval - 1); 4015837e9f00SVardan Mikayelyan hs_ep->target_frame = TARGET_FRAME_INITIAL; 4016ab7d2192SVahram Aharonyan hs_ep->next_desc = 0; 4017729cac69SMinas Harutyunyan hs_ep->compl_desc = 0; 4018837e9f00SVardan Mikayelyan if (dir_in) { 401947a1685fSDinh Nguyen hs_ep->periodic = 1; 4020f25c42b8SGevorg Sahakyan mask = dwc2_readl(hsotg, DIEPMSK); 4021837e9f00SVardan Mikayelyan mask |= DIEPMSK_NAKMSK; 4022f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, mask, DIEPMSK); 4023837e9f00SVardan Mikayelyan } else { 4024f25c42b8SGevorg Sahakyan mask = dwc2_readl(hsotg, DOEPMSK); 4025837e9f00SVardan Mikayelyan mask |= DOEPMSK_OUTTKNEPDISMSK; 4026f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, mask, DOEPMSK); 4027837e9f00SVardan Mikayelyan } 402847a1685fSDinh Nguyen break; 402947a1685fSDinh Nguyen 403047a1685fSDinh Nguyen case USB_ENDPOINT_XFER_BULK: 403147a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_BULK; 403247a1685fSDinh Nguyen break; 403347a1685fSDinh Nguyen 403447a1685fSDinh Nguyen case USB_ENDPOINT_XFER_INT: 4035b203d0a2SRobert Baldyga if (dir_in) 403647a1685fSDinh Nguyen hs_ep->periodic = 1; 403747a1685fSDinh Nguyen 4038142bd33fSVardan Mikayelyan if (hsotg->gadget.speed == USB_SPEED_HIGH) 4039142bd33fSVardan Mikayelyan hs_ep->interval = 1 << (desc->bInterval - 1); 4040142bd33fSVardan Mikayelyan 404147a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_INTERRUPT; 404247a1685fSDinh Nguyen break; 404347a1685fSDinh Nguyen 404447a1685fSDinh Nguyen case USB_ENDPOINT_XFER_CONTROL: 404547a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_CONTROL; 404647a1685fSDinh Nguyen break; 404747a1685fSDinh Nguyen } 404847a1685fSDinh Nguyen 404947a1685fSDinh Nguyen /* 405047a1685fSDinh Nguyen * if the hardware has dedicated fifos, we must give each IN EP 405147a1685fSDinh Nguyen * a unique tx-fifo even if it is non-periodic. 405247a1685fSDinh Nguyen */ 405321f3bb52SRobert Baldyga if (dir_in && hsotg->dedicated_fifos) { 4054ca4c55adSMian Yousaf Kaukab u32 fifo_index = 0; 4055ca4c55adSMian Yousaf Kaukab u32 fifo_size = UINT_MAX; 40569da51974SJohn Youn 4057b203d0a2SRobert Baldyga size = hs_ep->ep.maxpacket * hs_ep->mc; 40585f2196bdSMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; ++i) { 4059b203d0a2SRobert Baldyga if (hsotg->fifo_map & (1 << i)) 4060b203d0a2SRobert Baldyga continue; 4061f25c42b8SGevorg Sahakyan val = dwc2_readl(hsotg, DPTXFSIZN(i)); 4062b203d0a2SRobert Baldyga val = (val >> FIFOSIZE_DEPTH_SHIFT) * 4; 4063b203d0a2SRobert Baldyga if (val < size) 4064b203d0a2SRobert Baldyga continue; 4065ca4c55adSMian Yousaf Kaukab /* Search for smallest acceptable fifo */ 4066ca4c55adSMian Yousaf Kaukab if (val < fifo_size) { 4067ca4c55adSMian Yousaf Kaukab fifo_size = val; 4068ca4c55adSMian Yousaf Kaukab fifo_index = i; 4069b203d0a2SRobert Baldyga } 4070ca4c55adSMian Yousaf Kaukab } 4071ca4c55adSMian Yousaf Kaukab if (!fifo_index) { 40725f2196bdSMian Yousaf Kaukab dev_err(hsotg->dev, 40735f2196bdSMian Yousaf Kaukab "%s: No suitable fifo found\n", __func__); 4074b585a48bSSudip Mukherjee ret = -ENOMEM; 40755f54c54bSVahram Aharonyan goto error1; 4076b585a48bSSudip Mukherjee } 407797311c8fSMinas Harutyunyan epctrl &= ~(DXEPCTL_TXFNUM_LIMIT << DXEPCTL_TXFNUM_SHIFT); 4078ca4c55adSMian Yousaf Kaukab hsotg->fifo_map |= 1 << fifo_index; 4079ca4c55adSMian Yousaf Kaukab epctrl |= DXEPCTL_TXFNUM(fifo_index); 4080ca4c55adSMian Yousaf Kaukab hs_ep->fifo_index = fifo_index; 4081ca4c55adSMian Yousaf Kaukab hs_ep->fifo_size = fifo_size; 4082b203d0a2SRobert Baldyga } 408347a1685fSDinh Nguyen 408447a1685fSDinh Nguyen /* for non control endpoints, set PID to D0 */ 4085837e9f00SVardan Mikayelyan if (index && !hs_ep->isochronous) 408647a1685fSDinh Nguyen epctrl |= DXEPCTL_SETD0PID; 408747a1685fSDinh Nguyen 40885295322aSArtur Petrosyan /* WA for Full speed ISOC IN in DDMA mode. 40895295322aSArtur Petrosyan * By Clear NAK status of EP, core will send ZLP 40905295322aSArtur Petrosyan * to IN token and assert NAK interrupt relying 40915295322aSArtur Petrosyan * on TxFIFO status only 40925295322aSArtur Petrosyan */ 40935295322aSArtur Petrosyan 40945295322aSArtur Petrosyan if (hsotg->gadget.speed == USB_SPEED_FULL && 40955295322aSArtur Petrosyan hs_ep->isochronous && dir_in) { 40965295322aSArtur Petrosyan /* The WA applies only to core versions from 2.72a 40975295322aSArtur Petrosyan * to 4.00a (including both). Also for FS_IOT_1.00a 40985295322aSArtur Petrosyan * and HS_IOT_1.00a. 40995295322aSArtur Petrosyan */ 4100f25c42b8SGevorg Sahakyan u32 gsnpsid = dwc2_readl(hsotg, GSNPSID); 41015295322aSArtur Petrosyan 41025295322aSArtur Petrosyan if ((gsnpsid >= DWC2_CORE_REV_2_72a && 41035295322aSArtur Petrosyan gsnpsid <= DWC2_CORE_REV_4_00a) || 41045295322aSArtur Petrosyan gsnpsid == DWC2_FS_IOT_REV_1_00a || 41055295322aSArtur Petrosyan gsnpsid == DWC2_HS_IOT_REV_1_00a) 41065295322aSArtur Petrosyan epctrl |= DXEPCTL_CNAK; 41075295322aSArtur Petrosyan } 41085295322aSArtur Petrosyan 410947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", 411047a1685fSDinh Nguyen __func__, epctrl); 411147a1685fSDinh Nguyen 4112f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, epctrl, epctrl_reg); 411347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", 4114f25c42b8SGevorg Sahakyan __func__, dwc2_readl(hsotg, epctrl_reg)); 411547a1685fSDinh Nguyen 411647a1685fSDinh Nguyen /* enable the endpoint interrupt */ 41171f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, index, dir_in, 1); 411847a1685fSDinh Nguyen 41195f54c54bSVahram Aharonyan error1: 412047a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 41215f54c54bSVahram Aharonyan 41225f54c54bSVahram Aharonyan error2: 41235f54c54bSVahram Aharonyan if (ret && using_desc_dma(hsotg) && hs_ep->desc_list) { 412454f37f56SMinas Harutyunyan dmam_free_coherent(hsotg->dev, desc_num * 41255f54c54bSVahram Aharonyan sizeof(struct dwc2_dma_desc), 41265f54c54bSVahram Aharonyan hs_ep->desc_list, hs_ep->desc_list_dma); 41275f54c54bSVahram Aharonyan hs_ep->desc_list = NULL; 41285f54c54bSVahram Aharonyan } 41295f54c54bSVahram Aharonyan 413047a1685fSDinh Nguyen return ret; 413147a1685fSDinh Nguyen } 413247a1685fSDinh Nguyen 413347a1685fSDinh Nguyen /** 41341f91b4ccSFelipe Balbi * dwc2_hsotg_ep_disable - disable given endpoint 413547a1685fSDinh Nguyen * @ep: The endpoint to disable. 413647a1685fSDinh Nguyen */ 41371f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_disable(struct usb_ep *ep) 413847a1685fSDinh Nguyen { 41391f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 4140941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 414147a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 414247a1685fSDinh Nguyen int index = hs_ep->index; 414347a1685fSDinh Nguyen u32 epctrl_reg; 414447a1685fSDinh Nguyen u32 ctrl; 414547a1685fSDinh Nguyen 41461e011293SMarek Szyprowski dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); 414747a1685fSDinh Nguyen 4148c6f5c050SMian Yousaf Kaukab if (ep == &hsotg->eps_out[0]->ep) { 414947a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: called for ep0\n", __func__); 415047a1685fSDinh Nguyen return -EINVAL; 415147a1685fSDinh Nguyen } 415247a1685fSDinh Nguyen 41539b481092SJohn Stultz if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { 41549b481092SJohn Stultz dev_err(hsotg->dev, "%s: called in host mode?\n", __func__); 41559b481092SJohn Stultz return -EINVAL; 41569b481092SJohn Stultz } 41579b481092SJohn Stultz 415847a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 415947a1685fSDinh Nguyen 4160f25c42b8SGevorg Sahakyan ctrl = dwc2_readl(hsotg, epctrl_reg); 4161a4f82771SVahram Aharonyan 4162a4f82771SVahram Aharonyan if (ctrl & DXEPCTL_EPENA) 4163a4f82771SVahram Aharonyan dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep); 4164a4f82771SVahram Aharonyan 416547a1685fSDinh Nguyen ctrl &= ~DXEPCTL_EPENA; 416647a1685fSDinh Nguyen ctrl &= ~DXEPCTL_USBACTEP; 416747a1685fSDinh Nguyen ctrl |= DXEPCTL_SNAK; 416847a1685fSDinh Nguyen 416947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 4170f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ctrl, epctrl_reg); 417147a1685fSDinh Nguyen 417247a1685fSDinh Nguyen /* disable endpoint interrupts */ 41731f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); 417447a1685fSDinh Nguyen 41751141ea01SMian Yousaf Kaukab /* terminate all requests with shutdown */ 41761141ea01SMian Yousaf Kaukab kill_all_requests(hsotg, hs_ep, -ESHUTDOWN); 41771141ea01SMian Yousaf Kaukab 41781c07b20eSRobert Baldyga hsotg->fifo_map &= ~(1 << hs_ep->fifo_index); 41791c07b20eSRobert Baldyga hs_ep->fifo_index = 0; 41801c07b20eSRobert Baldyga hs_ep->fifo_size = 0; 41811c07b20eSRobert Baldyga 418247a1685fSDinh Nguyen return 0; 418347a1685fSDinh Nguyen } 418447a1685fSDinh Nguyen 41854fe4f9feSMinas Harutyunyan static int dwc2_hsotg_ep_disable_lock(struct usb_ep *ep) 41864fe4f9feSMinas Harutyunyan { 41874fe4f9feSMinas Harutyunyan struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 41884fe4f9feSMinas Harutyunyan struct dwc2_hsotg *hsotg = hs_ep->parent; 41894fe4f9feSMinas Harutyunyan unsigned long flags; 41904fe4f9feSMinas Harutyunyan int ret; 41914fe4f9feSMinas Harutyunyan 41924fe4f9feSMinas Harutyunyan spin_lock_irqsave(&hsotg->lock, flags); 41934fe4f9feSMinas Harutyunyan ret = dwc2_hsotg_ep_disable(ep); 41944fe4f9feSMinas Harutyunyan spin_unlock_irqrestore(&hsotg->lock, flags); 41954fe4f9feSMinas Harutyunyan return ret; 41964fe4f9feSMinas Harutyunyan } 41974fe4f9feSMinas Harutyunyan 419847a1685fSDinh Nguyen /** 419947a1685fSDinh Nguyen * on_list - check request is on the given endpoint 420047a1685fSDinh Nguyen * @ep: The endpoint to check. 420147a1685fSDinh Nguyen * @test: The request to test if it is on the endpoint. 420247a1685fSDinh Nguyen */ 42031f91b4ccSFelipe Balbi static bool on_list(struct dwc2_hsotg_ep *ep, struct dwc2_hsotg_req *test) 420447a1685fSDinh Nguyen { 42051f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req, *treq; 420647a1685fSDinh Nguyen 420747a1685fSDinh Nguyen list_for_each_entry_safe(req, treq, &ep->queue, queue) { 420847a1685fSDinh Nguyen if (req == test) 420947a1685fSDinh Nguyen return true; 421047a1685fSDinh Nguyen } 421147a1685fSDinh Nguyen 421247a1685fSDinh Nguyen return false; 421347a1685fSDinh Nguyen } 421447a1685fSDinh Nguyen 421547a1685fSDinh Nguyen /** 42161f91b4ccSFelipe Balbi * dwc2_hsotg_ep_dequeue - dequeue given endpoint 421747a1685fSDinh Nguyen * @ep: The endpoint to dequeue. 421847a1685fSDinh Nguyen * @req: The request to be removed from a queue. 421947a1685fSDinh Nguyen */ 42201f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) 422147a1685fSDinh Nguyen { 42221f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 42231f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 4224941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 422547a1685fSDinh Nguyen unsigned long flags; 422647a1685fSDinh Nguyen 42271e011293SMarek Szyprowski dev_dbg(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); 422847a1685fSDinh Nguyen 422947a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 423047a1685fSDinh Nguyen 423147a1685fSDinh Nguyen if (!on_list(hs_ep, hs_req)) { 423247a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 423347a1685fSDinh Nguyen return -EINVAL; 423447a1685fSDinh Nguyen } 423547a1685fSDinh Nguyen 4236c524dd5fSMian Yousaf Kaukab /* Dequeue already started request */ 4237c524dd5fSMian Yousaf Kaukab if (req == &hs_ep->req->req) 4238c524dd5fSMian Yousaf Kaukab dwc2_hsotg_ep_stop_xfr(hs, hs_ep); 4239c524dd5fSMian Yousaf Kaukab 42401f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); 424147a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 424247a1685fSDinh Nguyen 424347a1685fSDinh Nguyen return 0; 424447a1685fSDinh Nguyen } 424547a1685fSDinh Nguyen 424647a1685fSDinh Nguyen /** 42471f91b4ccSFelipe Balbi * dwc2_hsotg_ep_sethalt - set halt on a given endpoint 424847a1685fSDinh Nguyen * @ep: The endpoint to set halt. 424947a1685fSDinh Nguyen * @value: Set or unset the halt. 425051da43b5SVahram Aharonyan * @now: If true, stall the endpoint now. Otherwise return -EAGAIN if 425151da43b5SVahram Aharonyan * the endpoint is busy processing requests. 425251da43b5SVahram Aharonyan * 425351da43b5SVahram Aharonyan * We need to stall the endpoint immediately if request comes from set_feature 425451da43b5SVahram Aharonyan * protocol command handler. 425547a1685fSDinh Nguyen */ 425651da43b5SVahram Aharonyan static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now) 425747a1685fSDinh Nguyen { 42581f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 4259941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 426047a1685fSDinh Nguyen int index = hs_ep->index; 426147a1685fSDinh Nguyen u32 epreg; 426247a1685fSDinh Nguyen u32 epctl; 426347a1685fSDinh Nguyen u32 xfertype; 426447a1685fSDinh Nguyen 426547a1685fSDinh Nguyen dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); 426647a1685fSDinh Nguyen 426747a1685fSDinh Nguyen if (index == 0) { 426847a1685fSDinh Nguyen if (value) 42691f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hs); 427047a1685fSDinh Nguyen else 427147a1685fSDinh Nguyen dev_warn(hs->dev, 427247a1685fSDinh Nguyen "%s: can't clear halt on ep0\n", __func__); 427347a1685fSDinh Nguyen return 0; 427447a1685fSDinh Nguyen } 427547a1685fSDinh Nguyen 427615186f10SVahram Aharonyan if (hs_ep->isochronous) { 427715186f10SVahram Aharonyan dev_err(hs->dev, "%s is Isochronous Endpoint\n", ep->name); 427815186f10SVahram Aharonyan return -EINVAL; 427915186f10SVahram Aharonyan } 428015186f10SVahram Aharonyan 428151da43b5SVahram Aharonyan if (!now && value && !list_empty(&hs_ep->queue)) { 428251da43b5SVahram Aharonyan dev_dbg(hs->dev, "%s request is pending, cannot halt\n", 428351da43b5SVahram Aharonyan ep->name); 428451da43b5SVahram Aharonyan return -EAGAIN; 428551da43b5SVahram Aharonyan } 428651da43b5SVahram Aharonyan 4287c6f5c050SMian Yousaf Kaukab if (hs_ep->dir_in) { 428847a1685fSDinh Nguyen epreg = DIEPCTL(index); 4289f25c42b8SGevorg Sahakyan epctl = dwc2_readl(hs, epreg); 429047a1685fSDinh Nguyen 429147a1685fSDinh Nguyen if (value) { 42925a350d53SFelipe Balbi epctl |= DXEPCTL_STALL | DXEPCTL_SNAK; 429347a1685fSDinh Nguyen if (epctl & DXEPCTL_EPENA) 429447a1685fSDinh Nguyen epctl |= DXEPCTL_EPDIS; 429547a1685fSDinh Nguyen } else { 429647a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 429747a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 429847a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 429947a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 430047a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 430147a1685fSDinh Nguyen } 4302f25c42b8SGevorg Sahakyan dwc2_writel(hs, epctl, epreg); 4303c6f5c050SMian Yousaf Kaukab } else { 430447a1685fSDinh Nguyen epreg = DOEPCTL(index); 4305f25c42b8SGevorg Sahakyan epctl = dwc2_readl(hs, epreg); 430647a1685fSDinh Nguyen 430734c0887fSJohn Youn if (value) { 430847a1685fSDinh Nguyen epctl |= DXEPCTL_STALL; 430934c0887fSJohn Youn } else { 431047a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 431147a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 431247a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 431347a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 431447a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 431547a1685fSDinh Nguyen } 4316f25c42b8SGevorg Sahakyan dwc2_writel(hs, epctl, epreg); 4317c6f5c050SMian Yousaf Kaukab } 431847a1685fSDinh Nguyen 431947a1685fSDinh Nguyen hs_ep->halted = value; 432047a1685fSDinh Nguyen 432147a1685fSDinh Nguyen return 0; 432247a1685fSDinh Nguyen } 432347a1685fSDinh Nguyen 432447a1685fSDinh Nguyen /** 43251f91b4ccSFelipe Balbi * dwc2_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held 432647a1685fSDinh Nguyen * @ep: The endpoint to set halt. 432747a1685fSDinh Nguyen * @value: Set or unset the halt. 432847a1685fSDinh Nguyen */ 43291f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) 433047a1685fSDinh Nguyen { 43311f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 4332941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 433347a1685fSDinh Nguyen unsigned long flags = 0; 433447a1685fSDinh Nguyen int ret = 0; 433547a1685fSDinh Nguyen 433647a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 433751da43b5SVahram Aharonyan ret = dwc2_hsotg_ep_sethalt(ep, value, false); 433847a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 433947a1685fSDinh Nguyen 434047a1685fSDinh Nguyen return ret; 434147a1685fSDinh Nguyen } 434247a1685fSDinh Nguyen 4343ebce561aSBhumika Goyal static const struct usb_ep_ops dwc2_hsotg_ep_ops = { 43441f91b4ccSFelipe Balbi .enable = dwc2_hsotg_ep_enable, 43454fe4f9feSMinas Harutyunyan .disable = dwc2_hsotg_ep_disable_lock, 43461f91b4ccSFelipe Balbi .alloc_request = dwc2_hsotg_ep_alloc_request, 43471f91b4ccSFelipe Balbi .free_request = dwc2_hsotg_ep_free_request, 43481f91b4ccSFelipe Balbi .queue = dwc2_hsotg_ep_queue_lock, 43491f91b4ccSFelipe Balbi .dequeue = dwc2_hsotg_ep_dequeue, 43501f91b4ccSFelipe Balbi .set_halt = dwc2_hsotg_ep_sethalt_lock, 435147a1685fSDinh Nguyen /* note, don't believe we have any call for the fifo routines */ 435247a1685fSDinh Nguyen }; 435347a1685fSDinh Nguyen 435447a1685fSDinh Nguyen /** 43559da51974SJohn Youn * dwc2_hsotg_init - initialize the usb core 435647a1685fSDinh Nguyen * @hsotg: The driver state 435747a1685fSDinh Nguyen */ 43581f91b4ccSFelipe Balbi static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) 435947a1685fSDinh Nguyen { 436047a1685fSDinh Nguyen /* unmask subset of endpoint interrupts */ 436147a1685fSDinh Nguyen 4362f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | 436347a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK, 4364f25c42b8SGevorg Sahakyan DIEPMSK); 436547a1685fSDinh Nguyen 4366f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | 436747a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK, 4368f25c42b8SGevorg Sahakyan DOEPMSK); 436947a1685fSDinh Nguyen 4370f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, 0, DAINTMSK); 437147a1685fSDinh Nguyen 437247a1685fSDinh Nguyen /* Be in disconnected state until gadget is registered */ 4373f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); 437447a1685fSDinh Nguyen 437547a1685fSDinh Nguyen /* setup fifos */ 437647a1685fSDinh Nguyen 437747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 4378f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, GRXFSIZ), 4379f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, GNPTXFSIZ)); 438047a1685fSDinh Nguyen 43811f91b4ccSFelipe Balbi dwc2_hsotg_init_fifo(hsotg); 438247a1685fSDinh Nguyen 4383f5090044SGregory Herrero if (using_dma(hsotg)) 4384f25c42b8SGevorg Sahakyan dwc2_set_bit(hsotg, GAHBCFG, GAHBCFG_DMA_EN); 438547a1685fSDinh Nguyen } 438647a1685fSDinh Nguyen 438747a1685fSDinh Nguyen /** 43881f91b4ccSFelipe Balbi * dwc2_hsotg_udc_start - prepare the udc for work 438947a1685fSDinh Nguyen * @gadget: The usb gadget state 439047a1685fSDinh Nguyen * @driver: The usb gadget driver 439147a1685fSDinh Nguyen * 439247a1685fSDinh Nguyen * Perform initialization to prepare udc device and driver 439347a1685fSDinh Nguyen * to work. 439447a1685fSDinh Nguyen */ 43951f91b4ccSFelipe Balbi static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, 439647a1685fSDinh Nguyen struct usb_gadget_driver *driver) 439747a1685fSDinh Nguyen { 4398941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 43995b9451f8SMarek Szyprowski unsigned long flags; 440047a1685fSDinh Nguyen int ret; 440147a1685fSDinh Nguyen 440247a1685fSDinh Nguyen if (!hsotg) { 440347a1685fSDinh Nguyen pr_err("%s: called with no device\n", __func__); 440447a1685fSDinh Nguyen return -ENODEV; 440547a1685fSDinh Nguyen } 440647a1685fSDinh Nguyen 440747a1685fSDinh Nguyen if (!driver) { 440847a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: no driver\n", __func__); 440947a1685fSDinh Nguyen return -EINVAL; 441047a1685fSDinh Nguyen } 441147a1685fSDinh Nguyen 441247a1685fSDinh Nguyen if (driver->max_speed < USB_SPEED_FULL) 441347a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: bad speed\n", __func__); 441447a1685fSDinh Nguyen 441547a1685fSDinh Nguyen if (!driver->setup) { 441647a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: missing entry points\n", __func__); 441747a1685fSDinh Nguyen return -EINVAL; 441847a1685fSDinh Nguyen } 441947a1685fSDinh Nguyen 442047a1685fSDinh Nguyen WARN_ON(hsotg->driver); 442147a1685fSDinh Nguyen 442247a1685fSDinh Nguyen driver->driver.bus = NULL; 442347a1685fSDinh Nguyen hsotg->driver = driver; 442447a1685fSDinh Nguyen hsotg->gadget.dev.of_node = hsotg->dev->of_node; 442547a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 442647a1685fSDinh Nguyen 442709a75e85SMarek Szyprowski if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) { 442809a75e85SMarek Szyprowski ret = dwc2_lowlevel_hw_enable(hsotg); 442909a75e85SMarek Szyprowski if (ret) 443047a1685fSDinh Nguyen goto err; 443147a1685fSDinh Nguyen } 443247a1685fSDinh Nguyen 4433f6c01592SGregory Herrero if (!IS_ERR_OR_NULL(hsotg->uphy)) 4434f6c01592SGregory Herrero otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget); 4435c816c47fSMarek Szyprowski 44365b9451f8SMarek Szyprowski spin_lock_irqsave(&hsotg->lock, flags); 4437d0f0ac56SJohn Youn if (dwc2_hw_is_device(hsotg)) { 44381f91b4ccSFelipe Balbi dwc2_hsotg_init(hsotg); 44391f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 4440d0f0ac56SJohn Youn } 4441d0f0ac56SJohn Youn 4442dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 44435b9451f8SMarek Szyprowski spin_unlock_irqrestore(&hsotg->lock, flags); 44445b9451f8SMarek Szyprowski 444510209abeSAndrzej Pietrasiewicz gadget->sg_supported = using_desc_dma(hsotg); 444647a1685fSDinh Nguyen dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); 44475b9451f8SMarek Szyprowski 444847a1685fSDinh Nguyen return 0; 444947a1685fSDinh Nguyen 445047a1685fSDinh Nguyen err: 445147a1685fSDinh Nguyen hsotg->driver = NULL; 445247a1685fSDinh Nguyen return ret; 445347a1685fSDinh Nguyen } 445447a1685fSDinh Nguyen 445547a1685fSDinh Nguyen /** 44561f91b4ccSFelipe Balbi * dwc2_hsotg_udc_stop - stop the udc 445747a1685fSDinh Nguyen * @gadget: The usb gadget state 445847a1685fSDinh Nguyen * 445947a1685fSDinh Nguyen * Stop udc hw block and stay tunned for future transmissions 446047a1685fSDinh Nguyen */ 44611f91b4ccSFelipe Balbi static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) 446247a1685fSDinh Nguyen { 4463941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 446447a1685fSDinh Nguyen unsigned long flags = 0; 446547a1685fSDinh Nguyen int ep; 446647a1685fSDinh Nguyen 446747a1685fSDinh Nguyen if (!hsotg) 446847a1685fSDinh Nguyen return -ENODEV; 446947a1685fSDinh Nguyen 447047a1685fSDinh Nguyen /* all endpoints should be shutdown */ 4471c6f5c050SMian Yousaf Kaukab for (ep = 1; ep < hsotg->num_of_eps; ep++) { 4472c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 44734fe4f9feSMinas Harutyunyan dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); 4474c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 44754fe4f9feSMinas Harutyunyan dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); 4476c6f5c050SMian Yousaf Kaukab } 447747a1685fSDinh Nguyen 447847a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 447947a1685fSDinh Nguyen 448047a1685fSDinh Nguyen hsotg->driver = NULL; 448147a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 4482dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 448347a1685fSDinh Nguyen 448447a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 448547a1685fSDinh Nguyen 4486f6c01592SGregory Herrero if (!IS_ERR_OR_NULL(hsotg->uphy)) 4487f6c01592SGregory Herrero otg_set_peripheral(hsotg->uphy->otg, NULL); 4488c816c47fSMarek Szyprowski 448909a75e85SMarek Szyprowski if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 449009a75e85SMarek Szyprowski dwc2_lowlevel_hw_disable(hsotg); 449147a1685fSDinh Nguyen 449247a1685fSDinh Nguyen return 0; 449347a1685fSDinh Nguyen } 449447a1685fSDinh Nguyen 449547a1685fSDinh Nguyen /** 44961f91b4ccSFelipe Balbi * dwc2_hsotg_gadget_getframe - read the frame number 449747a1685fSDinh Nguyen * @gadget: The usb gadget state 449847a1685fSDinh Nguyen * 449947a1685fSDinh Nguyen * Read the {micro} frame number 450047a1685fSDinh Nguyen */ 45011f91b4ccSFelipe Balbi static int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget) 450247a1685fSDinh Nguyen { 45031f91b4ccSFelipe Balbi return dwc2_hsotg_read_frameno(to_hsotg(gadget)); 450447a1685fSDinh Nguyen } 450547a1685fSDinh Nguyen 450647a1685fSDinh Nguyen /** 45071f91b4ccSFelipe Balbi * dwc2_hsotg_pullup - connect/disconnect the USB PHY 450847a1685fSDinh Nguyen * @gadget: The usb gadget state 450947a1685fSDinh Nguyen * @is_on: Current state of the USB PHY 451047a1685fSDinh Nguyen * 451147a1685fSDinh Nguyen * Connect/Disconnect the USB PHY pullup 451247a1685fSDinh Nguyen */ 45131f91b4ccSFelipe Balbi static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) 451447a1685fSDinh Nguyen { 4515941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 451647a1685fSDinh Nguyen unsigned long flags = 0; 451747a1685fSDinh Nguyen 451877ba9119SGregory Herrero dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on, 451977ba9119SGregory Herrero hsotg->op_state); 452077ba9119SGregory Herrero 452177ba9119SGregory Herrero /* Don't modify pullup state while in host mode */ 452277ba9119SGregory Herrero if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { 452377ba9119SGregory Herrero hsotg->enabled = is_on; 452477ba9119SGregory Herrero return 0; 452577ba9119SGregory Herrero } 452647a1685fSDinh Nguyen 452747a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 452847a1685fSDinh Nguyen if (is_on) { 4529dc6e69e6SMarek Szyprowski hsotg->enabled = 1; 45301f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 453166e77a24SRazmik Karapetyan /* Enable ACG feature in device mode,if supported */ 453266e77a24SRazmik Karapetyan dwc2_enable_acg(hsotg); 45331f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 453447a1685fSDinh Nguyen } else { 45351f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 45361f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 4537dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 453847a1685fSDinh Nguyen } 453947a1685fSDinh Nguyen 454047a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 454147a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 454247a1685fSDinh Nguyen 454347a1685fSDinh Nguyen return 0; 454447a1685fSDinh Nguyen } 454547a1685fSDinh Nguyen 45461f91b4ccSFelipe Balbi static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) 454783d98223SGregory Herrero { 454883d98223SGregory Herrero struct dwc2_hsotg *hsotg = to_hsotg(gadget); 454983d98223SGregory Herrero unsigned long flags; 455083d98223SGregory Herrero 455183d98223SGregory Herrero dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active); 455283d98223SGregory Herrero spin_lock_irqsave(&hsotg->lock, flags); 455383d98223SGregory Herrero 455418b2b37cSGregory Herrero /* 455541ba9b9bSVardan Mikayelyan * If controller is hibernated, it must exit from power_down 455661f7223bSGregory Herrero * before being initialized / de-initialized 455718b2b37cSGregory Herrero */ 4558065d3931SGregory Herrero if (hsotg->lx_state == DWC2_L2) 455941ba9b9bSVardan Mikayelyan dwc2_exit_partial_power_down(hsotg, false); 4560065d3931SGregory Herrero 456161f7223bSGregory Herrero if (is_active) { 456261f7223bSGregory Herrero hsotg->op_state = OTG_STATE_B_PERIPHERAL; 456361f7223bSGregory Herrero 45641f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 456566e77a24SRazmik Karapetyan if (hsotg->enabled) { 456666e77a24SRazmik Karapetyan /* Enable ACG feature in device mode,if supported */ 456766e77a24SRazmik Karapetyan dwc2_enable_acg(hsotg); 45681f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 456966e77a24SRazmik Karapetyan } 457083d98223SGregory Herrero } else { 45711f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 45721f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 457383d98223SGregory Herrero } 457483d98223SGregory Herrero 457583d98223SGregory Herrero spin_unlock_irqrestore(&hsotg->lock, flags); 457683d98223SGregory Herrero return 0; 457783d98223SGregory Herrero } 457883d98223SGregory Herrero 4579596d696aSGregory Herrero /** 45801f91b4ccSFelipe Balbi * dwc2_hsotg_vbus_draw - report bMaxPower field 4581596d696aSGregory Herrero * @gadget: The usb gadget state 4582596d696aSGregory Herrero * @mA: Amount of current 4583596d696aSGregory Herrero * 4584596d696aSGregory Herrero * Report how much power the device may consume to the phy. 4585596d696aSGregory Herrero */ 45869da51974SJohn Youn static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA) 4587596d696aSGregory Herrero { 4588596d696aSGregory Herrero struct dwc2_hsotg *hsotg = to_hsotg(gadget); 4589596d696aSGregory Herrero 4590596d696aSGregory Herrero if (IS_ERR_OR_NULL(hsotg->uphy)) 4591596d696aSGregory Herrero return -ENOTSUPP; 4592596d696aSGregory Herrero return usb_phy_set_power(hsotg->uphy, mA); 4593596d696aSGregory Herrero } 4594596d696aSGregory Herrero 45951f91b4ccSFelipe Balbi static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { 45961f91b4ccSFelipe Balbi .get_frame = dwc2_hsotg_gadget_getframe, 45971f91b4ccSFelipe Balbi .udc_start = dwc2_hsotg_udc_start, 45981f91b4ccSFelipe Balbi .udc_stop = dwc2_hsotg_udc_stop, 45991f91b4ccSFelipe Balbi .pullup = dwc2_hsotg_pullup, 46001f91b4ccSFelipe Balbi .vbus_session = dwc2_hsotg_vbus_session, 46011f91b4ccSFelipe Balbi .vbus_draw = dwc2_hsotg_vbus_draw, 460247a1685fSDinh Nguyen }; 460347a1685fSDinh Nguyen 460447a1685fSDinh Nguyen /** 46051f91b4ccSFelipe Balbi * dwc2_hsotg_initep - initialise a single endpoint 460647a1685fSDinh Nguyen * @hsotg: The device state. 460747a1685fSDinh Nguyen * @hs_ep: The endpoint to be initialised. 460847a1685fSDinh Nguyen * @epnum: The endpoint number 46096fb914d7SGrigor Tovmasyan * @dir_in: True if direction is in. 461047a1685fSDinh Nguyen * 461147a1685fSDinh Nguyen * Initialise the given endpoint (as part of the probe and device state 461247a1685fSDinh Nguyen * creation) to give to the gadget driver. Setup the endpoint name, any 461347a1685fSDinh Nguyen * direction information and other state that may be required. 461447a1685fSDinh Nguyen */ 46151f91b4ccSFelipe Balbi static void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, 46161f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 4617c6f5c050SMian Yousaf Kaukab int epnum, 4618c6f5c050SMian Yousaf Kaukab bool dir_in) 461947a1685fSDinh Nguyen { 462047a1685fSDinh Nguyen char *dir; 462147a1685fSDinh Nguyen 462247a1685fSDinh Nguyen if (epnum == 0) 462347a1685fSDinh Nguyen dir = ""; 4624c6f5c050SMian Yousaf Kaukab else if (dir_in) 462547a1685fSDinh Nguyen dir = "in"; 4626c6f5c050SMian Yousaf Kaukab else 4627c6f5c050SMian Yousaf Kaukab dir = "out"; 462847a1685fSDinh Nguyen 4629c6f5c050SMian Yousaf Kaukab hs_ep->dir_in = dir_in; 463047a1685fSDinh Nguyen hs_ep->index = epnum; 463147a1685fSDinh Nguyen 463247a1685fSDinh Nguyen snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); 463347a1685fSDinh Nguyen 463447a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->queue); 463547a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->ep.ep_list); 463647a1685fSDinh Nguyen 463747a1685fSDinh Nguyen /* add to the list of endpoints known by the gadget driver */ 463847a1685fSDinh Nguyen if (epnum) 463947a1685fSDinh Nguyen list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); 464047a1685fSDinh Nguyen 464147a1685fSDinh Nguyen hs_ep->parent = hsotg; 464247a1685fSDinh Nguyen hs_ep->ep.name = hs_ep->name; 464338e9002bSVardan Mikayelyan 464438e9002bSVardan Mikayelyan if (hsotg->params.speed == DWC2_SPEED_PARAM_LOW) 464538e9002bSVardan Mikayelyan usb_ep_set_maxpacket_limit(&hs_ep->ep, 8); 464638e9002bSVardan Mikayelyan else 464738e9002bSVardan Mikayelyan usb_ep_set_maxpacket_limit(&hs_ep->ep, 464838e9002bSVardan Mikayelyan epnum ? 1024 : EP0_MPS_LIMIT); 46491f91b4ccSFelipe Balbi hs_ep->ep.ops = &dwc2_hsotg_ep_ops; 465047a1685fSDinh Nguyen 46512954522fSRobert Baldyga if (epnum == 0) { 46522954522fSRobert Baldyga hs_ep->ep.caps.type_control = true; 46532954522fSRobert Baldyga } else { 465438e9002bSVardan Mikayelyan if (hsotg->params.speed != DWC2_SPEED_PARAM_LOW) { 46552954522fSRobert Baldyga hs_ep->ep.caps.type_iso = true; 46562954522fSRobert Baldyga hs_ep->ep.caps.type_bulk = true; 465738e9002bSVardan Mikayelyan } 46582954522fSRobert Baldyga hs_ep->ep.caps.type_int = true; 46592954522fSRobert Baldyga } 46602954522fSRobert Baldyga 46612954522fSRobert Baldyga if (dir_in) 46622954522fSRobert Baldyga hs_ep->ep.caps.dir_in = true; 46632954522fSRobert Baldyga else 46642954522fSRobert Baldyga hs_ep->ep.caps.dir_out = true; 46652954522fSRobert Baldyga 466647a1685fSDinh Nguyen /* 466747a1685fSDinh Nguyen * if we're using dma, we need to set the next-endpoint pointer 466847a1685fSDinh Nguyen * to be something valid. 466947a1685fSDinh Nguyen */ 467047a1685fSDinh Nguyen 467147a1685fSDinh Nguyen if (using_dma(hsotg)) { 467247a1685fSDinh Nguyen u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); 46739da51974SJohn Youn 4674c6f5c050SMian Yousaf Kaukab if (dir_in) 4675f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, next, DIEPCTL(epnum)); 4676c6f5c050SMian Yousaf Kaukab else 4677f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, next, DOEPCTL(epnum)); 467847a1685fSDinh Nguyen } 467947a1685fSDinh Nguyen } 468047a1685fSDinh Nguyen 468147a1685fSDinh Nguyen /** 46821f91b4ccSFelipe Balbi * dwc2_hsotg_hw_cfg - read HW configuration registers 46836fb914d7SGrigor Tovmasyan * @hsotg: Programming view of the DWC_otg controller 468447a1685fSDinh Nguyen * 468547a1685fSDinh Nguyen * Read the USB core HW configuration registers 468647a1685fSDinh Nguyen */ 46871f91b4ccSFelipe Balbi static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) 468847a1685fSDinh Nguyen { 4689c6f5c050SMian Yousaf Kaukab u32 cfg; 4690c6f5c050SMian Yousaf Kaukab u32 ep_type; 4691c6f5c050SMian Yousaf Kaukab u32 i; 4692c6f5c050SMian Yousaf Kaukab 469347a1685fSDinh Nguyen /* check hardware configuration */ 469447a1685fSDinh Nguyen 469543e90349SJohn Youn hsotg->num_of_eps = hsotg->hw_params.num_dev_ep; 469643e90349SJohn Youn 4697c6f5c050SMian Yousaf Kaukab /* Add ep0 */ 4698c6f5c050SMian Yousaf Kaukab hsotg->num_of_eps++; 469947a1685fSDinh Nguyen 4700b98866c2SJohn Youn hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, 4701b98866c2SJohn Youn sizeof(struct dwc2_hsotg_ep), 4702c6f5c050SMian Yousaf Kaukab GFP_KERNEL); 4703c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_in[0]) 4704c6f5c050SMian Yousaf Kaukab return -ENOMEM; 47051f91b4ccSFelipe Balbi /* Same dwc2_hsotg_ep is used in both directions for ep0 */ 4706c6f5c050SMian Yousaf Kaukab hsotg->eps_out[0] = hsotg->eps_in[0]; 470747a1685fSDinh Nguyen 470843e90349SJohn Youn cfg = hsotg->hw_params.dev_ep_dirs; 4709251a17f5SRoshan Pius for (i = 1, cfg >>= 2; i < hsotg->num_of_eps; i++, cfg >>= 2) { 4710c6f5c050SMian Yousaf Kaukab ep_type = cfg & 3; 4711c6f5c050SMian Yousaf Kaukab /* Direction in or both */ 4712c6f5c050SMian Yousaf Kaukab if (!(ep_type & 2)) { 4713c6f5c050SMian Yousaf Kaukab hsotg->eps_in[i] = devm_kzalloc(hsotg->dev, 47141f91b4ccSFelipe Balbi sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 4715c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_in[i]) 4716c6f5c050SMian Yousaf Kaukab return -ENOMEM; 4717c6f5c050SMian Yousaf Kaukab } 4718c6f5c050SMian Yousaf Kaukab /* Direction out or both */ 4719c6f5c050SMian Yousaf Kaukab if (!(ep_type & 1)) { 4720c6f5c050SMian Yousaf Kaukab hsotg->eps_out[i] = devm_kzalloc(hsotg->dev, 47211f91b4ccSFelipe Balbi sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 4722c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_out[i]) 4723c6f5c050SMian Yousaf Kaukab return -ENOMEM; 4724c6f5c050SMian Yousaf Kaukab } 4725c6f5c050SMian Yousaf Kaukab } 4726c6f5c050SMian Yousaf Kaukab 472743e90349SJohn Youn hsotg->fifo_mem = hsotg->hw_params.total_fifo_size; 472843e90349SJohn Youn hsotg->dedicated_fifos = hsotg->hw_params.en_multiple_tx_fifo; 472947a1685fSDinh Nguyen 4730cff9eb75SMarek Szyprowski dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n", 4731cff9eb75SMarek Szyprowski hsotg->num_of_eps, 4732cff9eb75SMarek Szyprowski hsotg->dedicated_fifos ? "dedicated" : "shared", 4733cff9eb75SMarek Szyprowski hsotg->fifo_mem); 4734c6f5c050SMian Yousaf Kaukab return 0; 473547a1685fSDinh Nguyen } 473647a1685fSDinh Nguyen 473747a1685fSDinh Nguyen /** 47381f91b4ccSFelipe Balbi * dwc2_hsotg_dump - dump state of the udc 47396fb914d7SGrigor Tovmasyan * @hsotg: Programming view of the DWC_otg controller 47406fb914d7SGrigor Tovmasyan * 474147a1685fSDinh Nguyen */ 47421f91b4ccSFelipe Balbi static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) 474347a1685fSDinh Nguyen { 474447a1685fSDinh Nguyen #ifdef DEBUG 474547a1685fSDinh Nguyen struct device *dev = hsotg->dev; 474647a1685fSDinh Nguyen u32 val; 474747a1685fSDinh Nguyen int idx; 474847a1685fSDinh Nguyen 474947a1685fSDinh Nguyen dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", 4750f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DCFG), dwc2_readl(hsotg, DCTL), 4751f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DIEPMSK)); 475247a1685fSDinh Nguyen 4753f889f23dSMian Yousaf Kaukab dev_info(dev, "GAHBCFG=0x%08x, GHWCFG1=0x%08x\n", 4754f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, GAHBCFG), dwc2_readl(hsotg, GHWCFG1)); 475547a1685fSDinh Nguyen 475647a1685fSDinh Nguyen dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 4757f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, GRXFSIZ), dwc2_readl(hsotg, GNPTXFSIZ)); 475847a1685fSDinh Nguyen 475947a1685fSDinh Nguyen /* show periodic fifo settings */ 476047a1685fSDinh Nguyen 4761364f8e93SMian Yousaf Kaukab for (idx = 1; idx < hsotg->num_of_eps; idx++) { 4762f25c42b8SGevorg Sahakyan val = dwc2_readl(hsotg, DPTXFSIZN(idx)); 476347a1685fSDinh Nguyen dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, 476447a1685fSDinh Nguyen val >> FIFOSIZE_DEPTH_SHIFT, 476547a1685fSDinh Nguyen val & FIFOSIZE_STARTADDR_MASK); 476647a1685fSDinh Nguyen } 476747a1685fSDinh Nguyen 4768364f8e93SMian Yousaf Kaukab for (idx = 0; idx < hsotg->num_of_eps; idx++) { 476947a1685fSDinh Nguyen dev_info(dev, 477047a1685fSDinh Nguyen "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, 4771f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DIEPCTL(idx)), 4772f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DIEPTSIZ(idx)), 4773f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DIEPDMA(idx))); 477447a1685fSDinh Nguyen 4775f25c42b8SGevorg Sahakyan val = dwc2_readl(hsotg, DOEPCTL(idx)); 477647a1685fSDinh Nguyen dev_info(dev, 477747a1685fSDinh Nguyen "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", 4778f25c42b8SGevorg Sahakyan idx, dwc2_readl(hsotg, DOEPCTL(idx)), 4779f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DOEPTSIZ(idx)), 4780f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DOEPDMA(idx))); 478147a1685fSDinh Nguyen } 478247a1685fSDinh Nguyen 478347a1685fSDinh Nguyen dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", 4784f25c42b8SGevorg Sahakyan dwc2_readl(hsotg, DVBUSDIS), dwc2_readl(hsotg, DVBUSPULSE)); 478547a1685fSDinh Nguyen #endif 478647a1685fSDinh Nguyen } 478747a1685fSDinh Nguyen 478847a1685fSDinh Nguyen /** 4789117777b2SDinh Nguyen * dwc2_gadget_init - init function for gadget 47906fb914d7SGrigor Tovmasyan * @hsotg: Programming view of the DWC_otg controller 47916fb914d7SGrigor Tovmasyan * 479247a1685fSDinh Nguyen */ 4793f3768997SVardan Mikayelyan int dwc2_gadget_init(struct dwc2_hsotg *hsotg) 479447a1685fSDinh Nguyen { 4795117777b2SDinh Nguyen struct device *dev = hsotg->dev; 479647a1685fSDinh Nguyen int epnum; 479747a1685fSDinh Nguyen int ret; 479843e90349SJohn Youn 47990a176279SGregory Herrero /* Dump fifo information */ 48000a176279SGregory Herrero dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n", 480105ee799fSJohn Youn hsotg->params.g_np_tx_fifo_size); 480205ee799fSJohn Youn dev_dbg(dev, "RXFIFO size: %d\n", hsotg->params.g_rx_fifo_size); 480347a1685fSDinh Nguyen 480447a1685fSDinh Nguyen hsotg->gadget.max_speed = USB_SPEED_HIGH; 48051f91b4ccSFelipe Balbi hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; 480647a1685fSDinh Nguyen hsotg->gadget.name = dev_name(dev); 4807fa389a6dSVardan Mikayelyan hsotg->remote_wakeup_allowed = 0; 48087455f8b7SJohn Youn 48097455f8b7SJohn Youn if (hsotg->params.lpm) 48107455f8b7SJohn Youn hsotg->gadget.lpm_capable = true; 48117455f8b7SJohn Youn 4812097ee662SGregory Herrero if (hsotg->dr_mode == USB_DR_MODE_OTG) 4813097ee662SGregory Herrero hsotg->gadget.is_otg = 1; 4814ec4cc657SMian Yousaf Kaukab else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 4815ec4cc657SMian Yousaf Kaukab hsotg->op_state = OTG_STATE_B_PERIPHERAL; 481647a1685fSDinh Nguyen 48171f91b4ccSFelipe Balbi ret = dwc2_hsotg_hw_cfg(hsotg); 4818c6f5c050SMian Yousaf Kaukab if (ret) { 4819c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret); 482009a75e85SMarek Szyprowski return ret; 4821c6f5c050SMian Yousaf Kaukab } 4822c6f5c050SMian Yousaf Kaukab 48233f95001dSMian Yousaf Kaukab hsotg->ctrl_buff = devm_kzalloc(hsotg->dev, 48243f95001dSMian Yousaf Kaukab DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 48258bae0f8cSWolfram Sang if (!hsotg->ctrl_buff) 482609a75e85SMarek Szyprowski return -ENOMEM; 48273f95001dSMian Yousaf Kaukab 48283f95001dSMian Yousaf Kaukab hsotg->ep0_buff = devm_kzalloc(hsotg->dev, 48293f95001dSMian Yousaf Kaukab DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 48308bae0f8cSWolfram Sang if (!hsotg->ep0_buff) 483109a75e85SMarek Szyprowski return -ENOMEM; 48323f95001dSMian Yousaf Kaukab 48330f6b80c0SVahram Aharonyan if (using_desc_dma(hsotg)) { 48340f6b80c0SVahram Aharonyan ret = dwc2_gadget_alloc_ctrl_desc_chains(hsotg); 48350f6b80c0SVahram Aharonyan if (ret < 0) 48360f6b80c0SVahram Aharonyan return ret; 48370f6b80c0SVahram Aharonyan } 48380f6b80c0SVahram Aharonyan 4839f3768997SVardan Mikayelyan ret = devm_request_irq(hsotg->dev, hsotg->irq, dwc2_hsotg_irq, 4840f3768997SVardan Mikayelyan IRQF_SHARED, dev_name(hsotg->dev), hsotg); 4841eb3c56c5SMarek Szyprowski if (ret < 0) { 4842db8178c3SDinh Nguyen dev_err(dev, "cannot claim IRQ for gadget\n"); 484309a75e85SMarek Szyprowski return ret; 4844eb3c56c5SMarek Szyprowski } 4845eb3c56c5SMarek Szyprowski 484647a1685fSDinh Nguyen /* hsotg->num_of_eps holds number of EPs other than ep0 */ 484747a1685fSDinh Nguyen 484847a1685fSDinh Nguyen if (hsotg->num_of_eps == 0) { 484947a1685fSDinh Nguyen dev_err(dev, "wrong number of EPs (zero)\n"); 485009a75e85SMarek Szyprowski return -EINVAL; 485147a1685fSDinh Nguyen } 485247a1685fSDinh Nguyen 485347a1685fSDinh Nguyen /* setup endpoint information */ 485447a1685fSDinh Nguyen 485547a1685fSDinh Nguyen INIT_LIST_HEAD(&hsotg->gadget.ep_list); 4856c6f5c050SMian Yousaf Kaukab hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep; 485747a1685fSDinh Nguyen 485847a1685fSDinh Nguyen /* allocate EP0 request */ 485947a1685fSDinh Nguyen 48601f91b4ccSFelipe Balbi hsotg->ctrl_req = dwc2_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep, 486147a1685fSDinh Nguyen GFP_KERNEL); 486247a1685fSDinh Nguyen if (!hsotg->ctrl_req) { 486347a1685fSDinh Nguyen dev_err(dev, "failed to allocate ctrl req\n"); 486409a75e85SMarek Szyprowski return -ENOMEM; 486547a1685fSDinh Nguyen } 486647a1685fSDinh Nguyen 486747a1685fSDinh Nguyen /* initialise the endpoints now the core has been initialised */ 4868c6f5c050SMian Yousaf Kaukab for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) { 4869c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[epnum]) 48701f91b4ccSFelipe Balbi dwc2_hsotg_initep(hsotg, hsotg->eps_in[epnum], 4871c6f5c050SMian Yousaf Kaukab epnum, 1); 4872c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[epnum]) 48731f91b4ccSFelipe Balbi dwc2_hsotg_initep(hsotg, hsotg->eps_out[epnum], 4874c6f5c050SMian Yousaf Kaukab epnum, 0); 4875c6f5c050SMian Yousaf Kaukab } 487647a1685fSDinh Nguyen 4877117777b2SDinh Nguyen ret = usb_add_gadget_udc(dev, &hsotg->gadget); 48789bb073a0SGrigor Tovmasyan if (ret) { 48799bb073a0SGrigor Tovmasyan dwc2_hsotg_ep_free_request(&hsotg->eps_out[0]->ep, 48809bb073a0SGrigor Tovmasyan hsotg->ctrl_req); 488109a75e85SMarek Szyprowski return ret; 48829bb073a0SGrigor Tovmasyan } 48831f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 488447a1685fSDinh Nguyen 488547a1685fSDinh Nguyen return 0; 488647a1685fSDinh Nguyen } 488747a1685fSDinh Nguyen 488847a1685fSDinh Nguyen /** 48891f91b4ccSFelipe Balbi * dwc2_hsotg_remove - remove function for hsotg driver 48906fb914d7SGrigor Tovmasyan * @hsotg: Programming view of the DWC_otg controller 48916fb914d7SGrigor Tovmasyan * 489247a1685fSDinh Nguyen */ 48931f91b4ccSFelipe Balbi int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg) 489447a1685fSDinh Nguyen { 489547a1685fSDinh Nguyen usb_del_gadget_udc(&hsotg->gadget); 48969bb073a0SGrigor Tovmasyan dwc2_hsotg_ep_free_request(&hsotg->eps_out[0]->ep, hsotg->ctrl_req); 489747a1685fSDinh Nguyen 489847a1685fSDinh Nguyen return 0; 489947a1685fSDinh Nguyen } 490047a1685fSDinh Nguyen 49011f91b4ccSFelipe Balbi int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) 490247a1685fSDinh Nguyen { 490347a1685fSDinh Nguyen unsigned long flags; 490447a1685fSDinh Nguyen 49059e779778SGregory Herrero if (hsotg->lx_state != DWC2_L0) 490609a75e85SMarek Szyprowski return 0; 49079e779778SGregory Herrero 4908dc6e69e6SMarek Szyprowski if (hsotg->driver) { 4909dc6e69e6SMarek Szyprowski int ep; 4910dc6e69e6SMarek Szyprowski 491147a1685fSDinh Nguyen dev_info(hsotg->dev, "suspending usb gadget %s\n", 491247a1685fSDinh Nguyen hsotg->driver->driver.name); 491347a1685fSDinh Nguyen 491447a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 4915dc6e69e6SMarek Szyprowski if (hsotg->enabled) 49161f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 49171f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 491847a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 491947a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 492047a1685fSDinh Nguyen 4921c6f5c050SMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps; ep++) { 4922c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 49234fe4f9feSMinas Harutyunyan dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); 4924c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 49254fe4f9feSMinas Harutyunyan dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); 4926c6f5c050SMian Yousaf Kaukab } 492747a1685fSDinh Nguyen } 492847a1685fSDinh Nguyen 492909a75e85SMarek Szyprowski return 0; 493047a1685fSDinh Nguyen } 493147a1685fSDinh Nguyen 49321f91b4ccSFelipe Balbi int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg) 493347a1685fSDinh Nguyen { 493447a1685fSDinh Nguyen unsigned long flags; 493547a1685fSDinh Nguyen 49369e779778SGregory Herrero if (hsotg->lx_state == DWC2_L2) 493709a75e85SMarek Szyprowski return 0; 49389e779778SGregory Herrero 493947a1685fSDinh Nguyen if (hsotg->driver) { 494047a1685fSDinh Nguyen dev_info(hsotg->dev, "resuming usb gadget %s\n", 494147a1685fSDinh Nguyen hsotg->driver->driver.name); 4942d00b4142SRobert Baldyga 494347a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 49441f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 494566e77a24SRazmik Karapetyan if (hsotg->enabled) { 494666e77a24SRazmik Karapetyan /* Enable ACG feature in device mode,if supported */ 494766e77a24SRazmik Karapetyan dwc2_enable_acg(hsotg); 49481f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 494966e77a24SRazmik Karapetyan } 495047a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 4951dc6e69e6SMarek Szyprowski } 495247a1685fSDinh Nguyen 495309a75e85SMarek Szyprowski return 0; 495447a1685fSDinh Nguyen } 495558e52ff6SJohn Youn 495658e52ff6SJohn Youn /** 495758e52ff6SJohn Youn * dwc2_backup_device_registers() - Backup controller device registers. 495858e52ff6SJohn Youn * When suspending usb bus, registers needs to be backuped 495958e52ff6SJohn Youn * if controller power is disabled once suspended. 496058e52ff6SJohn Youn * 496158e52ff6SJohn Youn * @hsotg: Programming view of the DWC_otg controller 496258e52ff6SJohn Youn */ 496358e52ff6SJohn Youn int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg) 496458e52ff6SJohn Youn { 496558e52ff6SJohn Youn struct dwc2_dregs_backup *dr; 496658e52ff6SJohn Youn int i; 496758e52ff6SJohn Youn 496858e52ff6SJohn Youn dev_dbg(hsotg->dev, "%s\n", __func__); 496958e52ff6SJohn Youn 497058e52ff6SJohn Youn /* Backup dev regs */ 497158e52ff6SJohn Youn dr = &hsotg->dr_backup; 497258e52ff6SJohn Youn 4973f25c42b8SGevorg Sahakyan dr->dcfg = dwc2_readl(hsotg, DCFG); 4974f25c42b8SGevorg Sahakyan dr->dctl = dwc2_readl(hsotg, DCTL); 4975f25c42b8SGevorg Sahakyan dr->daintmsk = dwc2_readl(hsotg, DAINTMSK); 4976f25c42b8SGevorg Sahakyan dr->diepmsk = dwc2_readl(hsotg, DIEPMSK); 4977f25c42b8SGevorg Sahakyan dr->doepmsk = dwc2_readl(hsotg, DOEPMSK); 497858e52ff6SJohn Youn 497958e52ff6SJohn Youn for (i = 0; i < hsotg->num_of_eps; i++) { 498058e52ff6SJohn Youn /* Backup IN EPs */ 4981f25c42b8SGevorg Sahakyan dr->diepctl[i] = dwc2_readl(hsotg, DIEPCTL(i)); 498258e52ff6SJohn Youn 498358e52ff6SJohn Youn /* Ensure DATA PID is correctly configured */ 498458e52ff6SJohn Youn if (dr->diepctl[i] & DXEPCTL_DPID) 498558e52ff6SJohn Youn dr->diepctl[i] |= DXEPCTL_SETD1PID; 498658e52ff6SJohn Youn else 498758e52ff6SJohn Youn dr->diepctl[i] |= DXEPCTL_SETD0PID; 498858e52ff6SJohn Youn 4989f25c42b8SGevorg Sahakyan dr->dieptsiz[i] = dwc2_readl(hsotg, DIEPTSIZ(i)); 4990f25c42b8SGevorg Sahakyan dr->diepdma[i] = dwc2_readl(hsotg, DIEPDMA(i)); 499158e52ff6SJohn Youn 499258e52ff6SJohn Youn /* Backup OUT EPs */ 4993f25c42b8SGevorg Sahakyan dr->doepctl[i] = dwc2_readl(hsotg, DOEPCTL(i)); 499458e52ff6SJohn Youn 499558e52ff6SJohn Youn /* Ensure DATA PID is correctly configured */ 499658e52ff6SJohn Youn if (dr->doepctl[i] & DXEPCTL_DPID) 499758e52ff6SJohn Youn dr->doepctl[i] |= DXEPCTL_SETD1PID; 499858e52ff6SJohn Youn else 499958e52ff6SJohn Youn dr->doepctl[i] |= DXEPCTL_SETD0PID; 500058e52ff6SJohn Youn 5001f25c42b8SGevorg Sahakyan dr->doeptsiz[i] = dwc2_readl(hsotg, DOEPTSIZ(i)); 5002f25c42b8SGevorg Sahakyan dr->doepdma[i] = dwc2_readl(hsotg, DOEPDMA(i)); 5003f25c42b8SGevorg Sahakyan dr->dtxfsiz[i] = dwc2_readl(hsotg, DPTXFSIZN(i)); 500458e52ff6SJohn Youn } 500558e52ff6SJohn Youn dr->valid = true; 500658e52ff6SJohn Youn return 0; 500758e52ff6SJohn Youn } 500858e52ff6SJohn Youn 500958e52ff6SJohn Youn /** 501058e52ff6SJohn Youn * dwc2_restore_device_registers() - Restore controller device registers. 501158e52ff6SJohn Youn * When resuming usb bus, device registers needs to be restored 501258e52ff6SJohn Youn * if controller power were disabled. 501358e52ff6SJohn Youn * 501458e52ff6SJohn Youn * @hsotg: Programming view of the DWC_otg controller 50159a5d2816SVardan Mikayelyan * @remote_wakeup: Indicates whether resume is initiated by Device or Host. 50169a5d2816SVardan Mikayelyan * 50179a5d2816SVardan Mikayelyan * Return: 0 if successful, negative error code otherwise 501858e52ff6SJohn Youn */ 50199a5d2816SVardan Mikayelyan int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup) 502058e52ff6SJohn Youn { 502158e52ff6SJohn Youn struct dwc2_dregs_backup *dr; 502258e52ff6SJohn Youn int i; 502358e52ff6SJohn Youn 502458e52ff6SJohn Youn dev_dbg(hsotg->dev, "%s\n", __func__); 502558e52ff6SJohn Youn 502658e52ff6SJohn Youn /* Restore dev regs */ 502758e52ff6SJohn Youn dr = &hsotg->dr_backup; 502858e52ff6SJohn Youn if (!dr->valid) { 502958e52ff6SJohn Youn dev_err(hsotg->dev, "%s: no device registers to restore\n", 503058e52ff6SJohn Youn __func__); 503158e52ff6SJohn Youn return -EINVAL; 503258e52ff6SJohn Youn } 503358e52ff6SJohn Youn dr->valid = false; 503458e52ff6SJohn Youn 50359a5d2816SVardan Mikayelyan if (!remote_wakeup) 5036f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->dctl, DCTL); 50379a5d2816SVardan Mikayelyan 5038f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->daintmsk, DAINTMSK); 5039f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->diepmsk, DIEPMSK); 5040f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->doepmsk, DOEPMSK); 504158e52ff6SJohn Youn 504258e52ff6SJohn Youn for (i = 0; i < hsotg->num_of_eps; i++) { 504358e52ff6SJohn Youn /* Restore IN EPs */ 5044f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->dieptsiz[i], DIEPTSIZ(i)); 5045f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->diepdma[i], DIEPDMA(i)); 5046f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->doeptsiz[i], DOEPTSIZ(i)); 50479a5d2816SVardan Mikayelyan /** WA for enabled EPx's IN in DDMA mode. On entering to 50489a5d2816SVardan Mikayelyan * hibernation wrong value read and saved from DIEPDMAx, 50499a5d2816SVardan Mikayelyan * as result BNA interrupt asserted on hibernation exit 50509a5d2816SVardan Mikayelyan * by restoring from saved area. 50519a5d2816SVardan Mikayelyan */ 50529a5d2816SVardan Mikayelyan if (hsotg->params.g_dma_desc && 50539a5d2816SVardan Mikayelyan (dr->diepctl[i] & DXEPCTL_EPENA)) 50549a5d2816SVardan Mikayelyan dr->diepdma[i] = hsotg->eps_in[i]->desc_list_dma; 5055f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->dtxfsiz[i], DPTXFSIZN(i)); 5056f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->diepctl[i], DIEPCTL(i)); 50579a5d2816SVardan Mikayelyan /* Restore OUT EPs */ 5058f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->doeptsiz[i], DOEPTSIZ(i)); 50599a5d2816SVardan Mikayelyan /* WA for enabled EPx's OUT in DDMA mode. On entering to 50609a5d2816SVardan Mikayelyan * hibernation wrong value read and saved from DOEPDMAx, 50619a5d2816SVardan Mikayelyan * as result BNA interrupt asserted on hibernation exit 50629a5d2816SVardan Mikayelyan * by restoring from saved area. 50639a5d2816SVardan Mikayelyan */ 50649a5d2816SVardan Mikayelyan if (hsotg->params.g_dma_desc && 50659a5d2816SVardan Mikayelyan (dr->doepctl[i] & DXEPCTL_EPENA)) 50669a5d2816SVardan Mikayelyan dr->doepdma[i] = hsotg->eps_out[i]->desc_list_dma; 5067f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->doepdma[i], DOEPDMA(i)); 5068f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->doepctl[i], DOEPCTL(i)); 506958e52ff6SJohn Youn } 507058e52ff6SJohn Youn 507158e52ff6SJohn Youn return 0; 507258e52ff6SJohn Youn } 507321b03405SSevak Arakelyan 507421b03405SSevak Arakelyan /** 507521b03405SSevak Arakelyan * dwc2_gadget_init_lpm - Configure the core to support LPM in device mode 507621b03405SSevak Arakelyan * 507721b03405SSevak Arakelyan * @hsotg: Programming view of DWC_otg controller 507821b03405SSevak Arakelyan * 507921b03405SSevak Arakelyan */ 508021b03405SSevak Arakelyan void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) 508121b03405SSevak Arakelyan { 508221b03405SSevak Arakelyan u32 val; 508321b03405SSevak Arakelyan 508421b03405SSevak Arakelyan if (!hsotg->params.lpm) 508521b03405SSevak Arakelyan return; 508621b03405SSevak Arakelyan 508721b03405SSevak Arakelyan val = GLPMCFG_LPMCAP | GLPMCFG_APPL1RES; 508821b03405SSevak Arakelyan val |= hsotg->params.hird_threshold_en ? GLPMCFG_HIRD_THRES_EN : 0; 508921b03405SSevak Arakelyan val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0; 509021b03405SSevak Arakelyan val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT; 509121b03405SSevak Arakelyan val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; 509246637565SMinas Harutyunyan val |= GLPMCFG_LPM_REJECT_CTRL_CONTROL; 50939aed8c08SArtur Petrosyan val |= GLPMCFG_LPM_ACCEPT_CTRL_ISOC; 5094f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, val, GLPMCFG); 5095f25c42b8SGevorg Sahakyan dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG)); 50964abe4537SGrigor Tovmasyan 50974abe4537SGrigor Tovmasyan /* Unmask WKUP_ALERT Interrupt */ 50984abe4537SGrigor Tovmasyan if (hsotg->params.service_interval) 50994abe4537SGrigor Tovmasyan dwc2_set_bit(hsotg, GINTMSK2, GINTMSK2_WKUP_ALERT_INT_MSK); 510021b03405SSevak Arakelyan } 5101c5c403dcSVardan Mikayelyan 5102c5c403dcSVardan Mikayelyan /** 510315d9dbf8SGrigor Tovmasyan * dwc2_gadget_program_ref_clk - Program GREFCLK register in device mode 510415d9dbf8SGrigor Tovmasyan * 510515d9dbf8SGrigor Tovmasyan * @hsotg: Programming view of DWC_otg controller 510615d9dbf8SGrigor Tovmasyan * 510715d9dbf8SGrigor Tovmasyan */ 510815d9dbf8SGrigor Tovmasyan void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) 510915d9dbf8SGrigor Tovmasyan { 511015d9dbf8SGrigor Tovmasyan u32 val = 0; 511115d9dbf8SGrigor Tovmasyan 511215d9dbf8SGrigor Tovmasyan val |= GREFCLK_REF_CLK_MODE; 511315d9dbf8SGrigor Tovmasyan val |= hsotg->params.ref_clk_per << GREFCLK_REFCLKPER_SHIFT; 511415d9dbf8SGrigor Tovmasyan val |= hsotg->params.sof_cnt_wkup_alert << 511515d9dbf8SGrigor Tovmasyan GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT; 511615d9dbf8SGrigor Tovmasyan 511715d9dbf8SGrigor Tovmasyan dwc2_writel(hsotg, val, GREFCLK); 511815d9dbf8SGrigor Tovmasyan dev_dbg(hsotg->dev, "GREFCLK=0x%08x\n", dwc2_readl(hsotg, GREFCLK)); 511915d9dbf8SGrigor Tovmasyan } 512015d9dbf8SGrigor Tovmasyan 512115d9dbf8SGrigor Tovmasyan /** 5122c5c403dcSVardan Mikayelyan * dwc2_gadget_enter_hibernation() - Put controller in Hibernation. 5123c5c403dcSVardan Mikayelyan * 5124c5c403dcSVardan Mikayelyan * @hsotg: Programming view of the DWC_otg controller 5125c5c403dcSVardan Mikayelyan * 5126c5c403dcSVardan Mikayelyan * Return non-zero if failed to enter to hibernation. 5127c5c403dcSVardan Mikayelyan */ 5128c5c403dcSVardan Mikayelyan int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg) 5129c5c403dcSVardan Mikayelyan { 5130c5c403dcSVardan Mikayelyan u32 gpwrdn; 5131c5c403dcSVardan Mikayelyan int ret = 0; 5132c5c403dcSVardan Mikayelyan 5133c5c403dcSVardan Mikayelyan /* Change to L2(suspend) state */ 5134c5c403dcSVardan Mikayelyan hsotg->lx_state = DWC2_L2; 5135c5c403dcSVardan Mikayelyan dev_dbg(hsotg->dev, "Start of hibernation completed\n"); 5136c5c403dcSVardan Mikayelyan ret = dwc2_backup_global_registers(hsotg); 5137c5c403dcSVardan Mikayelyan if (ret) { 5138c5c403dcSVardan Mikayelyan dev_err(hsotg->dev, "%s: failed to backup global registers\n", 5139c5c403dcSVardan Mikayelyan __func__); 5140c5c403dcSVardan Mikayelyan return ret; 5141c5c403dcSVardan Mikayelyan } 5142c5c403dcSVardan Mikayelyan ret = dwc2_backup_device_registers(hsotg); 5143c5c403dcSVardan Mikayelyan if (ret) { 5144c5c403dcSVardan Mikayelyan dev_err(hsotg->dev, "%s: failed to backup device registers\n", 5145c5c403dcSVardan Mikayelyan __func__); 5146c5c403dcSVardan Mikayelyan return ret; 5147c5c403dcSVardan Mikayelyan } 5148c5c403dcSVardan Mikayelyan 5149c5c403dcSVardan Mikayelyan gpwrdn = GPWRDN_PWRDNRSTN; 5150c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_PMUACTV; 5151f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 5152c5c403dcSVardan Mikayelyan udelay(10); 5153c5c403dcSVardan Mikayelyan 5154c5c403dcSVardan Mikayelyan /* Set flag to indicate that we are in hibernation */ 5155c5c403dcSVardan Mikayelyan hsotg->hibernated = 1; 5156c5c403dcSVardan Mikayelyan 5157c5c403dcSVardan Mikayelyan /* Enable interrupts from wake up logic */ 5158f25c42b8SGevorg Sahakyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 5159c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_PMUINTSEL; 5160f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 5161c5c403dcSVardan Mikayelyan udelay(10); 5162c5c403dcSVardan Mikayelyan 5163c5c403dcSVardan Mikayelyan /* Unmask device mode interrupts in GPWRDN */ 5164f25c42b8SGevorg Sahakyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 5165c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_RST_DET_MSK; 5166c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_LNSTSCHG_MSK; 5167c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_STS_CHGINT_MSK; 5168f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 5169c5c403dcSVardan Mikayelyan udelay(10); 5170c5c403dcSVardan Mikayelyan 5171c5c403dcSVardan Mikayelyan /* Enable Power Down Clamp */ 5172f25c42b8SGevorg Sahakyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 5173c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_PWRDNCLMP; 5174f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 5175c5c403dcSVardan Mikayelyan udelay(10); 5176c5c403dcSVardan Mikayelyan 5177c5c403dcSVardan Mikayelyan /* Switch off VDD */ 5178f25c42b8SGevorg Sahakyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 5179c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_PWRDNSWTCH; 5180f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 5181c5c403dcSVardan Mikayelyan udelay(10); 5182c5c403dcSVardan Mikayelyan 5183c5c403dcSVardan Mikayelyan /* Save gpwrdn register for further usage if stschng interrupt */ 5184f25c42b8SGevorg Sahakyan hsotg->gr_backup.gpwrdn = dwc2_readl(hsotg, GPWRDN); 5185c5c403dcSVardan Mikayelyan dev_dbg(hsotg->dev, "Hibernation completed\n"); 5186c5c403dcSVardan Mikayelyan 5187c5c403dcSVardan Mikayelyan return ret; 5188c5c403dcSVardan Mikayelyan } 5189c5c403dcSVardan Mikayelyan 5190c5c403dcSVardan Mikayelyan /** 5191c5c403dcSVardan Mikayelyan * dwc2_gadget_exit_hibernation() 5192c5c403dcSVardan Mikayelyan * This function is for exiting from Device mode hibernation by host initiated 5193c5c403dcSVardan Mikayelyan * resume/reset and device initiated remote-wakeup. 5194c5c403dcSVardan Mikayelyan * 5195c5c403dcSVardan Mikayelyan * @hsotg: Programming view of the DWC_otg controller 5196c5c403dcSVardan Mikayelyan * @rem_wakeup: indicates whether resume is initiated by Device or Host. 51976fb914d7SGrigor Tovmasyan * @reset: indicates whether resume is initiated by Reset. 5198c5c403dcSVardan Mikayelyan * 5199c5c403dcSVardan Mikayelyan * Return non-zero if failed to exit from hibernation. 5200c5c403dcSVardan Mikayelyan */ 5201c5c403dcSVardan Mikayelyan int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, 5202c5c403dcSVardan Mikayelyan int rem_wakeup, int reset) 5203c5c403dcSVardan Mikayelyan { 5204c5c403dcSVardan Mikayelyan u32 pcgcctl; 5205c5c403dcSVardan Mikayelyan u32 gpwrdn; 5206c5c403dcSVardan Mikayelyan u32 dctl; 5207c5c403dcSVardan Mikayelyan int ret = 0; 5208c5c403dcSVardan Mikayelyan struct dwc2_gregs_backup *gr; 5209c5c403dcSVardan Mikayelyan struct dwc2_dregs_backup *dr; 5210c5c403dcSVardan Mikayelyan 5211c5c403dcSVardan Mikayelyan gr = &hsotg->gr_backup; 5212c5c403dcSVardan Mikayelyan dr = &hsotg->dr_backup; 5213c5c403dcSVardan Mikayelyan 5214c5c403dcSVardan Mikayelyan if (!hsotg->hibernated) { 5215c5c403dcSVardan Mikayelyan dev_dbg(hsotg->dev, "Already exited from Hibernation\n"); 5216c5c403dcSVardan Mikayelyan return 1; 5217c5c403dcSVardan Mikayelyan } 5218c5c403dcSVardan Mikayelyan dev_dbg(hsotg->dev, 5219c5c403dcSVardan Mikayelyan "%s: called with rem_wakeup = %d reset = %d\n", 5220c5c403dcSVardan Mikayelyan __func__, rem_wakeup, reset); 5221c5c403dcSVardan Mikayelyan 5222c5c403dcSVardan Mikayelyan dwc2_hib_restore_common(hsotg, rem_wakeup, 0); 5223c5c403dcSVardan Mikayelyan 5224c5c403dcSVardan Mikayelyan if (!reset) { 5225c5c403dcSVardan Mikayelyan /* Clear all pending interupts */ 5226f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, 0xffffffff, GINTSTS); 5227c5c403dcSVardan Mikayelyan } 5228c5c403dcSVardan Mikayelyan 5229c5c403dcSVardan Mikayelyan /* De-assert Restore */ 5230f25c42b8SGevorg Sahakyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 5231c5c403dcSVardan Mikayelyan gpwrdn &= ~GPWRDN_RESTORE; 5232f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 5233c5c403dcSVardan Mikayelyan udelay(10); 5234c5c403dcSVardan Mikayelyan 5235c5c403dcSVardan Mikayelyan if (!rem_wakeup) { 5236f25c42b8SGevorg Sahakyan pcgcctl = dwc2_readl(hsotg, PCGCTL); 5237c5c403dcSVardan Mikayelyan pcgcctl &= ~PCGCTL_RSTPDWNMODULE; 5238f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, pcgcctl, PCGCTL); 5239c5c403dcSVardan Mikayelyan } 5240c5c403dcSVardan Mikayelyan 5241c5c403dcSVardan Mikayelyan /* Restore GUSBCFG, DCFG and DCTL */ 5242f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); 5243f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->dcfg, DCFG); 5244f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->dctl, DCTL); 5245c5c403dcSVardan Mikayelyan 5246c5c403dcSVardan Mikayelyan /* De-assert Wakeup Logic */ 5247f25c42b8SGevorg Sahakyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 5248c5c403dcSVardan Mikayelyan gpwrdn &= ~GPWRDN_PMUACTV; 5249f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 5250c5c403dcSVardan Mikayelyan 5251c5c403dcSVardan Mikayelyan if (rem_wakeup) { 5252c5c403dcSVardan Mikayelyan udelay(10); 5253c5c403dcSVardan Mikayelyan /* Start Remote Wakeup Signaling */ 5254f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->dctl | DCTL_RMTWKUPSIG, DCTL); 5255c5c403dcSVardan Mikayelyan } else { 5256c5c403dcSVardan Mikayelyan udelay(50); 5257c5c403dcSVardan Mikayelyan /* Set Device programming done bit */ 5258f25c42b8SGevorg Sahakyan dctl = dwc2_readl(hsotg, DCTL); 5259c5c403dcSVardan Mikayelyan dctl |= DCTL_PWRONPRGDONE; 5260f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dctl, DCTL); 5261c5c403dcSVardan Mikayelyan } 5262c5c403dcSVardan Mikayelyan /* Wait for interrupts which must be cleared */ 5263c5c403dcSVardan Mikayelyan mdelay(2); 5264c5c403dcSVardan Mikayelyan /* Clear all pending interupts */ 5265f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, 0xffffffff, GINTSTS); 5266c5c403dcSVardan Mikayelyan 5267c5c403dcSVardan Mikayelyan /* Restore global registers */ 5268c5c403dcSVardan Mikayelyan ret = dwc2_restore_global_registers(hsotg); 5269c5c403dcSVardan Mikayelyan if (ret) { 5270c5c403dcSVardan Mikayelyan dev_err(hsotg->dev, "%s: failed to restore registers\n", 5271c5c403dcSVardan Mikayelyan __func__); 5272c5c403dcSVardan Mikayelyan return ret; 5273c5c403dcSVardan Mikayelyan } 5274c5c403dcSVardan Mikayelyan 5275c5c403dcSVardan Mikayelyan /* Restore device registers */ 5276c5c403dcSVardan Mikayelyan ret = dwc2_restore_device_registers(hsotg, rem_wakeup); 5277c5c403dcSVardan Mikayelyan if (ret) { 5278c5c403dcSVardan Mikayelyan dev_err(hsotg->dev, "%s: failed to restore device registers\n", 5279c5c403dcSVardan Mikayelyan __func__); 5280c5c403dcSVardan Mikayelyan return ret; 5281c5c403dcSVardan Mikayelyan } 5282c5c403dcSVardan Mikayelyan 5283c5c403dcSVardan Mikayelyan if (rem_wakeup) { 5284c5c403dcSVardan Mikayelyan mdelay(10); 5285f25c42b8SGevorg Sahakyan dctl = dwc2_readl(hsotg, DCTL); 5286c5c403dcSVardan Mikayelyan dctl &= ~DCTL_RMTWKUPSIG; 5287f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dctl, DCTL); 5288c5c403dcSVardan Mikayelyan } 5289c5c403dcSVardan Mikayelyan 5290c5c403dcSVardan Mikayelyan hsotg->hibernated = 0; 5291c5c403dcSVardan Mikayelyan hsotg->lx_state = DWC2_L0; 5292c5c403dcSVardan Mikayelyan dev_dbg(hsotg->dev, "Hibernation recovery completes here\n"); 5293c5c403dcSVardan Mikayelyan 5294c5c403dcSVardan Mikayelyan return ret; 5295c5c403dcSVardan Mikayelyan } 5296