15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 247a1685fSDinh Nguyen /** 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> 3047a1685fSDinh Nguyen 31f7c0b143SDinh Nguyen #include "core.h" 32941fcce4SDinh Nguyen #include "hw.h" 3347a1685fSDinh Nguyen 3447a1685fSDinh Nguyen /* conversion functions */ 351f91b4ccSFelipe Balbi static inline struct dwc2_hsotg_req *our_req(struct usb_request *req) 3647a1685fSDinh Nguyen { 371f91b4ccSFelipe Balbi return container_of(req, struct dwc2_hsotg_req, req); 3847a1685fSDinh Nguyen } 3947a1685fSDinh Nguyen 401f91b4ccSFelipe Balbi static inline struct dwc2_hsotg_ep *our_ep(struct usb_ep *ep) 4147a1685fSDinh Nguyen { 421f91b4ccSFelipe Balbi return container_of(ep, struct dwc2_hsotg_ep, ep); 4347a1685fSDinh Nguyen } 4447a1685fSDinh Nguyen 45941fcce4SDinh Nguyen static inline struct dwc2_hsotg *to_hsotg(struct usb_gadget *gadget) 4647a1685fSDinh Nguyen { 47941fcce4SDinh Nguyen return container_of(gadget, struct dwc2_hsotg, gadget); 4847a1685fSDinh Nguyen } 4947a1685fSDinh Nguyen 50abd064a1SRazmik Karapetyan static inline void dwc2_set_bit(void __iomem *ptr, u32 val) 5147a1685fSDinh Nguyen { 5295c8bc36SAntti Seppälä dwc2_writel(dwc2_readl(ptr) | val, ptr); 5347a1685fSDinh Nguyen } 5447a1685fSDinh Nguyen 55abd064a1SRazmik Karapetyan static inline void dwc2_clear_bit(void __iomem *ptr, u32 val) 5647a1685fSDinh Nguyen { 5795c8bc36SAntti Seppälä dwc2_writel(dwc2_readl(ptr) & ~val, ptr); 5847a1685fSDinh Nguyen } 5947a1685fSDinh Nguyen 601f91b4ccSFelipe Balbi static inline struct dwc2_hsotg_ep *index_to_ep(struct dwc2_hsotg *hsotg, 61c6f5c050SMian Yousaf Kaukab u32 ep_index, u32 dir_in) 62c6f5c050SMian Yousaf Kaukab { 63c6f5c050SMian Yousaf Kaukab if (dir_in) 64c6f5c050SMian Yousaf Kaukab return hsotg->eps_in[ep_index]; 65c6f5c050SMian Yousaf Kaukab else 66c6f5c050SMian Yousaf Kaukab return hsotg->eps_out[ep_index]; 67c6f5c050SMian Yousaf Kaukab } 68c6f5c050SMian Yousaf Kaukab 69997f4f81SMickael Maison /* forward declaration of functions */ 701f91b4ccSFelipe Balbi static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg); 7147a1685fSDinh Nguyen 7247a1685fSDinh Nguyen /** 7347a1685fSDinh Nguyen * using_dma - return the DMA status of the driver. 7447a1685fSDinh Nguyen * @hsotg: The driver state. 7547a1685fSDinh Nguyen * 7647a1685fSDinh Nguyen * Return true if we're using DMA. 7747a1685fSDinh Nguyen * 7847a1685fSDinh Nguyen * Currently, we have the DMA support code worked into everywhere 7947a1685fSDinh Nguyen * that needs it, but the AMBA DMA implementation in the hardware can 8047a1685fSDinh Nguyen * only DMA from 32bit aligned addresses. This means that gadgets such 8147a1685fSDinh Nguyen * as the CDC Ethernet cannot work as they often pass packets which are 8247a1685fSDinh Nguyen * not 32bit aligned. 8347a1685fSDinh Nguyen * 8447a1685fSDinh Nguyen * Unfortunately the choice to use DMA or not is global to the controller 8547a1685fSDinh Nguyen * and seems to be only settable when the controller is being put through 8647a1685fSDinh Nguyen * a core reset. This means we either need to fix the gadgets to take 8747a1685fSDinh Nguyen * account of DMA alignment, or add bounce buffers (yuerk). 8847a1685fSDinh Nguyen * 89edd74be8SGregory Herrero * g_using_dma is set depending on dts flag. 9047a1685fSDinh Nguyen */ 91941fcce4SDinh Nguyen static inline bool using_dma(struct dwc2_hsotg *hsotg) 9247a1685fSDinh Nguyen { 9305ee799fSJohn Youn return hsotg->params.g_dma; 9447a1685fSDinh Nguyen } 9547a1685fSDinh Nguyen 96dec4b556SVahram Aharonyan /* 97dec4b556SVahram Aharonyan * using_desc_dma - return the descriptor DMA status of the driver. 98dec4b556SVahram Aharonyan * @hsotg: The driver state. 99dec4b556SVahram Aharonyan * 100dec4b556SVahram Aharonyan * Return true if we're using descriptor DMA. 101dec4b556SVahram Aharonyan */ 102dec4b556SVahram Aharonyan static inline bool using_desc_dma(struct dwc2_hsotg *hsotg) 103dec4b556SVahram Aharonyan { 104dec4b556SVahram Aharonyan return hsotg->params.g_dma_desc; 105dec4b556SVahram Aharonyan } 106dec4b556SVahram Aharonyan 10747a1685fSDinh Nguyen /** 10892d1635dSVardan Mikayelyan * dwc2_gadget_incr_frame_num - Increments the targeted frame number. 10992d1635dSVardan Mikayelyan * @hs_ep: The endpoint 11092d1635dSVardan Mikayelyan * @increment: The value to increment by 11192d1635dSVardan Mikayelyan * 11292d1635dSVardan Mikayelyan * This function will also check if the frame number overruns DSTS_SOFFN_LIMIT. 11392d1635dSVardan Mikayelyan * If an overrun occurs it will wrap the value and set the frame_overrun flag. 11492d1635dSVardan Mikayelyan */ 11592d1635dSVardan Mikayelyan static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep) 11692d1635dSVardan Mikayelyan { 11792d1635dSVardan Mikayelyan hs_ep->target_frame += hs_ep->interval; 11892d1635dSVardan Mikayelyan if (hs_ep->target_frame > DSTS_SOFFN_LIMIT) { 119c1d5df69SGustavo A. R. Silva hs_ep->frame_overrun = true; 12092d1635dSVardan Mikayelyan hs_ep->target_frame &= DSTS_SOFFN_LIMIT; 12192d1635dSVardan Mikayelyan } else { 122c1d5df69SGustavo A. R. Silva hs_ep->frame_overrun = false; 12392d1635dSVardan Mikayelyan } 12492d1635dSVardan Mikayelyan } 12592d1635dSVardan Mikayelyan 12692d1635dSVardan Mikayelyan /** 1271f91b4ccSFelipe Balbi * dwc2_hsotg_en_gsint - enable one or more of the general interrupt 12847a1685fSDinh Nguyen * @hsotg: The device state 12947a1685fSDinh Nguyen * @ints: A bitmask of the interrupts to enable 13047a1685fSDinh Nguyen */ 1311f91b4ccSFelipe Balbi static void dwc2_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints) 13247a1685fSDinh Nguyen { 13395c8bc36SAntti Seppälä u32 gsintmsk = dwc2_readl(hsotg->regs + GINTMSK); 13447a1685fSDinh Nguyen u32 new_gsintmsk; 13547a1685fSDinh Nguyen 13647a1685fSDinh Nguyen new_gsintmsk = gsintmsk | ints; 13747a1685fSDinh Nguyen 13847a1685fSDinh Nguyen if (new_gsintmsk != gsintmsk) { 13947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); 14095c8bc36SAntti Seppälä dwc2_writel(new_gsintmsk, hsotg->regs + GINTMSK); 14147a1685fSDinh Nguyen } 14247a1685fSDinh Nguyen } 14347a1685fSDinh Nguyen 14447a1685fSDinh Nguyen /** 1451f91b4ccSFelipe Balbi * dwc2_hsotg_disable_gsint - disable one or more of the general interrupt 14647a1685fSDinh Nguyen * @hsotg: The device state 14747a1685fSDinh Nguyen * @ints: A bitmask of the interrupts to enable 14847a1685fSDinh Nguyen */ 1491f91b4ccSFelipe Balbi static void dwc2_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints) 15047a1685fSDinh Nguyen { 15195c8bc36SAntti Seppälä u32 gsintmsk = dwc2_readl(hsotg->regs + GINTMSK); 15247a1685fSDinh Nguyen u32 new_gsintmsk; 15347a1685fSDinh Nguyen 15447a1685fSDinh Nguyen new_gsintmsk = gsintmsk & ~ints; 15547a1685fSDinh Nguyen 15647a1685fSDinh Nguyen if (new_gsintmsk != gsintmsk) 15795c8bc36SAntti Seppälä dwc2_writel(new_gsintmsk, hsotg->regs + GINTMSK); 15847a1685fSDinh Nguyen } 15947a1685fSDinh Nguyen 16047a1685fSDinh Nguyen /** 1611f91b4ccSFelipe Balbi * dwc2_hsotg_ctrl_epint - enable/disable an endpoint irq 16247a1685fSDinh Nguyen * @hsotg: The device state 16347a1685fSDinh Nguyen * @ep: The endpoint index 16447a1685fSDinh Nguyen * @dir_in: True if direction is in. 16547a1685fSDinh Nguyen * @en: The enable value, true to enable 16647a1685fSDinh Nguyen * 16747a1685fSDinh Nguyen * Set or clear the mask for an individual endpoint's interrupt 16847a1685fSDinh Nguyen * request. 16947a1685fSDinh Nguyen */ 1701f91b4ccSFelipe Balbi static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, 17147a1685fSDinh Nguyen unsigned int ep, unsigned int dir_in, 17247a1685fSDinh Nguyen unsigned int en) 17347a1685fSDinh Nguyen { 17447a1685fSDinh Nguyen unsigned long flags; 17547a1685fSDinh Nguyen u32 bit = 1 << ep; 17647a1685fSDinh Nguyen u32 daint; 17747a1685fSDinh Nguyen 17847a1685fSDinh Nguyen if (!dir_in) 17947a1685fSDinh Nguyen bit <<= 16; 18047a1685fSDinh Nguyen 18147a1685fSDinh Nguyen local_irq_save(flags); 18295c8bc36SAntti Seppälä daint = dwc2_readl(hsotg->regs + DAINTMSK); 18347a1685fSDinh Nguyen if (en) 18447a1685fSDinh Nguyen daint |= bit; 18547a1685fSDinh Nguyen else 18647a1685fSDinh Nguyen daint &= ~bit; 18795c8bc36SAntti Seppälä dwc2_writel(daint, hsotg->regs + DAINTMSK); 18847a1685fSDinh Nguyen local_irq_restore(flags); 18947a1685fSDinh Nguyen } 19047a1685fSDinh Nguyen 19147a1685fSDinh Nguyen /** 192c138ecfaSSevak Arakelyan * dwc2_hsotg_tx_fifo_count - return count of TX FIFOs in device mode 193c138ecfaSSevak Arakelyan */ 194c138ecfaSSevak Arakelyan int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) 195c138ecfaSSevak Arakelyan { 196c138ecfaSSevak Arakelyan if (hsotg->hw_params.en_multiple_tx_fifo) 197c138ecfaSSevak Arakelyan /* In dedicated FIFO mode we need count of IN EPs */ 1989273083aSMinas Harutyunyan return hsotg->hw_params.num_dev_in_eps; 199c138ecfaSSevak Arakelyan else 200c138ecfaSSevak Arakelyan /* In shared FIFO mode we need count of Periodic IN EPs */ 201c138ecfaSSevak Arakelyan return hsotg->hw_params.num_dev_perio_in_ep; 202c138ecfaSSevak Arakelyan } 203c138ecfaSSevak Arakelyan 204c138ecfaSSevak Arakelyan /** 205c138ecfaSSevak Arakelyan * dwc2_hsotg_tx_fifo_total_depth - return total FIFO depth available for 206c138ecfaSSevak Arakelyan * device mode TX FIFOs 207c138ecfaSSevak Arakelyan */ 208c138ecfaSSevak Arakelyan int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) 209c138ecfaSSevak Arakelyan { 210c138ecfaSSevak Arakelyan int addr; 211c138ecfaSSevak Arakelyan int tx_addr_max; 212c138ecfaSSevak Arakelyan u32 np_tx_fifo_size; 213c138ecfaSSevak Arakelyan 214c138ecfaSSevak Arakelyan np_tx_fifo_size = min_t(u32, hsotg->hw_params.dev_nperio_tx_fifo_size, 215c138ecfaSSevak Arakelyan hsotg->params.g_np_tx_fifo_size); 216c138ecfaSSevak Arakelyan 217c138ecfaSSevak Arakelyan /* Get Endpoint Info Control block size in DWORDs. */ 2189273083aSMinas Harutyunyan tx_addr_max = hsotg->hw_params.total_fifo_size; 219c138ecfaSSevak Arakelyan 220c138ecfaSSevak Arakelyan addr = hsotg->params.g_rx_fifo_size + np_tx_fifo_size; 221c138ecfaSSevak Arakelyan if (tx_addr_max <= addr) 222c138ecfaSSevak Arakelyan return 0; 223c138ecfaSSevak Arakelyan 224c138ecfaSSevak Arakelyan return tx_addr_max - addr; 225c138ecfaSSevak Arakelyan } 226c138ecfaSSevak Arakelyan 227c138ecfaSSevak Arakelyan /** 228c138ecfaSSevak Arakelyan * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode 229c138ecfaSSevak Arakelyan * TX FIFOs 230c138ecfaSSevak Arakelyan */ 231c138ecfaSSevak Arakelyan int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) 232c138ecfaSSevak Arakelyan { 233c138ecfaSSevak Arakelyan int tx_fifo_count; 234c138ecfaSSevak Arakelyan int tx_fifo_depth; 235c138ecfaSSevak Arakelyan 236c138ecfaSSevak Arakelyan tx_fifo_depth = dwc2_hsotg_tx_fifo_total_depth(hsotg); 237c138ecfaSSevak Arakelyan 238c138ecfaSSevak Arakelyan tx_fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); 239c138ecfaSSevak Arakelyan 240c138ecfaSSevak Arakelyan if (!tx_fifo_count) 241c138ecfaSSevak Arakelyan return tx_fifo_depth; 242c138ecfaSSevak Arakelyan else 243c138ecfaSSevak Arakelyan return tx_fifo_depth / tx_fifo_count; 244c138ecfaSSevak Arakelyan } 245c138ecfaSSevak Arakelyan 246c138ecfaSSevak Arakelyan /** 2471f91b4ccSFelipe Balbi * dwc2_hsotg_init_fifo - initialise non-periodic FIFOs 24847a1685fSDinh Nguyen * @hsotg: The device instance. 24947a1685fSDinh Nguyen */ 2501f91b4ccSFelipe Balbi static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) 25147a1685fSDinh Nguyen { 2522317eacdSJohn Youn unsigned int ep; 25347a1685fSDinh Nguyen unsigned int addr; 25447a1685fSDinh Nguyen int timeout; 25579d6b8c5SSevak Arakelyan 25647a1685fSDinh Nguyen u32 val; 25705ee799fSJohn Youn u32 *txfsz = hsotg->params.g_tx_fifo_size; 25847a1685fSDinh Nguyen 2597fcbc95cSGregory Herrero /* Reset fifo map if not correctly cleared during previous session */ 2607fcbc95cSGregory Herrero WARN_ON(hsotg->fifo_map); 2617fcbc95cSGregory Herrero hsotg->fifo_map = 0; 2627fcbc95cSGregory Herrero 2630a176279SGregory Herrero /* set RX/NPTX FIFO sizes */ 26405ee799fSJohn Youn dwc2_writel(hsotg->params.g_rx_fifo_size, hsotg->regs + GRXFSIZ); 26505ee799fSJohn Youn dwc2_writel((hsotg->params.g_rx_fifo_size << FIFOSIZE_STARTADDR_SHIFT) | 26605ee799fSJohn Youn (hsotg->params.g_np_tx_fifo_size << FIFOSIZE_DEPTH_SHIFT), 2670a176279SGregory Herrero hsotg->regs + GNPTXFSIZ); 26847a1685fSDinh Nguyen 26947a1685fSDinh Nguyen /* 27047a1685fSDinh Nguyen * arange all the rest of the TX FIFOs, as some versions of this 27147a1685fSDinh Nguyen * block have overlapping default addresses. This also ensures 27247a1685fSDinh Nguyen * that if the settings have been changed, then they are set to 27347a1685fSDinh Nguyen * known values. 27447a1685fSDinh Nguyen */ 27547a1685fSDinh Nguyen 27647a1685fSDinh Nguyen /* start at the end of the GNPTXFSIZ, rounded up */ 27705ee799fSJohn Youn addr = hsotg->params.g_rx_fifo_size + hsotg->params.g_np_tx_fifo_size; 27847a1685fSDinh Nguyen 27947a1685fSDinh Nguyen /* 2800a176279SGregory Herrero * Configure fifos sizes from provided configuration and assign 281b203d0a2SRobert Baldyga * them to endpoints dynamically according to maxpacket size value of 282b203d0a2SRobert Baldyga * given endpoint. 28347a1685fSDinh Nguyen */ 2842317eacdSJohn Youn for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) { 28505ee799fSJohn Youn if (!txfsz[ep]) 2863fa95385SJohn Youn continue; 2873fa95385SJohn Youn val = addr; 28805ee799fSJohn Youn val |= txfsz[ep] << FIFOSIZE_DEPTH_SHIFT; 28905ee799fSJohn Youn WARN_ONCE(addr + txfsz[ep] > hsotg->fifo_mem, 2903fa95385SJohn Youn "insufficient fifo memory"); 29105ee799fSJohn Youn addr += txfsz[ep]; 29247a1685fSDinh Nguyen 2932317eacdSJohn Youn dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep)); 29405ee799fSJohn Youn val = dwc2_readl(hsotg->regs + DPTXFSIZN(ep)); 29547a1685fSDinh Nguyen } 29647a1685fSDinh Nguyen 297f87c842fSSevak Arakelyan dwc2_writel(hsotg->hw_params.total_fifo_size | 298f87c842fSSevak Arakelyan addr << GDFIFOCFG_EPINFOBASE_SHIFT, 299f87c842fSSevak Arakelyan hsotg->regs + GDFIFOCFG); 30047a1685fSDinh Nguyen /* 30147a1685fSDinh Nguyen * according to p428 of the design guide, we need to ensure that 30247a1685fSDinh Nguyen * all fifos are flushed before continuing 30347a1685fSDinh Nguyen */ 30447a1685fSDinh Nguyen 30595c8bc36SAntti Seppälä dwc2_writel(GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | 30647a1685fSDinh Nguyen GRSTCTL_RXFFLSH, hsotg->regs + GRSTCTL); 30747a1685fSDinh Nguyen 30847a1685fSDinh Nguyen /* wait until the fifos are both flushed */ 30947a1685fSDinh Nguyen timeout = 100; 31047a1685fSDinh Nguyen while (1) { 31195c8bc36SAntti Seppälä val = dwc2_readl(hsotg->regs + GRSTCTL); 31247a1685fSDinh Nguyen 31347a1685fSDinh Nguyen if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0) 31447a1685fSDinh Nguyen break; 31547a1685fSDinh Nguyen 31647a1685fSDinh Nguyen if (--timeout == 0) { 31747a1685fSDinh Nguyen dev_err(hsotg->dev, 31847a1685fSDinh Nguyen "%s: timeout flushing fifos (GRSTCTL=%08x)\n", 31947a1685fSDinh Nguyen __func__, val); 32048b20bcbSGregory Herrero break; 32147a1685fSDinh Nguyen } 32247a1685fSDinh Nguyen 32347a1685fSDinh Nguyen udelay(1); 32447a1685fSDinh Nguyen } 32547a1685fSDinh Nguyen 32647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); 32747a1685fSDinh Nguyen } 32847a1685fSDinh Nguyen 32947a1685fSDinh Nguyen /** 33047a1685fSDinh Nguyen * @ep: USB endpoint to allocate request for. 33147a1685fSDinh Nguyen * @flags: Allocation flags 33247a1685fSDinh Nguyen * 33347a1685fSDinh Nguyen * Allocate a new USB request structure appropriate for the specified endpoint 33447a1685fSDinh Nguyen */ 3351f91b4ccSFelipe Balbi static struct usb_request *dwc2_hsotg_ep_alloc_request(struct usb_ep *ep, 33647a1685fSDinh Nguyen gfp_t flags) 33747a1685fSDinh Nguyen { 3381f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req; 33947a1685fSDinh Nguyen 340ec33efe2SJohn Youn req = kzalloc(sizeof(*req), flags); 34147a1685fSDinh Nguyen if (!req) 34247a1685fSDinh Nguyen return NULL; 34347a1685fSDinh Nguyen 34447a1685fSDinh Nguyen INIT_LIST_HEAD(&req->queue); 34547a1685fSDinh Nguyen 34647a1685fSDinh Nguyen return &req->req; 34747a1685fSDinh Nguyen } 34847a1685fSDinh Nguyen 34947a1685fSDinh Nguyen /** 35047a1685fSDinh Nguyen * is_ep_periodic - return true if the endpoint is in periodic mode. 35147a1685fSDinh Nguyen * @hs_ep: The endpoint to query. 35247a1685fSDinh Nguyen * 35347a1685fSDinh Nguyen * Returns true if the endpoint is in periodic mode, meaning it is being 35447a1685fSDinh Nguyen * used for an Interrupt or ISO transfer. 35547a1685fSDinh Nguyen */ 3561f91b4ccSFelipe Balbi static inline int is_ep_periodic(struct dwc2_hsotg_ep *hs_ep) 35747a1685fSDinh Nguyen { 35847a1685fSDinh Nguyen return hs_ep->periodic; 35947a1685fSDinh Nguyen } 36047a1685fSDinh Nguyen 36147a1685fSDinh Nguyen /** 3621f91b4ccSFelipe Balbi * dwc2_hsotg_unmap_dma - unmap the DMA memory being used for the request 36347a1685fSDinh Nguyen * @hsotg: The device state. 36447a1685fSDinh Nguyen * @hs_ep: The endpoint for the request 36547a1685fSDinh Nguyen * @hs_req: The request being processed. 36647a1685fSDinh Nguyen * 3671f91b4ccSFelipe Balbi * This is the reverse of dwc2_hsotg_map_dma(), called for the completion 36847a1685fSDinh Nguyen * of a request to ensure the buffer is ready for access by the caller. 36947a1685fSDinh Nguyen */ 3701f91b4ccSFelipe Balbi static void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg, 3711f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 3721f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req) 37347a1685fSDinh Nguyen { 37447a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 3759da51974SJohn Youn 37647a1685fSDinh Nguyen usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); 37747a1685fSDinh Nguyen } 37847a1685fSDinh Nguyen 3790f6b80c0SVahram Aharonyan /* 3800f6b80c0SVahram Aharonyan * dwc2_gadget_alloc_ctrl_desc_chains - allocate DMA descriptor chains 3810f6b80c0SVahram Aharonyan * for Control endpoint 3820f6b80c0SVahram Aharonyan * @hsotg: The device state. 3830f6b80c0SVahram Aharonyan * 3840f6b80c0SVahram Aharonyan * This function will allocate 4 descriptor chains for EP 0: 2 for 3850f6b80c0SVahram Aharonyan * Setup stage, per one for IN and OUT data/status transactions. 3860f6b80c0SVahram Aharonyan */ 3870f6b80c0SVahram Aharonyan static int dwc2_gadget_alloc_ctrl_desc_chains(struct dwc2_hsotg *hsotg) 3880f6b80c0SVahram Aharonyan { 3890f6b80c0SVahram Aharonyan hsotg->setup_desc[0] = 3900f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 3910f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 3920f6b80c0SVahram Aharonyan &hsotg->setup_desc_dma[0], 3930f6b80c0SVahram Aharonyan GFP_KERNEL); 3940f6b80c0SVahram Aharonyan if (!hsotg->setup_desc[0]) 3950f6b80c0SVahram Aharonyan goto fail; 3960f6b80c0SVahram Aharonyan 3970f6b80c0SVahram Aharonyan hsotg->setup_desc[1] = 3980f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 3990f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 4000f6b80c0SVahram Aharonyan &hsotg->setup_desc_dma[1], 4010f6b80c0SVahram Aharonyan GFP_KERNEL); 4020f6b80c0SVahram Aharonyan if (!hsotg->setup_desc[1]) 4030f6b80c0SVahram Aharonyan goto fail; 4040f6b80c0SVahram Aharonyan 4050f6b80c0SVahram Aharonyan hsotg->ctrl_in_desc = 4060f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 4070f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 4080f6b80c0SVahram Aharonyan &hsotg->ctrl_in_desc_dma, 4090f6b80c0SVahram Aharonyan GFP_KERNEL); 4100f6b80c0SVahram Aharonyan if (!hsotg->ctrl_in_desc) 4110f6b80c0SVahram Aharonyan goto fail; 4120f6b80c0SVahram Aharonyan 4130f6b80c0SVahram Aharonyan hsotg->ctrl_out_desc = 4140f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 4150f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 4160f6b80c0SVahram Aharonyan &hsotg->ctrl_out_desc_dma, 4170f6b80c0SVahram Aharonyan GFP_KERNEL); 4180f6b80c0SVahram Aharonyan if (!hsotg->ctrl_out_desc) 4190f6b80c0SVahram Aharonyan goto fail; 4200f6b80c0SVahram Aharonyan 4210f6b80c0SVahram Aharonyan return 0; 4220f6b80c0SVahram Aharonyan 4230f6b80c0SVahram Aharonyan fail: 4240f6b80c0SVahram Aharonyan return -ENOMEM; 4250f6b80c0SVahram Aharonyan } 4260f6b80c0SVahram Aharonyan 42747a1685fSDinh Nguyen /** 4281f91b4ccSFelipe Balbi * dwc2_hsotg_write_fifo - write packet Data to the TxFIFO 42947a1685fSDinh Nguyen * @hsotg: The controller state. 43047a1685fSDinh Nguyen * @hs_ep: The endpoint we're going to write for. 43147a1685fSDinh Nguyen * @hs_req: The request to write data for. 43247a1685fSDinh Nguyen * 43347a1685fSDinh Nguyen * This is called when the TxFIFO has some space in it to hold a new 43447a1685fSDinh Nguyen * transmission and we have something to give it. The actual setup of 43547a1685fSDinh Nguyen * the data size is done elsewhere, so all we have to do is to actually 43647a1685fSDinh Nguyen * write the data. 43747a1685fSDinh Nguyen * 43847a1685fSDinh Nguyen * The return value is zero if there is more space (or nothing was done) 43947a1685fSDinh Nguyen * otherwise -ENOSPC is returned if the FIFO space was used up. 44047a1685fSDinh Nguyen * 44147a1685fSDinh Nguyen * This routine is only needed for PIO 44247a1685fSDinh Nguyen */ 4431f91b4ccSFelipe Balbi static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, 4441f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 4451f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req) 44647a1685fSDinh Nguyen { 44747a1685fSDinh Nguyen bool periodic = is_ep_periodic(hs_ep); 44895c8bc36SAntti Seppälä u32 gnptxsts = dwc2_readl(hsotg->regs + GNPTXSTS); 44947a1685fSDinh Nguyen int buf_pos = hs_req->req.actual; 45047a1685fSDinh Nguyen int to_write = hs_ep->size_loaded; 45147a1685fSDinh Nguyen void *data; 45247a1685fSDinh Nguyen int can_write; 45347a1685fSDinh Nguyen int pkt_round; 45447a1685fSDinh Nguyen int max_transfer; 45547a1685fSDinh Nguyen 45647a1685fSDinh Nguyen to_write -= (buf_pos - hs_ep->last_load); 45747a1685fSDinh Nguyen 45847a1685fSDinh Nguyen /* if there's nothing to write, get out early */ 45947a1685fSDinh Nguyen if (to_write == 0) 46047a1685fSDinh Nguyen return 0; 46147a1685fSDinh Nguyen 46247a1685fSDinh Nguyen if (periodic && !hsotg->dedicated_fifos) { 46395c8bc36SAntti Seppälä u32 epsize = dwc2_readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); 46447a1685fSDinh Nguyen int size_left; 46547a1685fSDinh Nguyen int size_done; 46647a1685fSDinh Nguyen 46747a1685fSDinh Nguyen /* 46847a1685fSDinh Nguyen * work out how much data was loaded so we can calculate 46947a1685fSDinh Nguyen * how much data is left in the fifo. 47047a1685fSDinh Nguyen */ 47147a1685fSDinh Nguyen 47247a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 47347a1685fSDinh Nguyen 47447a1685fSDinh Nguyen /* 47547a1685fSDinh Nguyen * if shared fifo, we cannot write anything until the 47647a1685fSDinh Nguyen * previous data has been completely sent. 47747a1685fSDinh Nguyen */ 47847a1685fSDinh Nguyen if (hs_ep->fifo_load != 0) { 4791f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 48047a1685fSDinh Nguyen return -ENOSPC; 48147a1685fSDinh Nguyen } 48247a1685fSDinh Nguyen 48347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", 48447a1685fSDinh Nguyen __func__, size_left, 48547a1685fSDinh Nguyen hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); 48647a1685fSDinh Nguyen 48747a1685fSDinh Nguyen /* how much of the data has moved */ 48847a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 48947a1685fSDinh Nguyen 49047a1685fSDinh Nguyen /* how much data is left in the fifo */ 49147a1685fSDinh Nguyen can_write = hs_ep->fifo_load - size_done; 49247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", 49347a1685fSDinh Nguyen __func__, can_write); 49447a1685fSDinh Nguyen 49547a1685fSDinh Nguyen can_write = hs_ep->fifo_size - can_write; 49647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", 49747a1685fSDinh Nguyen __func__, can_write); 49847a1685fSDinh Nguyen 49947a1685fSDinh Nguyen if (can_write <= 0) { 5001f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 50147a1685fSDinh Nguyen return -ENOSPC; 50247a1685fSDinh Nguyen } 50347a1685fSDinh Nguyen } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { 504ad674a15SRobert Baldyga can_write = dwc2_readl(hsotg->regs + 505ad674a15SRobert Baldyga DTXFSTS(hs_ep->fifo_index)); 50647a1685fSDinh Nguyen 50747a1685fSDinh Nguyen can_write &= 0xffff; 50847a1685fSDinh Nguyen can_write *= 4; 50947a1685fSDinh Nguyen } else { 51047a1685fSDinh Nguyen if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) { 51147a1685fSDinh Nguyen dev_dbg(hsotg->dev, 51247a1685fSDinh Nguyen "%s: no queue slots available (0x%08x)\n", 51347a1685fSDinh Nguyen __func__, gnptxsts); 51447a1685fSDinh Nguyen 5151f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP); 51647a1685fSDinh Nguyen return -ENOSPC; 51747a1685fSDinh Nguyen } 51847a1685fSDinh Nguyen 51947a1685fSDinh Nguyen can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts); 52047a1685fSDinh Nguyen can_write *= 4; /* fifo size is in 32bit quantities. */ 52147a1685fSDinh Nguyen } 52247a1685fSDinh Nguyen 52347a1685fSDinh Nguyen max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; 52447a1685fSDinh Nguyen 52547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", 52647a1685fSDinh Nguyen __func__, gnptxsts, can_write, to_write, max_transfer); 52747a1685fSDinh Nguyen 52847a1685fSDinh Nguyen /* 52947a1685fSDinh Nguyen * limit to 512 bytes of data, it seems at least on the non-periodic 53047a1685fSDinh Nguyen * FIFO, requests of >512 cause the endpoint to get stuck with a 53147a1685fSDinh Nguyen * fragment of the end of the transfer in it. 53247a1685fSDinh Nguyen */ 53347a1685fSDinh Nguyen if (can_write > 512 && !periodic) 53447a1685fSDinh Nguyen can_write = 512; 53547a1685fSDinh Nguyen 53647a1685fSDinh Nguyen /* 53747a1685fSDinh Nguyen * limit the write to one max-packet size worth of data, but allow 53847a1685fSDinh Nguyen * the transfer to return that it did not run out of fifo space 53947a1685fSDinh Nguyen * doing it. 54047a1685fSDinh Nguyen */ 54147a1685fSDinh Nguyen if (to_write > max_transfer) { 54247a1685fSDinh Nguyen to_write = max_transfer; 54347a1685fSDinh Nguyen 54447a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 54547a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 5461f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, 54747a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 54847a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 54947a1685fSDinh Nguyen } 55047a1685fSDinh Nguyen 55147a1685fSDinh Nguyen /* see if we can write data */ 55247a1685fSDinh Nguyen 55347a1685fSDinh Nguyen if (to_write > can_write) { 55447a1685fSDinh Nguyen to_write = can_write; 55547a1685fSDinh Nguyen pkt_round = to_write % max_transfer; 55647a1685fSDinh Nguyen 55747a1685fSDinh Nguyen /* 55847a1685fSDinh Nguyen * Round the write down to an 55947a1685fSDinh Nguyen * exact number of packets. 56047a1685fSDinh Nguyen * 56147a1685fSDinh Nguyen * Note, we do not currently check to see if we can ever 56247a1685fSDinh Nguyen * write a full packet or not to the FIFO. 56347a1685fSDinh Nguyen */ 56447a1685fSDinh Nguyen 56547a1685fSDinh Nguyen if (pkt_round) 56647a1685fSDinh Nguyen to_write -= pkt_round; 56747a1685fSDinh Nguyen 56847a1685fSDinh Nguyen /* 56947a1685fSDinh Nguyen * enable correct FIFO interrupt to alert us when there 57047a1685fSDinh Nguyen * is more room left. 57147a1685fSDinh Nguyen */ 57247a1685fSDinh Nguyen 57347a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 57447a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 5751f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, 57647a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 57747a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 57847a1685fSDinh Nguyen } 57947a1685fSDinh Nguyen 58047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", 58147a1685fSDinh Nguyen to_write, hs_req->req.length, can_write, buf_pos); 58247a1685fSDinh Nguyen 58347a1685fSDinh Nguyen if (to_write <= 0) 58447a1685fSDinh Nguyen return -ENOSPC; 58547a1685fSDinh Nguyen 58647a1685fSDinh Nguyen hs_req->req.actual = buf_pos + to_write; 58747a1685fSDinh Nguyen hs_ep->total_data += to_write; 58847a1685fSDinh Nguyen 58947a1685fSDinh Nguyen if (periodic) 59047a1685fSDinh Nguyen hs_ep->fifo_load += to_write; 59147a1685fSDinh Nguyen 59247a1685fSDinh Nguyen to_write = DIV_ROUND_UP(to_write, 4); 59347a1685fSDinh Nguyen data = hs_req->req.buf + buf_pos; 59447a1685fSDinh Nguyen 59547a1685fSDinh Nguyen iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); 59647a1685fSDinh Nguyen 59747a1685fSDinh Nguyen return (to_write >= can_write) ? -ENOSPC : 0; 59847a1685fSDinh Nguyen } 59947a1685fSDinh Nguyen 60047a1685fSDinh Nguyen /** 60147a1685fSDinh Nguyen * get_ep_limit - get the maximum data legnth for this endpoint 60247a1685fSDinh Nguyen * @hs_ep: The endpoint 60347a1685fSDinh Nguyen * 60447a1685fSDinh Nguyen * Return the maximum data that can be queued in one go on a given endpoint 60547a1685fSDinh Nguyen * so that transfers that are too long can be split. 60647a1685fSDinh Nguyen */ 6079da51974SJohn Youn static unsigned int get_ep_limit(struct dwc2_hsotg_ep *hs_ep) 60847a1685fSDinh Nguyen { 60947a1685fSDinh Nguyen int index = hs_ep->index; 6109da51974SJohn Youn unsigned int maxsize; 6119da51974SJohn Youn unsigned int maxpkt; 61247a1685fSDinh Nguyen 61347a1685fSDinh Nguyen if (index != 0) { 61447a1685fSDinh Nguyen maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; 61547a1685fSDinh Nguyen maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; 61647a1685fSDinh Nguyen } else { 61747a1685fSDinh Nguyen maxsize = 64 + 64; 61847a1685fSDinh Nguyen if (hs_ep->dir_in) 61947a1685fSDinh Nguyen maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; 62047a1685fSDinh Nguyen else 62147a1685fSDinh Nguyen maxpkt = 2; 62247a1685fSDinh Nguyen } 62347a1685fSDinh Nguyen 62447a1685fSDinh Nguyen /* we made the constant loading easier above by using +1 */ 62547a1685fSDinh Nguyen maxpkt--; 62647a1685fSDinh Nguyen maxsize--; 62747a1685fSDinh Nguyen 62847a1685fSDinh Nguyen /* 62947a1685fSDinh Nguyen * constrain by packet count if maxpkts*pktsize is greater 63047a1685fSDinh Nguyen * than the length register size. 63147a1685fSDinh Nguyen */ 63247a1685fSDinh Nguyen 63347a1685fSDinh Nguyen if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) 63447a1685fSDinh Nguyen maxsize = maxpkt * hs_ep->ep.maxpacket; 63547a1685fSDinh Nguyen 63647a1685fSDinh Nguyen return maxsize; 63747a1685fSDinh Nguyen } 63847a1685fSDinh Nguyen 63947a1685fSDinh Nguyen /** 640381fc8f8SVardan Mikayelyan * dwc2_hsotg_read_frameno - read current frame number 641381fc8f8SVardan Mikayelyan * @hsotg: The device instance 642381fc8f8SVardan Mikayelyan * 643381fc8f8SVardan Mikayelyan * Return the current frame number 644381fc8f8SVardan Mikayelyan */ 645381fc8f8SVardan Mikayelyan static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg) 646381fc8f8SVardan Mikayelyan { 647381fc8f8SVardan Mikayelyan u32 dsts; 648381fc8f8SVardan Mikayelyan 649381fc8f8SVardan Mikayelyan dsts = dwc2_readl(hsotg->regs + DSTS); 650381fc8f8SVardan Mikayelyan dsts &= DSTS_SOFFN_MASK; 651381fc8f8SVardan Mikayelyan dsts >>= DSTS_SOFFN_SHIFT; 652381fc8f8SVardan Mikayelyan 653381fc8f8SVardan Mikayelyan return dsts; 654381fc8f8SVardan Mikayelyan } 655381fc8f8SVardan Mikayelyan 656381fc8f8SVardan Mikayelyan /** 657cf77b5fbSVahram Aharonyan * dwc2_gadget_get_chain_limit - get the maximum data payload value of the 658cf77b5fbSVahram Aharonyan * DMA descriptor chain prepared for specific endpoint 659cf77b5fbSVahram Aharonyan * @hs_ep: The endpoint 660cf77b5fbSVahram Aharonyan * 661cf77b5fbSVahram Aharonyan * Return the maximum data that can be queued in one go on a given endpoint 662cf77b5fbSVahram Aharonyan * depending on its descriptor chain capacity so that transfers that 663cf77b5fbSVahram Aharonyan * are too long can be split. 664cf77b5fbSVahram Aharonyan */ 665cf77b5fbSVahram Aharonyan static unsigned int dwc2_gadget_get_chain_limit(struct dwc2_hsotg_ep *hs_ep) 666cf77b5fbSVahram Aharonyan { 667cf77b5fbSVahram Aharonyan int is_isoc = hs_ep->isochronous; 668cf77b5fbSVahram Aharonyan unsigned int maxsize; 669cf77b5fbSVahram Aharonyan 670cf77b5fbSVahram Aharonyan if (is_isoc) 671cf77b5fbSVahram Aharonyan maxsize = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_LIMIT : 672cf77b5fbSVahram Aharonyan DEV_DMA_ISOC_RX_NBYTES_LIMIT; 673cf77b5fbSVahram Aharonyan else 674cf77b5fbSVahram Aharonyan maxsize = DEV_DMA_NBYTES_LIMIT; 675cf77b5fbSVahram Aharonyan 676cf77b5fbSVahram Aharonyan /* Above size of one descriptor was chosen, multiple it */ 677cf77b5fbSVahram Aharonyan maxsize *= MAX_DMA_DESC_NUM_GENERIC; 678cf77b5fbSVahram Aharonyan 679cf77b5fbSVahram Aharonyan return maxsize; 680cf77b5fbSVahram Aharonyan } 681cf77b5fbSVahram Aharonyan 682e02f9aa6SVahram Aharonyan /* 683e02f9aa6SVahram Aharonyan * dwc2_gadget_get_desc_params - get DMA descriptor parameters. 684e02f9aa6SVahram Aharonyan * @hs_ep: The endpoint 685e02f9aa6SVahram Aharonyan * @mask: RX/TX bytes mask to be defined 686e02f9aa6SVahram Aharonyan * 687e02f9aa6SVahram Aharonyan * Returns maximum data payload for one descriptor after analyzing endpoint 688e02f9aa6SVahram Aharonyan * characteristics. 689e02f9aa6SVahram Aharonyan * DMA descriptor transfer bytes limit depends on EP type: 690e02f9aa6SVahram Aharonyan * Control out - MPS, 691e02f9aa6SVahram Aharonyan * Isochronous - descriptor rx/tx bytes bitfield limit, 692e02f9aa6SVahram Aharonyan * Control In/Bulk/Interrupt - multiple of mps. This will allow to not 693e02f9aa6SVahram Aharonyan * have concatenations from various descriptors within one packet. 694e02f9aa6SVahram Aharonyan * 695e02f9aa6SVahram Aharonyan * Selects corresponding mask for RX/TX bytes as well. 696e02f9aa6SVahram Aharonyan */ 697e02f9aa6SVahram Aharonyan static u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask) 698e02f9aa6SVahram Aharonyan { 699e02f9aa6SVahram Aharonyan u32 mps = hs_ep->ep.maxpacket; 700e02f9aa6SVahram Aharonyan int dir_in = hs_ep->dir_in; 701e02f9aa6SVahram Aharonyan u32 desc_size = 0; 702e02f9aa6SVahram Aharonyan 703e02f9aa6SVahram Aharonyan if (!hs_ep->index && !dir_in) { 704e02f9aa6SVahram Aharonyan desc_size = mps; 705e02f9aa6SVahram Aharonyan *mask = DEV_DMA_NBYTES_MASK; 706e02f9aa6SVahram Aharonyan } else if (hs_ep->isochronous) { 707e02f9aa6SVahram Aharonyan if (dir_in) { 708e02f9aa6SVahram Aharonyan desc_size = DEV_DMA_ISOC_TX_NBYTES_LIMIT; 709e02f9aa6SVahram Aharonyan *mask = DEV_DMA_ISOC_TX_NBYTES_MASK; 710e02f9aa6SVahram Aharonyan } else { 711e02f9aa6SVahram Aharonyan desc_size = DEV_DMA_ISOC_RX_NBYTES_LIMIT; 712e02f9aa6SVahram Aharonyan *mask = DEV_DMA_ISOC_RX_NBYTES_MASK; 713e02f9aa6SVahram Aharonyan } 714e02f9aa6SVahram Aharonyan } else { 715e02f9aa6SVahram Aharonyan desc_size = DEV_DMA_NBYTES_LIMIT; 716e02f9aa6SVahram Aharonyan *mask = DEV_DMA_NBYTES_MASK; 717e02f9aa6SVahram Aharonyan 718e02f9aa6SVahram Aharonyan /* Round down desc_size to be mps multiple */ 719e02f9aa6SVahram Aharonyan desc_size -= desc_size % mps; 720e02f9aa6SVahram Aharonyan } 721e02f9aa6SVahram Aharonyan 722e02f9aa6SVahram Aharonyan return desc_size; 723e02f9aa6SVahram Aharonyan } 724e02f9aa6SVahram Aharonyan 725e02f9aa6SVahram Aharonyan /* 726e02f9aa6SVahram Aharonyan * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. 727e02f9aa6SVahram Aharonyan * @hs_ep: The endpoint 728e02f9aa6SVahram Aharonyan * @dma_buff: DMA address to use 729e02f9aa6SVahram Aharonyan * @len: Length of the transfer 730e02f9aa6SVahram Aharonyan * 731e02f9aa6SVahram Aharonyan * This function will iterate over descriptor chain and fill its entries 732e02f9aa6SVahram Aharonyan * with corresponding information based on transfer data. 733e02f9aa6SVahram Aharonyan */ 734e02f9aa6SVahram Aharonyan static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, 735e02f9aa6SVahram Aharonyan dma_addr_t dma_buff, 736e02f9aa6SVahram Aharonyan unsigned int len) 737e02f9aa6SVahram Aharonyan { 738e02f9aa6SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 739e02f9aa6SVahram Aharonyan int dir_in = hs_ep->dir_in; 740e02f9aa6SVahram Aharonyan struct dwc2_dma_desc *desc = hs_ep->desc_list; 741e02f9aa6SVahram Aharonyan u32 mps = hs_ep->ep.maxpacket; 742e02f9aa6SVahram Aharonyan u32 maxsize = 0; 743e02f9aa6SVahram Aharonyan u32 offset = 0; 744e02f9aa6SVahram Aharonyan u32 mask = 0; 745e02f9aa6SVahram Aharonyan int i; 746e02f9aa6SVahram Aharonyan 747e02f9aa6SVahram Aharonyan maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); 748e02f9aa6SVahram Aharonyan 749e02f9aa6SVahram Aharonyan hs_ep->desc_count = (len / maxsize) + 750e02f9aa6SVahram Aharonyan ((len % maxsize) ? 1 : 0); 751e02f9aa6SVahram Aharonyan if (len == 0) 752e02f9aa6SVahram Aharonyan hs_ep->desc_count = 1; 753e02f9aa6SVahram Aharonyan 754e02f9aa6SVahram Aharonyan for (i = 0; i < hs_ep->desc_count; ++i) { 755e02f9aa6SVahram Aharonyan desc->status = 0; 756e02f9aa6SVahram Aharonyan desc->status |= (DEV_DMA_BUFF_STS_HBUSY 757e02f9aa6SVahram Aharonyan << DEV_DMA_BUFF_STS_SHIFT); 758e02f9aa6SVahram Aharonyan 759e02f9aa6SVahram Aharonyan if (len > maxsize) { 760e02f9aa6SVahram Aharonyan if (!hs_ep->index && !dir_in) 761e02f9aa6SVahram Aharonyan desc->status |= (DEV_DMA_L | DEV_DMA_IOC); 762e02f9aa6SVahram Aharonyan 763e02f9aa6SVahram Aharonyan desc->status |= (maxsize << 764e02f9aa6SVahram Aharonyan DEV_DMA_NBYTES_SHIFT & mask); 765e02f9aa6SVahram Aharonyan desc->buf = dma_buff + offset; 766e02f9aa6SVahram Aharonyan 767e02f9aa6SVahram Aharonyan len -= maxsize; 768e02f9aa6SVahram Aharonyan offset += maxsize; 769e02f9aa6SVahram Aharonyan } else { 770e02f9aa6SVahram Aharonyan desc->status |= (DEV_DMA_L | DEV_DMA_IOC); 771e02f9aa6SVahram Aharonyan 772e02f9aa6SVahram Aharonyan if (dir_in) 773e02f9aa6SVahram Aharonyan desc->status |= (len % mps) ? DEV_DMA_SHORT : 774e02f9aa6SVahram Aharonyan ((hs_ep->send_zlp) ? DEV_DMA_SHORT : 0); 775e02f9aa6SVahram Aharonyan if (len > maxsize) 776e02f9aa6SVahram Aharonyan dev_err(hsotg->dev, "wrong len %d\n", len); 777e02f9aa6SVahram Aharonyan 778e02f9aa6SVahram Aharonyan desc->status |= 779e02f9aa6SVahram Aharonyan len << DEV_DMA_NBYTES_SHIFT & mask; 780e02f9aa6SVahram Aharonyan desc->buf = dma_buff + offset; 781e02f9aa6SVahram Aharonyan } 782e02f9aa6SVahram Aharonyan 783e02f9aa6SVahram Aharonyan desc->status &= ~DEV_DMA_BUFF_STS_MASK; 784e02f9aa6SVahram Aharonyan desc->status |= (DEV_DMA_BUFF_STS_HREADY 785e02f9aa6SVahram Aharonyan << DEV_DMA_BUFF_STS_SHIFT); 786e02f9aa6SVahram Aharonyan desc++; 787e02f9aa6SVahram Aharonyan } 788e02f9aa6SVahram Aharonyan } 789e02f9aa6SVahram Aharonyan 790540ccba0SVahram Aharonyan /* 791540ccba0SVahram Aharonyan * dwc2_gadget_fill_isoc_desc - fills next isochronous descriptor in chain. 792540ccba0SVahram Aharonyan * @hs_ep: The isochronous endpoint. 793540ccba0SVahram Aharonyan * @dma_buff: usb requests dma buffer. 794540ccba0SVahram Aharonyan * @len: usb request transfer length. 795540ccba0SVahram Aharonyan * 796729cac69SMinas Harutyunyan * Fills next free descriptor with the data of the arrived usb request, 797540ccba0SVahram Aharonyan * frame info, sets Last and IOC bits increments next_desc. If filled 798540ccba0SVahram Aharonyan * descriptor is not the first one, removes L bit from the previous descriptor 799540ccba0SVahram Aharonyan * status. 800540ccba0SVahram Aharonyan */ 801540ccba0SVahram Aharonyan static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, 802540ccba0SVahram Aharonyan dma_addr_t dma_buff, unsigned int len) 803540ccba0SVahram Aharonyan { 804540ccba0SVahram Aharonyan struct dwc2_dma_desc *desc; 805540ccba0SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 806540ccba0SVahram Aharonyan u32 index; 807540ccba0SVahram Aharonyan u32 maxsize = 0; 808540ccba0SVahram Aharonyan u32 mask = 0; 809540ccba0SVahram Aharonyan 810540ccba0SVahram Aharonyan maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); 811540ccba0SVahram Aharonyan 812729cac69SMinas Harutyunyan index = hs_ep->next_desc; 813540ccba0SVahram Aharonyan desc = &hs_ep->desc_list[index]; 814540ccba0SVahram Aharonyan 815729cac69SMinas Harutyunyan /* Check if descriptor chain full */ 816729cac69SMinas Harutyunyan if ((desc->status >> DEV_DMA_BUFF_STS_SHIFT) == 817729cac69SMinas Harutyunyan DEV_DMA_BUFF_STS_HREADY) { 818729cac69SMinas Harutyunyan dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__); 819729cac69SMinas Harutyunyan return 1; 820729cac69SMinas Harutyunyan } 821729cac69SMinas Harutyunyan 822540ccba0SVahram Aharonyan /* Clear L bit of previous desc if more than one entries in the chain */ 823540ccba0SVahram Aharonyan if (hs_ep->next_desc) 824540ccba0SVahram Aharonyan hs_ep->desc_list[index - 1].status &= ~DEV_DMA_L; 825540ccba0SVahram Aharonyan 826540ccba0SVahram Aharonyan dev_dbg(hsotg->dev, "%s: Filling ep %d, dir %s isoc desc # %d\n", 827540ccba0SVahram Aharonyan __func__, hs_ep->index, hs_ep->dir_in ? "in" : "out", index); 828540ccba0SVahram Aharonyan 829540ccba0SVahram Aharonyan desc->status = 0; 830540ccba0SVahram Aharonyan desc->status |= (DEV_DMA_BUFF_STS_HBUSY << DEV_DMA_BUFF_STS_SHIFT); 831540ccba0SVahram Aharonyan 832540ccba0SVahram Aharonyan desc->buf = dma_buff; 833540ccba0SVahram Aharonyan desc->status |= (DEV_DMA_L | DEV_DMA_IOC | 834540ccba0SVahram Aharonyan ((len << DEV_DMA_NBYTES_SHIFT) & mask)); 835540ccba0SVahram Aharonyan 836540ccba0SVahram Aharonyan if (hs_ep->dir_in) { 837540ccba0SVahram Aharonyan desc->status |= ((hs_ep->mc << DEV_DMA_ISOC_PID_SHIFT) & 838540ccba0SVahram Aharonyan DEV_DMA_ISOC_PID_MASK) | 839540ccba0SVahram Aharonyan ((len % hs_ep->ep.maxpacket) ? 840540ccba0SVahram Aharonyan DEV_DMA_SHORT : 0) | 841540ccba0SVahram Aharonyan ((hs_ep->target_frame << 842540ccba0SVahram Aharonyan DEV_DMA_ISOC_FRNUM_SHIFT) & 843540ccba0SVahram Aharonyan DEV_DMA_ISOC_FRNUM_MASK); 844540ccba0SVahram Aharonyan } 845540ccba0SVahram Aharonyan 846540ccba0SVahram Aharonyan desc->status &= ~DEV_DMA_BUFF_STS_MASK; 847540ccba0SVahram Aharonyan desc->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT); 848540ccba0SVahram Aharonyan 849729cac69SMinas Harutyunyan /* Increment frame number by interval for IN */ 850729cac69SMinas Harutyunyan if (hs_ep->dir_in) 851729cac69SMinas Harutyunyan dwc2_gadget_incr_frame_num(hs_ep); 852729cac69SMinas Harutyunyan 853540ccba0SVahram Aharonyan /* Update index of last configured entry in the chain */ 854540ccba0SVahram Aharonyan hs_ep->next_desc++; 855729cac69SMinas Harutyunyan if (hs_ep->next_desc >= MAX_DMA_DESC_NUM_GENERIC) 856729cac69SMinas Harutyunyan hs_ep->next_desc = 0; 857540ccba0SVahram Aharonyan 858540ccba0SVahram Aharonyan return 0; 859540ccba0SVahram Aharonyan } 860540ccba0SVahram Aharonyan 861540ccba0SVahram Aharonyan /* 862540ccba0SVahram Aharonyan * dwc2_gadget_start_isoc_ddma - start isochronous transfer in DDMA 863540ccba0SVahram Aharonyan * @hs_ep: The isochronous endpoint. 864540ccba0SVahram Aharonyan * 865729cac69SMinas Harutyunyan * Prepare descriptor chain for isochronous endpoints. Afterwards 866540ccba0SVahram Aharonyan * write DMA address to HW and enable the endpoint. 867540ccba0SVahram Aharonyan */ 868540ccba0SVahram Aharonyan static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) 869540ccba0SVahram Aharonyan { 870540ccba0SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 871540ccba0SVahram Aharonyan struct dwc2_hsotg_req *hs_req, *treq; 872540ccba0SVahram Aharonyan int index = hs_ep->index; 873540ccba0SVahram Aharonyan int ret; 874729cac69SMinas Harutyunyan int i; 875540ccba0SVahram Aharonyan u32 dma_reg; 876540ccba0SVahram Aharonyan u32 depctl; 877540ccba0SVahram Aharonyan u32 ctrl; 878729cac69SMinas Harutyunyan struct dwc2_dma_desc *desc; 879540ccba0SVahram Aharonyan 880540ccba0SVahram Aharonyan if (list_empty(&hs_ep->queue)) { 881540ccba0SVahram Aharonyan dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__); 882540ccba0SVahram Aharonyan return; 883540ccba0SVahram Aharonyan } 884540ccba0SVahram Aharonyan 885729cac69SMinas Harutyunyan /* Initialize descriptor chain by Host Busy status */ 886729cac69SMinas Harutyunyan for (i = 0; i < MAX_DMA_DESC_NUM_GENERIC; i++) { 887729cac69SMinas Harutyunyan desc = &hs_ep->desc_list[i]; 888729cac69SMinas Harutyunyan desc->status = 0; 889729cac69SMinas Harutyunyan desc->status |= (DEV_DMA_BUFF_STS_HBUSY 890729cac69SMinas Harutyunyan << DEV_DMA_BUFF_STS_SHIFT); 891729cac69SMinas Harutyunyan } 892729cac69SMinas Harutyunyan 893729cac69SMinas Harutyunyan hs_ep->next_desc = 0; 894540ccba0SVahram Aharonyan list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) { 895540ccba0SVahram Aharonyan ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, 896540ccba0SVahram Aharonyan hs_req->req.length); 897729cac69SMinas Harutyunyan if (ret) 898540ccba0SVahram Aharonyan break; 899540ccba0SVahram Aharonyan } 900540ccba0SVahram Aharonyan 901729cac69SMinas Harutyunyan hs_ep->compl_desc = 0; 902540ccba0SVahram Aharonyan depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 903540ccba0SVahram Aharonyan dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index); 904540ccba0SVahram Aharonyan 905540ccba0SVahram Aharonyan /* write descriptor chain address to control register */ 906540ccba0SVahram Aharonyan dwc2_writel(hs_ep->desc_list_dma, hsotg->regs + dma_reg); 907540ccba0SVahram Aharonyan 908540ccba0SVahram Aharonyan ctrl = dwc2_readl(hsotg->regs + depctl); 909540ccba0SVahram Aharonyan ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK; 910540ccba0SVahram Aharonyan dwc2_writel(ctrl, hsotg->regs + depctl); 911540ccba0SVahram Aharonyan } 912540ccba0SVahram Aharonyan 913cf77b5fbSVahram Aharonyan /** 9141f91b4ccSFelipe Balbi * dwc2_hsotg_start_req - start a USB request from an endpoint's queue 91547a1685fSDinh Nguyen * @hsotg: The controller state. 91647a1685fSDinh Nguyen * @hs_ep: The endpoint to process a request for 91747a1685fSDinh Nguyen * @hs_req: The request to start. 91847a1685fSDinh Nguyen * @continuing: True if we are doing more for the current request. 91947a1685fSDinh Nguyen * 92047a1685fSDinh Nguyen * Start the given request running by setting the endpoint registers 92147a1685fSDinh Nguyen * appropriately, and writing any data to the FIFOs. 92247a1685fSDinh Nguyen */ 9231f91b4ccSFelipe Balbi static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, 9241f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 9251f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req, 92647a1685fSDinh Nguyen bool continuing) 92747a1685fSDinh Nguyen { 92847a1685fSDinh Nguyen struct usb_request *ureq = &hs_req->req; 92947a1685fSDinh Nguyen int index = hs_ep->index; 93047a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 93147a1685fSDinh Nguyen u32 epctrl_reg; 93247a1685fSDinh Nguyen u32 epsize_reg; 93347a1685fSDinh Nguyen u32 epsize; 93447a1685fSDinh Nguyen u32 ctrl; 9359da51974SJohn Youn unsigned int length; 9369da51974SJohn Youn unsigned int packets; 9379da51974SJohn Youn unsigned int maxreq; 938aa3e8bc8SVahram Aharonyan unsigned int dma_reg; 93947a1685fSDinh Nguyen 94047a1685fSDinh Nguyen if (index != 0) { 94147a1685fSDinh Nguyen if (hs_ep->req && !continuing) { 94247a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: active request\n", __func__); 94347a1685fSDinh Nguyen WARN_ON(1); 94447a1685fSDinh Nguyen return; 94547a1685fSDinh Nguyen } else if (hs_ep->req != hs_req && continuing) { 94647a1685fSDinh Nguyen dev_err(hsotg->dev, 94747a1685fSDinh Nguyen "%s: continue different req\n", __func__); 94847a1685fSDinh Nguyen WARN_ON(1); 94947a1685fSDinh Nguyen return; 95047a1685fSDinh Nguyen } 95147a1685fSDinh Nguyen } 95247a1685fSDinh Nguyen 953aa3e8bc8SVahram Aharonyan dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); 95447a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 95547a1685fSDinh Nguyen epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 95647a1685fSDinh Nguyen 95747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", 95895c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctrl_reg), index, 95947a1685fSDinh Nguyen hs_ep->dir_in ? "in" : "out"); 96047a1685fSDinh Nguyen 96147a1685fSDinh Nguyen /* If endpoint is stalled, we will restart request later */ 96295c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctrl_reg); 96347a1685fSDinh Nguyen 964b2d4c54eSMian Yousaf Kaukab if (index && ctrl & DXEPCTL_STALL) { 96547a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); 96647a1685fSDinh Nguyen return; 96747a1685fSDinh Nguyen } 96847a1685fSDinh Nguyen 96947a1685fSDinh Nguyen length = ureq->length - ureq->actual; 97047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", 97147a1685fSDinh Nguyen ureq->length, ureq->actual); 97247a1685fSDinh Nguyen 973cf77b5fbSVahram Aharonyan if (!using_desc_dma(hsotg)) 97447a1685fSDinh Nguyen maxreq = get_ep_limit(hs_ep); 975cf77b5fbSVahram Aharonyan else 976cf77b5fbSVahram Aharonyan maxreq = dwc2_gadget_get_chain_limit(hs_ep); 977cf77b5fbSVahram Aharonyan 97847a1685fSDinh Nguyen if (length > maxreq) { 97947a1685fSDinh Nguyen int round = maxreq % hs_ep->ep.maxpacket; 98047a1685fSDinh Nguyen 98147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", 98247a1685fSDinh Nguyen __func__, length, maxreq, round); 98347a1685fSDinh Nguyen 98447a1685fSDinh Nguyen /* round down to multiple of packets */ 98547a1685fSDinh Nguyen if (round) 98647a1685fSDinh Nguyen maxreq -= round; 98747a1685fSDinh Nguyen 98847a1685fSDinh Nguyen length = maxreq; 98947a1685fSDinh Nguyen } 99047a1685fSDinh Nguyen 99147a1685fSDinh Nguyen if (length) 99247a1685fSDinh Nguyen packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); 99347a1685fSDinh Nguyen else 99447a1685fSDinh Nguyen packets = 1; /* send one packet if length is zero. */ 99547a1685fSDinh Nguyen 99647a1685fSDinh Nguyen if (hs_ep->isochronous && length > (hs_ep->mc * hs_ep->ep.maxpacket)) { 99747a1685fSDinh Nguyen dev_err(hsotg->dev, "req length > maxpacket*mc\n"); 99847a1685fSDinh Nguyen return; 99947a1685fSDinh Nguyen } 100047a1685fSDinh Nguyen 100147a1685fSDinh Nguyen if (dir_in && index != 0) 100247a1685fSDinh Nguyen if (hs_ep->isochronous) 100347a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(packets); 100447a1685fSDinh Nguyen else 100547a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(1); 100647a1685fSDinh Nguyen else 100747a1685fSDinh Nguyen epsize = 0; 100847a1685fSDinh Nguyen 100947a1685fSDinh Nguyen /* 1010f71b5e25SMian Yousaf Kaukab * zero length packet should be programmed on its own and should not 1011f71b5e25SMian Yousaf Kaukab * be counted in DIEPTSIZ.PktCnt with other packets. 101247a1685fSDinh Nguyen */ 1013f71b5e25SMian Yousaf Kaukab if (dir_in && ureq->zero && !continuing) { 1014f71b5e25SMian Yousaf Kaukab /* Test if zlp is actually required. */ 1015f71b5e25SMian Yousaf Kaukab if ((ureq->length >= hs_ep->ep.maxpacket) && 1016f71b5e25SMian Yousaf Kaukab !(ureq->length % hs_ep->ep.maxpacket)) 10178a20fa45SMian Yousaf Kaukab hs_ep->send_zlp = 1; 101847a1685fSDinh Nguyen } 101947a1685fSDinh Nguyen 102047a1685fSDinh Nguyen epsize |= DXEPTSIZ_PKTCNT(packets); 102147a1685fSDinh Nguyen epsize |= DXEPTSIZ_XFERSIZE(length); 102247a1685fSDinh Nguyen 102347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", 102447a1685fSDinh Nguyen __func__, packets, length, ureq->length, epsize, epsize_reg); 102547a1685fSDinh Nguyen 102647a1685fSDinh Nguyen /* store the request as the current one we're doing */ 102747a1685fSDinh Nguyen hs_ep->req = hs_req; 102847a1685fSDinh Nguyen 1029aa3e8bc8SVahram Aharonyan if (using_desc_dma(hsotg)) { 1030aa3e8bc8SVahram Aharonyan u32 offset = 0; 1031aa3e8bc8SVahram Aharonyan u32 mps = hs_ep->ep.maxpacket; 1032aa3e8bc8SVahram Aharonyan 1033aa3e8bc8SVahram Aharonyan /* Adjust length: EP0 - MPS, other OUT EPs - multiple of MPS */ 1034aa3e8bc8SVahram Aharonyan if (!dir_in) { 1035aa3e8bc8SVahram Aharonyan if (!index) 1036aa3e8bc8SVahram Aharonyan length = mps; 1037aa3e8bc8SVahram Aharonyan else if (length % mps) 1038aa3e8bc8SVahram Aharonyan length += (mps - (length % mps)); 1039aa3e8bc8SVahram Aharonyan } 1040aa3e8bc8SVahram Aharonyan 1041aa3e8bc8SVahram Aharonyan /* 1042aa3e8bc8SVahram Aharonyan * If more data to send, adjust DMA for EP0 out data stage. 1043aa3e8bc8SVahram Aharonyan * ureq->dma stays unchanged, hence increment it by already 1044aa3e8bc8SVahram Aharonyan * passed passed data count before starting new transaction. 1045aa3e8bc8SVahram Aharonyan */ 1046aa3e8bc8SVahram Aharonyan if (!index && hsotg->ep0_state == DWC2_EP0_DATA_OUT && 1047aa3e8bc8SVahram Aharonyan continuing) 1048aa3e8bc8SVahram Aharonyan offset = ureq->actual; 1049aa3e8bc8SVahram Aharonyan 1050aa3e8bc8SVahram Aharonyan /* Fill DDMA chain entries */ 1051aa3e8bc8SVahram Aharonyan dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq->dma + offset, 1052aa3e8bc8SVahram Aharonyan length); 1053aa3e8bc8SVahram Aharonyan 1054aa3e8bc8SVahram Aharonyan /* write descriptor chain address to control register */ 1055aa3e8bc8SVahram Aharonyan dwc2_writel(hs_ep->desc_list_dma, hsotg->regs + dma_reg); 1056aa3e8bc8SVahram Aharonyan 1057aa3e8bc8SVahram Aharonyan dev_dbg(hsotg->dev, "%s: %08x pad => 0x%08x\n", 1058aa3e8bc8SVahram Aharonyan __func__, (u32)hs_ep->desc_list_dma, dma_reg); 1059aa3e8bc8SVahram Aharonyan } else { 106047a1685fSDinh Nguyen /* write size / packets */ 106195c8bc36SAntti Seppälä dwc2_writel(epsize, hsotg->regs + epsize_reg); 106247a1685fSDinh Nguyen 1063729e6574SRazmik Karapetyan if (using_dma(hsotg) && !continuing && (length != 0)) { 106447a1685fSDinh Nguyen /* 1065aa3e8bc8SVahram Aharonyan * write DMA address to control register, buffer 1066aa3e8bc8SVahram Aharonyan * already synced by dwc2_hsotg_ep_queue(). 106747a1685fSDinh Nguyen */ 106847a1685fSDinh Nguyen 106995c8bc36SAntti Seppälä dwc2_writel(ureq->dma, hsotg->regs + dma_reg); 107047a1685fSDinh Nguyen 10710cc4cf6fSFabio Estevam dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n", 107247a1685fSDinh Nguyen __func__, &ureq->dma, dma_reg); 107347a1685fSDinh Nguyen } 1074aa3e8bc8SVahram Aharonyan } 107547a1685fSDinh Nguyen 1076837e9f00SVardan Mikayelyan if (hs_ep->isochronous && hs_ep->interval == 1) { 1077837e9f00SVardan Mikayelyan hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg); 1078837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 1079837e9f00SVardan Mikayelyan 1080837e9f00SVardan Mikayelyan if (hs_ep->target_frame & 0x1) 1081837e9f00SVardan Mikayelyan ctrl |= DXEPCTL_SETODDFR; 1082837e9f00SVardan Mikayelyan else 1083837e9f00SVardan Mikayelyan ctrl |= DXEPCTL_SETEVENFR; 1084837e9f00SVardan Mikayelyan } 1085837e9f00SVardan Mikayelyan 108647a1685fSDinh Nguyen ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 108747a1685fSDinh Nguyen 1088fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state); 108947a1685fSDinh Nguyen 109047a1685fSDinh Nguyen /* For Setup request do not clear NAK */ 1091fe0b94abSMian Yousaf Kaukab if (!(index == 0 && hsotg->ep0_state == DWC2_EP0_SETUP)) 109247a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 109347a1685fSDinh Nguyen 109447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 109595c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + epctrl_reg); 109647a1685fSDinh Nguyen 109747a1685fSDinh Nguyen /* 109847a1685fSDinh Nguyen * set these, it seems that DMA support increments past the end 109947a1685fSDinh Nguyen * of the packet buffer so we need to calculate the length from 110047a1685fSDinh Nguyen * this information. 110147a1685fSDinh Nguyen */ 110247a1685fSDinh Nguyen hs_ep->size_loaded = length; 110347a1685fSDinh Nguyen hs_ep->last_load = ureq->actual; 110447a1685fSDinh Nguyen 110547a1685fSDinh Nguyen if (dir_in && !using_dma(hsotg)) { 110647a1685fSDinh Nguyen /* set these anyway, we may need them for non-periodic in */ 110747a1685fSDinh Nguyen hs_ep->fifo_load = 0; 110847a1685fSDinh Nguyen 11091f91b4ccSFelipe Balbi dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 111047a1685fSDinh Nguyen } 111147a1685fSDinh Nguyen 111247a1685fSDinh Nguyen /* 111347a1685fSDinh Nguyen * Note, trying to clear the NAK here causes problems with transmit 111447a1685fSDinh Nguyen * on the S3C6400 ending up with the TXFIFO becoming full. 111547a1685fSDinh Nguyen */ 111647a1685fSDinh Nguyen 111747a1685fSDinh Nguyen /* check ep is enabled */ 111895c8bc36SAntti Seppälä if (!(dwc2_readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA)) 11191a0ed863SMian Yousaf Kaukab dev_dbg(hsotg->dev, 112047a1685fSDinh Nguyen "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", 112195c8bc36SAntti Seppälä index, dwc2_readl(hsotg->regs + epctrl_reg)); 112247a1685fSDinh Nguyen 112347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", 112495c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctrl_reg)); 112547a1685fSDinh Nguyen 112647a1685fSDinh Nguyen /* enable ep interrupts */ 11271f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1); 112847a1685fSDinh Nguyen } 112947a1685fSDinh Nguyen 113047a1685fSDinh Nguyen /** 11311f91b4ccSFelipe Balbi * dwc2_hsotg_map_dma - map the DMA memory being used for the request 113247a1685fSDinh Nguyen * @hsotg: The device state. 113347a1685fSDinh Nguyen * @hs_ep: The endpoint the request is on. 113447a1685fSDinh Nguyen * @req: The request being processed. 113547a1685fSDinh Nguyen * 113647a1685fSDinh Nguyen * We've been asked to queue a request, so ensure that the memory buffer 113747a1685fSDinh Nguyen * is correctly setup for DMA. If we've been passed an extant DMA address 113847a1685fSDinh Nguyen * then ensure the buffer has been synced to memory. If our buffer has no 113947a1685fSDinh Nguyen * DMA memory, then we map the memory and mark our request to allow us to 114047a1685fSDinh Nguyen * cleanup on completion. 114147a1685fSDinh Nguyen */ 11421f91b4ccSFelipe Balbi static int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg, 11431f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 114447a1685fSDinh Nguyen struct usb_request *req) 114547a1685fSDinh Nguyen { 114647a1685fSDinh Nguyen int ret; 114747a1685fSDinh Nguyen 114847a1685fSDinh Nguyen ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); 114947a1685fSDinh Nguyen if (ret) 115047a1685fSDinh Nguyen goto dma_error; 115147a1685fSDinh Nguyen 115247a1685fSDinh Nguyen return 0; 115347a1685fSDinh Nguyen 115447a1685fSDinh Nguyen dma_error: 115547a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", 115647a1685fSDinh Nguyen __func__, req->buf, req->length); 115747a1685fSDinh Nguyen 115847a1685fSDinh Nguyen return -EIO; 115947a1685fSDinh Nguyen } 116047a1685fSDinh Nguyen 11611f91b4ccSFelipe Balbi static int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, 1162b98866c2SJohn Youn struct dwc2_hsotg_ep *hs_ep, 1163b98866c2SJohn Youn struct dwc2_hsotg_req *hs_req) 11647d24c1b5SMian Yousaf Kaukab { 11657d24c1b5SMian Yousaf Kaukab void *req_buf = hs_req->req.buf; 11667d24c1b5SMian Yousaf Kaukab 11677d24c1b5SMian Yousaf Kaukab /* If dma is not being used or buffer is aligned */ 11687d24c1b5SMian Yousaf Kaukab if (!using_dma(hsotg) || !((long)req_buf & 3)) 11697d24c1b5SMian Yousaf Kaukab return 0; 11707d24c1b5SMian Yousaf Kaukab 11717d24c1b5SMian Yousaf Kaukab WARN_ON(hs_req->saved_req_buf); 11727d24c1b5SMian Yousaf Kaukab 11737d24c1b5SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__, 11747d24c1b5SMian Yousaf Kaukab hs_ep->ep.name, req_buf, hs_req->req.length); 11757d24c1b5SMian Yousaf Kaukab 11767d24c1b5SMian Yousaf Kaukab hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC); 11777d24c1b5SMian Yousaf Kaukab if (!hs_req->req.buf) { 11787d24c1b5SMian Yousaf Kaukab hs_req->req.buf = req_buf; 11797d24c1b5SMian Yousaf Kaukab dev_err(hsotg->dev, 11807d24c1b5SMian Yousaf Kaukab "%s: unable to allocate memory for bounce buffer\n", 11817d24c1b5SMian Yousaf Kaukab __func__); 11827d24c1b5SMian Yousaf Kaukab return -ENOMEM; 11837d24c1b5SMian Yousaf Kaukab } 11847d24c1b5SMian Yousaf Kaukab 11857d24c1b5SMian Yousaf Kaukab /* Save actual buffer */ 11867d24c1b5SMian Yousaf Kaukab hs_req->saved_req_buf = req_buf; 11877d24c1b5SMian Yousaf Kaukab 11887d24c1b5SMian Yousaf Kaukab if (hs_ep->dir_in) 11897d24c1b5SMian Yousaf Kaukab memcpy(hs_req->req.buf, req_buf, hs_req->req.length); 11907d24c1b5SMian Yousaf Kaukab return 0; 11917d24c1b5SMian Yousaf Kaukab } 11927d24c1b5SMian Yousaf Kaukab 1193b98866c2SJohn Youn static void 1194b98866c2SJohn Youn dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, 1195b98866c2SJohn Youn struct dwc2_hsotg_ep *hs_ep, 1196b98866c2SJohn Youn struct dwc2_hsotg_req *hs_req) 11977d24c1b5SMian Yousaf Kaukab { 11987d24c1b5SMian Yousaf Kaukab /* If dma is not being used or buffer was aligned */ 11997d24c1b5SMian Yousaf Kaukab if (!using_dma(hsotg) || !hs_req->saved_req_buf) 12007d24c1b5SMian Yousaf Kaukab return; 12017d24c1b5SMian Yousaf Kaukab 12027d24c1b5SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: %s: status=%d actual-length=%d\n", __func__, 12037d24c1b5SMian Yousaf Kaukab hs_ep->ep.name, hs_req->req.status, hs_req->req.actual); 12047d24c1b5SMian Yousaf Kaukab 12057d24c1b5SMian Yousaf Kaukab /* Copy data from bounce buffer on successful out transfer */ 12067d24c1b5SMian Yousaf Kaukab if (!hs_ep->dir_in && !hs_req->req.status) 12077d24c1b5SMian Yousaf Kaukab memcpy(hs_req->saved_req_buf, hs_req->req.buf, 12087d24c1b5SMian Yousaf Kaukab hs_req->req.actual); 12097d24c1b5SMian Yousaf Kaukab 12107d24c1b5SMian Yousaf Kaukab /* Free bounce buffer */ 12117d24c1b5SMian Yousaf Kaukab kfree(hs_req->req.buf); 12127d24c1b5SMian Yousaf Kaukab 12137d24c1b5SMian Yousaf Kaukab hs_req->req.buf = hs_req->saved_req_buf; 12147d24c1b5SMian Yousaf Kaukab hs_req->saved_req_buf = NULL; 12157d24c1b5SMian Yousaf Kaukab } 12167d24c1b5SMian Yousaf Kaukab 1217381fc8f8SVardan Mikayelyan /** 1218381fc8f8SVardan Mikayelyan * dwc2_gadget_target_frame_elapsed - Checks target frame 1219381fc8f8SVardan Mikayelyan * @hs_ep: The driver endpoint to check 1220381fc8f8SVardan Mikayelyan * 1221381fc8f8SVardan Mikayelyan * Returns 1 if targeted frame elapsed. If returned 1 then we need to drop 1222381fc8f8SVardan Mikayelyan * corresponding transfer. 1223381fc8f8SVardan Mikayelyan */ 1224381fc8f8SVardan Mikayelyan static bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep) 1225381fc8f8SVardan Mikayelyan { 1226381fc8f8SVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 1227381fc8f8SVardan Mikayelyan u32 target_frame = hs_ep->target_frame; 1228*c7c24e7aSArtur Petrosyan u32 current_frame = hsotg->frame_number; 1229381fc8f8SVardan Mikayelyan bool frame_overrun = hs_ep->frame_overrun; 1230381fc8f8SVardan Mikayelyan 1231381fc8f8SVardan Mikayelyan if (!frame_overrun && current_frame >= target_frame) 1232381fc8f8SVardan Mikayelyan return true; 1233381fc8f8SVardan Mikayelyan 1234381fc8f8SVardan Mikayelyan if (frame_overrun && current_frame >= target_frame && 1235381fc8f8SVardan Mikayelyan ((current_frame - target_frame) < DSTS_SOFFN_LIMIT / 2)) 1236381fc8f8SVardan Mikayelyan return true; 1237381fc8f8SVardan Mikayelyan 1238381fc8f8SVardan Mikayelyan return false; 1239381fc8f8SVardan Mikayelyan } 1240381fc8f8SVardan Mikayelyan 1241e02f9aa6SVahram Aharonyan /* 1242e02f9aa6SVahram Aharonyan * dwc2_gadget_set_ep0_desc_chain - Set EP's desc chain pointers 1243e02f9aa6SVahram Aharonyan * @hsotg: The driver state 1244e02f9aa6SVahram Aharonyan * @hs_ep: the ep descriptor chain is for 1245e02f9aa6SVahram Aharonyan * 1246e02f9aa6SVahram Aharonyan * Called to update EP0 structure's pointers depend on stage of 1247e02f9aa6SVahram Aharonyan * control transfer. 1248e02f9aa6SVahram Aharonyan */ 1249e02f9aa6SVahram Aharonyan static int dwc2_gadget_set_ep0_desc_chain(struct dwc2_hsotg *hsotg, 1250e02f9aa6SVahram Aharonyan struct dwc2_hsotg_ep *hs_ep) 1251e02f9aa6SVahram Aharonyan { 1252e02f9aa6SVahram Aharonyan switch (hsotg->ep0_state) { 1253e02f9aa6SVahram Aharonyan case DWC2_EP0_SETUP: 1254e02f9aa6SVahram Aharonyan case DWC2_EP0_STATUS_OUT: 1255e02f9aa6SVahram Aharonyan hs_ep->desc_list = hsotg->setup_desc[0]; 1256e02f9aa6SVahram Aharonyan hs_ep->desc_list_dma = hsotg->setup_desc_dma[0]; 1257e02f9aa6SVahram Aharonyan break; 1258e02f9aa6SVahram Aharonyan case DWC2_EP0_DATA_IN: 1259e02f9aa6SVahram Aharonyan case DWC2_EP0_STATUS_IN: 1260e02f9aa6SVahram Aharonyan hs_ep->desc_list = hsotg->ctrl_in_desc; 1261e02f9aa6SVahram Aharonyan hs_ep->desc_list_dma = hsotg->ctrl_in_desc_dma; 1262e02f9aa6SVahram Aharonyan break; 1263e02f9aa6SVahram Aharonyan case DWC2_EP0_DATA_OUT: 1264e02f9aa6SVahram Aharonyan hs_ep->desc_list = hsotg->ctrl_out_desc; 1265e02f9aa6SVahram Aharonyan hs_ep->desc_list_dma = hsotg->ctrl_out_desc_dma; 1266e02f9aa6SVahram Aharonyan break; 1267e02f9aa6SVahram Aharonyan default: 1268e02f9aa6SVahram Aharonyan dev_err(hsotg->dev, "invalid EP 0 state in queue %d\n", 1269e02f9aa6SVahram Aharonyan hsotg->ep0_state); 1270e02f9aa6SVahram Aharonyan return -EINVAL; 1271e02f9aa6SVahram Aharonyan } 1272e02f9aa6SVahram Aharonyan 1273e02f9aa6SVahram Aharonyan return 0; 1274e02f9aa6SVahram Aharonyan } 1275e02f9aa6SVahram Aharonyan 12761f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, 127747a1685fSDinh Nguyen gfp_t gfp_flags) 127847a1685fSDinh Nguyen { 12791f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 12801f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1281941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 128247a1685fSDinh Nguyen bool first; 12837d24c1b5SMian Yousaf Kaukab int ret; 1284729cac69SMinas Harutyunyan u32 maxsize = 0; 1285729cac69SMinas Harutyunyan u32 mask = 0; 1286729cac69SMinas Harutyunyan 128747a1685fSDinh Nguyen 128847a1685fSDinh Nguyen dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", 128947a1685fSDinh Nguyen ep->name, req, req->length, req->buf, req->no_interrupt, 129047a1685fSDinh Nguyen req->zero, req->short_not_ok); 129147a1685fSDinh Nguyen 12927ababa92SGregory Herrero /* Prevent new request submission when controller is suspended */ 129388b02f2cSGrigor Tovmasyan if (hs->lx_state != DWC2_L0) { 129488b02f2cSGrigor Tovmasyan dev_dbg(hs->dev, "%s: submit request only in active state\n", 12957ababa92SGregory Herrero __func__); 12967ababa92SGregory Herrero return -EAGAIN; 12977ababa92SGregory Herrero } 12987ababa92SGregory Herrero 129947a1685fSDinh Nguyen /* initialise status of the request */ 130047a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_req->queue); 130147a1685fSDinh Nguyen req->actual = 0; 130247a1685fSDinh Nguyen req->status = -EINPROGRESS; 130347a1685fSDinh Nguyen 1304729cac69SMinas Harutyunyan /* In DDMA mode for ISOC's don't queue request if length greater 1305729cac69SMinas Harutyunyan * than descriptor limits. 1306729cac69SMinas Harutyunyan */ 1307729cac69SMinas Harutyunyan if (using_desc_dma(hs) && hs_ep->isochronous) { 1308729cac69SMinas Harutyunyan maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); 1309729cac69SMinas Harutyunyan if (hs_ep->dir_in && req->length > maxsize) { 1310729cac69SMinas Harutyunyan dev_err(hs->dev, "wrong length %d (maxsize=%d)\n", 1311729cac69SMinas Harutyunyan req->length, maxsize); 1312729cac69SMinas Harutyunyan return -EINVAL; 1313729cac69SMinas Harutyunyan } 1314729cac69SMinas Harutyunyan 1315729cac69SMinas Harutyunyan if (!hs_ep->dir_in && req->length > hs_ep->ep.maxpacket) { 1316729cac69SMinas Harutyunyan dev_err(hs->dev, "ISOC OUT: wrong length %d (mps=%d)\n", 1317729cac69SMinas Harutyunyan req->length, hs_ep->ep.maxpacket); 1318729cac69SMinas Harutyunyan return -EINVAL; 1319729cac69SMinas Harutyunyan } 1320729cac69SMinas Harutyunyan } 1321729cac69SMinas Harutyunyan 13221f91b4ccSFelipe Balbi ret = dwc2_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req); 13237d24c1b5SMian Yousaf Kaukab if (ret) 13247d24c1b5SMian Yousaf Kaukab return ret; 13257d24c1b5SMian Yousaf Kaukab 132647a1685fSDinh Nguyen /* if we're using DMA, sync the buffers as necessary */ 132747a1685fSDinh Nguyen if (using_dma(hs)) { 13281f91b4ccSFelipe Balbi ret = dwc2_hsotg_map_dma(hs, hs_ep, req); 132947a1685fSDinh Nguyen if (ret) 133047a1685fSDinh Nguyen return ret; 133147a1685fSDinh Nguyen } 1332e02f9aa6SVahram Aharonyan /* If using descriptor DMA configure EP0 descriptor chain pointers */ 1333e02f9aa6SVahram Aharonyan if (using_desc_dma(hs) && !hs_ep->index) { 1334e02f9aa6SVahram Aharonyan ret = dwc2_gadget_set_ep0_desc_chain(hs, hs_ep); 1335e02f9aa6SVahram Aharonyan if (ret) 1336e02f9aa6SVahram Aharonyan return ret; 1337e02f9aa6SVahram Aharonyan } 133847a1685fSDinh Nguyen 133947a1685fSDinh Nguyen first = list_empty(&hs_ep->queue); 134047a1685fSDinh Nguyen list_add_tail(&hs_req->queue, &hs_ep->queue); 134147a1685fSDinh Nguyen 1342540ccba0SVahram Aharonyan /* 1343540ccba0SVahram Aharonyan * Handle DDMA isochronous transfers separately - just add new entry 1344729cac69SMinas Harutyunyan * to the descriptor chain. 1345540ccba0SVahram Aharonyan * Transfer will be started once SW gets either one of NAK or 1346540ccba0SVahram Aharonyan * OutTknEpDis interrupts. 1347540ccba0SVahram Aharonyan */ 1348729cac69SMinas Harutyunyan if (using_desc_dma(hs) && hs_ep->isochronous) { 1349729cac69SMinas Harutyunyan if (hs_ep->target_frame != TARGET_FRAME_INITIAL) { 1350729cac69SMinas Harutyunyan dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, 1351540ccba0SVahram Aharonyan hs_req->req.length); 1352729cac69SMinas Harutyunyan } 1353540ccba0SVahram Aharonyan return 0; 1354540ccba0SVahram Aharonyan } 1355540ccba0SVahram Aharonyan 1356837e9f00SVardan Mikayelyan if (first) { 1357837e9f00SVardan Mikayelyan if (!hs_ep->isochronous) { 13581f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 1359837e9f00SVardan Mikayelyan return 0; 1360837e9f00SVardan Mikayelyan } 136147a1685fSDinh Nguyen 1362*c7c24e7aSArtur Petrosyan /* Update current frame number value. */ 1363*c7c24e7aSArtur Petrosyan hs->frame_number = dwc2_hsotg_read_frameno(hs); 1364*c7c24e7aSArtur Petrosyan while (dwc2_gadget_target_frame_elapsed(hs_ep)) { 1365837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 1366*c7c24e7aSArtur Petrosyan /* Update current frame number value once more as it 1367*c7c24e7aSArtur Petrosyan * changes here. 1368*c7c24e7aSArtur Petrosyan */ 1369*c7c24e7aSArtur Petrosyan hs->frame_number = dwc2_hsotg_read_frameno(hs); 1370*c7c24e7aSArtur Petrosyan } 1371837e9f00SVardan Mikayelyan 1372837e9f00SVardan Mikayelyan if (hs_ep->target_frame != TARGET_FRAME_INITIAL) 1373837e9f00SVardan Mikayelyan dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 1374837e9f00SVardan Mikayelyan } 137547a1685fSDinh Nguyen return 0; 137647a1685fSDinh Nguyen } 137747a1685fSDinh Nguyen 13781f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, 137947a1685fSDinh Nguyen gfp_t gfp_flags) 138047a1685fSDinh Nguyen { 13811f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1382941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 138347a1685fSDinh Nguyen unsigned long flags = 0; 138447a1685fSDinh Nguyen int ret = 0; 138547a1685fSDinh Nguyen 138647a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 13871f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(ep, req, gfp_flags); 138847a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 138947a1685fSDinh Nguyen 139047a1685fSDinh Nguyen return ret; 139147a1685fSDinh Nguyen } 139247a1685fSDinh Nguyen 13931f91b4ccSFelipe Balbi static void dwc2_hsotg_ep_free_request(struct usb_ep *ep, 139447a1685fSDinh Nguyen struct usb_request *req) 139547a1685fSDinh Nguyen { 13961f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 139747a1685fSDinh Nguyen 139847a1685fSDinh Nguyen kfree(hs_req); 139947a1685fSDinh Nguyen } 140047a1685fSDinh Nguyen 140147a1685fSDinh Nguyen /** 14021f91b4ccSFelipe Balbi * dwc2_hsotg_complete_oursetup - setup completion callback 140347a1685fSDinh Nguyen * @ep: The endpoint the request was on. 140447a1685fSDinh Nguyen * @req: The request completed. 140547a1685fSDinh Nguyen * 140647a1685fSDinh Nguyen * Called on completion of any requests the driver itself 140747a1685fSDinh Nguyen * submitted that need cleaning up. 140847a1685fSDinh Nguyen */ 14091f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_oursetup(struct usb_ep *ep, 141047a1685fSDinh Nguyen struct usb_request *req) 141147a1685fSDinh Nguyen { 14121f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1413941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 141447a1685fSDinh Nguyen 141547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); 141647a1685fSDinh Nguyen 14171f91b4ccSFelipe Balbi dwc2_hsotg_ep_free_request(ep, req); 141847a1685fSDinh Nguyen } 141947a1685fSDinh Nguyen 142047a1685fSDinh Nguyen /** 142147a1685fSDinh Nguyen * ep_from_windex - convert control wIndex value to endpoint 142247a1685fSDinh Nguyen * @hsotg: The driver state. 142347a1685fSDinh Nguyen * @windex: The control request wIndex field (in host order). 142447a1685fSDinh Nguyen * 142547a1685fSDinh Nguyen * Convert the given wIndex into a pointer to an driver endpoint 142647a1685fSDinh Nguyen * structure, or return NULL if it is not a valid endpoint. 142747a1685fSDinh Nguyen */ 14281f91b4ccSFelipe Balbi static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, 142947a1685fSDinh Nguyen u32 windex) 143047a1685fSDinh Nguyen { 14311f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 143247a1685fSDinh Nguyen int dir = (windex & USB_DIR_IN) ? 1 : 0; 143347a1685fSDinh Nguyen int idx = windex & 0x7F; 143447a1685fSDinh Nguyen 143547a1685fSDinh Nguyen if (windex >= 0x100) 143647a1685fSDinh Nguyen return NULL; 143747a1685fSDinh Nguyen 143847a1685fSDinh Nguyen if (idx > hsotg->num_of_eps) 143947a1685fSDinh Nguyen return NULL; 144047a1685fSDinh Nguyen 1441c6f5c050SMian Yousaf Kaukab ep = index_to_ep(hsotg, idx, dir); 1442c6f5c050SMian Yousaf Kaukab 144347a1685fSDinh Nguyen if (idx && ep->dir_in != dir) 144447a1685fSDinh Nguyen return NULL; 144547a1685fSDinh Nguyen 144647a1685fSDinh Nguyen return ep; 144747a1685fSDinh Nguyen } 144847a1685fSDinh Nguyen 144947a1685fSDinh Nguyen /** 14501f91b4ccSFelipe Balbi * dwc2_hsotg_set_test_mode - Enable usb Test Modes 14519e14d0a5SGregory Herrero * @hsotg: The driver state. 14529e14d0a5SGregory Herrero * @testmode: requested usb test mode 14539e14d0a5SGregory Herrero * Enable usb Test Mode requested by the Host. 14549e14d0a5SGregory Herrero */ 14551f91b4ccSFelipe Balbi int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode) 14569e14d0a5SGregory Herrero { 145795c8bc36SAntti Seppälä int dctl = dwc2_readl(hsotg->regs + DCTL); 14589e14d0a5SGregory Herrero 14599e14d0a5SGregory Herrero dctl &= ~DCTL_TSTCTL_MASK; 14609e14d0a5SGregory Herrero switch (testmode) { 14619e14d0a5SGregory Herrero case TEST_J: 14629e14d0a5SGregory Herrero case TEST_K: 14639e14d0a5SGregory Herrero case TEST_SE0_NAK: 14649e14d0a5SGregory Herrero case TEST_PACKET: 14659e14d0a5SGregory Herrero case TEST_FORCE_EN: 14669e14d0a5SGregory Herrero dctl |= testmode << DCTL_TSTCTL_SHIFT; 14679e14d0a5SGregory Herrero break; 14689e14d0a5SGregory Herrero default: 14699e14d0a5SGregory Herrero return -EINVAL; 14709e14d0a5SGregory Herrero } 147195c8bc36SAntti Seppälä dwc2_writel(dctl, hsotg->regs + DCTL); 14729e14d0a5SGregory Herrero return 0; 14739e14d0a5SGregory Herrero } 14749e14d0a5SGregory Herrero 14759e14d0a5SGregory Herrero /** 14761f91b4ccSFelipe Balbi * dwc2_hsotg_send_reply - send reply to control request 147747a1685fSDinh Nguyen * @hsotg: The device state 147847a1685fSDinh Nguyen * @ep: Endpoint 0 147947a1685fSDinh Nguyen * @buff: Buffer for request 148047a1685fSDinh Nguyen * @length: Length of reply. 148147a1685fSDinh Nguyen * 148247a1685fSDinh Nguyen * Create a request and queue it on the given endpoint. This is useful as 148347a1685fSDinh Nguyen * an internal method of sending replies to certain control requests, etc. 148447a1685fSDinh Nguyen */ 14851f91b4ccSFelipe Balbi static int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg, 14861f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep, 148747a1685fSDinh Nguyen void *buff, 148847a1685fSDinh Nguyen int length) 148947a1685fSDinh Nguyen { 149047a1685fSDinh Nguyen struct usb_request *req; 149147a1685fSDinh Nguyen int ret; 149247a1685fSDinh Nguyen 149347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); 149447a1685fSDinh Nguyen 14951f91b4ccSFelipe Balbi req = dwc2_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); 149647a1685fSDinh Nguyen hsotg->ep0_reply = req; 149747a1685fSDinh Nguyen if (!req) { 149847a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); 149947a1685fSDinh Nguyen return -ENOMEM; 150047a1685fSDinh Nguyen } 150147a1685fSDinh Nguyen 150247a1685fSDinh Nguyen req->buf = hsotg->ep0_buff; 150347a1685fSDinh Nguyen req->length = length; 1504f71b5e25SMian Yousaf Kaukab /* 1505f71b5e25SMian Yousaf Kaukab * zero flag is for sending zlp in DATA IN stage. It has no impact on 1506f71b5e25SMian Yousaf Kaukab * STATUS stage. 1507f71b5e25SMian Yousaf Kaukab */ 1508f71b5e25SMian Yousaf Kaukab req->zero = 0; 15091f91b4ccSFelipe Balbi req->complete = dwc2_hsotg_complete_oursetup; 151047a1685fSDinh Nguyen 151147a1685fSDinh Nguyen if (length) 151247a1685fSDinh Nguyen memcpy(req->buf, buff, length); 151347a1685fSDinh Nguyen 15141f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); 151547a1685fSDinh Nguyen if (ret) { 151647a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); 151747a1685fSDinh Nguyen return ret; 151847a1685fSDinh Nguyen } 151947a1685fSDinh Nguyen 152047a1685fSDinh Nguyen return 0; 152147a1685fSDinh Nguyen } 152247a1685fSDinh Nguyen 152347a1685fSDinh Nguyen /** 15241f91b4ccSFelipe Balbi * dwc2_hsotg_process_req_status - process request GET_STATUS 152547a1685fSDinh Nguyen * @hsotg: The device state 152647a1685fSDinh Nguyen * @ctrl: USB control request 152747a1685fSDinh Nguyen */ 15281f91b4ccSFelipe Balbi static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, 152947a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 153047a1685fSDinh Nguyen { 15311f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 15321f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 153347a1685fSDinh Nguyen __le16 reply; 153447a1685fSDinh Nguyen int ret; 153547a1685fSDinh Nguyen 153647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); 153747a1685fSDinh Nguyen 153847a1685fSDinh Nguyen if (!ep0->dir_in) { 153947a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: direction out?\n", __func__); 154047a1685fSDinh Nguyen return -EINVAL; 154147a1685fSDinh Nguyen } 154247a1685fSDinh Nguyen 154347a1685fSDinh Nguyen switch (ctrl->bRequestType & USB_RECIP_MASK) { 154447a1685fSDinh Nguyen case USB_RECIP_DEVICE: 154538beaec6SJohn Youn /* 154638beaec6SJohn Youn * bit 0 => self powered 154738beaec6SJohn Youn * bit 1 => remote wakeup 154838beaec6SJohn Youn */ 154938beaec6SJohn Youn reply = cpu_to_le16(0); 155047a1685fSDinh Nguyen break; 155147a1685fSDinh Nguyen 155247a1685fSDinh Nguyen case USB_RECIP_INTERFACE: 155347a1685fSDinh Nguyen /* currently, the data result should be zero */ 155447a1685fSDinh Nguyen reply = cpu_to_le16(0); 155547a1685fSDinh Nguyen break; 155647a1685fSDinh Nguyen 155747a1685fSDinh Nguyen case USB_RECIP_ENDPOINT: 155847a1685fSDinh Nguyen ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); 155947a1685fSDinh Nguyen if (!ep) 156047a1685fSDinh Nguyen return -ENOENT; 156147a1685fSDinh Nguyen 156247a1685fSDinh Nguyen reply = cpu_to_le16(ep->halted ? 1 : 0); 156347a1685fSDinh Nguyen break; 156447a1685fSDinh Nguyen 156547a1685fSDinh Nguyen default: 156647a1685fSDinh Nguyen return 0; 156747a1685fSDinh Nguyen } 156847a1685fSDinh Nguyen 156947a1685fSDinh Nguyen if (le16_to_cpu(ctrl->wLength) != 2) 157047a1685fSDinh Nguyen return -EINVAL; 157147a1685fSDinh Nguyen 15721f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, &reply, 2); 157347a1685fSDinh Nguyen if (ret) { 157447a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); 157547a1685fSDinh Nguyen return ret; 157647a1685fSDinh Nguyen } 157747a1685fSDinh Nguyen 157847a1685fSDinh Nguyen return 1; 157947a1685fSDinh Nguyen } 158047a1685fSDinh Nguyen 158151da43b5SVahram Aharonyan static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now); 158247a1685fSDinh Nguyen 158347a1685fSDinh Nguyen /** 158447a1685fSDinh Nguyen * get_ep_head - return the first request on the endpoint 158547a1685fSDinh Nguyen * @hs_ep: The controller endpoint to get 158647a1685fSDinh Nguyen * 158747a1685fSDinh Nguyen * Get the first request on the endpoint. 158847a1685fSDinh Nguyen */ 15891f91b4ccSFelipe Balbi static struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep) 159047a1685fSDinh Nguyen { 1591ffc4b406SMasahiro Yamada return list_first_entry_or_null(&hs_ep->queue, struct dwc2_hsotg_req, 1592ffc4b406SMasahiro Yamada queue); 159347a1685fSDinh Nguyen } 159447a1685fSDinh Nguyen 159547a1685fSDinh Nguyen /** 159641cc4cd2SVardan Mikayelyan * dwc2_gadget_start_next_request - Starts next request from ep queue 159741cc4cd2SVardan Mikayelyan * @hs_ep: Endpoint structure 159841cc4cd2SVardan Mikayelyan * 159941cc4cd2SVardan Mikayelyan * If queue is empty and EP is ISOC-OUT - unmasks OUTTKNEPDIS which is masked 160041cc4cd2SVardan Mikayelyan * in its handler. Hence we need to unmask it here to be able to do 160141cc4cd2SVardan Mikayelyan * resynchronization. 160241cc4cd2SVardan Mikayelyan */ 160341cc4cd2SVardan Mikayelyan static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep) 160441cc4cd2SVardan Mikayelyan { 160541cc4cd2SVardan Mikayelyan u32 mask; 160641cc4cd2SVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 160741cc4cd2SVardan Mikayelyan int dir_in = hs_ep->dir_in; 160841cc4cd2SVardan Mikayelyan struct dwc2_hsotg_req *hs_req; 160941cc4cd2SVardan Mikayelyan u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; 161041cc4cd2SVardan Mikayelyan 161141cc4cd2SVardan Mikayelyan if (!list_empty(&hs_ep->queue)) { 161241cc4cd2SVardan Mikayelyan hs_req = get_ep_head(hs_ep); 161341cc4cd2SVardan Mikayelyan dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false); 161441cc4cd2SVardan Mikayelyan return; 161541cc4cd2SVardan Mikayelyan } 161641cc4cd2SVardan Mikayelyan if (!hs_ep->isochronous) 161741cc4cd2SVardan Mikayelyan return; 161841cc4cd2SVardan Mikayelyan 161941cc4cd2SVardan Mikayelyan if (dir_in) { 162041cc4cd2SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: No more ISOC-IN requests\n", 162141cc4cd2SVardan Mikayelyan __func__); 162241cc4cd2SVardan Mikayelyan } else { 162341cc4cd2SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: No more ISOC-OUT requests\n", 162441cc4cd2SVardan Mikayelyan __func__); 162541cc4cd2SVardan Mikayelyan mask = dwc2_readl(hsotg->regs + epmsk_reg); 162641cc4cd2SVardan Mikayelyan mask |= DOEPMSK_OUTTKNEPDISMSK; 162741cc4cd2SVardan Mikayelyan dwc2_writel(mask, hsotg->regs + epmsk_reg); 162841cc4cd2SVardan Mikayelyan } 162941cc4cd2SVardan Mikayelyan } 163041cc4cd2SVardan Mikayelyan 163141cc4cd2SVardan Mikayelyan /** 16321f91b4ccSFelipe Balbi * dwc2_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE 163347a1685fSDinh Nguyen * @hsotg: The device state 163447a1685fSDinh Nguyen * @ctrl: USB control request 163547a1685fSDinh Nguyen */ 16361f91b4ccSFelipe Balbi static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, 163747a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 163847a1685fSDinh Nguyen { 16391f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 16401f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req; 164147a1685fSDinh Nguyen bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); 16421f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 164347a1685fSDinh Nguyen int ret; 164447a1685fSDinh Nguyen bool halted; 16459e14d0a5SGregory Herrero u32 recip; 16469e14d0a5SGregory Herrero u32 wValue; 16479e14d0a5SGregory Herrero u32 wIndex; 164847a1685fSDinh Nguyen 164947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", 165047a1685fSDinh Nguyen __func__, set ? "SET" : "CLEAR"); 165147a1685fSDinh Nguyen 16529e14d0a5SGregory Herrero wValue = le16_to_cpu(ctrl->wValue); 16539e14d0a5SGregory Herrero wIndex = le16_to_cpu(ctrl->wIndex); 16549e14d0a5SGregory Herrero recip = ctrl->bRequestType & USB_RECIP_MASK; 16559e14d0a5SGregory Herrero 16569e14d0a5SGregory Herrero switch (recip) { 16579e14d0a5SGregory Herrero case USB_RECIP_DEVICE: 16589e14d0a5SGregory Herrero switch (wValue) { 1659fa389a6dSVardan Mikayelyan case USB_DEVICE_REMOTE_WAKEUP: 1660fa389a6dSVardan Mikayelyan hsotg->remote_wakeup_allowed = 1; 1661fa389a6dSVardan Mikayelyan break; 1662fa389a6dSVardan Mikayelyan 16639e14d0a5SGregory Herrero case USB_DEVICE_TEST_MODE: 16649e14d0a5SGregory Herrero if ((wIndex & 0xff) != 0) 16659e14d0a5SGregory Herrero return -EINVAL; 16669e14d0a5SGregory Herrero if (!set) 16679e14d0a5SGregory Herrero return -EINVAL; 16689e14d0a5SGregory Herrero 16699e14d0a5SGregory Herrero hsotg->test_mode = wIndex >> 8; 16701f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 16719e14d0a5SGregory Herrero if (ret) { 16729e14d0a5SGregory Herrero dev_err(hsotg->dev, 16739e14d0a5SGregory Herrero "%s: failed to send reply\n", __func__); 16749e14d0a5SGregory Herrero return ret; 16759e14d0a5SGregory Herrero } 16769e14d0a5SGregory Herrero break; 16779e14d0a5SGregory Herrero default: 16789e14d0a5SGregory Herrero return -ENOENT; 16799e14d0a5SGregory Herrero } 16809e14d0a5SGregory Herrero break; 16819e14d0a5SGregory Herrero 16829e14d0a5SGregory Herrero case USB_RECIP_ENDPOINT: 16839e14d0a5SGregory Herrero ep = ep_from_windex(hsotg, wIndex); 168447a1685fSDinh Nguyen if (!ep) { 168547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", 16869e14d0a5SGregory Herrero __func__, wIndex); 168747a1685fSDinh Nguyen return -ENOENT; 168847a1685fSDinh Nguyen } 168947a1685fSDinh Nguyen 16909e14d0a5SGregory Herrero switch (wValue) { 169147a1685fSDinh Nguyen case USB_ENDPOINT_HALT: 169247a1685fSDinh Nguyen halted = ep->halted; 169347a1685fSDinh Nguyen 169451da43b5SVahram Aharonyan dwc2_hsotg_ep_sethalt(&ep->ep, set, true); 169547a1685fSDinh Nguyen 16961f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 169747a1685fSDinh Nguyen if (ret) { 169847a1685fSDinh Nguyen dev_err(hsotg->dev, 169947a1685fSDinh Nguyen "%s: failed to send reply\n", __func__); 170047a1685fSDinh Nguyen return ret; 170147a1685fSDinh Nguyen } 170247a1685fSDinh Nguyen 170347a1685fSDinh Nguyen /* 170447a1685fSDinh Nguyen * we have to complete all requests for ep if it was 170547a1685fSDinh Nguyen * halted, and the halt was cleared by CLEAR_FEATURE 170647a1685fSDinh Nguyen */ 170747a1685fSDinh Nguyen 170847a1685fSDinh Nguyen if (!set && halted) { 170947a1685fSDinh Nguyen /* 171047a1685fSDinh Nguyen * If we have request in progress, 171147a1685fSDinh Nguyen * then complete it 171247a1685fSDinh Nguyen */ 171347a1685fSDinh Nguyen if (ep->req) { 171447a1685fSDinh Nguyen hs_req = ep->req; 171547a1685fSDinh Nguyen ep->req = NULL; 171647a1685fSDinh Nguyen list_del_init(&hs_req->queue); 1717c00dd4a6SGregory Herrero if (hs_req->req.complete) { 1718c00dd4a6SGregory Herrero spin_unlock(&hsotg->lock); 1719c00dd4a6SGregory Herrero usb_gadget_giveback_request( 1720c00dd4a6SGregory Herrero &ep->ep, &hs_req->req); 1721c00dd4a6SGregory Herrero spin_lock(&hsotg->lock); 1722c00dd4a6SGregory Herrero } 172347a1685fSDinh Nguyen } 172447a1685fSDinh Nguyen 172547a1685fSDinh Nguyen /* If we have pending request, then start it */ 172634c0887fSJohn Youn if (!ep->req) 172741cc4cd2SVardan Mikayelyan dwc2_gadget_start_next_request(ep); 172847a1685fSDinh Nguyen } 172947a1685fSDinh Nguyen 173047a1685fSDinh Nguyen break; 173147a1685fSDinh Nguyen 173247a1685fSDinh Nguyen default: 173347a1685fSDinh Nguyen return -ENOENT; 173447a1685fSDinh Nguyen } 17359e14d0a5SGregory Herrero break; 17369e14d0a5SGregory Herrero default: 17379e14d0a5SGregory Herrero return -ENOENT; 17389e14d0a5SGregory Herrero } 173947a1685fSDinh Nguyen return 1; 174047a1685fSDinh Nguyen } 174147a1685fSDinh Nguyen 17421f91b4ccSFelipe Balbi static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg); 174347a1685fSDinh Nguyen 174447a1685fSDinh Nguyen /** 17451f91b4ccSFelipe Balbi * dwc2_hsotg_stall_ep0 - stall ep0 174647a1685fSDinh Nguyen * @hsotg: The device state 174747a1685fSDinh Nguyen * 174847a1685fSDinh Nguyen * Set stall for ep0 as response for setup request. 174947a1685fSDinh Nguyen */ 17501f91b4ccSFelipe Balbi static void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg) 1751e9ebe7c3SJingoo Han { 17521f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 175347a1685fSDinh Nguyen u32 reg; 175447a1685fSDinh Nguyen u32 ctrl; 175547a1685fSDinh Nguyen 175647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); 175747a1685fSDinh Nguyen reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; 175847a1685fSDinh Nguyen 175947a1685fSDinh Nguyen /* 176047a1685fSDinh Nguyen * DxEPCTL_Stall will be cleared by EP once it has 176147a1685fSDinh Nguyen * taken effect, so no need to clear later. 176247a1685fSDinh Nguyen */ 176347a1685fSDinh Nguyen 176495c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + reg); 176547a1685fSDinh Nguyen ctrl |= DXEPCTL_STALL; 176647a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; 176795c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + reg); 176847a1685fSDinh Nguyen 176947a1685fSDinh Nguyen dev_dbg(hsotg->dev, 177047a1685fSDinh Nguyen "written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n", 177195c8bc36SAntti Seppälä ctrl, reg, dwc2_readl(hsotg->regs + reg)); 177247a1685fSDinh Nguyen 177347a1685fSDinh Nguyen /* 177447a1685fSDinh Nguyen * complete won't be called, so we enqueue 177547a1685fSDinh Nguyen * setup request here 177647a1685fSDinh Nguyen */ 17771f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 177847a1685fSDinh Nguyen } 177947a1685fSDinh Nguyen 178047a1685fSDinh Nguyen /** 17811f91b4ccSFelipe Balbi * dwc2_hsotg_process_control - process a control request 178247a1685fSDinh Nguyen * @hsotg: The device state 178347a1685fSDinh Nguyen * @ctrl: The control request received 178447a1685fSDinh Nguyen * 178547a1685fSDinh Nguyen * The controller has received the SETUP phase of a control request, and 178647a1685fSDinh Nguyen * needs to work out what to do next (and whether to pass it on to the 178747a1685fSDinh Nguyen * gadget driver). 178847a1685fSDinh Nguyen */ 17891f91b4ccSFelipe Balbi static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, 179047a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 179147a1685fSDinh Nguyen { 17921f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 179347a1685fSDinh Nguyen int ret = 0; 179447a1685fSDinh Nguyen u32 dcfg; 179547a1685fSDinh Nguyen 1796e525e743SMian Yousaf Kaukab dev_dbg(hsotg->dev, 1797e525e743SMian Yousaf Kaukab "ctrl Type=%02x, Req=%02x, V=%04x, I=%04x, L=%04x\n", 1798e525e743SMian Yousaf Kaukab ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, 1799e525e743SMian Yousaf Kaukab ctrl->wIndex, ctrl->wLength); 180047a1685fSDinh Nguyen 1801fe0b94abSMian Yousaf Kaukab if (ctrl->wLength == 0) { 180247a1685fSDinh Nguyen ep0->dir_in = 1; 1803fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_STATUS_IN; 1804fe0b94abSMian Yousaf Kaukab } else if (ctrl->bRequestType & USB_DIR_IN) { 1805fe0b94abSMian Yousaf Kaukab ep0->dir_in = 1; 1806fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_DATA_IN; 1807fe0b94abSMian Yousaf Kaukab } else { 1808fe0b94abSMian Yousaf Kaukab ep0->dir_in = 0; 1809fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_DATA_OUT; 1810fe0b94abSMian Yousaf Kaukab } 181147a1685fSDinh Nguyen 181247a1685fSDinh Nguyen if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 181347a1685fSDinh Nguyen switch (ctrl->bRequest) { 181447a1685fSDinh Nguyen case USB_REQ_SET_ADDRESS: 18156d713c15SMian Yousaf Kaukab hsotg->connected = 1; 181695c8bc36SAntti Seppälä dcfg = dwc2_readl(hsotg->regs + DCFG); 181747a1685fSDinh Nguyen dcfg &= ~DCFG_DEVADDR_MASK; 1818d5dbd3f7SPaul Zimmerman dcfg |= (le16_to_cpu(ctrl->wValue) << 1819d5dbd3f7SPaul Zimmerman DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK; 182095c8bc36SAntti Seppälä dwc2_writel(dcfg, hsotg->regs + DCFG); 182147a1685fSDinh Nguyen 182247a1685fSDinh Nguyen dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); 182347a1685fSDinh Nguyen 18241f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 182547a1685fSDinh Nguyen return; 182647a1685fSDinh Nguyen 182747a1685fSDinh Nguyen case USB_REQ_GET_STATUS: 18281f91b4ccSFelipe Balbi ret = dwc2_hsotg_process_req_status(hsotg, ctrl); 182947a1685fSDinh Nguyen break; 183047a1685fSDinh Nguyen 183147a1685fSDinh Nguyen case USB_REQ_CLEAR_FEATURE: 183247a1685fSDinh Nguyen case USB_REQ_SET_FEATURE: 18331f91b4ccSFelipe Balbi ret = dwc2_hsotg_process_req_feature(hsotg, ctrl); 183447a1685fSDinh Nguyen break; 183547a1685fSDinh Nguyen } 183647a1685fSDinh Nguyen } 183747a1685fSDinh Nguyen 183847a1685fSDinh Nguyen /* as a fallback, try delivering it to the driver to deal with */ 183947a1685fSDinh Nguyen 184047a1685fSDinh Nguyen if (ret == 0 && hsotg->driver) { 184147a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 184247a1685fSDinh Nguyen ret = hsotg->driver->setup(&hsotg->gadget, ctrl); 184347a1685fSDinh Nguyen spin_lock(&hsotg->lock); 184447a1685fSDinh Nguyen if (ret < 0) 184547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); 184647a1685fSDinh Nguyen } 184747a1685fSDinh Nguyen 184847a1685fSDinh Nguyen /* 184947a1685fSDinh Nguyen * the request is either unhandlable, or is not formatted correctly 185047a1685fSDinh Nguyen * so respond with a STALL for the status stage to indicate failure. 185147a1685fSDinh Nguyen */ 185247a1685fSDinh Nguyen 185347a1685fSDinh Nguyen if (ret < 0) 18541f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hsotg); 185547a1685fSDinh Nguyen } 185647a1685fSDinh Nguyen 185747a1685fSDinh Nguyen /** 18581f91b4ccSFelipe Balbi * dwc2_hsotg_complete_setup - completion of a setup transfer 185947a1685fSDinh Nguyen * @ep: The endpoint the request was on. 186047a1685fSDinh Nguyen * @req: The request completed. 186147a1685fSDinh Nguyen * 186247a1685fSDinh Nguyen * Called on completion of any requests the driver itself submitted for 186347a1685fSDinh Nguyen * EP0 setup packets 186447a1685fSDinh Nguyen */ 18651f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_setup(struct usb_ep *ep, 186647a1685fSDinh Nguyen struct usb_request *req) 186747a1685fSDinh Nguyen { 18681f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1869941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 187047a1685fSDinh Nguyen 187147a1685fSDinh Nguyen if (req->status < 0) { 187247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); 187347a1685fSDinh Nguyen return; 187447a1685fSDinh Nguyen } 187547a1685fSDinh Nguyen 187647a1685fSDinh Nguyen spin_lock(&hsotg->lock); 187747a1685fSDinh Nguyen if (req->actual == 0) 18781f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 187947a1685fSDinh Nguyen else 18801f91b4ccSFelipe Balbi dwc2_hsotg_process_control(hsotg, req->buf); 188147a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 188247a1685fSDinh Nguyen } 188347a1685fSDinh Nguyen 188447a1685fSDinh Nguyen /** 18851f91b4ccSFelipe Balbi * dwc2_hsotg_enqueue_setup - start a request for EP0 packets 188647a1685fSDinh Nguyen * @hsotg: The device state. 188747a1685fSDinh Nguyen * 188847a1685fSDinh Nguyen * Enqueue a request on EP0 if necessary to received any SETUP packets 188947a1685fSDinh Nguyen * received from the host. 189047a1685fSDinh Nguyen */ 18911f91b4ccSFelipe Balbi static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg) 189247a1685fSDinh Nguyen { 189347a1685fSDinh Nguyen struct usb_request *req = hsotg->ctrl_req; 18941f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 189547a1685fSDinh Nguyen int ret; 189647a1685fSDinh Nguyen 189747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); 189847a1685fSDinh Nguyen 189947a1685fSDinh Nguyen req->zero = 0; 190047a1685fSDinh Nguyen req->length = 8; 190147a1685fSDinh Nguyen req->buf = hsotg->ctrl_buff; 19021f91b4ccSFelipe Balbi req->complete = dwc2_hsotg_complete_setup; 190347a1685fSDinh Nguyen 190447a1685fSDinh Nguyen if (!list_empty(&hs_req->queue)) { 190547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s already queued???\n", __func__); 190647a1685fSDinh Nguyen return; 190747a1685fSDinh Nguyen } 190847a1685fSDinh Nguyen 1909c6f5c050SMian Yousaf Kaukab hsotg->eps_out[0]->dir_in = 0; 19108a20fa45SMian Yousaf Kaukab hsotg->eps_out[0]->send_zlp = 0; 1911fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_SETUP; 191247a1685fSDinh Nguyen 19131f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(&hsotg->eps_out[0]->ep, req, GFP_ATOMIC); 191447a1685fSDinh Nguyen if (ret < 0) { 191547a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); 191647a1685fSDinh Nguyen /* 191747a1685fSDinh Nguyen * Don't think there's much we can do other than watch the 191847a1685fSDinh Nguyen * driver fail. 191947a1685fSDinh Nguyen */ 192047a1685fSDinh Nguyen } 192147a1685fSDinh Nguyen } 192247a1685fSDinh Nguyen 19231f91b4ccSFelipe Balbi static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, 19241f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 1925fe0b94abSMian Yousaf Kaukab { 1926fe0b94abSMian Yousaf Kaukab u32 ctrl; 1927fe0b94abSMian Yousaf Kaukab u8 index = hs_ep->index; 1928fe0b94abSMian Yousaf Kaukab u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 1929fe0b94abSMian Yousaf Kaukab u32 epsiz_reg = hs_ep->dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 1930fe0b94abSMian Yousaf Kaukab 1931ccb34a91SMian Yousaf Kaukab if (hs_ep->dir_in) 1932ccb34a91SMian Yousaf Kaukab dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n", 1933ccb34a91SMian Yousaf Kaukab index); 1934ccb34a91SMian Yousaf Kaukab else 1935ccb34a91SMian Yousaf Kaukab dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n", 1936ccb34a91SMian Yousaf Kaukab index); 1937e02f9aa6SVahram Aharonyan if (using_desc_dma(hsotg)) { 1938e02f9aa6SVahram Aharonyan /* Not specific buffer needed for ep0 ZLP */ 1939e02f9aa6SVahram Aharonyan dma_addr_t dma = hs_ep->desc_list_dma; 1940fe0b94abSMian Yousaf Kaukab 1941201ec568SMinas Harutyunyan if (!index) 1942e02f9aa6SVahram Aharonyan dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep); 1943201ec568SMinas Harutyunyan 1944e02f9aa6SVahram Aharonyan dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0); 1945e02f9aa6SVahram Aharonyan } else { 194695c8bc36SAntti Seppälä dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 1947fe0b94abSMian Yousaf Kaukab DXEPTSIZ_XFERSIZE(0), hsotg->regs + 1948fe0b94abSMian Yousaf Kaukab epsiz_reg); 1949e02f9aa6SVahram Aharonyan } 1950fe0b94abSMian Yousaf Kaukab 195195c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctl_reg); 1952fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 1953fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 1954fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_USBACTEP; 195595c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + epctl_reg); 1956fe0b94abSMian Yousaf Kaukab } 1957fe0b94abSMian Yousaf Kaukab 195847a1685fSDinh Nguyen /** 19591f91b4ccSFelipe Balbi * dwc2_hsotg_complete_request - complete a request given to us 196047a1685fSDinh Nguyen * @hsotg: The device state. 196147a1685fSDinh Nguyen * @hs_ep: The endpoint the request was on. 196247a1685fSDinh Nguyen * @hs_req: The request to complete. 196347a1685fSDinh Nguyen * @result: The result code (0 => Ok, otherwise errno) 196447a1685fSDinh Nguyen * 196547a1685fSDinh Nguyen * The given request has finished, so call the necessary completion 196647a1685fSDinh Nguyen * if it has one and then look to see if we can start a new request 196747a1685fSDinh Nguyen * on the endpoint. 196847a1685fSDinh Nguyen * 196947a1685fSDinh Nguyen * Note, expects the ep to already be locked as appropriate. 197047a1685fSDinh Nguyen */ 19711f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, 19721f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 19731f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req, 197447a1685fSDinh Nguyen int result) 197547a1685fSDinh Nguyen { 197647a1685fSDinh Nguyen if (!hs_req) { 197747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); 197847a1685fSDinh Nguyen return; 197947a1685fSDinh Nguyen } 198047a1685fSDinh Nguyen 198147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", 198247a1685fSDinh Nguyen hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); 198347a1685fSDinh Nguyen 198447a1685fSDinh Nguyen /* 198547a1685fSDinh Nguyen * only replace the status if we've not already set an error 198647a1685fSDinh Nguyen * from a previous transaction 198747a1685fSDinh Nguyen */ 198847a1685fSDinh Nguyen 198947a1685fSDinh Nguyen if (hs_req->req.status == -EINPROGRESS) 199047a1685fSDinh Nguyen hs_req->req.status = result; 199147a1685fSDinh Nguyen 199244583fecSYunzhi Li if (using_dma(hsotg)) 199344583fecSYunzhi Li dwc2_hsotg_unmap_dma(hsotg, hs_ep, hs_req); 199444583fecSYunzhi Li 19951f91b4ccSFelipe Balbi dwc2_hsotg_handle_unaligned_buf_complete(hsotg, hs_ep, hs_req); 19967d24c1b5SMian Yousaf Kaukab 199747a1685fSDinh Nguyen hs_ep->req = NULL; 199847a1685fSDinh Nguyen list_del_init(&hs_req->queue); 199947a1685fSDinh Nguyen 200047a1685fSDinh Nguyen /* 200147a1685fSDinh Nguyen * call the complete request with the locks off, just in case the 200247a1685fSDinh Nguyen * request tries to queue more work for this endpoint. 200347a1685fSDinh Nguyen */ 200447a1685fSDinh Nguyen 200547a1685fSDinh Nguyen if (hs_req->req.complete) { 200647a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 2007304f7e5eSMichal Sojka usb_gadget_giveback_request(&hs_ep->ep, &hs_req->req); 200847a1685fSDinh Nguyen spin_lock(&hsotg->lock); 200947a1685fSDinh Nguyen } 201047a1685fSDinh Nguyen 2011540ccba0SVahram Aharonyan /* In DDMA don't need to proceed to starting of next ISOC request */ 2012540ccba0SVahram Aharonyan if (using_desc_dma(hsotg) && hs_ep->isochronous) 2013540ccba0SVahram Aharonyan return; 2014540ccba0SVahram Aharonyan 201547a1685fSDinh Nguyen /* 201647a1685fSDinh Nguyen * Look to see if there is anything else to do. Note, the completion 201747a1685fSDinh Nguyen * of the previous request may have caused a new request to be started 201847a1685fSDinh Nguyen * so be careful when doing this. 201947a1685fSDinh Nguyen */ 202047a1685fSDinh Nguyen 202134c0887fSJohn Youn if (!hs_ep->req && result >= 0) 202241cc4cd2SVardan Mikayelyan dwc2_gadget_start_next_request(hs_ep); 202347a1685fSDinh Nguyen } 202447a1685fSDinh Nguyen 2025540ccba0SVahram Aharonyan /* 2026540ccba0SVahram Aharonyan * dwc2_gadget_complete_isoc_request_ddma - complete an isoc request in DDMA 2027540ccba0SVahram Aharonyan * @hs_ep: The endpoint the request was on. 2028540ccba0SVahram Aharonyan * 2029540ccba0SVahram Aharonyan * Get first request from the ep queue, determine descriptor on which complete 2030729cac69SMinas Harutyunyan * happened. SW discovers which descriptor currently in use by HW, adjusts 2031729cac69SMinas Harutyunyan * dma_address and calculates index of completed descriptor based on the value 2032729cac69SMinas Harutyunyan * of DEPDMA register. Update actual length of request, giveback to gadget. 2033540ccba0SVahram Aharonyan */ 2034540ccba0SVahram Aharonyan static void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep) 2035540ccba0SVahram Aharonyan { 2036540ccba0SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 2037540ccba0SVahram Aharonyan struct dwc2_hsotg_req *hs_req; 2038540ccba0SVahram Aharonyan struct usb_request *ureq; 2039540ccba0SVahram Aharonyan u32 desc_sts; 2040540ccba0SVahram Aharonyan u32 mask; 2041540ccba0SVahram Aharonyan 2042729cac69SMinas Harutyunyan desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status; 2043729cac69SMinas Harutyunyan 2044729cac69SMinas Harutyunyan /* Process only descriptors with buffer status set to DMA done */ 2045729cac69SMinas Harutyunyan while ((desc_sts & DEV_DMA_BUFF_STS_MASK) >> 2046729cac69SMinas Harutyunyan DEV_DMA_BUFF_STS_SHIFT == DEV_DMA_BUFF_STS_DMADONE) { 2047729cac69SMinas Harutyunyan 2048540ccba0SVahram Aharonyan hs_req = get_ep_head(hs_ep); 2049540ccba0SVahram Aharonyan if (!hs_req) { 2050540ccba0SVahram Aharonyan dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n", __func__); 2051540ccba0SVahram Aharonyan return; 2052540ccba0SVahram Aharonyan } 2053540ccba0SVahram Aharonyan ureq = &hs_req->req; 2054540ccba0SVahram Aharonyan 2055729cac69SMinas Harutyunyan /* Check completion status */ 2056729cac69SMinas Harutyunyan if ((desc_sts & DEV_DMA_STS_MASK) >> DEV_DMA_STS_SHIFT == 2057729cac69SMinas Harutyunyan DEV_DMA_STS_SUCC) { 2058540ccba0SVahram Aharonyan mask = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_MASK : 2059540ccba0SVahram Aharonyan DEV_DMA_ISOC_RX_NBYTES_MASK; 2060729cac69SMinas Harutyunyan ureq->actual = ureq->length - ((desc_sts & mask) >> 2061729cac69SMinas Harutyunyan DEV_DMA_ISOC_NBYTES_SHIFT); 2062540ccba0SVahram Aharonyan 2063729cac69SMinas Harutyunyan /* Adjust actual len for ISOC Out if len is 2064729cac69SMinas Harutyunyan * not align of 4 2065729cac69SMinas Harutyunyan */ 206695d2b037SVahram Aharonyan if (!hs_ep->dir_in && ureq->length & 0x3) 206795d2b037SVahram Aharonyan ureq->actual += 4 - (ureq->length & 0x3); 2068729cac69SMinas Harutyunyan } 206995d2b037SVahram Aharonyan 2070540ccba0SVahram Aharonyan dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 2071729cac69SMinas Harutyunyan 2072729cac69SMinas Harutyunyan hs_ep->compl_desc++; 2073729cac69SMinas Harutyunyan if (hs_ep->compl_desc > (MAX_DMA_DESC_NUM_GENERIC - 1)) 2074729cac69SMinas Harutyunyan hs_ep->compl_desc = 0; 2075729cac69SMinas Harutyunyan desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status; 2076729cac69SMinas Harutyunyan } 2077540ccba0SVahram Aharonyan } 2078540ccba0SVahram Aharonyan 2079540ccba0SVahram Aharonyan /* 2080729cac69SMinas Harutyunyan * dwc2_gadget_handle_isoc_bna - handle BNA interrupt for ISOC. 2081729cac69SMinas Harutyunyan * @hs_ep: The isochronous endpoint. 2082540ccba0SVahram Aharonyan * 2083729cac69SMinas Harutyunyan * If EP ISOC OUT then need to flush RX FIFO to remove source of BNA 2084729cac69SMinas Harutyunyan * interrupt. Reset target frame and next_desc to allow to start 2085729cac69SMinas Harutyunyan * ISOC's on NAK interrupt for IN direction or on OUTTKNEPDIS 2086729cac69SMinas Harutyunyan * interrupt for OUT direction. 2087540ccba0SVahram Aharonyan */ 2088729cac69SMinas Harutyunyan static void dwc2_gadget_handle_isoc_bna(struct dwc2_hsotg_ep *hs_ep) 2089540ccba0SVahram Aharonyan { 2090540ccba0SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 2091540ccba0SVahram Aharonyan 2092729cac69SMinas Harutyunyan if (!hs_ep->dir_in) 2093729cac69SMinas Harutyunyan dwc2_flush_rx_fifo(hsotg); 2094729cac69SMinas Harutyunyan dwc2_hsotg_complete_request(hsotg, hs_ep, get_ep_head(hs_ep), 0); 2095540ccba0SVahram Aharonyan 2096729cac69SMinas Harutyunyan hs_ep->target_frame = TARGET_FRAME_INITIAL; 2097540ccba0SVahram Aharonyan hs_ep->next_desc = 0; 2098729cac69SMinas Harutyunyan hs_ep->compl_desc = 0; 2099540ccba0SVahram Aharonyan } 2100540ccba0SVahram Aharonyan 210147a1685fSDinh Nguyen /** 21021f91b4ccSFelipe Balbi * dwc2_hsotg_rx_data - receive data from the FIFO for an endpoint 210347a1685fSDinh Nguyen * @hsotg: The device state. 210447a1685fSDinh Nguyen * @ep_idx: The endpoint index for the data 210547a1685fSDinh Nguyen * @size: The size of data in the fifo, in bytes 210647a1685fSDinh Nguyen * 210747a1685fSDinh Nguyen * The FIFO status shows there is data to read from the FIFO for a given 210847a1685fSDinh Nguyen * endpoint, so sort out whether we need to read the data into a request 210947a1685fSDinh Nguyen * that has been made for that endpoint. 211047a1685fSDinh Nguyen */ 21111f91b4ccSFelipe Balbi static void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size) 211247a1685fSDinh Nguyen { 21131f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[ep_idx]; 21141f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 211547a1685fSDinh Nguyen void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx); 211647a1685fSDinh Nguyen int to_read; 211747a1685fSDinh Nguyen int max_req; 211847a1685fSDinh Nguyen int read_ptr; 211947a1685fSDinh Nguyen 212047a1685fSDinh Nguyen if (!hs_req) { 212195c8bc36SAntti Seppälä u32 epctl = dwc2_readl(hsotg->regs + DOEPCTL(ep_idx)); 212247a1685fSDinh Nguyen int ptr; 212347a1685fSDinh Nguyen 21246b448af4SRobert Baldyga dev_dbg(hsotg->dev, 212547a1685fSDinh Nguyen "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", 212647a1685fSDinh Nguyen __func__, size, ep_idx, epctl); 212747a1685fSDinh Nguyen 212847a1685fSDinh Nguyen /* dump the data from the FIFO, we've nothing we can do */ 212947a1685fSDinh Nguyen for (ptr = 0; ptr < size; ptr += 4) 213095c8bc36SAntti Seppälä (void)dwc2_readl(fifo); 213147a1685fSDinh Nguyen 213247a1685fSDinh Nguyen return; 213347a1685fSDinh Nguyen } 213447a1685fSDinh Nguyen 213547a1685fSDinh Nguyen to_read = size; 213647a1685fSDinh Nguyen read_ptr = hs_req->req.actual; 213747a1685fSDinh Nguyen max_req = hs_req->req.length - read_ptr; 213847a1685fSDinh Nguyen 213947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", 214047a1685fSDinh Nguyen __func__, to_read, max_req, read_ptr, hs_req->req.length); 214147a1685fSDinh Nguyen 214247a1685fSDinh Nguyen if (to_read > max_req) { 214347a1685fSDinh Nguyen /* 214447a1685fSDinh Nguyen * more data appeared than we where willing 214547a1685fSDinh Nguyen * to deal with in this request. 214647a1685fSDinh Nguyen */ 214747a1685fSDinh Nguyen 214847a1685fSDinh Nguyen /* currently we don't deal this */ 214947a1685fSDinh Nguyen WARN_ON_ONCE(1); 215047a1685fSDinh Nguyen } 215147a1685fSDinh Nguyen 215247a1685fSDinh Nguyen hs_ep->total_data += to_read; 215347a1685fSDinh Nguyen hs_req->req.actual += to_read; 215447a1685fSDinh Nguyen to_read = DIV_ROUND_UP(to_read, 4); 215547a1685fSDinh Nguyen 215647a1685fSDinh Nguyen /* 215747a1685fSDinh Nguyen * note, we might over-write the buffer end by 3 bytes depending on 215847a1685fSDinh Nguyen * alignment of the data. 215947a1685fSDinh Nguyen */ 216047a1685fSDinh Nguyen ioread32_rep(fifo, hs_req->req.buf + read_ptr, to_read); 216147a1685fSDinh Nguyen } 216247a1685fSDinh Nguyen 216347a1685fSDinh Nguyen /** 21641f91b4ccSFelipe Balbi * dwc2_hsotg_ep0_zlp - send/receive zero-length packet on control endpoint 216547a1685fSDinh Nguyen * @hsotg: The device instance 2166fe0b94abSMian Yousaf Kaukab * @dir_in: If IN zlp 216747a1685fSDinh Nguyen * 216847a1685fSDinh Nguyen * Generate a zero-length IN packet request for terminating a SETUP 216947a1685fSDinh Nguyen * transaction. 217047a1685fSDinh Nguyen * 217147a1685fSDinh Nguyen * Note, since we don't write any data to the TxFIFO, then it is 217247a1685fSDinh Nguyen * currently believed that we do not need to wait for any space in 217347a1685fSDinh Nguyen * the TxFIFO. 217447a1685fSDinh Nguyen */ 21751f91b4ccSFelipe Balbi static void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in) 217647a1685fSDinh Nguyen { 2177c6f5c050SMian Yousaf Kaukab /* eps_out[0] is used in both directions */ 2178fe0b94abSMian Yousaf Kaukab hsotg->eps_out[0]->dir_in = dir_in; 2179fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = dir_in ? DWC2_EP0_STATUS_IN : DWC2_EP0_STATUS_OUT; 218047a1685fSDinh Nguyen 21811f91b4ccSFelipe Balbi dwc2_hsotg_program_zlp(hsotg, hsotg->eps_out[0]); 218247a1685fSDinh Nguyen } 218347a1685fSDinh Nguyen 2184ec1f9d9fSRoman Bacik static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg, 2185ec1f9d9fSRoman Bacik u32 epctl_reg) 2186ec1f9d9fSRoman Bacik { 2187ec1f9d9fSRoman Bacik u32 ctrl; 2188ec1f9d9fSRoman Bacik 2189ec1f9d9fSRoman Bacik ctrl = dwc2_readl(hsotg->regs + epctl_reg); 2190ec1f9d9fSRoman Bacik if (ctrl & DXEPCTL_EOFRNUM) 2191ec1f9d9fSRoman Bacik ctrl |= DXEPCTL_SETEVENFR; 2192ec1f9d9fSRoman Bacik else 2193ec1f9d9fSRoman Bacik ctrl |= DXEPCTL_SETODDFR; 2194ec1f9d9fSRoman Bacik dwc2_writel(ctrl, hsotg->regs + epctl_reg); 2195ec1f9d9fSRoman Bacik } 2196ec1f9d9fSRoman Bacik 2197aa3e8bc8SVahram Aharonyan /* 2198aa3e8bc8SVahram Aharonyan * dwc2_gadget_get_xfersize_ddma - get transferred bytes amount from desc 2199aa3e8bc8SVahram Aharonyan * @hs_ep - The endpoint on which transfer went 2200aa3e8bc8SVahram Aharonyan * 2201aa3e8bc8SVahram Aharonyan * Iterate over endpoints descriptor chain and get info on bytes remained 2202aa3e8bc8SVahram Aharonyan * in DMA descriptors after transfer has completed. Used for non isoc EPs. 2203aa3e8bc8SVahram Aharonyan */ 2204aa3e8bc8SVahram Aharonyan static unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep) 2205aa3e8bc8SVahram Aharonyan { 2206aa3e8bc8SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 2207aa3e8bc8SVahram Aharonyan unsigned int bytes_rem = 0; 2208aa3e8bc8SVahram Aharonyan struct dwc2_dma_desc *desc = hs_ep->desc_list; 2209aa3e8bc8SVahram Aharonyan int i; 2210aa3e8bc8SVahram Aharonyan u32 status; 2211aa3e8bc8SVahram Aharonyan 2212aa3e8bc8SVahram Aharonyan if (!desc) 2213aa3e8bc8SVahram Aharonyan return -EINVAL; 2214aa3e8bc8SVahram Aharonyan 2215aa3e8bc8SVahram Aharonyan for (i = 0; i < hs_ep->desc_count; ++i) { 2216aa3e8bc8SVahram Aharonyan status = desc->status; 2217aa3e8bc8SVahram Aharonyan bytes_rem += status & DEV_DMA_NBYTES_MASK; 2218aa3e8bc8SVahram Aharonyan 2219aa3e8bc8SVahram Aharonyan if (status & DEV_DMA_STS_MASK) 2220aa3e8bc8SVahram Aharonyan dev_err(hsotg->dev, "descriptor %d closed with %x\n", 2221aa3e8bc8SVahram Aharonyan i, status & DEV_DMA_STS_MASK); 2222aa3e8bc8SVahram Aharonyan } 2223aa3e8bc8SVahram Aharonyan 2224aa3e8bc8SVahram Aharonyan return bytes_rem; 2225aa3e8bc8SVahram Aharonyan } 2226aa3e8bc8SVahram Aharonyan 222747a1685fSDinh Nguyen /** 22281f91b4ccSFelipe Balbi * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO 222947a1685fSDinh Nguyen * @hsotg: The device instance 223047a1685fSDinh Nguyen * @epnum: The endpoint received from 223147a1685fSDinh Nguyen * 223247a1685fSDinh Nguyen * The RXFIFO has delivered an OutDone event, which means that the data 223347a1685fSDinh Nguyen * transfer for an OUT endpoint has been completed, either by a short 223447a1685fSDinh Nguyen * packet or by the finish of a transfer. 223547a1685fSDinh Nguyen */ 22361f91b4ccSFelipe Balbi static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) 223747a1685fSDinh Nguyen { 223895c8bc36SAntti Seppälä u32 epsize = dwc2_readl(hsotg->regs + DOEPTSIZ(epnum)); 22391f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[epnum]; 22401f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 224147a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 22429da51974SJohn Youn unsigned int size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 224347a1685fSDinh Nguyen int result = 0; 224447a1685fSDinh Nguyen 224547a1685fSDinh Nguyen if (!hs_req) { 224647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no request active\n", __func__); 224747a1685fSDinh Nguyen return; 224847a1685fSDinh Nguyen } 224947a1685fSDinh Nguyen 2250fe0b94abSMian Yousaf Kaukab if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_OUT) { 2251fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "zlp packet received\n"); 22521f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 22531f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 2254fe0b94abSMian Yousaf Kaukab return; 2255fe0b94abSMian Yousaf Kaukab } 2256fe0b94abSMian Yousaf Kaukab 2257aa3e8bc8SVahram Aharonyan if (using_desc_dma(hsotg)) 2258aa3e8bc8SVahram Aharonyan size_left = dwc2_gadget_get_xfersize_ddma(hs_ep); 2259aa3e8bc8SVahram Aharonyan 226047a1685fSDinh Nguyen if (using_dma(hsotg)) { 22619da51974SJohn Youn unsigned int size_done; 226247a1685fSDinh Nguyen 226347a1685fSDinh Nguyen /* 226447a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much 226547a1685fSDinh Nguyen * is left in the endpoint size register and then working it 226647a1685fSDinh Nguyen * out from the amount we loaded for the transfer. 226747a1685fSDinh Nguyen * 226847a1685fSDinh Nguyen * We need to do this as DMA pointers are always 32bit aligned 226947a1685fSDinh Nguyen * so may overshoot/undershoot the transfer. 227047a1685fSDinh Nguyen */ 227147a1685fSDinh Nguyen 227247a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 227347a1685fSDinh Nguyen size_done += hs_ep->last_load; 227447a1685fSDinh Nguyen 227547a1685fSDinh Nguyen req->actual = size_done; 227647a1685fSDinh Nguyen } 227747a1685fSDinh Nguyen 227847a1685fSDinh Nguyen /* if there is more request to do, schedule new transfer */ 227947a1685fSDinh Nguyen if (req->actual < req->length && size_left == 0) { 22801f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 228147a1685fSDinh Nguyen return; 228247a1685fSDinh Nguyen } 228347a1685fSDinh Nguyen 228447a1685fSDinh Nguyen if (req->actual < req->length && req->short_not_ok) { 228547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", 228647a1685fSDinh Nguyen __func__, req->actual, req->length); 228747a1685fSDinh Nguyen 228847a1685fSDinh Nguyen /* 228947a1685fSDinh Nguyen * todo - what should we return here? there's no one else 229047a1685fSDinh Nguyen * even bothering to check the status. 229147a1685fSDinh Nguyen */ 229247a1685fSDinh Nguyen } 229347a1685fSDinh Nguyen 2294ef750c71SVahram Aharonyan /* DDMA IN status phase will start from StsPhseRcvd interrupt */ 2295ef750c71SVahram Aharonyan if (!using_desc_dma(hsotg) && epnum == 0 && 2296ef750c71SVahram Aharonyan hsotg->ep0_state == DWC2_EP0_DATA_OUT) { 2297fe0b94abSMian Yousaf Kaukab /* Move to STATUS IN */ 22981f91b4ccSFelipe Balbi dwc2_hsotg_ep0_zlp(hsotg, true); 2299fe0b94abSMian Yousaf Kaukab return; 230047a1685fSDinh Nguyen } 230147a1685fSDinh Nguyen 2302ec1f9d9fSRoman Bacik /* 2303ec1f9d9fSRoman Bacik * Slave mode OUT transfers do not go through XferComplete so 2304ec1f9d9fSRoman Bacik * adjust the ISOC parity here. 2305ec1f9d9fSRoman Bacik */ 2306ec1f9d9fSRoman Bacik if (!using_dma(hsotg)) { 2307ec1f9d9fSRoman Bacik if (hs_ep->isochronous && hs_ep->interval == 1) 2308ec1f9d9fSRoman Bacik dwc2_hsotg_change_ep_iso_parity(hsotg, DOEPCTL(epnum)); 2309837e9f00SVardan Mikayelyan else if (hs_ep->isochronous && hs_ep->interval > 1) 2310837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 2311ec1f9d9fSRoman Bacik } 2312ec1f9d9fSRoman Bacik 23131f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result); 231447a1685fSDinh Nguyen } 231547a1685fSDinh Nguyen 231647a1685fSDinh Nguyen /** 23171f91b4ccSFelipe Balbi * dwc2_hsotg_handle_rx - RX FIFO has data 231847a1685fSDinh Nguyen * @hsotg: The device instance 231947a1685fSDinh Nguyen * 232047a1685fSDinh Nguyen * The IRQ handler has detected that the RX FIFO has some data in it 232147a1685fSDinh Nguyen * that requires processing, so find out what is in there and do the 232247a1685fSDinh Nguyen * appropriate read. 232347a1685fSDinh Nguyen * 232447a1685fSDinh Nguyen * The RXFIFO is a true FIFO, the packets coming out are still in packet 232547a1685fSDinh Nguyen * chunks, so if you have x packets received on an endpoint you'll get x 232647a1685fSDinh Nguyen * FIFO events delivered, each with a packet's worth of data in it. 232747a1685fSDinh Nguyen * 232847a1685fSDinh Nguyen * When using DMA, we should not be processing events from the RXFIFO 232947a1685fSDinh Nguyen * as the actual data should be sent to the memory directly and we turn 233047a1685fSDinh Nguyen * on the completion interrupts to get notifications of transfer completion. 233147a1685fSDinh Nguyen */ 23321f91b4ccSFelipe Balbi static void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg) 233347a1685fSDinh Nguyen { 233495c8bc36SAntti Seppälä u32 grxstsr = dwc2_readl(hsotg->regs + GRXSTSP); 233547a1685fSDinh Nguyen u32 epnum, status, size; 233647a1685fSDinh Nguyen 233747a1685fSDinh Nguyen WARN_ON(using_dma(hsotg)); 233847a1685fSDinh Nguyen 233947a1685fSDinh Nguyen epnum = grxstsr & GRXSTS_EPNUM_MASK; 234047a1685fSDinh Nguyen status = grxstsr & GRXSTS_PKTSTS_MASK; 234147a1685fSDinh Nguyen 234247a1685fSDinh Nguyen size = grxstsr & GRXSTS_BYTECNT_MASK; 234347a1685fSDinh Nguyen size >>= GRXSTS_BYTECNT_SHIFT; 234447a1685fSDinh Nguyen 234547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", 234647a1685fSDinh Nguyen __func__, grxstsr, size, epnum); 234747a1685fSDinh Nguyen 234847a1685fSDinh Nguyen switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { 234947a1685fSDinh Nguyen case GRXSTS_PKTSTS_GLOBALOUTNAK: 235047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GLOBALOUTNAK\n"); 235147a1685fSDinh Nguyen break; 235247a1685fSDinh Nguyen 235347a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTDONE: 235447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", 23551f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg)); 235647a1685fSDinh Nguyen 235747a1685fSDinh Nguyen if (!using_dma(hsotg)) 23581f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, epnum); 235947a1685fSDinh Nguyen break; 236047a1685fSDinh Nguyen 236147a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPDONE: 236247a1685fSDinh Nguyen dev_dbg(hsotg->dev, 236347a1685fSDinh Nguyen "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 23641f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg), 236595c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL(0))); 2366fe0b94abSMian Yousaf Kaukab /* 23671f91b4ccSFelipe Balbi * Call dwc2_hsotg_handle_outdone here if it was not called from 2368fe0b94abSMian Yousaf Kaukab * GRXSTS_PKTSTS_OUTDONE. That is, if the core didn't 2369fe0b94abSMian Yousaf Kaukab * generate GRXSTS_PKTSTS_OUTDONE for setup packet. 2370fe0b94abSMian Yousaf Kaukab */ 2371fe0b94abSMian Yousaf Kaukab if (hsotg->ep0_state == DWC2_EP0_SETUP) 23721f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, epnum); 237347a1685fSDinh Nguyen break; 237447a1685fSDinh Nguyen 237547a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTRX: 23761f91b4ccSFelipe Balbi dwc2_hsotg_rx_data(hsotg, epnum, size); 237747a1685fSDinh Nguyen break; 237847a1685fSDinh Nguyen 237947a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPRX: 238047a1685fSDinh Nguyen dev_dbg(hsotg->dev, 238147a1685fSDinh Nguyen "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 23821f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg), 238395c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL(0))); 238447a1685fSDinh Nguyen 2385fe0b94abSMian Yousaf Kaukab WARN_ON(hsotg->ep0_state != DWC2_EP0_SETUP); 2386fe0b94abSMian Yousaf Kaukab 23871f91b4ccSFelipe Balbi dwc2_hsotg_rx_data(hsotg, epnum, size); 238847a1685fSDinh Nguyen break; 238947a1685fSDinh Nguyen 239047a1685fSDinh Nguyen default: 239147a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: unknown status %08x\n", 239247a1685fSDinh Nguyen __func__, grxstsr); 239347a1685fSDinh Nguyen 23941f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 239547a1685fSDinh Nguyen break; 239647a1685fSDinh Nguyen } 239747a1685fSDinh Nguyen } 239847a1685fSDinh Nguyen 239947a1685fSDinh Nguyen /** 24001f91b4ccSFelipe Balbi * dwc2_hsotg_ep0_mps - turn max packet size into register setting 240147a1685fSDinh Nguyen * @mps: The maximum packet size in bytes. 240247a1685fSDinh Nguyen */ 24031f91b4ccSFelipe Balbi static u32 dwc2_hsotg_ep0_mps(unsigned int mps) 240447a1685fSDinh Nguyen { 240547a1685fSDinh Nguyen switch (mps) { 240647a1685fSDinh Nguyen case 64: 240747a1685fSDinh Nguyen return D0EPCTL_MPS_64; 240847a1685fSDinh Nguyen case 32: 240947a1685fSDinh Nguyen return D0EPCTL_MPS_32; 241047a1685fSDinh Nguyen case 16: 241147a1685fSDinh Nguyen return D0EPCTL_MPS_16; 241247a1685fSDinh Nguyen case 8: 241347a1685fSDinh Nguyen return D0EPCTL_MPS_8; 241447a1685fSDinh Nguyen } 241547a1685fSDinh Nguyen 241647a1685fSDinh Nguyen /* bad max packet size, warn and return invalid result */ 241747a1685fSDinh Nguyen WARN_ON(1); 241847a1685fSDinh Nguyen return (u32)-1; 241947a1685fSDinh Nguyen } 242047a1685fSDinh Nguyen 242147a1685fSDinh Nguyen /** 24221f91b4ccSFelipe Balbi * dwc2_hsotg_set_ep_maxpacket - set endpoint's max-packet field 242347a1685fSDinh Nguyen * @hsotg: The driver state. 242447a1685fSDinh Nguyen * @ep: The index number of the endpoint 242547a1685fSDinh Nguyen * @mps: The maximum packet size in bytes 2426ee2c40deSVardan Mikayelyan * @mc: The multicount value 242747a1685fSDinh Nguyen * 242847a1685fSDinh Nguyen * Configure the maximum packet size for the given endpoint, updating 242947a1685fSDinh Nguyen * the hardware control registers to reflect this. 243047a1685fSDinh Nguyen */ 24311f91b4ccSFelipe Balbi static void dwc2_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg, 2432ee2c40deSVardan Mikayelyan unsigned int ep, unsigned int mps, 2433ee2c40deSVardan Mikayelyan unsigned int mc, unsigned int dir_in) 243447a1685fSDinh Nguyen { 24351f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep; 243647a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 243747a1685fSDinh Nguyen u32 reg; 243847a1685fSDinh Nguyen 2439c6f5c050SMian Yousaf Kaukab hs_ep = index_to_ep(hsotg, ep, dir_in); 2440c6f5c050SMian Yousaf Kaukab if (!hs_ep) 2441c6f5c050SMian Yousaf Kaukab return; 2442c6f5c050SMian Yousaf Kaukab 244347a1685fSDinh Nguyen if (ep == 0) { 2444ee2c40deSVardan Mikayelyan u32 mps_bytes = mps; 2445ee2c40deSVardan Mikayelyan 244647a1685fSDinh Nguyen /* EP0 is a special case */ 2447ee2c40deSVardan Mikayelyan mps = dwc2_hsotg_ep0_mps(mps_bytes); 2448ee2c40deSVardan Mikayelyan if (mps > 3) 244947a1685fSDinh Nguyen goto bad_mps; 2450ee2c40deSVardan Mikayelyan hs_ep->ep.maxpacket = mps_bytes; 245147a1685fSDinh Nguyen hs_ep->mc = 1; 245247a1685fSDinh Nguyen } else { 2453ee2c40deSVardan Mikayelyan if (mps > 1024) 245447a1685fSDinh Nguyen goto bad_mps; 2455ee2c40deSVardan Mikayelyan hs_ep->mc = mc; 2456ee2c40deSVardan Mikayelyan if (mc > 3) 245747a1685fSDinh Nguyen goto bad_mps; 2458ee2c40deSVardan Mikayelyan hs_ep->ep.maxpacket = mps; 245947a1685fSDinh Nguyen } 246047a1685fSDinh Nguyen 2461c6f5c050SMian Yousaf Kaukab if (dir_in) { 246295c8bc36SAntti Seppälä reg = dwc2_readl(regs + DIEPCTL(ep)); 246347a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 2464ee2c40deSVardan Mikayelyan reg |= mps; 246595c8bc36SAntti Seppälä dwc2_writel(reg, regs + DIEPCTL(ep)); 2466c6f5c050SMian Yousaf Kaukab } else { 246795c8bc36SAntti Seppälä reg = dwc2_readl(regs + DOEPCTL(ep)); 246847a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 2469ee2c40deSVardan Mikayelyan reg |= mps; 247095c8bc36SAntti Seppälä dwc2_writel(reg, regs + DOEPCTL(ep)); 247147a1685fSDinh Nguyen } 247247a1685fSDinh Nguyen 247347a1685fSDinh Nguyen return; 247447a1685fSDinh Nguyen 247547a1685fSDinh Nguyen bad_mps: 247647a1685fSDinh Nguyen dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); 247747a1685fSDinh Nguyen } 247847a1685fSDinh Nguyen 247947a1685fSDinh Nguyen /** 24801f91b4ccSFelipe Balbi * dwc2_hsotg_txfifo_flush - flush Tx FIFO 248147a1685fSDinh Nguyen * @hsotg: The driver state 248247a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 248347a1685fSDinh Nguyen */ 24841f91b4ccSFelipe Balbi static void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx) 248547a1685fSDinh Nguyen { 248695c8bc36SAntti Seppälä dwc2_writel(GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH, 248747a1685fSDinh Nguyen hsotg->regs + GRSTCTL); 248847a1685fSDinh Nguyen 248947a1685fSDinh Nguyen /* wait until the fifo is flushed */ 249079d6b8c5SSevak Arakelyan if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 100)) 249179d6b8c5SSevak Arakelyan dev_warn(hsotg->dev, "%s: timeout flushing fifo GRSTCTL_TXFFLSH\n", 249279d6b8c5SSevak Arakelyan __func__); 249347a1685fSDinh Nguyen } 249447a1685fSDinh Nguyen 249547a1685fSDinh Nguyen /** 24961f91b4ccSFelipe Balbi * dwc2_hsotg_trytx - check to see if anything needs transmitting 249747a1685fSDinh Nguyen * @hsotg: The driver state 249847a1685fSDinh Nguyen * @hs_ep: The driver endpoint to check. 249947a1685fSDinh Nguyen * 250047a1685fSDinh Nguyen * Check to see if there is a request that has data to send, and if so 250147a1685fSDinh Nguyen * make an attempt to write data into the FIFO. 250247a1685fSDinh Nguyen */ 25031f91b4ccSFelipe Balbi static int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, 25041f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 250547a1685fSDinh Nguyen { 25061f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 250747a1685fSDinh Nguyen 250847a1685fSDinh Nguyen if (!hs_ep->dir_in || !hs_req) { 250947a1685fSDinh Nguyen /** 251047a1685fSDinh Nguyen * if request is not enqueued, we disable interrupts 251147a1685fSDinh Nguyen * for endpoints, excepting ep0 251247a1685fSDinh Nguyen */ 251347a1685fSDinh Nguyen if (hs_ep->index != 0) 25141f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, 251547a1685fSDinh Nguyen hs_ep->dir_in, 0); 251647a1685fSDinh Nguyen return 0; 251747a1685fSDinh Nguyen } 251847a1685fSDinh Nguyen 251947a1685fSDinh Nguyen if (hs_req->req.actual < hs_req->req.length) { 252047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "trying to write more for ep%d\n", 252147a1685fSDinh Nguyen hs_ep->index); 25221f91b4ccSFelipe Balbi return dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 252347a1685fSDinh Nguyen } 252447a1685fSDinh Nguyen 252547a1685fSDinh Nguyen return 0; 252647a1685fSDinh Nguyen } 252747a1685fSDinh Nguyen 252847a1685fSDinh Nguyen /** 25291f91b4ccSFelipe Balbi * dwc2_hsotg_complete_in - complete IN transfer 253047a1685fSDinh Nguyen * @hsotg: The device state. 253147a1685fSDinh Nguyen * @hs_ep: The endpoint that has just completed. 253247a1685fSDinh Nguyen * 253347a1685fSDinh Nguyen * An IN transfer has been completed, update the transfer's state and then 253447a1685fSDinh Nguyen * call the relevant completion routines. 253547a1685fSDinh Nguyen */ 25361f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, 25371f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 253847a1685fSDinh Nguyen { 25391f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 254095c8bc36SAntti Seppälä u32 epsize = dwc2_readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); 254147a1685fSDinh Nguyen int size_left, size_done; 254247a1685fSDinh Nguyen 254347a1685fSDinh Nguyen if (!hs_req) { 254447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "XferCompl but no req\n"); 254547a1685fSDinh Nguyen return; 254647a1685fSDinh Nguyen } 254747a1685fSDinh Nguyen 254847a1685fSDinh Nguyen /* Finish ZLP handling for IN EP0 transactions */ 2549fe0b94abSMian Yousaf Kaukab if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) { 2550fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "zlp packet sent\n"); 2551c3b22fe2SRazmik Karapetyan 2552c3b22fe2SRazmik Karapetyan /* 2553c3b22fe2SRazmik Karapetyan * While send zlp for DWC2_EP0_STATUS_IN EP direction was 2554c3b22fe2SRazmik Karapetyan * changed to IN. Change back to complete OUT transfer request 2555c3b22fe2SRazmik Karapetyan */ 2556c3b22fe2SRazmik Karapetyan hs_ep->dir_in = 0; 2557c3b22fe2SRazmik Karapetyan 25581f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 25599e14d0a5SGregory Herrero if (hsotg->test_mode) { 25609e14d0a5SGregory Herrero int ret; 25619e14d0a5SGregory Herrero 25621f91b4ccSFelipe Balbi ret = dwc2_hsotg_set_test_mode(hsotg, hsotg->test_mode); 25639e14d0a5SGregory Herrero if (ret < 0) { 25649e14d0a5SGregory Herrero dev_dbg(hsotg->dev, "Invalid Test #%d\n", 25659e14d0a5SGregory Herrero hsotg->test_mode); 25661f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hsotg); 25679e14d0a5SGregory Herrero return; 25689e14d0a5SGregory Herrero } 25699e14d0a5SGregory Herrero } 25701f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 257147a1685fSDinh Nguyen return; 257247a1685fSDinh Nguyen } 257347a1685fSDinh Nguyen 257447a1685fSDinh Nguyen /* 257547a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much is left 257647a1685fSDinh Nguyen * in the endpoint size register and then working it out from 257747a1685fSDinh Nguyen * the amount we loaded for the transfer. 257847a1685fSDinh Nguyen * 257947a1685fSDinh Nguyen * We do this even for DMA, as the transfer may have incremented 258047a1685fSDinh Nguyen * past the end of the buffer (DMA transfers are always 32bit 258147a1685fSDinh Nguyen * aligned). 258247a1685fSDinh Nguyen */ 2583aa3e8bc8SVahram Aharonyan if (using_desc_dma(hsotg)) { 2584aa3e8bc8SVahram Aharonyan size_left = dwc2_gadget_get_xfersize_ddma(hs_ep); 2585aa3e8bc8SVahram Aharonyan if (size_left < 0) 2586aa3e8bc8SVahram Aharonyan dev_err(hsotg->dev, "error parsing DDMA results %d\n", 2587aa3e8bc8SVahram Aharonyan size_left); 2588aa3e8bc8SVahram Aharonyan } else { 258947a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 2590aa3e8bc8SVahram Aharonyan } 259147a1685fSDinh Nguyen 259247a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 259347a1685fSDinh Nguyen size_done += hs_ep->last_load; 259447a1685fSDinh Nguyen 259547a1685fSDinh Nguyen if (hs_req->req.actual != size_done) 259647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", 259747a1685fSDinh Nguyen __func__, hs_req->req.actual, size_done); 259847a1685fSDinh Nguyen 259947a1685fSDinh Nguyen hs_req->req.actual = size_done; 260047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", 260147a1685fSDinh Nguyen hs_req->req.length, hs_req->req.actual, hs_req->req.zero); 260247a1685fSDinh Nguyen 260347a1685fSDinh Nguyen if (!size_left && hs_req->req.actual < hs_req->req.length) { 260447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); 26051f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 2606fe0b94abSMian Yousaf Kaukab return; 2607fe0b94abSMian Yousaf Kaukab } 2608fe0b94abSMian Yousaf Kaukab 2609f71b5e25SMian Yousaf Kaukab /* Zlp for all endpoints, for ep0 only in DATA IN stage */ 26108a20fa45SMian Yousaf Kaukab if (hs_ep->send_zlp) { 26111f91b4ccSFelipe Balbi dwc2_hsotg_program_zlp(hsotg, hs_ep); 26128a20fa45SMian Yousaf Kaukab hs_ep->send_zlp = 0; 2613f71b5e25SMian Yousaf Kaukab /* transfer will be completed on next complete interrupt */ 2614f71b5e25SMian Yousaf Kaukab return; 2615f71b5e25SMian Yousaf Kaukab } 2616f71b5e25SMian Yousaf Kaukab 2617fe0b94abSMian Yousaf Kaukab if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_DATA_IN) { 2618fe0b94abSMian Yousaf Kaukab /* Move to STATUS OUT */ 26191f91b4ccSFelipe Balbi dwc2_hsotg_ep0_zlp(hsotg, false); 2620fe0b94abSMian Yousaf Kaukab return; 2621fe0b94abSMian Yousaf Kaukab } 2622fe0b94abSMian Yousaf Kaukab 26231f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 262447a1685fSDinh Nguyen } 262547a1685fSDinh Nguyen 262647a1685fSDinh Nguyen /** 262732601588SVardan Mikayelyan * dwc2_gadget_read_ep_interrupts - reads interrupts for given ep 262832601588SVardan Mikayelyan * @hsotg: The device state. 262932601588SVardan Mikayelyan * @idx: Index of ep. 263032601588SVardan Mikayelyan * @dir_in: Endpoint direction 1-in 0-out. 263132601588SVardan Mikayelyan * 263232601588SVardan Mikayelyan * Reads for endpoint with given index and direction, by masking 263332601588SVardan Mikayelyan * epint_reg with coresponding mask. 263432601588SVardan Mikayelyan */ 263532601588SVardan Mikayelyan static u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg, 263632601588SVardan Mikayelyan unsigned int idx, int dir_in) 263732601588SVardan Mikayelyan { 263832601588SVardan Mikayelyan u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; 263932601588SVardan Mikayelyan u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 264032601588SVardan Mikayelyan u32 ints; 264132601588SVardan Mikayelyan u32 mask; 264232601588SVardan Mikayelyan u32 diepempmsk; 264332601588SVardan Mikayelyan 264432601588SVardan Mikayelyan mask = dwc2_readl(hsotg->regs + epmsk_reg); 264532601588SVardan Mikayelyan diepempmsk = dwc2_readl(hsotg->regs + DIEPEMPMSK); 264632601588SVardan Mikayelyan mask |= ((diepempmsk >> idx) & 0x1) ? DIEPMSK_TXFIFOEMPTY : 0; 264732601588SVardan Mikayelyan mask |= DXEPINT_SETUP_RCVD; 264832601588SVardan Mikayelyan 264932601588SVardan Mikayelyan ints = dwc2_readl(hsotg->regs + epint_reg); 265032601588SVardan Mikayelyan ints &= mask; 265132601588SVardan Mikayelyan return ints; 265232601588SVardan Mikayelyan } 265332601588SVardan Mikayelyan 265432601588SVardan Mikayelyan /** 2655bd9971f0SVardan Mikayelyan * dwc2_gadget_handle_ep_disabled - handle DXEPINT_EPDISBLD 2656bd9971f0SVardan Mikayelyan * @hs_ep: The endpoint on which interrupt is asserted. 2657bd9971f0SVardan Mikayelyan * 2658bd9971f0SVardan Mikayelyan * This interrupt indicates that the endpoint has been disabled per the 2659bd9971f0SVardan Mikayelyan * application's request. 2660bd9971f0SVardan Mikayelyan * 2661bd9971f0SVardan Mikayelyan * For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK, 2662bd9971f0SVardan Mikayelyan * in case of ISOC completes current request. 2663bd9971f0SVardan Mikayelyan * 2664bd9971f0SVardan Mikayelyan * For ISOC-OUT endpoints completes expired requests. If there is remaining 2665bd9971f0SVardan Mikayelyan * request starts it. 2666bd9971f0SVardan Mikayelyan */ 2667bd9971f0SVardan Mikayelyan static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) 2668bd9971f0SVardan Mikayelyan { 2669bd9971f0SVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 2670bd9971f0SVardan Mikayelyan struct dwc2_hsotg_req *hs_req; 2671bd9971f0SVardan Mikayelyan unsigned char idx = hs_ep->index; 2672bd9971f0SVardan Mikayelyan int dir_in = hs_ep->dir_in; 2673bd9971f0SVardan Mikayelyan u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 2674bd9971f0SVardan Mikayelyan int dctl = dwc2_readl(hsotg->regs + DCTL); 2675bd9971f0SVardan Mikayelyan 2676bd9971f0SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); 2677bd9971f0SVardan Mikayelyan 2678bd9971f0SVardan Mikayelyan if (dir_in) { 2679bd9971f0SVardan Mikayelyan int epctl = dwc2_readl(hsotg->regs + epctl_reg); 2680bd9971f0SVardan Mikayelyan 2681bd9971f0SVardan Mikayelyan dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); 2682bd9971f0SVardan Mikayelyan 2683bd9971f0SVardan Mikayelyan if (hs_ep->isochronous) { 2684bd9971f0SVardan Mikayelyan dwc2_hsotg_complete_in(hsotg, hs_ep); 2685bd9971f0SVardan Mikayelyan return; 2686bd9971f0SVardan Mikayelyan } 2687bd9971f0SVardan Mikayelyan 2688bd9971f0SVardan Mikayelyan if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) { 2689bd9971f0SVardan Mikayelyan int dctl = dwc2_readl(hsotg->regs + DCTL); 2690bd9971f0SVardan Mikayelyan 2691bd9971f0SVardan Mikayelyan dctl |= DCTL_CGNPINNAK; 2692bd9971f0SVardan Mikayelyan dwc2_writel(dctl, hsotg->regs + DCTL); 2693bd9971f0SVardan Mikayelyan } 2694bd9971f0SVardan Mikayelyan return; 2695bd9971f0SVardan Mikayelyan } 2696bd9971f0SVardan Mikayelyan 2697bd9971f0SVardan Mikayelyan if (dctl & DCTL_GOUTNAKSTS) { 2698bd9971f0SVardan Mikayelyan dctl |= DCTL_CGOUTNAK; 2699bd9971f0SVardan Mikayelyan dwc2_writel(dctl, hsotg->regs + DCTL); 2700bd9971f0SVardan Mikayelyan } 2701bd9971f0SVardan Mikayelyan 2702bd9971f0SVardan Mikayelyan if (!hs_ep->isochronous) 2703bd9971f0SVardan Mikayelyan return; 2704bd9971f0SVardan Mikayelyan 2705bd9971f0SVardan Mikayelyan if (list_empty(&hs_ep->queue)) { 2706bd9971f0SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: complete_ep 0x%p, ep->queue empty!\n", 2707bd9971f0SVardan Mikayelyan __func__, hs_ep); 2708bd9971f0SVardan Mikayelyan return; 2709bd9971f0SVardan Mikayelyan } 2710bd9971f0SVardan Mikayelyan 2711bd9971f0SVardan Mikayelyan do { 2712bd9971f0SVardan Mikayelyan hs_req = get_ep_head(hs_ep); 2713bd9971f0SVardan Mikayelyan if (hs_req) 2714bd9971f0SVardan Mikayelyan dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 2715bd9971f0SVardan Mikayelyan -ENODATA); 2716bd9971f0SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 2717*c7c24e7aSArtur Petrosyan /* Update current frame number value. */ 2718*c7c24e7aSArtur Petrosyan hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg); 2719bd9971f0SVardan Mikayelyan } while (dwc2_gadget_target_frame_elapsed(hs_ep)); 2720bd9971f0SVardan Mikayelyan 2721bd9971f0SVardan Mikayelyan dwc2_gadget_start_next_request(hs_ep); 2722bd9971f0SVardan Mikayelyan } 2723bd9971f0SVardan Mikayelyan 2724bd9971f0SVardan Mikayelyan /** 27255321922cSVardan Mikayelyan * dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS 27265321922cSVardan Mikayelyan * @hs_ep: The endpoint on which interrupt is asserted. 27275321922cSVardan Mikayelyan * 27285321922cSVardan Mikayelyan * This is starting point for ISOC-OUT transfer, synchronization done with 27295321922cSVardan Mikayelyan * first out token received from host while corresponding EP is disabled. 27305321922cSVardan Mikayelyan * 27315321922cSVardan Mikayelyan * Device does not know initial frame in which out token will come. For this 27325321922cSVardan Mikayelyan * HW generates OUTTKNEPDIS - out token is received while EP is disabled. Upon 27335321922cSVardan Mikayelyan * getting this interrupt SW starts calculation for next transfer frame. 27345321922cSVardan Mikayelyan */ 27355321922cSVardan Mikayelyan static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) 27365321922cSVardan Mikayelyan { 27375321922cSVardan Mikayelyan struct dwc2_hsotg *hsotg = ep->parent; 27385321922cSVardan Mikayelyan int dir_in = ep->dir_in; 27395321922cSVardan Mikayelyan u32 doepmsk; 2740540ccba0SVahram Aharonyan u32 tmp; 27415321922cSVardan Mikayelyan 27425321922cSVardan Mikayelyan if (dir_in || !ep->isochronous) 27435321922cSVardan Mikayelyan return; 27445321922cSVardan Mikayelyan 2745540ccba0SVahram Aharonyan /* 2746540ccba0SVahram Aharonyan * Store frame in which irq was asserted here, as 2747540ccba0SVahram Aharonyan * it can change while completing request below. 2748540ccba0SVahram Aharonyan */ 2749540ccba0SVahram Aharonyan tmp = dwc2_hsotg_read_frameno(hsotg); 2750540ccba0SVahram Aharonyan 2751729cac69SMinas Harutyunyan dwc2_hsotg_complete_request(hsotg, ep, get_ep_head(ep), 0); 27525321922cSVardan Mikayelyan 2753540ccba0SVahram Aharonyan if (using_desc_dma(hsotg)) { 2754540ccba0SVahram Aharonyan if (ep->target_frame == TARGET_FRAME_INITIAL) { 2755540ccba0SVahram Aharonyan /* Start first ISO Out */ 2756540ccba0SVahram Aharonyan ep->target_frame = tmp; 2757540ccba0SVahram Aharonyan dwc2_gadget_start_isoc_ddma(ep); 2758540ccba0SVahram Aharonyan } 2759540ccba0SVahram Aharonyan return; 2760540ccba0SVahram Aharonyan } 2761540ccba0SVahram Aharonyan 27625321922cSVardan Mikayelyan if (ep->interval > 1 && 27635321922cSVardan Mikayelyan ep->target_frame == TARGET_FRAME_INITIAL) { 27645321922cSVardan Mikayelyan u32 dsts; 27655321922cSVardan Mikayelyan u32 ctrl; 27665321922cSVardan Mikayelyan 27675321922cSVardan Mikayelyan dsts = dwc2_readl(hsotg->regs + DSTS); 27685321922cSVardan Mikayelyan ep->target_frame = dwc2_hsotg_read_frameno(hsotg); 27695321922cSVardan Mikayelyan dwc2_gadget_incr_frame_num(ep); 27705321922cSVardan Mikayelyan 27715321922cSVardan Mikayelyan ctrl = dwc2_readl(hsotg->regs + DOEPCTL(ep->index)); 27725321922cSVardan Mikayelyan if (ep->target_frame & 0x1) 27735321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETODDFR; 27745321922cSVardan Mikayelyan else 27755321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETEVENFR; 27765321922cSVardan Mikayelyan 27775321922cSVardan Mikayelyan dwc2_writel(ctrl, hsotg->regs + DOEPCTL(ep->index)); 27785321922cSVardan Mikayelyan } 27795321922cSVardan Mikayelyan 27805321922cSVardan Mikayelyan dwc2_gadget_start_next_request(ep); 27815321922cSVardan Mikayelyan doepmsk = dwc2_readl(hsotg->regs + DOEPMSK); 27825321922cSVardan Mikayelyan doepmsk &= ~DOEPMSK_OUTTKNEPDISMSK; 27835321922cSVardan Mikayelyan dwc2_writel(doepmsk, hsotg->regs + DOEPMSK); 27845321922cSVardan Mikayelyan } 27855321922cSVardan Mikayelyan 27865321922cSVardan Mikayelyan /** 27875321922cSVardan Mikayelyan * dwc2_gadget_handle_nak - handle NAK interrupt 27885321922cSVardan Mikayelyan * @hs_ep: The endpoint on which interrupt is asserted. 27895321922cSVardan Mikayelyan * 27905321922cSVardan Mikayelyan * This is starting point for ISOC-IN transfer, synchronization done with 27915321922cSVardan Mikayelyan * first IN token received from host while corresponding EP is disabled. 27925321922cSVardan Mikayelyan * 27935321922cSVardan Mikayelyan * Device does not know when first one token will arrive from host. On first 27945321922cSVardan Mikayelyan * token arrival HW generates 2 interrupts: 'in token received while FIFO empty' 27955321922cSVardan Mikayelyan * and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was 27965321922cSVardan Mikayelyan * sent in response to that as there was no data in FIFO. SW is basing on this 27975321922cSVardan Mikayelyan * interrupt to obtain frame in which token has come and then based on the 27985321922cSVardan Mikayelyan * interval calculates next frame for transfer. 27995321922cSVardan Mikayelyan */ 28005321922cSVardan Mikayelyan static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) 28015321922cSVardan Mikayelyan { 28025321922cSVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 28035321922cSVardan Mikayelyan int dir_in = hs_ep->dir_in; 2804729cac69SMinas Harutyunyan u32 tmp; 28055321922cSVardan Mikayelyan 28065321922cSVardan Mikayelyan if (!dir_in || !hs_ep->isochronous) 28075321922cSVardan Mikayelyan return; 28085321922cSVardan Mikayelyan 28095321922cSVardan Mikayelyan if (hs_ep->target_frame == TARGET_FRAME_INITIAL) { 2810540ccba0SVahram Aharonyan 2811729cac69SMinas Harutyunyan tmp = dwc2_hsotg_read_frameno(hsotg); 2812540ccba0SVahram Aharonyan if (using_desc_dma(hsotg)) { 2813729cac69SMinas Harutyunyan dwc2_hsotg_complete_request(hsotg, hs_ep, 2814729cac69SMinas Harutyunyan get_ep_head(hs_ep), 0); 2815729cac69SMinas Harutyunyan 2816729cac69SMinas Harutyunyan hs_ep->target_frame = tmp; 2817729cac69SMinas Harutyunyan dwc2_gadget_incr_frame_num(hs_ep); 2818540ccba0SVahram Aharonyan dwc2_gadget_start_isoc_ddma(hs_ep); 2819540ccba0SVahram Aharonyan return; 2820540ccba0SVahram Aharonyan } 2821540ccba0SVahram Aharonyan 2822729cac69SMinas Harutyunyan hs_ep->target_frame = tmp; 28235321922cSVardan Mikayelyan if (hs_ep->interval > 1) { 28245321922cSVardan Mikayelyan u32 ctrl = dwc2_readl(hsotg->regs + 28255321922cSVardan Mikayelyan DIEPCTL(hs_ep->index)); 28265321922cSVardan Mikayelyan if (hs_ep->target_frame & 0x1) 28275321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETODDFR; 28285321922cSVardan Mikayelyan else 28295321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETEVENFR; 28305321922cSVardan Mikayelyan 28315321922cSVardan Mikayelyan dwc2_writel(ctrl, hsotg->regs + DIEPCTL(hs_ep->index)); 28325321922cSVardan Mikayelyan } 28335321922cSVardan Mikayelyan 28345321922cSVardan Mikayelyan dwc2_hsotg_complete_request(hsotg, hs_ep, 28355321922cSVardan Mikayelyan get_ep_head(hs_ep), 0); 28365321922cSVardan Mikayelyan } 28375321922cSVardan Mikayelyan 2838729cac69SMinas Harutyunyan if (!using_desc_dma(hsotg)) 28395321922cSVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 28405321922cSVardan Mikayelyan } 28415321922cSVardan Mikayelyan 28425321922cSVardan Mikayelyan /** 28431f91b4ccSFelipe Balbi * dwc2_hsotg_epint - handle an in/out endpoint interrupt 284447a1685fSDinh Nguyen * @hsotg: The driver state 284547a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 284647a1685fSDinh Nguyen * @dir_in: Set if this is an IN endpoint 284747a1685fSDinh Nguyen * 284847a1685fSDinh Nguyen * Process and clear any interrupt pending for an individual endpoint 284947a1685fSDinh Nguyen */ 28501f91b4ccSFelipe Balbi static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, 285147a1685fSDinh Nguyen int dir_in) 285247a1685fSDinh Nguyen { 28531f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in); 285447a1685fSDinh Nguyen u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 285547a1685fSDinh Nguyen u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 285647a1685fSDinh Nguyen u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); 285747a1685fSDinh Nguyen u32 ints; 285847a1685fSDinh Nguyen u32 ctrl; 285947a1685fSDinh Nguyen 286032601588SVardan Mikayelyan ints = dwc2_gadget_read_ep_interrupts(hsotg, idx, dir_in); 286195c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctl_reg); 286247a1685fSDinh Nguyen 286347a1685fSDinh Nguyen /* Clear endpoint interrupts */ 286495c8bc36SAntti Seppälä dwc2_writel(ints, hsotg->regs + epint_reg); 286547a1685fSDinh Nguyen 2866c6f5c050SMian Yousaf Kaukab if (!hs_ep) { 2867c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n", 2868c6f5c050SMian Yousaf Kaukab __func__, idx, dir_in ? "in" : "out"); 2869c6f5c050SMian Yousaf Kaukab return; 2870c6f5c050SMian Yousaf Kaukab } 2871c6f5c050SMian Yousaf Kaukab 287247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", 287347a1685fSDinh Nguyen __func__, idx, dir_in ? "in" : "out", ints); 287447a1685fSDinh Nguyen 2875b787d755SMian Yousaf Kaukab /* Don't process XferCompl interrupt if it is a setup packet */ 2876b787d755SMian Yousaf Kaukab if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD))) 2877b787d755SMian Yousaf Kaukab ints &= ~DXEPINT_XFERCOMPL; 2878b787d755SMian Yousaf Kaukab 2879f0afdb42SVahram Aharonyan /* 2880f0afdb42SVahram Aharonyan * Don't process XferCompl interrupt in DDMA if EP0 is still in SETUP 2881f0afdb42SVahram Aharonyan * stage and xfercomplete was generated without SETUP phase done 2882f0afdb42SVahram Aharonyan * interrupt. SW should parse received setup packet only after host's 2883f0afdb42SVahram Aharonyan * exit from setup phase of control transfer. 2884f0afdb42SVahram Aharonyan */ 2885f0afdb42SVahram Aharonyan if (using_desc_dma(hsotg) && idx == 0 && !hs_ep->dir_in && 2886f0afdb42SVahram Aharonyan hsotg->ep0_state == DWC2_EP0_SETUP && !(ints & DXEPINT_SETUP)) 2887f0afdb42SVahram Aharonyan ints &= ~DXEPINT_XFERCOMPL; 2888f0afdb42SVahram Aharonyan 2889837e9f00SVardan Mikayelyan if (ints & DXEPINT_XFERCOMPL) { 289047a1685fSDinh Nguyen dev_dbg(hsotg->dev, 289147a1685fSDinh Nguyen "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", 289295c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctl_reg), 289395c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + epsiz_reg)); 289447a1685fSDinh Nguyen 2895540ccba0SVahram Aharonyan /* In DDMA handle isochronous requests separately */ 2896540ccba0SVahram Aharonyan if (using_desc_dma(hsotg) && hs_ep->isochronous) { 2897729cac69SMinas Harutyunyan /* XferCompl set along with BNA */ 2898729cac69SMinas Harutyunyan if (!(ints & DXEPINT_BNAINTR)) 2899540ccba0SVahram Aharonyan dwc2_gadget_complete_isoc_request_ddma(hs_ep); 2900540ccba0SVahram Aharonyan } else if (dir_in) { 290147a1685fSDinh Nguyen /* 2902540ccba0SVahram Aharonyan * We get OutDone from the FIFO, so we only 2903540ccba0SVahram Aharonyan * need to look at completing IN requests here 2904540ccba0SVahram Aharonyan * if operating slave mode 290547a1685fSDinh Nguyen */ 2906837e9f00SVardan Mikayelyan if (hs_ep->isochronous && hs_ep->interval > 1) 2907837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 2908837e9f00SVardan Mikayelyan 29091f91b4ccSFelipe Balbi dwc2_hsotg_complete_in(hsotg, hs_ep); 2910837e9f00SVardan Mikayelyan if (ints & DXEPINT_NAKINTRPT) 2911837e9f00SVardan Mikayelyan ints &= ~DXEPINT_NAKINTRPT; 291247a1685fSDinh Nguyen 291347a1685fSDinh Nguyen if (idx == 0 && !hs_ep->req) 29141f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 291547a1685fSDinh Nguyen } else if (using_dma(hsotg)) { 291647a1685fSDinh Nguyen /* 291747a1685fSDinh Nguyen * We're using DMA, we need to fire an OutDone here 291847a1685fSDinh Nguyen * as we ignore the RXFIFO. 291947a1685fSDinh Nguyen */ 2920837e9f00SVardan Mikayelyan if (hs_ep->isochronous && hs_ep->interval > 1) 2921837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 292247a1685fSDinh Nguyen 29231f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, idx); 292447a1685fSDinh Nguyen } 292547a1685fSDinh Nguyen } 292647a1685fSDinh Nguyen 2927bd9971f0SVardan Mikayelyan if (ints & DXEPINT_EPDISBLD) 2928bd9971f0SVardan Mikayelyan dwc2_gadget_handle_ep_disabled(hs_ep); 292947a1685fSDinh Nguyen 29305321922cSVardan Mikayelyan if (ints & DXEPINT_OUTTKNEPDIS) 29315321922cSVardan Mikayelyan dwc2_gadget_handle_out_token_ep_disabled(hs_ep); 29325321922cSVardan Mikayelyan 29335321922cSVardan Mikayelyan if (ints & DXEPINT_NAKINTRPT) 29345321922cSVardan Mikayelyan dwc2_gadget_handle_nak(hs_ep); 29355321922cSVardan Mikayelyan 293647a1685fSDinh Nguyen if (ints & DXEPINT_AHBERR) 293747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); 293847a1685fSDinh Nguyen 293947a1685fSDinh Nguyen if (ints & DXEPINT_SETUP) { /* Setup or Timeout */ 294047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); 294147a1685fSDinh Nguyen 294247a1685fSDinh Nguyen if (using_dma(hsotg) && idx == 0) { 294347a1685fSDinh Nguyen /* 294447a1685fSDinh Nguyen * this is the notification we've received a 294547a1685fSDinh Nguyen * setup packet. In non-DMA mode we'd get this 294647a1685fSDinh Nguyen * from the RXFIFO, instead we need to process 294747a1685fSDinh Nguyen * the setup here. 294847a1685fSDinh Nguyen */ 294947a1685fSDinh Nguyen 295047a1685fSDinh Nguyen if (dir_in) 295147a1685fSDinh Nguyen WARN_ON_ONCE(1); 295247a1685fSDinh Nguyen else 29531f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, 0); 295447a1685fSDinh Nguyen } 295547a1685fSDinh Nguyen } 295647a1685fSDinh Nguyen 2957ef750c71SVahram Aharonyan if (ints & DXEPINT_STSPHSERCVD) { 29589d9a6b07SVahram Aharonyan dev_dbg(hsotg->dev, "%s: StsPhseRcvd\n", __func__); 29599d9a6b07SVahram Aharonyan 29609e95a66cSMinas Harutyunyan /* Safety check EP0 state when STSPHSERCVD asserted */ 29619e95a66cSMinas Harutyunyan if (hsotg->ep0_state == DWC2_EP0_DATA_OUT) { 2962ef750c71SVahram Aharonyan /* Move to STATUS IN for DDMA */ 2963ef750c71SVahram Aharonyan if (using_desc_dma(hsotg)) 2964ef750c71SVahram Aharonyan dwc2_hsotg_ep0_zlp(hsotg, true); 2965ef750c71SVahram Aharonyan } 2966ef750c71SVahram Aharonyan 29679e95a66cSMinas Harutyunyan } 29689e95a66cSMinas Harutyunyan 296947a1685fSDinh Nguyen if (ints & DXEPINT_BACK2BACKSETUP) 297047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); 297147a1685fSDinh Nguyen 2972540ccba0SVahram Aharonyan if (ints & DXEPINT_BNAINTR) { 2973540ccba0SVahram Aharonyan dev_dbg(hsotg->dev, "%s: BNA interrupt\n", __func__); 2974540ccba0SVahram Aharonyan if (hs_ep->isochronous) 2975729cac69SMinas Harutyunyan dwc2_gadget_handle_isoc_bna(hs_ep); 2976540ccba0SVahram Aharonyan } 2977540ccba0SVahram Aharonyan 297847a1685fSDinh Nguyen if (dir_in && !hs_ep->isochronous) { 297947a1685fSDinh Nguyen /* not sure if this is important, but we'll clear it anyway */ 298026ddef5dSVardan Mikayelyan if (ints & DXEPINT_INTKNTXFEMP) { 298147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", 298247a1685fSDinh Nguyen __func__, idx); 298347a1685fSDinh Nguyen } 298447a1685fSDinh Nguyen 298547a1685fSDinh Nguyen /* this probably means something bad is happening */ 298626ddef5dSVardan Mikayelyan if (ints & DXEPINT_INTKNEPMIS) { 298747a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", 298847a1685fSDinh Nguyen __func__, idx); 298947a1685fSDinh Nguyen } 299047a1685fSDinh Nguyen 299147a1685fSDinh Nguyen /* FIFO has space or is empty (see GAHBCFG) */ 299247a1685fSDinh Nguyen if (hsotg->dedicated_fifos && 299326ddef5dSVardan Mikayelyan ints & DXEPINT_TXFEMP) { 299447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", 299547a1685fSDinh Nguyen __func__, idx); 299647a1685fSDinh Nguyen if (!using_dma(hsotg)) 29971f91b4ccSFelipe Balbi dwc2_hsotg_trytx(hsotg, hs_ep); 299847a1685fSDinh Nguyen } 299947a1685fSDinh Nguyen } 300047a1685fSDinh Nguyen } 300147a1685fSDinh Nguyen 300247a1685fSDinh Nguyen /** 30031f91b4ccSFelipe Balbi * dwc2_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) 300447a1685fSDinh Nguyen * @hsotg: The device state. 300547a1685fSDinh Nguyen * 300647a1685fSDinh Nguyen * Handle updating the device settings after the enumeration phase has 300747a1685fSDinh Nguyen * been completed. 300847a1685fSDinh Nguyen */ 30091f91b4ccSFelipe Balbi static void dwc2_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg) 301047a1685fSDinh Nguyen { 301195c8bc36SAntti Seppälä u32 dsts = dwc2_readl(hsotg->regs + DSTS); 30129b2667f1SJingoo Han int ep0_mps = 0, ep_mps = 8; 301347a1685fSDinh Nguyen 301447a1685fSDinh Nguyen /* 301547a1685fSDinh Nguyen * This should signal the finish of the enumeration phase 301647a1685fSDinh Nguyen * of the USB handshaking, so we should now know what rate 301747a1685fSDinh Nguyen * we connected at. 301847a1685fSDinh Nguyen */ 301947a1685fSDinh Nguyen 302047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); 302147a1685fSDinh Nguyen 302247a1685fSDinh Nguyen /* 302347a1685fSDinh Nguyen * note, since we're limited by the size of transfer on EP0, and 302447a1685fSDinh Nguyen * it seems IN transfers must be a even number of packets we do 302547a1685fSDinh Nguyen * not advertise a 64byte MPS on EP0. 302647a1685fSDinh Nguyen */ 302747a1685fSDinh Nguyen 302847a1685fSDinh Nguyen /* catch both EnumSpd_FS and EnumSpd_FS48 */ 30296d76c92cSMarek Vasut switch ((dsts & DSTS_ENUMSPD_MASK) >> DSTS_ENUMSPD_SHIFT) { 303047a1685fSDinh Nguyen case DSTS_ENUMSPD_FS: 303147a1685fSDinh Nguyen case DSTS_ENUMSPD_FS48: 303247a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_FULL; 303347a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 303447a1685fSDinh Nguyen ep_mps = 1023; 303547a1685fSDinh Nguyen break; 303647a1685fSDinh Nguyen 303747a1685fSDinh Nguyen case DSTS_ENUMSPD_HS: 303847a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_HIGH; 303947a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 304047a1685fSDinh Nguyen ep_mps = 1024; 304147a1685fSDinh Nguyen break; 304247a1685fSDinh Nguyen 304347a1685fSDinh Nguyen case DSTS_ENUMSPD_LS: 304447a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_LOW; 3045552d940fSVardan Mikayelyan ep0_mps = 8; 3046552d940fSVardan Mikayelyan ep_mps = 8; 304747a1685fSDinh Nguyen /* 304847a1685fSDinh Nguyen * note, we don't actually support LS in this driver at the 304947a1685fSDinh Nguyen * moment, and the documentation seems to imply that it isn't 305047a1685fSDinh Nguyen * supported by the PHYs on some of the devices. 305147a1685fSDinh Nguyen */ 305247a1685fSDinh Nguyen break; 305347a1685fSDinh Nguyen } 305447a1685fSDinh Nguyen dev_info(hsotg->dev, "new device is %s\n", 305547a1685fSDinh Nguyen usb_speed_string(hsotg->gadget.speed)); 305647a1685fSDinh Nguyen 305747a1685fSDinh Nguyen /* 305847a1685fSDinh Nguyen * we should now know the maximum packet size for an 305947a1685fSDinh Nguyen * endpoint, so set the endpoints to a default value. 306047a1685fSDinh Nguyen */ 306147a1685fSDinh Nguyen 306247a1685fSDinh Nguyen if (ep0_mps) { 306347a1685fSDinh Nguyen int i; 3064c6f5c050SMian Yousaf Kaukab /* Initialize ep0 for both in and out directions */ 3065ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 1); 3066ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 0); 3067c6f5c050SMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; i++) { 3068c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[i]) 3069ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 3070ee2c40deSVardan Mikayelyan 0, 1); 3071c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[i]) 3072ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 3073ee2c40deSVardan Mikayelyan 0, 0); 3074c6f5c050SMian Yousaf Kaukab } 307547a1685fSDinh Nguyen } 307647a1685fSDinh Nguyen 307747a1685fSDinh Nguyen /* ensure after enumeration our EP0 is active */ 307847a1685fSDinh Nguyen 30791f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 308047a1685fSDinh Nguyen 308147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 308295c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DIEPCTL0), 308395c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL0)); 308447a1685fSDinh Nguyen } 308547a1685fSDinh Nguyen 308647a1685fSDinh Nguyen /** 308747a1685fSDinh Nguyen * kill_all_requests - remove all requests from the endpoint's queue 308847a1685fSDinh Nguyen * @hsotg: The device state. 308947a1685fSDinh Nguyen * @ep: The endpoint the requests may be on. 309047a1685fSDinh Nguyen * @result: The result code to use. 309147a1685fSDinh Nguyen * 309247a1685fSDinh Nguyen * Go through the requests on the given endpoint and mark them 309347a1685fSDinh Nguyen * completed with the given result code. 309447a1685fSDinh Nguyen */ 3095941fcce4SDinh Nguyen static void kill_all_requests(struct dwc2_hsotg *hsotg, 30961f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep, 30976b448af4SRobert Baldyga int result) 309847a1685fSDinh Nguyen { 30991f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req, *treq; 31009da51974SJohn Youn unsigned int size; 310147a1685fSDinh Nguyen 31026b448af4SRobert Baldyga ep->req = NULL; 310347a1685fSDinh Nguyen 31046b448af4SRobert Baldyga list_for_each_entry_safe(req, treq, &ep->queue, queue) 31051f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, ep, req, 310647a1685fSDinh Nguyen result); 31076b448af4SRobert Baldyga 3108b203d0a2SRobert Baldyga if (!hsotg->dedicated_fifos) 3109b203d0a2SRobert Baldyga return; 3110ad674a15SRobert Baldyga size = (dwc2_readl(hsotg->regs + DTXFSTS(ep->fifo_index)) & 0xffff) * 4; 3111b203d0a2SRobert Baldyga if (size < ep->fifo_size) 31121f91b4ccSFelipe Balbi dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); 311347a1685fSDinh Nguyen } 311447a1685fSDinh Nguyen 311547a1685fSDinh Nguyen /** 31161f91b4ccSFelipe Balbi * dwc2_hsotg_disconnect - disconnect service 311747a1685fSDinh Nguyen * @hsotg: The device state. 311847a1685fSDinh Nguyen * 311947a1685fSDinh Nguyen * The device has been disconnected. Remove all current 312047a1685fSDinh Nguyen * transactions and signal the gadget driver that this 312147a1685fSDinh Nguyen * has happened. 312247a1685fSDinh Nguyen */ 31231f91b4ccSFelipe Balbi void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) 312447a1685fSDinh Nguyen { 31259da51974SJohn Youn unsigned int ep; 312647a1685fSDinh Nguyen 31274ace06e8SMarek Szyprowski if (!hsotg->connected) 31284ace06e8SMarek Szyprowski return; 31294ace06e8SMarek Szyprowski 31304ace06e8SMarek Szyprowski hsotg->connected = 0; 31319e14d0a5SGregory Herrero hsotg->test_mode = 0; 3132c6f5c050SMian Yousaf Kaukab 3133c6f5c050SMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps; ep++) { 3134c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 3135c6f5c050SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_in[ep], 3136c6f5c050SMian Yousaf Kaukab -ESHUTDOWN); 3137c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 3138c6f5c050SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_out[ep], 3139c6f5c050SMian Yousaf Kaukab -ESHUTDOWN); 3140c6f5c050SMian Yousaf Kaukab } 314147a1685fSDinh Nguyen 314247a1685fSDinh Nguyen call_gadget(hsotg, disconnect); 3143065d3931SGregory Herrero hsotg->lx_state = DWC2_L3; 3144ce2b21a4SJohn Stultz 3145ce2b21a4SJohn Stultz usb_gadget_set_state(&hsotg->gadget, USB_STATE_NOTATTACHED); 314647a1685fSDinh Nguyen } 314747a1685fSDinh Nguyen 314847a1685fSDinh Nguyen /** 31491f91b4ccSFelipe Balbi * dwc2_hsotg_irq_fifoempty - TX FIFO empty interrupt handler 315047a1685fSDinh Nguyen * @hsotg: The device state: 315147a1685fSDinh Nguyen * @periodic: True if this is a periodic FIFO interrupt 315247a1685fSDinh Nguyen */ 31531f91b4ccSFelipe Balbi static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) 315447a1685fSDinh Nguyen { 31551f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 315647a1685fSDinh Nguyen int epno, ret; 315747a1685fSDinh Nguyen 315847a1685fSDinh Nguyen /* look through for any more data to transmit */ 315947a1685fSDinh Nguyen for (epno = 0; epno < hsotg->num_of_eps; epno++) { 3160c6f5c050SMian Yousaf Kaukab ep = index_to_ep(hsotg, epno, 1); 3161c6f5c050SMian Yousaf Kaukab 3162c6f5c050SMian Yousaf Kaukab if (!ep) 3163c6f5c050SMian Yousaf Kaukab continue; 316447a1685fSDinh Nguyen 316547a1685fSDinh Nguyen if (!ep->dir_in) 316647a1685fSDinh Nguyen continue; 316747a1685fSDinh Nguyen 316847a1685fSDinh Nguyen if ((periodic && !ep->periodic) || 316947a1685fSDinh Nguyen (!periodic && ep->periodic)) 317047a1685fSDinh Nguyen continue; 317147a1685fSDinh Nguyen 31721f91b4ccSFelipe Balbi ret = dwc2_hsotg_trytx(hsotg, ep); 317347a1685fSDinh Nguyen if (ret < 0) 317447a1685fSDinh Nguyen break; 317547a1685fSDinh Nguyen } 317647a1685fSDinh Nguyen } 317747a1685fSDinh Nguyen 317847a1685fSDinh Nguyen /* IRQ flags which will trigger a retry around the IRQ loop */ 317947a1685fSDinh Nguyen #define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ 318047a1685fSDinh Nguyen GINTSTS_PTXFEMP | \ 318147a1685fSDinh Nguyen GINTSTS_RXFLVL) 318247a1685fSDinh Nguyen 318347a1685fSDinh Nguyen /** 31841f91b4ccSFelipe Balbi * dwc2_hsotg_core_init - issue softreset to the core 318547a1685fSDinh Nguyen * @hsotg: The device state 318647a1685fSDinh Nguyen * 318747a1685fSDinh Nguyen * Issue a soft reset to the core, and await the core finishing it. 318847a1685fSDinh Nguyen */ 31891f91b4ccSFelipe Balbi void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, 3190643cc4deSGregory Herrero bool is_usb_reset) 319147a1685fSDinh Nguyen { 31921ee6903bSGregory Herrero u32 intmsk; 3193643cc4deSGregory Herrero u32 val; 3194ecd9a7adSPrzemek Rudy u32 usbcfg; 319579c3b5bbSVahram Aharonyan u32 dcfg = 0; 3196643cc4deSGregory Herrero 31975390d438SMian Yousaf Kaukab /* Kill any ep0 requests as controller will be reinitialized */ 31985390d438SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); 31995390d438SMian Yousaf Kaukab 3200643cc4deSGregory Herrero if (!is_usb_reset) 32016e6360b6SJohn Stultz if (dwc2_core_reset(hsotg, true)) 320286de4895SGregory Herrero return; 320347a1685fSDinh Nguyen 320447a1685fSDinh Nguyen /* 320547a1685fSDinh Nguyen * we must now enable ep0 ready for host detection and then 320647a1685fSDinh Nguyen * set configuration. 320747a1685fSDinh Nguyen */ 320847a1685fSDinh Nguyen 3209ecd9a7adSPrzemek Rudy /* keep other bits untouched (so e.g. forced modes are not lost) */ 3210ecd9a7adSPrzemek Rudy usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); 3211ecd9a7adSPrzemek Rudy usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP | 3212ca02954aSAmelie Delaunay GUSBCFG_HNPCAP | GUSBCFG_USBTRDTIM_MASK); 3213ecd9a7adSPrzemek Rudy 321479c3b5bbSVahram Aharonyan if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS && 321538e9002bSVardan Mikayelyan (hsotg->params.speed == DWC2_SPEED_PARAM_FULL || 321638e9002bSVardan Mikayelyan hsotg->params.speed == DWC2_SPEED_PARAM_LOW)) { 321779c3b5bbSVahram Aharonyan /* FS/LS Dedicated Transceiver Interface */ 321879c3b5bbSVahram Aharonyan usbcfg |= GUSBCFG_PHYSEL; 321979c3b5bbSVahram Aharonyan } else { 322047a1685fSDinh Nguyen /* set the PLL on, remove the HNP/SRP and set the PHY */ 3221fa4a8d72SMian Yousaf Kaukab val = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5; 3222ecd9a7adSPrzemek Rudy usbcfg |= hsotg->phyif | GUSBCFG_TOUTCAL(7) | 3223ecd9a7adSPrzemek Rudy (val << GUSBCFG_USBTRDTIM_SHIFT); 322479c3b5bbSVahram Aharonyan } 3225ecd9a7adSPrzemek Rudy dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); 322647a1685fSDinh Nguyen 32271f91b4ccSFelipe Balbi dwc2_hsotg_init_fifo(hsotg); 322847a1685fSDinh Nguyen 3229643cc4deSGregory Herrero if (!is_usb_reset) 3230abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DCTL, DCTL_SFTDISCON); 323147a1685fSDinh Nguyen 323279c3b5bbSVahram Aharonyan dcfg |= DCFG_EPMISCNT(1); 323338e9002bSVardan Mikayelyan 323438e9002bSVardan Mikayelyan switch (hsotg->params.speed) { 323538e9002bSVardan Mikayelyan case DWC2_SPEED_PARAM_LOW: 323638e9002bSVardan Mikayelyan dcfg |= DCFG_DEVSPD_LS; 323738e9002bSVardan Mikayelyan break; 323838e9002bSVardan Mikayelyan case DWC2_SPEED_PARAM_FULL: 323979c3b5bbSVahram Aharonyan if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) 324079c3b5bbSVahram Aharonyan dcfg |= DCFG_DEVSPD_FS48; 324179c3b5bbSVahram Aharonyan else 324279c3b5bbSVahram Aharonyan dcfg |= DCFG_DEVSPD_FS; 324338e9002bSVardan Mikayelyan break; 324438e9002bSVardan Mikayelyan default: 324579c3b5bbSVahram Aharonyan dcfg |= DCFG_DEVSPD_HS; 324679c3b5bbSVahram Aharonyan } 324738e9002bSVardan Mikayelyan 3248b43ebc96SGrigor Tovmasyan if (hsotg->params.ipg_isoc_en) 3249b43ebc96SGrigor Tovmasyan dcfg |= DCFG_IPG_ISOC_SUPPORDED; 3250b43ebc96SGrigor Tovmasyan 325179c3b5bbSVahram Aharonyan dwc2_writel(dcfg, hsotg->regs + DCFG); 325247a1685fSDinh Nguyen 325347a1685fSDinh Nguyen /* Clear any pending OTG interrupts */ 325495c8bc36SAntti Seppälä dwc2_writel(0xffffffff, hsotg->regs + GOTGINT); 325547a1685fSDinh Nguyen 325647a1685fSDinh Nguyen /* Clear any pending interrupts */ 325795c8bc36SAntti Seppälä dwc2_writel(0xffffffff, hsotg->regs + GINTSTS); 32581ee6903bSGregory Herrero intmsk = GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT | 325947a1685fSDinh Nguyen GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | 32601ee6903bSGregory Herrero GINTSTS_USBRST | GINTSTS_RESETDET | 32611ee6903bSGregory Herrero GINTSTS_ENUMDONE | GINTSTS_OTGINT | 3262376f0401SSevak Arakelyan GINTSTS_USBSUSP | GINTSTS_WKUPINT | 3263376f0401SSevak Arakelyan GINTSTS_LPMTRANRCVD; 3264f4736701SVahram Aharonyan 3265f4736701SVahram Aharonyan if (!using_desc_dma(hsotg)) 3266f4736701SVahram Aharonyan intmsk |= GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT; 32671ee6903bSGregory Herrero 326895832c00SJohn Youn if (!hsotg->params.external_id_pin_ctl) 32691ee6903bSGregory Herrero intmsk |= GINTSTS_CONIDSTSCHNG; 32701ee6903bSGregory Herrero 32711ee6903bSGregory Herrero dwc2_writel(intmsk, hsotg->regs + GINTMSK); 327247a1685fSDinh Nguyen 3273a5c18f11SVahram Aharonyan if (using_dma(hsotg)) { 327495c8bc36SAntti Seppälä dwc2_writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN | 3275d1ac8c80SRazmik Karapetyan hsotg->params.ahbcfg, 327647a1685fSDinh Nguyen hsotg->regs + GAHBCFG); 3277a5c18f11SVahram Aharonyan 3278a5c18f11SVahram Aharonyan /* Set DDMA mode support in the core if needed */ 3279a5c18f11SVahram Aharonyan if (using_desc_dma(hsotg)) 3280abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DCFG, DCFG_DESCDMA_EN); 3281a5c18f11SVahram Aharonyan 3282a5c18f11SVahram Aharonyan } else { 328395c8bc36SAntti Seppälä dwc2_writel(((hsotg->dedicated_fifos) ? 328495c8bc36SAntti Seppälä (GAHBCFG_NP_TXF_EMP_LVL | 328547a1685fSDinh Nguyen GAHBCFG_P_TXF_EMP_LVL) : 0) | 328695c8bc36SAntti Seppälä GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG); 3287a5c18f11SVahram Aharonyan } 328847a1685fSDinh Nguyen 328947a1685fSDinh Nguyen /* 329047a1685fSDinh Nguyen * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts 329147a1685fSDinh Nguyen * when we have no data to transfer. Otherwise we get being flooded by 329247a1685fSDinh Nguyen * interrupts. 329347a1685fSDinh Nguyen */ 329447a1685fSDinh Nguyen 329595c8bc36SAntti Seppälä dwc2_writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ? 32966ff2e832SMian Yousaf Kaukab DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) | 329747a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | 3298837e9f00SVardan Mikayelyan DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK, 329947a1685fSDinh Nguyen hsotg->regs + DIEPMSK); 330047a1685fSDinh Nguyen 330147a1685fSDinh Nguyen /* 330247a1685fSDinh Nguyen * don't need XferCompl, we get that from RXFIFO in slave mode. In 33039d9a6b07SVahram Aharonyan * DMA mode we may need this and StsPhseRcvd. 330447a1685fSDinh Nguyen */ 33059d9a6b07SVahram Aharonyan dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK | 33069d9a6b07SVahram Aharonyan DOEPMSK_STSPHSERCVDMSK) : 0) | 330747a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | 33089d9a6b07SVahram Aharonyan DOEPMSK_SETUPMSK, 330947a1685fSDinh Nguyen hsotg->regs + DOEPMSK); 331047a1685fSDinh Nguyen 3311ec01f0b2SVahram Aharonyan /* Enable BNA interrupt for DDMA */ 331237981e00SMinas Harutyunyan if (using_desc_dma(hsotg)) { 3313abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DOEPMSK, DOEPMSK_BNAMSK); 331437981e00SMinas Harutyunyan dwc2_set_bit(hsotg->regs + DIEPMSK, DIEPMSK_BNAININTRMSK); 331537981e00SMinas Harutyunyan } 3316ec01f0b2SVahram Aharonyan 331795c8bc36SAntti Seppälä dwc2_writel(0, hsotg->regs + DAINTMSK); 331847a1685fSDinh Nguyen 331947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 332095c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DIEPCTL0), 332195c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL0)); 332247a1685fSDinh Nguyen 332347a1685fSDinh Nguyen /* enable in and out endpoint interrupts */ 33241f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT); 332547a1685fSDinh Nguyen 332647a1685fSDinh Nguyen /* 332747a1685fSDinh Nguyen * Enable the RXFIFO when in slave mode, as this is how we collect 332847a1685fSDinh Nguyen * the data. In DMA mode, we get events from the FIFO but also 332947a1685fSDinh Nguyen * things we cannot process, so do not use it. 333047a1685fSDinh Nguyen */ 333147a1685fSDinh Nguyen if (!using_dma(hsotg)) 33321f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL); 333347a1685fSDinh Nguyen 333447a1685fSDinh Nguyen /* Enable interrupts for EP0 in and out */ 33351f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, 0, 0, 1); 33361f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, 0, 1, 1); 333747a1685fSDinh Nguyen 3338643cc4deSGregory Herrero if (!is_usb_reset) { 3339abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); 334047a1685fSDinh Nguyen udelay(10); /* see openiboot */ 3341abd064a1SRazmik Karapetyan dwc2_clear_bit(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); 3342643cc4deSGregory Herrero } 334347a1685fSDinh Nguyen 334495c8bc36SAntti Seppälä dev_dbg(hsotg->dev, "DCTL=0x%08x\n", dwc2_readl(hsotg->regs + DCTL)); 334547a1685fSDinh Nguyen 334647a1685fSDinh Nguyen /* 334747a1685fSDinh Nguyen * DxEPCTL_USBActEp says RO in manual, but seems to be set by 334847a1685fSDinh Nguyen * writing to the EPCTL register.. 334947a1685fSDinh Nguyen */ 335047a1685fSDinh Nguyen 335147a1685fSDinh Nguyen /* set to read 1 8byte packet */ 335295c8bc36SAntti Seppälä dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 335347a1685fSDinh Nguyen DXEPTSIZ_XFERSIZE(8), hsotg->regs + DOEPTSIZ0); 335447a1685fSDinh Nguyen 335595c8bc36SAntti Seppälä dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 335647a1685fSDinh Nguyen DXEPCTL_CNAK | DXEPCTL_EPENA | 335747a1685fSDinh Nguyen DXEPCTL_USBACTEP, 335847a1685fSDinh Nguyen hsotg->regs + DOEPCTL0); 335947a1685fSDinh Nguyen 336047a1685fSDinh Nguyen /* enable, but don't activate EP0in */ 336195c8bc36SAntti Seppälä dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 336247a1685fSDinh Nguyen DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0); 336347a1685fSDinh Nguyen 336447a1685fSDinh Nguyen /* clear global NAKs */ 3365643cc4deSGregory Herrero val = DCTL_CGOUTNAK | DCTL_CGNPINNAK; 3366643cc4deSGregory Herrero if (!is_usb_reset) 3367643cc4deSGregory Herrero val |= DCTL_SFTDISCON; 3368abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DCTL, val); 336947a1685fSDinh Nguyen 337021b03405SSevak Arakelyan /* configure the core to support LPM */ 337121b03405SSevak Arakelyan dwc2_gadget_init_lpm(hsotg); 337221b03405SSevak Arakelyan 337347a1685fSDinh Nguyen /* must be at-least 3ms to allow bus to see disconnect */ 337447a1685fSDinh Nguyen mdelay(3); 337547a1685fSDinh Nguyen 3376065d3931SGregory Herrero hsotg->lx_state = DWC2_L0; 3377755d7395SVardan Mikayelyan 3378755d7395SVardan Mikayelyan dwc2_hsotg_enqueue_setup(hsotg); 3379755d7395SVardan Mikayelyan 3380755d7395SVardan Mikayelyan dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 3381755d7395SVardan Mikayelyan dwc2_readl(hsotg->regs + DIEPCTL0), 3382755d7395SVardan Mikayelyan dwc2_readl(hsotg->regs + DOEPCTL0)); 3383ad38dc5dSMarek Szyprowski } 3384ac3c81f3SMarek Szyprowski 33851f91b4ccSFelipe Balbi static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) 3386ad38dc5dSMarek Szyprowski { 3387ad38dc5dSMarek Szyprowski /* set the soft-disconnect bit */ 3388abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DCTL, DCTL_SFTDISCON); 3389ad38dc5dSMarek Szyprowski } 3390ad38dc5dSMarek Szyprowski 33911f91b4ccSFelipe Balbi void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) 3392ad38dc5dSMarek Szyprowski { 339347a1685fSDinh Nguyen /* remove the soft-disconnect and let's go */ 3394abd064a1SRazmik Karapetyan dwc2_clear_bit(hsotg->regs + DCTL, DCTL_SFTDISCON); 339547a1685fSDinh Nguyen } 339647a1685fSDinh Nguyen 339747a1685fSDinh Nguyen /** 3398381fc8f8SVardan Mikayelyan * dwc2_gadget_handle_incomplete_isoc_in - handle incomplete ISO IN Interrupt. 3399381fc8f8SVardan Mikayelyan * @hsotg: The device state: 3400381fc8f8SVardan Mikayelyan * 3401381fc8f8SVardan Mikayelyan * This interrupt indicates one of the following conditions occurred while 3402381fc8f8SVardan Mikayelyan * transmitting an ISOC transaction. 3403381fc8f8SVardan Mikayelyan * - Corrupted IN Token for ISOC EP. 3404381fc8f8SVardan Mikayelyan * - Packet not complete in FIFO. 3405381fc8f8SVardan Mikayelyan * 3406381fc8f8SVardan Mikayelyan * The following actions will be taken: 3407381fc8f8SVardan Mikayelyan * - Determine the EP 3408381fc8f8SVardan Mikayelyan * - Disable EP; when 'Endpoint Disabled' interrupt is received Flush FIFO 3409381fc8f8SVardan Mikayelyan */ 3410381fc8f8SVardan Mikayelyan static void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg) 3411381fc8f8SVardan Mikayelyan { 3412381fc8f8SVardan Mikayelyan struct dwc2_hsotg_ep *hs_ep; 3413381fc8f8SVardan Mikayelyan u32 epctrl; 34141b4977c7SRazmik Karapetyan u32 daintmsk; 3415381fc8f8SVardan Mikayelyan u32 idx; 3416381fc8f8SVardan Mikayelyan 3417381fc8f8SVardan Mikayelyan dev_dbg(hsotg->dev, "Incomplete isoc in interrupt received:\n"); 3418381fc8f8SVardan Mikayelyan 34191b4977c7SRazmik Karapetyan daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); 34201b4977c7SRazmik Karapetyan 3421d5d5f079SArtur Petrosyan for (idx = 1; idx < hsotg->num_of_eps; idx++) { 3422381fc8f8SVardan Mikayelyan hs_ep = hsotg->eps_in[idx]; 34231b4977c7SRazmik Karapetyan /* Proceed only unmasked ISOC EPs */ 34241b4977c7SRazmik Karapetyan if (!hs_ep->isochronous || (BIT(idx) & ~daintmsk)) 34251b4977c7SRazmik Karapetyan continue; 34261b4977c7SRazmik Karapetyan 3427381fc8f8SVardan Mikayelyan epctrl = dwc2_readl(hsotg->regs + DIEPCTL(idx)); 34281b4977c7SRazmik Karapetyan if ((epctrl & DXEPCTL_EPENA) && 3429381fc8f8SVardan Mikayelyan dwc2_gadget_target_frame_elapsed(hs_ep)) { 3430381fc8f8SVardan Mikayelyan epctrl |= DXEPCTL_SNAK; 3431381fc8f8SVardan Mikayelyan epctrl |= DXEPCTL_EPDIS; 3432381fc8f8SVardan Mikayelyan dwc2_writel(epctrl, hsotg->regs + DIEPCTL(idx)); 3433381fc8f8SVardan Mikayelyan } 3434381fc8f8SVardan Mikayelyan } 3435381fc8f8SVardan Mikayelyan 3436381fc8f8SVardan Mikayelyan /* Clear interrupt */ 3437381fc8f8SVardan Mikayelyan dwc2_writel(GINTSTS_INCOMPL_SOIN, hsotg->regs + GINTSTS); 3438381fc8f8SVardan Mikayelyan } 3439381fc8f8SVardan Mikayelyan 3440381fc8f8SVardan Mikayelyan /** 3441381fc8f8SVardan Mikayelyan * dwc2_gadget_handle_incomplete_isoc_out - handle incomplete ISO OUT Interrupt 3442381fc8f8SVardan Mikayelyan * @hsotg: The device state: 3443381fc8f8SVardan Mikayelyan * 3444381fc8f8SVardan Mikayelyan * This interrupt indicates one of the following conditions occurred while 3445381fc8f8SVardan Mikayelyan * transmitting an ISOC transaction. 3446381fc8f8SVardan Mikayelyan * - Corrupted OUT Token for ISOC EP. 3447381fc8f8SVardan Mikayelyan * - Packet not complete in FIFO. 3448381fc8f8SVardan Mikayelyan * 3449381fc8f8SVardan Mikayelyan * The following actions will be taken: 3450381fc8f8SVardan Mikayelyan * - Determine the EP 3451381fc8f8SVardan Mikayelyan * - Set DCTL_SGOUTNAK and unmask GOUTNAKEFF if target frame elapsed. 3452381fc8f8SVardan Mikayelyan */ 3453381fc8f8SVardan Mikayelyan static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg) 3454381fc8f8SVardan Mikayelyan { 3455381fc8f8SVardan Mikayelyan u32 gintsts; 3456381fc8f8SVardan Mikayelyan u32 gintmsk; 3457689efb26SRazmik Karapetyan u32 daintmsk; 3458381fc8f8SVardan Mikayelyan u32 epctrl; 3459381fc8f8SVardan Mikayelyan struct dwc2_hsotg_ep *hs_ep; 3460381fc8f8SVardan Mikayelyan int idx; 3461381fc8f8SVardan Mikayelyan 3462381fc8f8SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__); 3463381fc8f8SVardan Mikayelyan 3464689efb26SRazmik Karapetyan daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); 3465689efb26SRazmik Karapetyan daintmsk >>= DAINT_OUTEP_SHIFT; 3466689efb26SRazmik Karapetyan 3467d5d5f079SArtur Petrosyan for (idx = 1; idx < hsotg->num_of_eps; idx++) { 3468381fc8f8SVardan Mikayelyan hs_ep = hsotg->eps_out[idx]; 3469689efb26SRazmik Karapetyan /* Proceed only unmasked ISOC EPs */ 3470689efb26SRazmik Karapetyan if (!hs_ep->isochronous || (BIT(idx) & ~daintmsk)) 3471689efb26SRazmik Karapetyan continue; 3472689efb26SRazmik Karapetyan 3473381fc8f8SVardan Mikayelyan epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx)); 3474689efb26SRazmik Karapetyan if ((epctrl & DXEPCTL_EPENA) && 3475381fc8f8SVardan Mikayelyan dwc2_gadget_target_frame_elapsed(hs_ep)) { 3476381fc8f8SVardan Mikayelyan /* Unmask GOUTNAKEFF interrupt */ 3477381fc8f8SVardan Mikayelyan gintmsk = dwc2_readl(hsotg->regs + GINTMSK); 3478381fc8f8SVardan Mikayelyan gintmsk |= GINTSTS_GOUTNAKEFF; 3479381fc8f8SVardan Mikayelyan dwc2_writel(gintmsk, hsotg->regs + GINTMSK); 3480381fc8f8SVardan Mikayelyan 3481381fc8f8SVardan Mikayelyan gintsts = dwc2_readl(hsotg->regs + GINTSTS); 3482689efb26SRazmik Karapetyan if (!(gintsts & GINTSTS_GOUTNAKEFF)) { 3483abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DCTL, DCTL_SGOUTNAK); 3484689efb26SRazmik Karapetyan break; 3485689efb26SRazmik Karapetyan } 3486381fc8f8SVardan Mikayelyan } 3487381fc8f8SVardan Mikayelyan } 3488381fc8f8SVardan Mikayelyan 3489381fc8f8SVardan Mikayelyan /* Clear interrupt */ 3490381fc8f8SVardan Mikayelyan dwc2_writel(GINTSTS_INCOMPL_SOOUT, hsotg->regs + GINTSTS); 3491381fc8f8SVardan Mikayelyan } 3492381fc8f8SVardan Mikayelyan 3493381fc8f8SVardan Mikayelyan /** 34941f91b4ccSFelipe Balbi * dwc2_hsotg_irq - handle device interrupt 349547a1685fSDinh Nguyen * @irq: The IRQ number triggered 349647a1685fSDinh Nguyen * @pw: The pw value when registered the handler. 349747a1685fSDinh Nguyen */ 34981f91b4ccSFelipe Balbi static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) 349947a1685fSDinh Nguyen { 3500941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = pw; 350147a1685fSDinh Nguyen int retry_count = 8; 350247a1685fSDinh Nguyen u32 gintsts; 350347a1685fSDinh Nguyen u32 gintmsk; 350447a1685fSDinh Nguyen 3505ee3de8d7SVardan Mikayelyan if (!dwc2_is_device_mode(hsotg)) 3506ee3de8d7SVardan Mikayelyan return IRQ_NONE; 3507ee3de8d7SVardan Mikayelyan 350847a1685fSDinh Nguyen spin_lock(&hsotg->lock); 350947a1685fSDinh Nguyen irq_retry: 351095c8bc36SAntti Seppälä gintsts = dwc2_readl(hsotg->regs + GINTSTS); 351195c8bc36SAntti Seppälä gintmsk = dwc2_readl(hsotg->regs + GINTMSK); 351247a1685fSDinh Nguyen 351347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", 351447a1685fSDinh Nguyen __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); 351547a1685fSDinh Nguyen 351647a1685fSDinh Nguyen gintsts &= gintmsk; 351747a1685fSDinh Nguyen 35188fc37b82SMian Yousaf Kaukab if (gintsts & GINTSTS_RESETDET) { 35198fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: USBRstDet\n", __func__); 35208fc37b82SMian Yousaf Kaukab 35218fc37b82SMian Yousaf Kaukab dwc2_writel(GINTSTS_RESETDET, hsotg->regs + GINTSTS); 35228fc37b82SMian Yousaf Kaukab 35238fc37b82SMian Yousaf Kaukab /* This event must be used only if controller is suspended */ 35248fc37b82SMian Yousaf Kaukab if (hsotg->lx_state == DWC2_L2) { 352541ba9b9bSVardan Mikayelyan dwc2_exit_partial_power_down(hsotg, true); 35268fc37b82SMian Yousaf Kaukab hsotg->lx_state = DWC2_L0; 35278fc37b82SMian Yousaf Kaukab } 35288fc37b82SMian Yousaf Kaukab } 35298fc37b82SMian Yousaf Kaukab 35308fc37b82SMian Yousaf Kaukab if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) { 35318fc37b82SMian Yousaf Kaukab u32 usb_status = dwc2_readl(hsotg->regs + GOTGCTL); 35328fc37b82SMian Yousaf Kaukab u32 connected = hsotg->connected; 35338fc37b82SMian Yousaf Kaukab 35348fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: USBRst\n", __func__); 35358fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", 35368fc37b82SMian Yousaf Kaukab dwc2_readl(hsotg->regs + GNPTXSTS)); 35378fc37b82SMian Yousaf Kaukab 35388fc37b82SMian Yousaf Kaukab dwc2_writel(GINTSTS_USBRST, hsotg->regs + GINTSTS); 35398fc37b82SMian Yousaf Kaukab 35408fc37b82SMian Yousaf Kaukab /* Report disconnection if it is not already done. */ 35418fc37b82SMian Yousaf Kaukab dwc2_hsotg_disconnect(hsotg); 35428fc37b82SMian Yousaf Kaukab 3543307bc11fSMinas Harutyunyan /* Reset device address to zero */ 3544abd064a1SRazmik Karapetyan dwc2_clear_bit(hsotg->regs + DCFG, DCFG_DEVADDR_MASK); 3545307bc11fSMinas Harutyunyan 35468fc37b82SMian Yousaf Kaukab if (usb_status & GOTGCTL_BSESVLD && connected) 35478fc37b82SMian Yousaf Kaukab dwc2_hsotg_core_init_disconnected(hsotg, true); 35488fc37b82SMian Yousaf Kaukab } 35498fc37b82SMian Yousaf Kaukab 355047a1685fSDinh Nguyen if (gintsts & GINTSTS_ENUMDONE) { 355195c8bc36SAntti Seppälä dwc2_writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); 355247a1685fSDinh Nguyen 35531f91b4ccSFelipe Balbi dwc2_hsotg_irq_enumdone(hsotg); 355447a1685fSDinh Nguyen } 355547a1685fSDinh Nguyen 355647a1685fSDinh Nguyen if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { 355795c8bc36SAntti Seppälä u32 daint = dwc2_readl(hsotg->regs + DAINT); 355895c8bc36SAntti Seppälä u32 daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); 355947a1685fSDinh Nguyen u32 daint_out, daint_in; 356047a1685fSDinh Nguyen int ep; 356147a1685fSDinh Nguyen 356247a1685fSDinh Nguyen daint &= daintmsk; 356347a1685fSDinh Nguyen daint_out = daint >> DAINT_OUTEP_SHIFT; 356447a1685fSDinh Nguyen daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); 356547a1685fSDinh Nguyen 356647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); 356747a1685fSDinh Nguyen 3568cec87f1dSMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps && daint_out; 3569cec87f1dSMian Yousaf Kaukab ep++, daint_out >>= 1) { 357047a1685fSDinh Nguyen if (daint_out & 1) 35711f91b4ccSFelipe Balbi dwc2_hsotg_epint(hsotg, ep, 0); 357247a1685fSDinh Nguyen } 357347a1685fSDinh Nguyen 3574cec87f1dSMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps && daint_in; 3575cec87f1dSMian Yousaf Kaukab ep++, daint_in >>= 1) { 357647a1685fSDinh Nguyen if (daint_in & 1) 35771f91b4ccSFelipe Balbi dwc2_hsotg_epint(hsotg, ep, 1); 357847a1685fSDinh Nguyen } 357947a1685fSDinh Nguyen } 358047a1685fSDinh Nguyen 358147a1685fSDinh Nguyen /* check both FIFOs */ 358247a1685fSDinh Nguyen 358347a1685fSDinh Nguyen if (gintsts & GINTSTS_NPTXFEMP) { 358447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "NPTxFEmp\n"); 358547a1685fSDinh Nguyen 358647a1685fSDinh Nguyen /* 358747a1685fSDinh Nguyen * Disable the interrupt to stop it happening again 358847a1685fSDinh Nguyen * unless one of these endpoint routines decides that 358947a1685fSDinh Nguyen * it needs re-enabling 359047a1685fSDinh Nguyen */ 359147a1685fSDinh Nguyen 35921f91b4ccSFelipe Balbi dwc2_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); 35931f91b4ccSFelipe Balbi dwc2_hsotg_irq_fifoempty(hsotg, false); 359447a1685fSDinh Nguyen } 359547a1685fSDinh Nguyen 359647a1685fSDinh Nguyen if (gintsts & GINTSTS_PTXFEMP) { 359747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "PTxFEmp\n"); 359847a1685fSDinh Nguyen 359947a1685fSDinh Nguyen /* See note in GINTSTS_NPTxFEmp */ 360047a1685fSDinh Nguyen 36011f91b4ccSFelipe Balbi dwc2_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); 36021f91b4ccSFelipe Balbi dwc2_hsotg_irq_fifoempty(hsotg, true); 360347a1685fSDinh Nguyen } 360447a1685fSDinh Nguyen 360547a1685fSDinh Nguyen if (gintsts & GINTSTS_RXFLVL) { 360647a1685fSDinh Nguyen /* 360747a1685fSDinh Nguyen * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, 36081f91b4ccSFelipe Balbi * we need to retry dwc2_hsotg_handle_rx if this is still 360947a1685fSDinh Nguyen * set. 361047a1685fSDinh Nguyen */ 361147a1685fSDinh Nguyen 36121f91b4ccSFelipe Balbi dwc2_hsotg_handle_rx(hsotg); 361347a1685fSDinh Nguyen } 361447a1685fSDinh Nguyen 361547a1685fSDinh Nguyen if (gintsts & GINTSTS_ERLYSUSP) { 361647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); 361795c8bc36SAntti Seppälä dwc2_writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS); 361847a1685fSDinh Nguyen } 361947a1685fSDinh Nguyen 362047a1685fSDinh Nguyen /* 362147a1685fSDinh Nguyen * these next two seem to crop-up occasionally causing the core 362247a1685fSDinh Nguyen * to shutdown the USB transfer, so try clearing them and logging 362347a1685fSDinh Nguyen * the occurrence. 362447a1685fSDinh Nguyen */ 362547a1685fSDinh Nguyen 362647a1685fSDinh Nguyen if (gintsts & GINTSTS_GOUTNAKEFF) { 3627837e9f00SVardan Mikayelyan u8 idx; 3628837e9f00SVardan Mikayelyan u32 epctrl; 3629837e9f00SVardan Mikayelyan u32 gintmsk; 3630d8484552SRazmik Karapetyan u32 daintmsk; 3631837e9f00SVardan Mikayelyan struct dwc2_hsotg_ep *hs_ep; 363247a1685fSDinh Nguyen 3633d8484552SRazmik Karapetyan daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); 3634d8484552SRazmik Karapetyan daintmsk >>= DAINT_OUTEP_SHIFT; 3635837e9f00SVardan Mikayelyan /* Mask this interrupt */ 3636837e9f00SVardan Mikayelyan gintmsk = dwc2_readl(hsotg->regs + GINTMSK); 3637837e9f00SVardan Mikayelyan gintmsk &= ~GINTSTS_GOUTNAKEFF; 3638837e9f00SVardan Mikayelyan dwc2_writel(gintmsk, hsotg->regs + GINTMSK); 363947a1685fSDinh Nguyen 3640837e9f00SVardan Mikayelyan dev_dbg(hsotg->dev, "GOUTNakEff triggered\n"); 3641d5d5f079SArtur Petrosyan for (idx = 1; idx < hsotg->num_of_eps; idx++) { 3642837e9f00SVardan Mikayelyan hs_ep = hsotg->eps_out[idx]; 3643d8484552SRazmik Karapetyan /* Proceed only unmasked ISOC EPs */ 3644d8484552SRazmik Karapetyan if (!hs_ep->isochronous || (BIT(idx) & ~daintmsk)) 3645d8484552SRazmik Karapetyan continue; 3646d8484552SRazmik Karapetyan 3647837e9f00SVardan Mikayelyan epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx)); 3648837e9f00SVardan Mikayelyan 3649d8484552SRazmik Karapetyan if (epctrl & DXEPCTL_EPENA) { 3650837e9f00SVardan Mikayelyan epctrl |= DXEPCTL_SNAK; 3651837e9f00SVardan Mikayelyan epctrl |= DXEPCTL_EPDIS; 3652837e9f00SVardan Mikayelyan dwc2_writel(epctrl, hsotg->regs + DOEPCTL(idx)); 3653837e9f00SVardan Mikayelyan } 3654837e9f00SVardan Mikayelyan } 3655837e9f00SVardan Mikayelyan 3656837e9f00SVardan Mikayelyan /* This interrupt bit is cleared in DXEPINT_EPDISBLD handler */ 365747a1685fSDinh Nguyen } 365847a1685fSDinh Nguyen 365947a1685fSDinh Nguyen if (gintsts & GINTSTS_GINNAKEFF) { 366047a1685fSDinh Nguyen dev_info(hsotg->dev, "GINNakEff triggered\n"); 366147a1685fSDinh Nguyen 3662abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DCTL, DCTL_CGNPINNAK); 366347a1685fSDinh Nguyen 36641f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 366547a1685fSDinh Nguyen } 366647a1685fSDinh Nguyen 3667381fc8f8SVardan Mikayelyan if (gintsts & GINTSTS_INCOMPL_SOIN) 3668381fc8f8SVardan Mikayelyan dwc2_gadget_handle_incomplete_isoc_in(hsotg); 3669ec1f9d9fSRoman Bacik 3670381fc8f8SVardan Mikayelyan if (gintsts & GINTSTS_INCOMPL_SOOUT) 3671381fc8f8SVardan Mikayelyan dwc2_gadget_handle_incomplete_isoc_out(hsotg); 3672ec1f9d9fSRoman Bacik 367347a1685fSDinh Nguyen /* 367447a1685fSDinh Nguyen * if we've had fifo events, we should try and go around the 367547a1685fSDinh Nguyen * loop again to see if there's any point in returning yet. 367647a1685fSDinh Nguyen */ 367747a1685fSDinh Nguyen 367847a1685fSDinh Nguyen if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) 367947a1685fSDinh Nguyen goto irq_retry; 368047a1685fSDinh Nguyen 368147a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 368247a1685fSDinh Nguyen 368347a1685fSDinh Nguyen return IRQ_HANDLED; 368447a1685fSDinh Nguyen } 368547a1685fSDinh Nguyen 3686a4f82771SVahram Aharonyan static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, 3687a4f82771SVahram Aharonyan struct dwc2_hsotg_ep *hs_ep) 3688a4f82771SVahram Aharonyan { 3689a4f82771SVahram Aharonyan u32 epctrl_reg; 3690a4f82771SVahram Aharonyan u32 epint_reg; 3691a4f82771SVahram Aharonyan 3692a4f82771SVahram Aharonyan epctrl_reg = hs_ep->dir_in ? DIEPCTL(hs_ep->index) : 3693a4f82771SVahram Aharonyan DOEPCTL(hs_ep->index); 3694a4f82771SVahram Aharonyan epint_reg = hs_ep->dir_in ? DIEPINT(hs_ep->index) : 3695a4f82771SVahram Aharonyan DOEPINT(hs_ep->index); 3696a4f82771SVahram Aharonyan 3697a4f82771SVahram Aharonyan dev_dbg(hsotg->dev, "%s: stopping transfer on %s\n", __func__, 3698a4f82771SVahram Aharonyan hs_ep->name); 3699a4f82771SVahram Aharonyan 3700a4f82771SVahram Aharonyan if (hs_ep->dir_in) { 3701a4f82771SVahram Aharonyan if (hsotg->dedicated_fifos || hs_ep->periodic) { 3702abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + epctrl_reg, DXEPCTL_SNAK); 3703a4f82771SVahram Aharonyan /* Wait for Nak effect */ 3704a4f82771SVahram Aharonyan if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, 3705a4f82771SVahram Aharonyan DXEPINT_INEPNAKEFF, 100)) 3706a4f82771SVahram Aharonyan dev_warn(hsotg->dev, 3707a4f82771SVahram Aharonyan "%s: timeout DIEPINT.NAKEFF\n", 3708a4f82771SVahram Aharonyan __func__); 3709a4f82771SVahram Aharonyan } else { 3710abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DCTL, DCTL_SGNPINNAK); 3711a4f82771SVahram Aharonyan /* Wait for Nak effect */ 3712a4f82771SVahram Aharonyan if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 3713a4f82771SVahram Aharonyan GINTSTS_GINNAKEFF, 100)) 3714a4f82771SVahram Aharonyan dev_warn(hsotg->dev, 3715a4f82771SVahram Aharonyan "%s: timeout GINTSTS.GINNAKEFF\n", 3716a4f82771SVahram Aharonyan __func__); 3717a4f82771SVahram Aharonyan } 3718a4f82771SVahram Aharonyan } else { 3719a4f82771SVahram Aharonyan if (!(dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_GOUTNAKEFF)) 3720abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DCTL, DCTL_SGOUTNAK); 3721a4f82771SVahram Aharonyan 3722a4f82771SVahram Aharonyan /* Wait for global nak to take effect */ 3723a4f82771SVahram Aharonyan if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 3724a4f82771SVahram Aharonyan GINTSTS_GOUTNAKEFF, 100)) 3725a4f82771SVahram Aharonyan dev_warn(hsotg->dev, "%s: timeout GINTSTS.GOUTNAKEFF\n", 3726a4f82771SVahram Aharonyan __func__); 3727a4f82771SVahram Aharonyan } 3728a4f82771SVahram Aharonyan 3729a4f82771SVahram Aharonyan /* Disable ep */ 3730abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + epctrl_reg, DXEPCTL_EPDIS | DXEPCTL_SNAK); 3731a4f82771SVahram Aharonyan 3732a4f82771SVahram Aharonyan /* Wait for ep to be disabled */ 3733a4f82771SVahram Aharonyan if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, DXEPINT_EPDISBLD, 100)) 3734a4f82771SVahram Aharonyan dev_warn(hsotg->dev, 3735a4f82771SVahram Aharonyan "%s: timeout DOEPCTL.EPDisable\n", __func__); 3736a4f82771SVahram Aharonyan 3737a4f82771SVahram Aharonyan /* Clear EPDISBLD interrupt */ 3738abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + epint_reg, DXEPINT_EPDISBLD); 3739a4f82771SVahram Aharonyan 3740a4f82771SVahram Aharonyan if (hs_ep->dir_in) { 3741a4f82771SVahram Aharonyan unsigned short fifo_index; 3742a4f82771SVahram Aharonyan 3743a4f82771SVahram Aharonyan if (hsotg->dedicated_fifos || hs_ep->periodic) 3744a4f82771SVahram Aharonyan fifo_index = hs_ep->fifo_index; 3745a4f82771SVahram Aharonyan else 3746a4f82771SVahram Aharonyan fifo_index = 0; 3747a4f82771SVahram Aharonyan 3748a4f82771SVahram Aharonyan /* Flush TX FIFO */ 3749a4f82771SVahram Aharonyan dwc2_flush_tx_fifo(hsotg, fifo_index); 3750a4f82771SVahram Aharonyan 3751a4f82771SVahram Aharonyan /* Clear Global In NP NAK in Shared FIFO for non periodic ep */ 3752a4f82771SVahram Aharonyan if (!hsotg->dedicated_fifos && !hs_ep->periodic) 3753abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DCTL, DCTL_CGNPINNAK); 3754a4f82771SVahram Aharonyan 3755a4f82771SVahram Aharonyan } else { 3756a4f82771SVahram Aharonyan /* Remove global NAKs */ 3757abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DCTL, DCTL_CGOUTNAK); 3758a4f82771SVahram Aharonyan } 3759a4f82771SVahram Aharonyan } 3760a4f82771SVahram Aharonyan 376147a1685fSDinh Nguyen /** 37621f91b4ccSFelipe Balbi * dwc2_hsotg_ep_enable - enable the given endpoint 376347a1685fSDinh Nguyen * @ep: The USB endpint to configure 376447a1685fSDinh Nguyen * @desc: The USB endpoint descriptor to configure with. 376547a1685fSDinh Nguyen * 376647a1685fSDinh Nguyen * This is called from the USB gadget code's usb_ep_enable(). 376747a1685fSDinh Nguyen */ 37681f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_enable(struct usb_ep *ep, 376947a1685fSDinh Nguyen const struct usb_endpoint_descriptor *desc) 377047a1685fSDinh Nguyen { 37711f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 3772941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 377347a1685fSDinh Nguyen unsigned long flags; 3774ca4c55adSMian Yousaf Kaukab unsigned int index = hs_ep->index; 377547a1685fSDinh Nguyen u32 epctrl_reg; 377647a1685fSDinh Nguyen u32 epctrl; 377747a1685fSDinh Nguyen u32 mps; 3778ee2c40deSVardan Mikayelyan u32 mc; 3779837e9f00SVardan Mikayelyan u32 mask; 3780ca4c55adSMian Yousaf Kaukab unsigned int dir_in; 3781ca4c55adSMian Yousaf Kaukab unsigned int i, val, size; 378247a1685fSDinh Nguyen int ret = 0; 3783729cac69SMinas Harutyunyan unsigned char ep_type; 378447a1685fSDinh Nguyen 378547a1685fSDinh Nguyen dev_dbg(hsotg->dev, 378647a1685fSDinh Nguyen "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", 378747a1685fSDinh Nguyen __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, 378847a1685fSDinh Nguyen desc->wMaxPacketSize, desc->bInterval); 378947a1685fSDinh Nguyen 379047a1685fSDinh Nguyen /* not to be called for EP0 */ 37918c3d6092SVahram Aharonyan if (index == 0) { 37928c3d6092SVahram Aharonyan dev_err(hsotg->dev, "%s: called for EP 0\n", __func__); 37938c3d6092SVahram Aharonyan return -EINVAL; 37948c3d6092SVahram Aharonyan } 379547a1685fSDinh Nguyen 379647a1685fSDinh Nguyen dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; 379747a1685fSDinh Nguyen if (dir_in != hs_ep->dir_in) { 379847a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); 379947a1685fSDinh Nguyen return -EINVAL; 380047a1685fSDinh Nguyen } 380147a1685fSDinh Nguyen 3802729cac69SMinas Harutyunyan ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; 380347a1685fSDinh Nguyen mps = usb_endpoint_maxp(desc); 3804ee2c40deSVardan Mikayelyan mc = usb_endpoint_maxp_mult(desc); 380547a1685fSDinh Nguyen 3806729cac69SMinas Harutyunyan /* ISOC IN in DDMA supported bInterval up to 10 */ 3807729cac69SMinas Harutyunyan if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC && 3808729cac69SMinas Harutyunyan dir_in && desc->bInterval > 10) { 3809729cac69SMinas Harutyunyan dev_err(hsotg->dev, 3810729cac69SMinas Harutyunyan "%s: ISOC IN, DDMA: bInterval>10 not supported!\n", __func__); 3811729cac69SMinas Harutyunyan return -EINVAL; 3812729cac69SMinas Harutyunyan } 3813729cac69SMinas Harutyunyan 3814729cac69SMinas Harutyunyan /* High bandwidth ISOC OUT in DDMA not supported */ 3815729cac69SMinas Harutyunyan if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC && 3816729cac69SMinas Harutyunyan !dir_in && mc > 1) { 3817729cac69SMinas Harutyunyan dev_err(hsotg->dev, 3818729cac69SMinas Harutyunyan "%s: ISOC OUT, DDMA: HB not supported!\n", __func__); 3819729cac69SMinas Harutyunyan return -EINVAL; 3820729cac69SMinas Harutyunyan } 3821729cac69SMinas Harutyunyan 38221f91b4ccSFelipe Balbi /* note, we handle this here instead of dwc2_hsotg_set_ep_maxpacket */ 382347a1685fSDinh Nguyen 382447a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 382595c8bc36SAntti Seppälä epctrl = dwc2_readl(hsotg->regs + epctrl_reg); 382647a1685fSDinh Nguyen 382747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", 382847a1685fSDinh Nguyen __func__, epctrl, epctrl_reg); 382947a1685fSDinh Nguyen 38305f54c54bSVahram Aharonyan /* Allocate DMA descriptor chain for non-ctrl endpoints */ 38319383e084SVardan Mikayelyan if (using_desc_dma(hsotg) && !hs_ep->desc_list) { 38329383e084SVardan Mikayelyan hs_ep->desc_list = dmam_alloc_coherent(hsotg->dev, 38335f54c54bSVahram Aharonyan MAX_DMA_DESC_NUM_GENERIC * 38345f54c54bSVahram Aharonyan sizeof(struct dwc2_dma_desc), 383586e881e7SMarek Szyprowski &hs_ep->desc_list_dma, GFP_ATOMIC); 38365f54c54bSVahram Aharonyan if (!hs_ep->desc_list) { 38375f54c54bSVahram Aharonyan ret = -ENOMEM; 38385f54c54bSVahram Aharonyan goto error2; 38395f54c54bSVahram Aharonyan } 38405f54c54bSVahram Aharonyan } 38415f54c54bSVahram Aharonyan 384247a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 384347a1685fSDinh Nguyen 384447a1685fSDinh Nguyen epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK); 384547a1685fSDinh Nguyen epctrl |= DXEPCTL_MPS(mps); 384647a1685fSDinh Nguyen 384747a1685fSDinh Nguyen /* 384847a1685fSDinh Nguyen * mark the endpoint as active, otherwise the core may ignore 384947a1685fSDinh Nguyen * transactions entirely for this endpoint 385047a1685fSDinh Nguyen */ 385147a1685fSDinh Nguyen epctrl |= DXEPCTL_USBACTEP; 385247a1685fSDinh Nguyen 385347a1685fSDinh Nguyen /* update the endpoint state */ 3854ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, mc, dir_in); 385547a1685fSDinh Nguyen 385647a1685fSDinh Nguyen /* default, set to non-periodic */ 385747a1685fSDinh Nguyen hs_ep->isochronous = 0; 385847a1685fSDinh Nguyen hs_ep->periodic = 0; 385947a1685fSDinh Nguyen hs_ep->halted = 0; 386047a1685fSDinh Nguyen hs_ep->interval = desc->bInterval; 386147a1685fSDinh Nguyen 3862729cac69SMinas Harutyunyan switch (ep_type) { 386347a1685fSDinh Nguyen case USB_ENDPOINT_XFER_ISOC: 386447a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_ISO; 386547a1685fSDinh Nguyen epctrl |= DXEPCTL_SETEVENFR; 386647a1685fSDinh Nguyen hs_ep->isochronous = 1; 3867142bd33fSVardan Mikayelyan hs_ep->interval = 1 << (desc->bInterval - 1); 3868837e9f00SVardan Mikayelyan hs_ep->target_frame = TARGET_FRAME_INITIAL; 3869ab7d2192SVahram Aharonyan hs_ep->next_desc = 0; 3870729cac69SMinas Harutyunyan hs_ep->compl_desc = 0; 3871837e9f00SVardan Mikayelyan if (dir_in) { 387247a1685fSDinh Nguyen hs_ep->periodic = 1; 3873837e9f00SVardan Mikayelyan mask = dwc2_readl(hsotg->regs + DIEPMSK); 3874837e9f00SVardan Mikayelyan mask |= DIEPMSK_NAKMSK; 3875837e9f00SVardan Mikayelyan dwc2_writel(mask, hsotg->regs + DIEPMSK); 3876837e9f00SVardan Mikayelyan } else { 3877837e9f00SVardan Mikayelyan mask = dwc2_readl(hsotg->regs + DOEPMSK); 3878837e9f00SVardan Mikayelyan mask |= DOEPMSK_OUTTKNEPDISMSK; 3879837e9f00SVardan Mikayelyan dwc2_writel(mask, hsotg->regs + DOEPMSK); 3880837e9f00SVardan Mikayelyan } 388147a1685fSDinh Nguyen break; 388247a1685fSDinh Nguyen 388347a1685fSDinh Nguyen case USB_ENDPOINT_XFER_BULK: 388447a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_BULK; 388547a1685fSDinh Nguyen break; 388647a1685fSDinh Nguyen 388747a1685fSDinh Nguyen case USB_ENDPOINT_XFER_INT: 3888b203d0a2SRobert Baldyga if (dir_in) 388947a1685fSDinh Nguyen hs_ep->periodic = 1; 389047a1685fSDinh Nguyen 3891142bd33fSVardan Mikayelyan if (hsotg->gadget.speed == USB_SPEED_HIGH) 3892142bd33fSVardan Mikayelyan hs_ep->interval = 1 << (desc->bInterval - 1); 3893142bd33fSVardan Mikayelyan 389447a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_INTERRUPT; 389547a1685fSDinh Nguyen break; 389647a1685fSDinh Nguyen 389747a1685fSDinh Nguyen case USB_ENDPOINT_XFER_CONTROL: 389847a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_CONTROL; 389947a1685fSDinh Nguyen break; 390047a1685fSDinh Nguyen } 390147a1685fSDinh Nguyen 390247a1685fSDinh Nguyen /* 390347a1685fSDinh Nguyen * if the hardware has dedicated fifos, we must give each IN EP 390447a1685fSDinh Nguyen * a unique tx-fifo even if it is non-periodic. 390547a1685fSDinh Nguyen */ 390621f3bb52SRobert Baldyga if (dir_in && hsotg->dedicated_fifos) { 3907ca4c55adSMian Yousaf Kaukab u32 fifo_index = 0; 3908ca4c55adSMian Yousaf Kaukab u32 fifo_size = UINT_MAX; 39099da51974SJohn Youn 3910b203d0a2SRobert Baldyga size = hs_ep->ep.maxpacket * hs_ep->mc; 39115f2196bdSMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; ++i) { 3912b203d0a2SRobert Baldyga if (hsotg->fifo_map & (1 << i)) 3913b203d0a2SRobert Baldyga continue; 391495c8bc36SAntti Seppälä val = dwc2_readl(hsotg->regs + DPTXFSIZN(i)); 3915b203d0a2SRobert Baldyga val = (val >> FIFOSIZE_DEPTH_SHIFT) * 4; 3916b203d0a2SRobert Baldyga if (val < size) 3917b203d0a2SRobert Baldyga continue; 3918ca4c55adSMian Yousaf Kaukab /* Search for smallest acceptable fifo */ 3919ca4c55adSMian Yousaf Kaukab if (val < fifo_size) { 3920ca4c55adSMian Yousaf Kaukab fifo_size = val; 3921ca4c55adSMian Yousaf Kaukab fifo_index = i; 3922b203d0a2SRobert Baldyga } 3923ca4c55adSMian Yousaf Kaukab } 3924ca4c55adSMian Yousaf Kaukab if (!fifo_index) { 39255f2196bdSMian Yousaf Kaukab dev_err(hsotg->dev, 39265f2196bdSMian Yousaf Kaukab "%s: No suitable fifo found\n", __func__); 3927b585a48bSSudip Mukherjee ret = -ENOMEM; 39285f54c54bSVahram Aharonyan goto error1; 3929b585a48bSSudip Mukherjee } 3930ca4c55adSMian Yousaf Kaukab hsotg->fifo_map |= 1 << fifo_index; 3931ca4c55adSMian Yousaf Kaukab epctrl |= DXEPCTL_TXFNUM(fifo_index); 3932ca4c55adSMian Yousaf Kaukab hs_ep->fifo_index = fifo_index; 3933ca4c55adSMian Yousaf Kaukab hs_ep->fifo_size = fifo_size; 3934b203d0a2SRobert Baldyga } 393547a1685fSDinh Nguyen 393647a1685fSDinh Nguyen /* for non control endpoints, set PID to D0 */ 3937837e9f00SVardan Mikayelyan if (index && !hs_ep->isochronous) 393847a1685fSDinh Nguyen epctrl |= DXEPCTL_SETD0PID; 393947a1685fSDinh Nguyen 394047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", 394147a1685fSDinh Nguyen __func__, epctrl); 394247a1685fSDinh Nguyen 394395c8bc36SAntti Seppälä dwc2_writel(epctrl, hsotg->regs + epctrl_reg); 394447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", 394595c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctrl_reg)); 394647a1685fSDinh Nguyen 394747a1685fSDinh Nguyen /* enable the endpoint interrupt */ 39481f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, index, dir_in, 1); 394947a1685fSDinh Nguyen 39505f54c54bSVahram Aharonyan error1: 395147a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 39525f54c54bSVahram Aharonyan 39535f54c54bSVahram Aharonyan error2: 39545f54c54bSVahram Aharonyan if (ret && using_desc_dma(hsotg) && hs_ep->desc_list) { 39559383e084SVardan Mikayelyan dmam_free_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC * 39565f54c54bSVahram Aharonyan sizeof(struct dwc2_dma_desc), 39575f54c54bSVahram Aharonyan hs_ep->desc_list, hs_ep->desc_list_dma); 39585f54c54bSVahram Aharonyan hs_ep->desc_list = NULL; 39595f54c54bSVahram Aharonyan } 39605f54c54bSVahram Aharonyan 396147a1685fSDinh Nguyen return ret; 396247a1685fSDinh Nguyen } 396347a1685fSDinh Nguyen 396447a1685fSDinh Nguyen /** 39651f91b4ccSFelipe Balbi * dwc2_hsotg_ep_disable - disable given endpoint 396647a1685fSDinh Nguyen * @ep: The endpoint to disable. 396747a1685fSDinh Nguyen */ 39681f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_disable(struct usb_ep *ep) 396947a1685fSDinh Nguyen { 39701f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 3971941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 397247a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 397347a1685fSDinh Nguyen int index = hs_ep->index; 397447a1685fSDinh Nguyen unsigned long flags; 397547a1685fSDinh Nguyen u32 epctrl_reg; 397647a1685fSDinh Nguyen u32 ctrl; 397747a1685fSDinh Nguyen 39781e011293SMarek Szyprowski dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); 397947a1685fSDinh Nguyen 3980c6f5c050SMian Yousaf Kaukab if (ep == &hsotg->eps_out[0]->ep) { 398147a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: called for ep0\n", __func__); 398247a1685fSDinh Nguyen return -EINVAL; 398347a1685fSDinh Nguyen } 398447a1685fSDinh Nguyen 39859b481092SJohn Stultz if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { 39869b481092SJohn Stultz dev_err(hsotg->dev, "%s: called in host mode?\n", __func__); 39879b481092SJohn Stultz return -EINVAL; 39889b481092SJohn Stultz } 39899b481092SJohn Stultz 399047a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 399147a1685fSDinh Nguyen 399247a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 399347a1685fSDinh Nguyen 399495c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctrl_reg); 3995a4f82771SVahram Aharonyan 3996a4f82771SVahram Aharonyan if (ctrl & DXEPCTL_EPENA) 3997a4f82771SVahram Aharonyan dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep); 3998a4f82771SVahram Aharonyan 399947a1685fSDinh Nguyen ctrl &= ~DXEPCTL_EPENA; 400047a1685fSDinh Nguyen ctrl &= ~DXEPCTL_USBACTEP; 400147a1685fSDinh Nguyen ctrl |= DXEPCTL_SNAK; 400247a1685fSDinh Nguyen 400347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 400495c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + epctrl_reg); 400547a1685fSDinh Nguyen 400647a1685fSDinh Nguyen /* disable endpoint interrupts */ 40071f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); 400847a1685fSDinh Nguyen 40091141ea01SMian Yousaf Kaukab /* terminate all requests with shutdown */ 40101141ea01SMian Yousaf Kaukab kill_all_requests(hsotg, hs_ep, -ESHUTDOWN); 40111141ea01SMian Yousaf Kaukab 40121c07b20eSRobert Baldyga hsotg->fifo_map &= ~(1 << hs_ep->fifo_index); 40131c07b20eSRobert Baldyga hs_ep->fifo_index = 0; 40141c07b20eSRobert Baldyga hs_ep->fifo_size = 0; 40151c07b20eSRobert Baldyga 401647a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 401747a1685fSDinh Nguyen return 0; 401847a1685fSDinh Nguyen } 401947a1685fSDinh Nguyen 402047a1685fSDinh Nguyen /** 402147a1685fSDinh Nguyen * on_list - check request is on the given endpoint 402247a1685fSDinh Nguyen * @ep: The endpoint to check. 402347a1685fSDinh Nguyen * @test: The request to test if it is on the endpoint. 402447a1685fSDinh Nguyen */ 40251f91b4ccSFelipe Balbi static bool on_list(struct dwc2_hsotg_ep *ep, struct dwc2_hsotg_req *test) 402647a1685fSDinh Nguyen { 40271f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req, *treq; 402847a1685fSDinh Nguyen 402947a1685fSDinh Nguyen list_for_each_entry_safe(req, treq, &ep->queue, queue) { 403047a1685fSDinh Nguyen if (req == test) 403147a1685fSDinh Nguyen return true; 403247a1685fSDinh Nguyen } 403347a1685fSDinh Nguyen 403447a1685fSDinh Nguyen return false; 403547a1685fSDinh Nguyen } 403647a1685fSDinh Nguyen 403747a1685fSDinh Nguyen /** 40381f91b4ccSFelipe Balbi * dwc2_hsotg_ep_dequeue - dequeue given endpoint 403947a1685fSDinh Nguyen * @ep: The endpoint to dequeue. 404047a1685fSDinh Nguyen * @req: The request to be removed from a queue. 404147a1685fSDinh Nguyen */ 40421f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) 404347a1685fSDinh Nguyen { 40441f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 40451f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 4046941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 404747a1685fSDinh Nguyen unsigned long flags; 404847a1685fSDinh Nguyen 40491e011293SMarek Szyprowski dev_dbg(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); 405047a1685fSDinh Nguyen 405147a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 405247a1685fSDinh Nguyen 405347a1685fSDinh Nguyen if (!on_list(hs_ep, hs_req)) { 405447a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 405547a1685fSDinh Nguyen return -EINVAL; 405647a1685fSDinh Nguyen } 405747a1685fSDinh Nguyen 4058c524dd5fSMian Yousaf Kaukab /* Dequeue already started request */ 4059c524dd5fSMian Yousaf Kaukab if (req == &hs_ep->req->req) 4060c524dd5fSMian Yousaf Kaukab dwc2_hsotg_ep_stop_xfr(hs, hs_ep); 4061c524dd5fSMian Yousaf Kaukab 40621f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); 406347a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 406447a1685fSDinh Nguyen 406547a1685fSDinh Nguyen return 0; 406647a1685fSDinh Nguyen } 406747a1685fSDinh Nguyen 406847a1685fSDinh Nguyen /** 40691f91b4ccSFelipe Balbi * dwc2_hsotg_ep_sethalt - set halt on a given endpoint 407047a1685fSDinh Nguyen * @ep: The endpoint to set halt. 407147a1685fSDinh Nguyen * @value: Set or unset the halt. 407251da43b5SVahram Aharonyan * @now: If true, stall the endpoint now. Otherwise return -EAGAIN if 407351da43b5SVahram Aharonyan * the endpoint is busy processing requests. 407451da43b5SVahram Aharonyan * 407551da43b5SVahram Aharonyan * We need to stall the endpoint immediately if request comes from set_feature 407651da43b5SVahram Aharonyan * protocol command handler. 407747a1685fSDinh Nguyen */ 407851da43b5SVahram Aharonyan static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now) 407947a1685fSDinh Nguyen { 40801f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 4081941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 408247a1685fSDinh Nguyen int index = hs_ep->index; 408347a1685fSDinh Nguyen u32 epreg; 408447a1685fSDinh Nguyen u32 epctl; 408547a1685fSDinh Nguyen u32 xfertype; 408647a1685fSDinh Nguyen 408747a1685fSDinh Nguyen dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); 408847a1685fSDinh Nguyen 408947a1685fSDinh Nguyen if (index == 0) { 409047a1685fSDinh Nguyen if (value) 40911f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hs); 409247a1685fSDinh Nguyen else 409347a1685fSDinh Nguyen dev_warn(hs->dev, 409447a1685fSDinh Nguyen "%s: can't clear halt on ep0\n", __func__); 409547a1685fSDinh Nguyen return 0; 409647a1685fSDinh Nguyen } 409747a1685fSDinh Nguyen 409815186f10SVahram Aharonyan if (hs_ep->isochronous) { 409915186f10SVahram Aharonyan dev_err(hs->dev, "%s is Isochronous Endpoint\n", ep->name); 410015186f10SVahram Aharonyan return -EINVAL; 410115186f10SVahram Aharonyan } 410215186f10SVahram Aharonyan 410351da43b5SVahram Aharonyan if (!now && value && !list_empty(&hs_ep->queue)) { 410451da43b5SVahram Aharonyan dev_dbg(hs->dev, "%s request is pending, cannot halt\n", 410551da43b5SVahram Aharonyan ep->name); 410651da43b5SVahram Aharonyan return -EAGAIN; 410751da43b5SVahram Aharonyan } 410851da43b5SVahram Aharonyan 4109c6f5c050SMian Yousaf Kaukab if (hs_ep->dir_in) { 411047a1685fSDinh Nguyen epreg = DIEPCTL(index); 411195c8bc36SAntti Seppälä epctl = dwc2_readl(hs->regs + epreg); 411247a1685fSDinh Nguyen 411347a1685fSDinh Nguyen if (value) { 41145a350d53SFelipe Balbi epctl |= DXEPCTL_STALL | DXEPCTL_SNAK; 411547a1685fSDinh Nguyen if (epctl & DXEPCTL_EPENA) 411647a1685fSDinh Nguyen epctl |= DXEPCTL_EPDIS; 411747a1685fSDinh Nguyen } else { 411847a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 411947a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 412047a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 412147a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 412247a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 412347a1685fSDinh Nguyen } 412495c8bc36SAntti Seppälä dwc2_writel(epctl, hs->regs + epreg); 4125c6f5c050SMian Yousaf Kaukab } else { 412647a1685fSDinh Nguyen epreg = DOEPCTL(index); 412795c8bc36SAntti Seppälä epctl = dwc2_readl(hs->regs + epreg); 412847a1685fSDinh Nguyen 412934c0887fSJohn Youn if (value) { 413047a1685fSDinh Nguyen epctl |= DXEPCTL_STALL; 413134c0887fSJohn Youn } else { 413247a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 413347a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 413447a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 413547a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 413647a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 413747a1685fSDinh Nguyen } 413895c8bc36SAntti Seppälä dwc2_writel(epctl, hs->regs + epreg); 4139c6f5c050SMian Yousaf Kaukab } 414047a1685fSDinh Nguyen 414147a1685fSDinh Nguyen hs_ep->halted = value; 414247a1685fSDinh Nguyen 414347a1685fSDinh Nguyen return 0; 414447a1685fSDinh Nguyen } 414547a1685fSDinh Nguyen 414647a1685fSDinh Nguyen /** 41471f91b4ccSFelipe Balbi * dwc2_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held 414847a1685fSDinh Nguyen * @ep: The endpoint to set halt. 414947a1685fSDinh Nguyen * @value: Set or unset the halt. 415047a1685fSDinh Nguyen */ 41511f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) 415247a1685fSDinh Nguyen { 41531f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 4154941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 415547a1685fSDinh Nguyen unsigned long flags = 0; 415647a1685fSDinh Nguyen int ret = 0; 415747a1685fSDinh Nguyen 415847a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 415951da43b5SVahram Aharonyan ret = dwc2_hsotg_ep_sethalt(ep, value, false); 416047a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 416147a1685fSDinh Nguyen 416247a1685fSDinh Nguyen return ret; 416347a1685fSDinh Nguyen } 416447a1685fSDinh Nguyen 4165ebce561aSBhumika Goyal static const struct usb_ep_ops dwc2_hsotg_ep_ops = { 41661f91b4ccSFelipe Balbi .enable = dwc2_hsotg_ep_enable, 41671f91b4ccSFelipe Balbi .disable = dwc2_hsotg_ep_disable, 41681f91b4ccSFelipe Balbi .alloc_request = dwc2_hsotg_ep_alloc_request, 41691f91b4ccSFelipe Balbi .free_request = dwc2_hsotg_ep_free_request, 41701f91b4ccSFelipe Balbi .queue = dwc2_hsotg_ep_queue_lock, 41711f91b4ccSFelipe Balbi .dequeue = dwc2_hsotg_ep_dequeue, 41721f91b4ccSFelipe Balbi .set_halt = dwc2_hsotg_ep_sethalt_lock, 417347a1685fSDinh Nguyen /* note, don't believe we have any call for the fifo routines */ 417447a1685fSDinh Nguyen }; 417547a1685fSDinh Nguyen 417647a1685fSDinh Nguyen /** 41779da51974SJohn Youn * dwc2_hsotg_init - initialize the usb core 417847a1685fSDinh Nguyen * @hsotg: The driver state 417947a1685fSDinh Nguyen */ 41801f91b4ccSFelipe Balbi static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) 418147a1685fSDinh Nguyen { 4182fa4a8d72SMian Yousaf Kaukab u32 trdtim; 4183ecd9a7adSPrzemek Rudy u32 usbcfg; 418447a1685fSDinh Nguyen /* unmask subset of endpoint interrupts */ 418547a1685fSDinh Nguyen 418695c8bc36SAntti Seppälä dwc2_writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | 418747a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK, 418847a1685fSDinh Nguyen hsotg->regs + DIEPMSK); 418947a1685fSDinh Nguyen 419095c8bc36SAntti Seppälä dwc2_writel(DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | 419147a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK, 419247a1685fSDinh Nguyen hsotg->regs + DOEPMSK); 419347a1685fSDinh Nguyen 419495c8bc36SAntti Seppälä dwc2_writel(0, hsotg->regs + DAINTMSK); 419547a1685fSDinh Nguyen 419647a1685fSDinh Nguyen /* Be in disconnected state until gadget is registered */ 4197abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + DCTL, DCTL_SFTDISCON); 419847a1685fSDinh Nguyen 419947a1685fSDinh Nguyen /* setup fifos */ 420047a1685fSDinh Nguyen 420147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 420295c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + GRXFSIZ), 420395c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + GNPTXFSIZ)); 420447a1685fSDinh Nguyen 42051f91b4ccSFelipe Balbi dwc2_hsotg_init_fifo(hsotg); 420647a1685fSDinh Nguyen 4207ecd9a7adSPrzemek Rudy /* keep other bits untouched (so e.g. forced modes are not lost) */ 4208ecd9a7adSPrzemek Rudy usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); 4209ecd9a7adSPrzemek Rudy usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP | 4210ca02954aSAmelie Delaunay GUSBCFG_HNPCAP | GUSBCFG_USBTRDTIM_MASK); 4211ecd9a7adSPrzemek Rudy 421247a1685fSDinh Nguyen /* set the PLL on, remove the HNP/SRP and set the PHY */ 4213fa4a8d72SMian Yousaf Kaukab trdtim = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5; 4214ecd9a7adSPrzemek Rudy usbcfg |= hsotg->phyif | GUSBCFG_TOUTCAL(7) | 4215ecd9a7adSPrzemek Rudy (trdtim << GUSBCFG_USBTRDTIM_SHIFT); 4216ecd9a7adSPrzemek Rudy dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); 421747a1685fSDinh Nguyen 4218f5090044SGregory Herrero if (using_dma(hsotg)) 4219abd064a1SRazmik Karapetyan dwc2_set_bit(hsotg->regs + GAHBCFG, GAHBCFG_DMA_EN); 422047a1685fSDinh Nguyen } 422147a1685fSDinh Nguyen 422247a1685fSDinh Nguyen /** 42231f91b4ccSFelipe Balbi * dwc2_hsotg_udc_start - prepare the udc for work 422447a1685fSDinh Nguyen * @gadget: The usb gadget state 422547a1685fSDinh Nguyen * @driver: The usb gadget driver 422647a1685fSDinh Nguyen * 422747a1685fSDinh Nguyen * Perform initialization to prepare udc device and driver 422847a1685fSDinh Nguyen * to work. 422947a1685fSDinh Nguyen */ 42301f91b4ccSFelipe Balbi static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, 423147a1685fSDinh Nguyen struct usb_gadget_driver *driver) 423247a1685fSDinh Nguyen { 4233941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 42345b9451f8SMarek Szyprowski unsigned long flags; 423547a1685fSDinh Nguyen int ret; 423647a1685fSDinh Nguyen 423747a1685fSDinh Nguyen if (!hsotg) { 423847a1685fSDinh Nguyen pr_err("%s: called with no device\n", __func__); 423947a1685fSDinh Nguyen return -ENODEV; 424047a1685fSDinh Nguyen } 424147a1685fSDinh Nguyen 424247a1685fSDinh Nguyen if (!driver) { 424347a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: no driver\n", __func__); 424447a1685fSDinh Nguyen return -EINVAL; 424547a1685fSDinh Nguyen } 424647a1685fSDinh Nguyen 424747a1685fSDinh Nguyen if (driver->max_speed < USB_SPEED_FULL) 424847a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: bad speed\n", __func__); 424947a1685fSDinh Nguyen 425047a1685fSDinh Nguyen if (!driver->setup) { 425147a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: missing entry points\n", __func__); 425247a1685fSDinh Nguyen return -EINVAL; 425347a1685fSDinh Nguyen } 425447a1685fSDinh Nguyen 425547a1685fSDinh Nguyen WARN_ON(hsotg->driver); 425647a1685fSDinh Nguyen 425747a1685fSDinh Nguyen driver->driver.bus = NULL; 425847a1685fSDinh Nguyen hsotg->driver = driver; 425947a1685fSDinh Nguyen hsotg->gadget.dev.of_node = hsotg->dev->of_node; 426047a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 426147a1685fSDinh Nguyen 426209a75e85SMarek Szyprowski if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) { 426309a75e85SMarek Szyprowski ret = dwc2_lowlevel_hw_enable(hsotg); 426409a75e85SMarek Szyprowski if (ret) 426547a1685fSDinh Nguyen goto err; 426647a1685fSDinh Nguyen } 426747a1685fSDinh Nguyen 4268f6c01592SGregory Herrero if (!IS_ERR_OR_NULL(hsotg->uphy)) 4269f6c01592SGregory Herrero otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget); 4270c816c47fSMarek Szyprowski 42715b9451f8SMarek Szyprowski spin_lock_irqsave(&hsotg->lock, flags); 4272d0f0ac56SJohn Youn if (dwc2_hw_is_device(hsotg)) { 42731f91b4ccSFelipe Balbi dwc2_hsotg_init(hsotg); 42741f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 4275d0f0ac56SJohn Youn } 4276d0f0ac56SJohn Youn 4277dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 42785b9451f8SMarek Szyprowski spin_unlock_irqrestore(&hsotg->lock, flags); 42795b9451f8SMarek Szyprowski 428047a1685fSDinh Nguyen dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); 42815b9451f8SMarek Szyprowski 428247a1685fSDinh Nguyen return 0; 428347a1685fSDinh Nguyen 428447a1685fSDinh Nguyen err: 428547a1685fSDinh Nguyen hsotg->driver = NULL; 428647a1685fSDinh Nguyen return ret; 428747a1685fSDinh Nguyen } 428847a1685fSDinh Nguyen 428947a1685fSDinh Nguyen /** 42901f91b4ccSFelipe Balbi * dwc2_hsotg_udc_stop - stop the udc 429147a1685fSDinh Nguyen * @gadget: The usb gadget state 429247a1685fSDinh Nguyen * @driver: The usb gadget driver 429347a1685fSDinh Nguyen * 429447a1685fSDinh Nguyen * Stop udc hw block and stay tunned for future transmissions 429547a1685fSDinh Nguyen */ 42961f91b4ccSFelipe Balbi static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) 429747a1685fSDinh Nguyen { 4298941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 429947a1685fSDinh Nguyen unsigned long flags = 0; 430047a1685fSDinh Nguyen int ep; 430147a1685fSDinh Nguyen 430247a1685fSDinh Nguyen if (!hsotg) 430347a1685fSDinh Nguyen return -ENODEV; 430447a1685fSDinh Nguyen 430547a1685fSDinh Nguyen /* all endpoints should be shutdown */ 4306c6f5c050SMian Yousaf Kaukab for (ep = 1; ep < hsotg->num_of_eps; ep++) { 4307c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 43081f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 4309c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 43101f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 4311c6f5c050SMian Yousaf Kaukab } 431247a1685fSDinh Nguyen 431347a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 431447a1685fSDinh Nguyen 431547a1685fSDinh Nguyen hsotg->driver = NULL; 431647a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 4317dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 431847a1685fSDinh Nguyen 431947a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 432047a1685fSDinh Nguyen 4321f6c01592SGregory Herrero if (!IS_ERR_OR_NULL(hsotg->uphy)) 4322f6c01592SGregory Herrero otg_set_peripheral(hsotg->uphy->otg, NULL); 4323c816c47fSMarek Szyprowski 432409a75e85SMarek Szyprowski if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 432509a75e85SMarek Szyprowski dwc2_lowlevel_hw_disable(hsotg); 432647a1685fSDinh Nguyen 432747a1685fSDinh Nguyen return 0; 432847a1685fSDinh Nguyen } 432947a1685fSDinh Nguyen 433047a1685fSDinh Nguyen /** 43311f91b4ccSFelipe Balbi * dwc2_hsotg_gadget_getframe - read the frame number 433247a1685fSDinh Nguyen * @gadget: The usb gadget state 433347a1685fSDinh Nguyen * 433447a1685fSDinh Nguyen * Read the {micro} frame number 433547a1685fSDinh Nguyen */ 43361f91b4ccSFelipe Balbi static int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget) 433747a1685fSDinh Nguyen { 43381f91b4ccSFelipe Balbi return dwc2_hsotg_read_frameno(to_hsotg(gadget)); 433947a1685fSDinh Nguyen } 434047a1685fSDinh Nguyen 434147a1685fSDinh Nguyen /** 43421f91b4ccSFelipe Balbi * dwc2_hsotg_pullup - connect/disconnect the USB PHY 434347a1685fSDinh Nguyen * @gadget: The usb gadget state 434447a1685fSDinh Nguyen * @is_on: Current state of the USB PHY 434547a1685fSDinh Nguyen * 434647a1685fSDinh Nguyen * Connect/Disconnect the USB PHY pullup 434747a1685fSDinh Nguyen */ 43481f91b4ccSFelipe Balbi static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) 434947a1685fSDinh Nguyen { 4350941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 435147a1685fSDinh Nguyen unsigned long flags = 0; 435247a1685fSDinh Nguyen 435377ba9119SGregory Herrero dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on, 435477ba9119SGregory Herrero hsotg->op_state); 435577ba9119SGregory Herrero 435677ba9119SGregory Herrero /* Don't modify pullup state while in host mode */ 435777ba9119SGregory Herrero if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { 435877ba9119SGregory Herrero hsotg->enabled = is_on; 435977ba9119SGregory Herrero return 0; 436077ba9119SGregory Herrero } 436147a1685fSDinh Nguyen 436247a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 436347a1685fSDinh Nguyen if (is_on) { 4364dc6e69e6SMarek Szyprowski hsotg->enabled = 1; 43651f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 436666e77a24SRazmik Karapetyan /* Enable ACG feature in device mode,if supported */ 436766e77a24SRazmik Karapetyan dwc2_enable_acg(hsotg); 43681f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 436947a1685fSDinh Nguyen } else { 43701f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 43711f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 4372dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 437347a1685fSDinh Nguyen } 437447a1685fSDinh Nguyen 437547a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 437647a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 437747a1685fSDinh Nguyen 437847a1685fSDinh Nguyen return 0; 437947a1685fSDinh Nguyen } 438047a1685fSDinh Nguyen 43811f91b4ccSFelipe Balbi static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) 438283d98223SGregory Herrero { 438383d98223SGregory Herrero struct dwc2_hsotg *hsotg = to_hsotg(gadget); 438483d98223SGregory Herrero unsigned long flags; 438583d98223SGregory Herrero 438683d98223SGregory Herrero dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active); 438783d98223SGregory Herrero spin_lock_irqsave(&hsotg->lock, flags); 438883d98223SGregory Herrero 438918b2b37cSGregory Herrero /* 439041ba9b9bSVardan Mikayelyan * If controller is hibernated, it must exit from power_down 439161f7223bSGregory Herrero * before being initialized / de-initialized 439218b2b37cSGregory Herrero */ 4393065d3931SGregory Herrero if (hsotg->lx_state == DWC2_L2) 439441ba9b9bSVardan Mikayelyan dwc2_exit_partial_power_down(hsotg, false); 4395065d3931SGregory Herrero 439661f7223bSGregory Herrero if (is_active) { 439761f7223bSGregory Herrero hsotg->op_state = OTG_STATE_B_PERIPHERAL; 439861f7223bSGregory Herrero 43991f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 440066e77a24SRazmik Karapetyan if (hsotg->enabled) { 440166e77a24SRazmik Karapetyan /* Enable ACG feature in device mode,if supported */ 440266e77a24SRazmik Karapetyan dwc2_enable_acg(hsotg); 44031f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 440466e77a24SRazmik Karapetyan } 440583d98223SGregory Herrero } else { 44061f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 44071f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 440883d98223SGregory Herrero } 440983d98223SGregory Herrero 441083d98223SGregory Herrero spin_unlock_irqrestore(&hsotg->lock, flags); 441183d98223SGregory Herrero return 0; 441283d98223SGregory Herrero } 441383d98223SGregory Herrero 4414596d696aSGregory Herrero /** 44151f91b4ccSFelipe Balbi * dwc2_hsotg_vbus_draw - report bMaxPower field 4416596d696aSGregory Herrero * @gadget: The usb gadget state 4417596d696aSGregory Herrero * @mA: Amount of current 4418596d696aSGregory Herrero * 4419596d696aSGregory Herrero * Report how much power the device may consume to the phy. 4420596d696aSGregory Herrero */ 44219da51974SJohn Youn static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA) 4422596d696aSGregory Herrero { 4423596d696aSGregory Herrero struct dwc2_hsotg *hsotg = to_hsotg(gadget); 4424596d696aSGregory Herrero 4425596d696aSGregory Herrero if (IS_ERR_OR_NULL(hsotg->uphy)) 4426596d696aSGregory Herrero return -ENOTSUPP; 4427596d696aSGregory Herrero return usb_phy_set_power(hsotg->uphy, mA); 4428596d696aSGregory Herrero } 4429596d696aSGregory Herrero 44301f91b4ccSFelipe Balbi static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { 44311f91b4ccSFelipe Balbi .get_frame = dwc2_hsotg_gadget_getframe, 44321f91b4ccSFelipe Balbi .udc_start = dwc2_hsotg_udc_start, 44331f91b4ccSFelipe Balbi .udc_stop = dwc2_hsotg_udc_stop, 44341f91b4ccSFelipe Balbi .pullup = dwc2_hsotg_pullup, 44351f91b4ccSFelipe Balbi .vbus_session = dwc2_hsotg_vbus_session, 44361f91b4ccSFelipe Balbi .vbus_draw = dwc2_hsotg_vbus_draw, 443747a1685fSDinh Nguyen }; 443847a1685fSDinh Nguyen 443947a1685fSDinh Nguyen /** 44401f91b4ccSFelipe Balbi * dwc2_hsotg_initep - initialise a single endpoint 444147a1685fSDinh Nguyen * @hsotg: The device state. 444247a1685fSDinh Nguyen * @hs_ep: The endpoint to be initialised. 444347a1685fSDinh Nguyen * @epnum: The endpoint number 444447a1685fSDinh Nguyen * 444547a1685fSDinh Nguyen * Initialise the given endpoint (as part of the probe and device state 444647a1685fSDinh Nguyen * creation) to give to the gadget driver. Setup the endpoint name, any 444747a1685fSDinh Nguyen * direction information and other state that may be required. 444847a1685fSDinh Nguyen */ 44491f91b4ccSFelipe Balbi static void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, 44501f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 4451c6f5c050SMian Yousaf Kaukab int epnum, 4452c6f5c050SMian Yousaf Kaukab bool dir_in) 445347a1685fSDinh Nguyen { 445447a1685fSDinh Nguyen char *dir; 445547a1685fSDinh Nguyen 445647a1685fSDinh Nguyen if (epnum == 0) 445747a1685fSDinh Nguyen dir = ""; 4458c6f5c050SMian Yousaf Kaukab else if (dir_in) 445947a1685fSDinh Nguyen dir = "in"; 4460c6f5c050SMian Yousaf Kaukab else 4461c6f5c050SMian Yousaf Kaukab dir = "out"; 446247a1685fSDinh Nguyen 4463c6f5c050SMian Yousaf Kaukab hs_ep->dir_in = dir_in; 446447a1685fSDinh Nguyen hs_ep->index = epnum; 446547a1685fSDinh Nguyen 446647a1685fSDinh Nguyen snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); 446747a1685fSDinh Nguyen 446847a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->queue); 446947a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->ep.ep_list); 447047a1685fSDinh Nguyen 447147a1685fSDinh Nguyen /* add to the list of endpoints known by the gadget driver */ 447247a1685fSDinh Nguyen if (epnum) 447347a1685fSDinh Nguyen list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); 447447a1685fSDinh Nguyen 447547a1685fSDinh Nguyen hs_ep->parent = hsotg; 447647a1685fSDinh Nguyen hs_ep->ep.name = hs_ep->name; 447738e9002bSVardan Mikayelyan 447838e9002bSVardan Mikayelyan if (hsotg->params.speed == DWC2_SPEED_PARAM_LOW) 447938e9002bSVardan Mikayelyan usb_ep_set_maxpacket_limit(&hs_ep->ep, 8); 448038e9002bSVardan Mikayelyan else 448138e9002bSVardan Mikayelyan usb_ep_set_maxpacket_limit(&hs_ep->ep, 448238e9002bSVardan Mikayelyan epnum ? 1024 : EP0_MPS_LIMIT); 44831f91b4ccSFelipe Balbi hs_ep->ep.ops = &dwc2_hsotg_ep_ops; 448447a1685fSDinh Nguyen 44852954522fSRobert Baldyga if (epnum == 0) { 44862954522fSRobert Baldyga hs_ep->ep.caps.type_control = true; 44872954522fSRobert Baldyga } else { 448838e9002bSVardan Mikayelyan if (hsotg->params.speed != DWC2_SPEED_PARAM_LOW) { 44892954522fSRobert Baldyga hs_ep->ep.caps.type_iso = true; 44902954522fSRobert Baldyga hs_ep->ep.caps.type_bulk = true; 449138e9002bSVardan Mikayelyan } 44922954522fSRobert Baldyga hs_ep->ep.caps.type_int = true; 44932954522fSRobert Baldyga } 44942954522fSRobert Baldyga 44952954522fSRobert Baldyga if (dir_in) 44962954522fSRobert Baldyga hs_ep->ep.caps.dir_in = true; 44972954522fSRobert Baldyga else 44982954522fSRobert Baldyga hs_ep->ep.caps.dir_out = true; 44992954522fSRobert Baldyga 450047a1685fSDinh Nguyen /* 450147a1685fSDinh Nguyen * if we're using dma, we need to set the next-endpoint pointer 450247a1685fSDinh Nguyen * to be something valid. 450347a1685fSDinh Nguyen */ 450447a1685fSDinh Nguyen 450547a1685fSDinh Nguyen if (using_dma(hsotg)) { 450647a1685fSDinh Nguyen u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); 45079da51974SJohn Youn 4508c6f5c050SMian Yousaf Kaukab if (dir_in) 450995c8bc36SAntti Seppälä dwc2_writel(next, hsotg->regs + DIEPCTL(epnum)); 4510c6f5c050SMian Yousaf Kaukab else 451195c8bc36SAntti Seppälä dwc2_writel(next, hsotg->regs + DOEPCTL(epnum)); 451247a1685fSDinh Nguyen } 451347a1685fSDinh Nguyen } 451447a1685fSDinh Nguyen 451547a1685fSDinh Nguyen /** 45161f91b4ccSFelipe Balbi * dwc2_hsotg_hw_cfg - read HW configuration registers 451747a1685fSDinh Nguyen * @param: The device state 451847a1685fSDinh Nguyen * 451947a1685fSDinh Nguyen * Read the USB core HW configuration registers 452047a1685fSDinh Nguyen */ 45211f91b4ccSFelipe Balbi static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) 452247a1685fSDinh Nguyen { 4523c6f5c050SMian Yousaf Kaukab u32 cfg; 4524c6f5c050SMian Yousaf Kaukab u32 ep_type; 4525c6f5c050SMian Yousaf Kaukab u32 i; 4526c6f5c050SMian Yousaf Kaukab 452747a1685fSDinh Nguyen /* check hardware configuration */ 452847a1685fSDinh Nguyen 452943e90349SJohn Youn hsotg->num_of_eps = hsotg->hw_params.num_dev_ep; 453043e90349SJohn Youn 4531c6f5c050SMian Yousaf Kaukab /* Add ep0 */ 4532c6f5c050SMian Yousaf Kaukab hsotg->num_of_eps++; 453347a1685fSDinh Nguyen 4534b98866c2SJohn Youn hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, 4535b98866c2SJohn Youn sizeof(struct dwc2_hsotg_ep), 4536c6f5c050SMian Yousaf Kaukab GFP_KERNEL); 4537c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_in[0]) 4538c6f5c050SMian Yousaf Kaukab return -ENOMEM; 45391f91b4ccSFelipe Balbi /* Same dwc2_hsotg_ep is used in both directions for ep0 */ 4540c6f5c050SMian Yousaf Kaukab hsotg->eps_out[0] = hsotg->eps_in[0]; 454147a1685fSDinh Nguyen 454243e90349SJohn Youn cfg = hsotg->hw_params.dev_ep_dirs; 4543251a17f5SRoshan Pius for (i = 1, cfg >>= 2; i < hsotg->num_of_eps; i++, cfg >>= 2) { 4544c6f5c050SMian Yousaf Kaukab ep_type = cfg & 3; 4545c6f5c050SMian Yousaf Kaukab /* Direction in or both */ 4546c6f5c050SMian Yousaf Kaukab if (!(ep_type & 2)) { 4547c6f5c050SMian Yousaf Kaukab hsotg->eps_in[i] = devm_kzalloc(hsotg->dev, 45481f91b4ccSFelipe Balbi sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 4549c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_in[i]) 4550c6f5c050SMian Yousaf Kaukab return -ENOMEM; 4551c6f5c050SMian Yousaf Kaukab } 4552c6f5c050SMian Yousaf Kaukab /* Direction out or both */ 4553c6f5c050SMian Yousaf Kaukab if (!(ep_type & 1)) { 4554c6f5c050SMian Yousaf Kaukab hsotg->eps_out[i] = devm_kzalloc(hsotg->dev, 45551f91b4ccSFelipe Balbi sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 4556c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_out[i]) 4557c6f5c050SMian Yousaf Kaukab return -ENOMEM; 4558c6f5c050SMian Yousaf Kaukab } 4559c6f5c050SMian Yousaf Kaukab } 4560c6f5c050SMian Yousaf Kaukab 456143e90349SJohn Youn hsotg->fifo_mem = hsotg->hw_params.total_fifo_size; 456243e90349SJohn Youn hsotg->dedicated_fifos = hsotg->hw_params.en_multiple_tx_fifo; 456347a1685fSDinh Nguyen 4564cff9eb75SMarek Szyprowski dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n", 4565cff9eb75SMarek Szyprowski hsotg->num_of_eps, 4566cff9eb75SMarek Szyprowski hsotg->dedicated_fifos ? "dedicated" : "shared", 4567cff9eb75SMarek Szyprowski hsotg->fifo_mem); 4568c6f5c050SMian Yousaf Kaukab return 0; 456947a1685fSDinh Nguyen } 457047a1685fSDinh Nguyen 457147a1685fSDinh Nguyen /** 45721f91b4ccSFelipe Balbi * dwc2_hsotg_dump - dump state of the udc 457347a1685fSDinh Nguyen * @param: The device state 457447a1685fSDinh Nguyen */ 45751f91b4ccSFelipe Balbi static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) 457647a1685fSDinh Nguyen { 457747a1685fSDinh Nguyen #ifdef DEBUG 457847a1685fSDinh Nguyen struct device *dev = hsotg->dev; 457947a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 458047a1685fSDinh Nguyen u32 val; 458147a1685fSDinh Nguyen int idx; 458247a1685fSDinh Nguyen 458347a1685fSDinh Nguyen dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", 458495c8bc36SAntti Seppälä dwc2_readl(regs + DCFG), dwc2_readl(regs + DCTL), 458595c8bc36SAntti Seppälä dwc2_readl(regs + DIEPMSK)); 458647a1685fSDinh Nguyen 4587f889f23dSMian Yousaf Kaukab dev_info(dev, "GAHBCFG=0x%08x, GHWCFG1=0x%08x\n", 458895c8bc36SAntti Seppälä dwc2_readl(regs + GAHBCFG), dwc2_readl(regs + GHWCFG1)); 458947a1685fSDinh Nguyen 459047a1685fSDinh Nguyen dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 459195c8bc36SAntti Seppälä dwc2_readl(regs + GRXFSIZ), dwc2_readl(regs + GNPTXFSIZ)); 459247a1685fSDinh Nguyen 459347a1685fSDinh Nguyen /* show periodic fifo settings */ 459447a1685fSDinh Nguyen 4595364f8e93SMian Yousaf Kaukab for (idx = 1; idx < hsotg->num_of_eps; idx++) { 459695c8bc36SAntti Seppälä val = dwc2_readl(regs + DPTXFSIZN(idx)); 459747a1685fSDinh Nguyen dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, 459847a1685fSDinh Nguyen val >> FIFOSIZE_DEPTH_SHIFT, 459947a1685fSDinh Nguyen val & FIFOSIZE_STARTADDR_MASK); 460047a1685fSDinh Nguyen } 460147a1685fSDinh Nguyen 4602364f8e93SMian Yousaf Kaukab for (idx = 0; idx < hsotg->num_of_eps; idx++) { 460347a1685fSDinh Nguyen dev_info(dev, 460447a1685fSDinh Nguyen "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, 460595c8bc36SAntti Seppälä dwc2_readl(regs + DIEPCTL(idx)), 460695c8bc36SAntti Seppälä dwc2_readl(regs + DIEPTSIZ(idx)), 460795c8bc36SAntti Seppälä dwc2_readl(regs + DIEPDMA(idx))); 460847a1685fSDinh Nguyen 460995c8bc36SAntti Seppälä val = dwc2_readl(regs + DOEPCTL(idx)); 461047a1685fSDinh Nguyen dev_info(dev, 461147a1685fSDinh Nguyen "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", 461295c8bc36SAntti Seppälä idx, dwc2_readl(regs + DOEPCTL(idx)), 461395c8bc36SAntti Seppälä dwc2_readl(regs + DOEPTSIZ(idx)), 461495c8bc36SAntti Seppälä dwc2_readl(regs + DOEPDMA(idx))); 461547a1685fSDinh Nguyen } 461647a1685fSDinh Nguyen 461747a1685fSDinh Nguyen dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", 461895c8bc36SAntti Seppälä dwc2_readl(regs + DVBUSDIS), dwc2_readl(regs + DVBUSPULSE)); 461947a1685fSDinh Nguyen #endif 462047a1685fSDinh Nguyen } 462147a1685fSDinh Nguyen 462247a1685fSDinh Nguyen /** 4623117777b2SDinh Nguyen * dwc2_gadget_init - init function for gadget 4624117777b2SDinh Nguyen * @dwc2: The data structure for the DWC2 driver. 462547a1685fSDinh Nguyen */ 4626f3768997SVardan Mikayelyan int dwc2_gadget_init(struct dwc2_hsotg *hsotg) 462747a1685fSDinh Nguyen { 4628117777b2SDinh Nguyen struct device *dev = hsotg->dev; 462947a1685fSDinh Nguyen int epnum; 463047a1685fSDinh Nguyen int ret; 463143e90349SJohn Youn 46320a176279SGregory Herrero /* Dump fifo information */ 46330a176279SGregory Herrero dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n", 463405ee799fSJohn Youn hsotg->params.g_np_tx_fifo_size); 463505ee799fSJohn Youn dev_dbg(dev, "RXFIFO size: %d\n", hsotg->params.g_rx_fifo_size); 463647a1685fSDinh Nguyen 463747a1685fSDinh Nguyen hsotg->gadget.max_speed = USB_SPEED_HIGH; 46381f91b4ccSFelipe Balbi hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; 463947a1685fSDinh Nguyen hsotg->gadget.name = dev_name(dev); 4640fa389a6dSVardan Mikayelyan hsotg->remote_wakeup_allowed = 0; 46417455f8b7SJohn Youn 46427455f8b7SJohn Youn if (hsotg->params.lpm) 46437455f8b7SJohn Youn hsotg->gadget.lpm_capable = true; 46447455f8b7SJohn Youn 4645097ee662SGregory Herrero if (hsotg->dr_mode == USB_DR_MODE_OTG) 4646097ee662SGregory Herrero hsotg->gadget.is_otg = 1; 4647ec4cc657SMian Yousaf Kaukab else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 4648ec4cc657SMian Yousaf Kaukab hsotg->op_state = OTG_STATE_B_PERIPHERAL; 464947a1685fSDinh Nguyen 46501f91b4ccSFelipe Balbi ret = dwc2_hsotg_hw_cfg(hsotg); 4651c6f5c050SMian Yousaf Kaukab if (ret) { 4652c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret); 465309a75e85SMarek Szyprowski return ret; 4654c6f5c050SMian Yousaf Kaukab } 4655c6f5c050SMian Yousaf Kaukab 46563f95001dSMian Yousaf Kaukab hsotg->ctrl_buff = devm_kzalloc(hsotg->dev, 46573f95001dSMian Yousaf Kaukab DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 46588bae0f8cSWolfram Sang if (!hsotg->ctrl_buff) 465909a75e85SMarek Szyprowski return -ENOMEM; 46603f95001dSMian Yousaf Kaukab 46613f95001dSMian Yousaf Kaukab hsotg->ep0_buff = devm_kzalloc(hsotg->dev, 46623f95001dSMian Yousaf Kaukab DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 46638bae0f8cSWolfram Sang if (!hsotg->ep0_buff) 466409a75e85SMarek Szyprowski return -ENOMEM; 46653f95001dSMian Yousaf Kaukab 46660f6b80c0SVahram Aharonyan if (using_desc_dma(hsotg)) { 46670f6b80c0SVahram Aharonyan ret = dwc2_gadget_alloc_ctrl_desc_chains(hsotg); 46680f6b80c0SVahram Aharonyan if (ret < 0) 46690f6b80c0SVahram Aharonyan return ret; 46700f6b80c0SVahram Aharonyan } 46710f6b80c0SVahram Aharonyan 4672f3768997SVardan Mikayelyan ret = devm_request_irq(hsotg->dev, hsotg->irq, dwc2_hsotg_irq, 4673f3768997SVardan Mikayelyan IRQF_SHARED, dev_name(hsotg->dev), hsotg); 4674eb3c56c5SMarek Szyprowski if (ret < 0) { 4675db8178c3SDinh Nguyen dev_err(dev, "cannot claim IRQ for gadget\n"); 467609a75e85SMarek Szyprowski return ret; 4677eb3c56c5SMarek Szyprowski } 4678eb3c56c5SMarek Szyprowski 467947a1685fSDinh Nguyen /* hsotg->num_of_eps holds number of EPs other than ep0 */ 468047a1685fSDinh Nguyen 468147a1685fSDinh Nguyen if (hsotg->num_of_eps == 0) { 468247a1685fSDinh Nguyen dev_err(dev, "wrong number of EPs (zero)\n"); 468309a75e85SMarek Szyprowski return -EINVAL; 468447a1685fSDinh Nguyen } 468547a1685fSDinh Nguyen 468647a1685fSDinh Nguyen /* setup endpoint information */ 468747a1685fSDinh Nguyen 468847a1685fSDinh Nguyen INIT_LIST_HEAD(&hsotg->gadget.ep_list); 4689c6f5c050SMian Yousaf Kaukab hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep; 469047a1685fSDinh Nguyen 469147a1685fSDinh Nguyen /* allocate EP0 request */ 469247a1685fSDinh Nguyen 46931f91b4ccSFelipe Balbi hsotg->ctrl_req = dwc2_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep, 469447a1685fSDinh Nguyen GFP_KERNEL); 469547a1685fSDinh Nguyen if (!hsotg->ctrl_req) { 469647a1685fSDinh Nguyen dev_err(dev, "failed to allocate ctrl req\n"); 469709a75e85SMarek Szyprowski return -ENOMEM; 469847a1685fSDinh Nguyen } 469947a1685fSDinh Nguyen 470047a1685fSDinh Nguyen /* initialise the endpoints now the core has been initialised */ 4701c6f5c050SMian Yousaf Kaukab for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) { 4702c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[epnum]) 47031f91b4ccSFelipe Balbi dwc2_hsotg_initep(hsotg, hsotg->eps_in[epnum], 4704c6f5c050SMian Yousaf Kaukab epnum, 1); 4705c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[epnum]) 47061f91b4ccSFelipe Balbi dwc2_hsotg_initep(hsotg, hsotg->eps_out[epnum], 4707c6f5c050SMian Yousaf Kaukab epnum, 0); 4708c6f5c050SMian Yousaf Kaukab } 470947a1685fSDinh Nguyen 4710117777b2SDinh Nguyen ret = usb_add_gadget_udc(dev, &hsotg->gadget); 471147a1685fSDinh Nguyen if (ret) 471209a75e85SMarek Szyprowski return ret; 471347a1685fSDinh Nguyen 47141f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 471547a1685fSDinh Nguyen 471647a1685fSDinh Nguyen return 0; 471747a1685fSDinh Nguyen } 471847a1685fSDinh Nguyen 471947a1685fSDinh Nguyen /** 47201f91b4ccSFelipe Balbi * dwc2_hsotg_remove - remove function for hsotg driver 472147a1685fSDinh Nguyen * @pdev: The platform information for the driver 472247a1685fSDinh Nguyen */ 47231f91b4ccSFelipe Balbi int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg) 472447a1685fSDinh Nguyen { 472547a1685fSDinh Nguyen usb_del_gadget_udc(&hsotg->gadget); 472647a1685fSDinh Nguyen 472747a1685fSDinh Nguyen return 0; 472847a1685fSDinh Nguyen } 472947a1685fSDinh Nguyen 47301f91b4ccSFelipe Balbi int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) 473147a1685fSDinh Nguyen { 473247a1685fSDinh Nguyen unsigned long flags; 473347a1685fSDinh Nguyen 47349e779778SGregory Herrero if (hsotg->lx_state != DWC2_L0) 473509a75e85SMarek Szyprowski return 0; 47369e779778SGregory Herrero 4737dc6e69e6SMarek Szyprowski if (hsotg->driver) { 4738dc6e69e6SMarek Szyprowski int ep; 4739dc6e69e6SMarek Szyprowski 474047a1685fSDinh Nguyen dev_info(hsotg->dev, "suspending usb gadget %s\n", 474147a1685fSDinh Nguyen hsotg->driver->driver.name); 474247a1685fSDinh Nguyen 474347a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 4744dc6e69e6SMarek Szyprowski if (hsotg->enabled) 47451f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 47461f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 474747a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 474847a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 474947a1685fSDinh Nguyen 4750c6f5c050SMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps; ep++) { 4751c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 47521f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 4753c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 47541f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 4755c6f5c050SMian Yousaf Kaukab } 475647a1685fSDinh Nguyen } 475747a1685fSDinh Nguyen 475809a75e85SMarek Szyprowski return 0; 475947a1685fSDinh Nguyen } 476047a1685fSDinh Nguyen 47611f91b4ccSFelipe Balbi int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg) 476247a1685fSDinh Nguyen { 476347a1685fSDinh Nguyen unsigned long flags; 476447a1685fSDinh Nguyen 47659e779778SGregory Herrero if (hsotg->lx_state == DWC2_L2) 476609a75e85SMarek Szyprowski return 0; 47679e779778SGregory Herrero 476847a1685fSDinh Nguyen if (hsotg->driver) { 476947a1685fSDinh Nguyen dev_info(hsotg->dev, "resuming usb gadget %s\n", 477047a1685fSDinh Nguyen hsotg->driver->driver.name); 4771d00b4142SRobert Baldyga 477247a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 47731f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 477466e77a24SRazmik Karapetyan if (hsotg->enabled) { 477566e77a24SRazmik Karapetyan /* Enable ACG feature in device mode,if supported */ 477666e77a24SRazmik Karapetyan dwc2_enable_acg(hsotg); 47771f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 477866e77a24SRazmik Karapetyan } 477947a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 4780dc6e69e6SMarek Szyprowski } 478147a1685fSDinh Nguyen 478209a75e85SMarek Szyprowski return 0; 478347a1685fSDinh Nguyen } 478458e52ff6SJohn Youn 478558e52ff6SJohn Youn /** 478658e52ff6SJohn Youn * dwc2_backup_device_registers() - Backup controller device registers. 478758e52ff6SJohn Youn * When suspending usb bus, registers needs to be backuped 478858e52ff6SJohn Youn * if controller power is disabled once suspended. 478958e52ff6SJohn Youn * 479058e52ff6SJohn Youn * @hsotg: Programming view of the DWC_otg controller 479158e52ff6SJohn Youn */ 479258e52ff6SJohn Youn int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg) 479358e52ff6SJohn Youn { 479458e52ff6SJohn Youn struct dwc2_dregs_backup *dr; 479558e52ff6SJohn Youn int i; 479658e52ff6SJohn Youn 479758e52ff6SJohn Youn dev_dbg(hsotg->dev, "%s\n", __func__); 479858e52ff6SJohn Youn 479958e52ff6SJohn Youn /* Backup dev regs */ 480058e52ff6SJohn Youn dr = &hsotg->dr_backup; 480158e52ff6SJohn Youn 480258e52ff6SJohn Youn dr->dcfg = dwc2_readl(hsotg->regs + DCFG); 480358e52ff6SJohn Youn dr->dctl = dwc2_readl(hsotg->regs + DCTL); 480458e52ff6SJohn Youn dr->daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); 480558e52ff6SJohn Youn dr->diepmsk = dwc2_readl(hsotg->regs + DIEPMSK); 480658e52ff6SJohn Youn dr->doepmsk = dwc2_readl(hsotg->regs + DOEPMSK); 480758e52ff6SJohn Youn 480858e52ff6SJohn Youn for (i = 0; i < hsotg->num_of_eps; i++) { 480958e52ff6SJohn Youn /* Backup IN EPs */ 481058e52ff6SJohn Youn dr->diepctl[i] = dwc2_readl(hsotg->regs + DIEPCTL(i)); 481158e52ff6SJohn Youn 481258e52ff6SJohn Youn /* Ensure DATA PID is correctly configured */ 481358e52ff6SJohn Youn if (dr->diepctl[i] & DXEPCTL_DPID) 481458e52ff6SJohn Youn dr->diepctl[i] |= DXEPCTL_SETD1PID; 481558e52ff6SJohn Youn else 481658e52ff6SJohn Youn dr->diepctl[i] |= DXEPCTL_SETD0PID; 481758e52ff6SJohn Youn 481858e52ff6SJohn Youn dr->dieptsiz[i] = dwc2_readl(hsotg->regs + DIEPTSIZ(i)); 481958e52ff6SJohn Youn dr->diepdma[i] = dwc2_readl(hsotg->regs + DIEPDMA(i)); 482058e52ff6SJohn Youn 482158e52ff6SJohn Youn /* Backup OUT EPs */ 482258e52ff6SJohn Youn dr->doepctl[i] = dwc2_readl(hsotg->regs + DOEPCTL(i)); 482358e52ff6SJohn Youn 482458e52ff6SJohn Youn /* Ensure DATA PID is correctly configured */ 482558e52ff6SJohn Youn if (dr->doepctl[i] & DXEPCTL_DPID) 482658e52ff6SJohn Youn dr->doepctl[i] |= DXEPCTL_SETD1PID; 482758e52ff6SJohn Youn else 482858e52ff6SJohn Youn dr->doepctl[i] |= DXEPCTL_SETD0PID; 482958e52ff6SJohn Youn 483058e52ff6SJohn Youn dr->doeptsiz[i] = dwc2_readl(hsotg->regs + DOEPTSIZ(i)); 483158e52ff6SJohn Youn dr->doepdma[i] = dwc2_readl(hsotg->regs + DOEPDMA(i)); 4832af7c2bd3SVardan Mikayelyan dr->dtxfsiz[i] = dwc2_readl(hsotg->regs + DPTXFSIZN(i)); 483358e52ff6SJohn Youn } 483458e52ff6SJohn Youn dr->valid = true; 483558e52ff6SJohn Youn return 0; 483658e52ff6SJohn Youn } 483758e52ff6SJohn Youn 483858e52ff6SJohn Youn /** 483958e52ff6SJohn Youn * dwc2_restore_device_registers() - Restore controller device registers. 484058e52ff6SJohn Youn * When resuming usb bus, device registers needs to be restored 484158e52ff6SJohn Youn * if controller power were disabled. 484258e52ff6SJohn Youn * 484358e52ff6SJohn Youn * @hsotg: Programming view of the DWC_otg controller 48449a5d2816SVardan Mikayelyan * @remote_wakeup: Indicates whether resume is initiated by Device or Host. 48459a5d2816SVardan Mikayelyan * 48469a5d2816SVardan Mikayelyan * Return: 0 if successful, negative error code otherwise 484758e52ff6SJohn Youn */ 48489a5d2816SVardan Mikayelyan int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup) 484958e52ff6SJohn Youn { 485058e52ff6SJohn Youn struct dwc2_dregs_backup *dr; 485158e52ff6SJohn Youn int i; 485258e52ff6SJohn Youn 485358e52ff6SJohn Youn dev_dbg(hsotg->dev, "%s\n", __func__); 485458e52ff6SJohn Youn 485558e52ff6SJohn Youn /* Restore dev regs */ 485658e52ff6SJohn Youn dr = &hsotg->dr_backup; 485758e52ff6SJohn Youn if (!dr->valid) { 485858e52ff6SJohn Youn dev_err(hsotg->dev, "%s: no device registers to restore\n", 485958e52ff6SJohn Youn __func__); 486058e52ff6SJohn Youn return -EINVAL; 486158e52ff6SJohn Youn } 486258e52ff6SJohn Youn dr->valid = false; 486358e52ff6SJohn Youn 48649a5d2816SVardan Mikayelyan if (!remote_wakeup) 486558e52ff6SJohn Youn dwc2_writel(dr->dctl, hsotg->regs + DCTL); 48669a5d2816SVardan Mikayelyan 486758e52ff6SJohn Youn dwc2_writel(dr->daintmsk, hsotg->regs + DAINTMSK); 486858e52ff6SJohn Youn dwc2_writel(dr->diepmsk, hsotg->regs + DIEPMSK); 486958e52ff6SJohn Youn dwc2_writel(dr->doepmsk, hsotg->regs + DOEPMSK); 487058e52ff6SJohn Youn 487158e52ff6SJohn Youn for (i = 0; i < hsotg->num_of_eps; i++) { 487258e52ff6SJohn Youn /* Restore IN EPs */ 487358e52ff6SJohn Youn dwc2_writel(dr->dieptsiz[i], hsotg->regs + DIEPTSIZ(i)); 487458e52ff6SJohn Youn dwc2_writel(dr->diepdma[i], hsotg->regs + DIEPDMA(i)); 487558e52ff6SJohn Youn dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i)); 48769a5d2816SVardan Mikayelyan /** WA for enabled EPx's IN in DDMA mode. On entering to 48779a5d2816SVardan Mikayelyan * hibernation wrong value read and saved from DIEPDMAx, 48789a5d2816SVardan Mikayelyan * as result BNA interrupt asserted on hibernation exit 48799a5d2816SVardan Mikayelyan * by restoring from saved area. 48809a5d2816SVardan Mikayelyan */ 48819a5d2816SVardan Mikayelyan if (hsotg->params.g_dma_desc && 48829a5d2816SVardan Mikayelyan (dr->diepctl[i] & DXEPCTL_EPENA)) 48839a5d2816SVardan Mikayelyan dr->diepdma[i] = hsotg->eps_in[i]->desc_list_dma; 48849a5d2816SVardan Mikayelyan dwc2_writel(dr->dtxfsiz[i], hsotg->regs + DPTXFSIZN(i)); 48859a5d2816SVardan Mikayelyan dwc2_writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i)); 48869a5d2816SVardan Mikayelyan /* Restore OUT EPs */ 48879a5d2816SVardan Mikayelyan dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i)); 48889a5d2816SVardan Mikayelyan /* WA for enabled EPx's OUT in DDMA mode. On entering to 48899a5d2816SVardan Mikayelyan * hibernation wrong value read and saved from DOEPDMAx, 48909a5d2816SVardan Mikayelyan * as result BNA interrupt asserted on hibernation exit 48919a5d2816SVardan Mikayelyan * by restoring from saved area. 48929a5d2816SVardan Mikayelyan */ 48939a5d2816SVardan Mikayelyan if (hsotg->params.g_dma_desc && 48949a5d2816SVardan Mikayelyan (dr->doepctl[i] & DXEPCTL_EPENA)) 48959a5d2816SVardan Mikayelyan dr->doepdma[i] = hsotg->eps_out[i]->desc_list_dma; 489658e52ff6SJohn Youn dwc2_writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i)); 48979a5d2816SVardan Mikayelyan dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i)); 489858e52ff6SJohn Youn } 489958e52ff6SJohn Youn 490058e52ff6SJohn Youn return 0; 490158e52ff6SJohn Youn } 490221b03405SSevak Arakelyan 490321b03405SSevak Arakelyan /** 490421b03405SSevak Arakelyan * dwc2_gadget_init_lpm - Configure the core to support LPM in device mode 490521b03405SSevak Arakelyan * 490621b03405SSevak Arakelyan * @hsotg: Programming view of DWC_otg controller 490721b03405SSevak Arakelyan * 490821b03405SSevak Arakelyan */ 490921b03405SSevak Arakelyan void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) 491021b03405SSevak Arakelyan { 491121b03405SSevak Arakelyan u32 val; 491221b03405SSevak Arakelyan 491321b03405SSevak Arakelyan if (!hsotg->params.lpm) 491421b03405SSevak Arakelyan return; 491521b03405SSevak Arakelyan 491621b03405SSevak Arakelyan val = GLPMCFG_LPMCAP | GLPMCFG_APPL1RES; 491721b03405SSevak Arakelyan val |= hsotg->params.hird_threshold_en ? GLPMCFG_HIRD_THRES_EN : 0; 491821b03405SSevak Arakelyan val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0; 491921b03405SSevak Arakelyan val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT; 492021b03405SSevak Arakelyan val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; 492121b03405SSevak Arakelyan dwc2_writel(val, hsotg->regs + GLPMCFG); 492221b03405SSevak Arakelyan dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg->regs 492321b03405SSevak Arakelyan + GLPMCFG)); 492421b03405SSevak Arakelyan } 4925c5c403dcSVardan Mikayelyan 4926c5c403dcSVardan Mikayelyan /** 4927c5c403dcSVardan Mikayelyan * dwc2_gadget_enter_hibernation() - Put controller in Hibernation. 4928c5c403dcSVardan Mikayelyan * 4929c5c403dcSVardan Mikayelyan * @hsotg: Programming view of the DWC_otg controller 4930c5c403dcSVardan Mikayelyan * 4931c5c403dcSVardan Mikayelyan * Return non-zero if failed to enter to hibernation. 4932c5c403dcSVardan Mikayelyan */ 4933c5c403dcSVardan Mikayelyan int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg) 4934c5c403dcSVardan Mikayelyan { 4935c5c403dcSVardan Mikayelyan u32 gpwrdn; 4936c5c403dcSVardan Mikayelyan int ret = 0; 4937c5c403dcSVardan Mikayelyan 4938c5c403dcSVardan Mikayelyan /* Change to L2(suspend) state */ 4939c5c403dcSVardan Mikayelyan hsotg->lx_state = DWC2_L2; 4940c5c403dcSVardan Mikayelyan dev_dbg(hsotg->dev, "Start of hibernation completed\n"); 4941c5c403dcSVardan Mikayelyan ret = dwc2_backup_global_registers(hsotg); 4942c5c403dcSVardan Mikayelyan if (ret) { 4943c5c403dcSVardan Mikayelyan dev_err(hsotg->dev, "%s: failed to backup global registers\n", 4944c5c403dcSVardan Mikayelyan __func__); 4945c5c403dcSVardan Mikayelyan return ret; 4946c5c403dcSVardan Mikayelyan } 4947c5c403dcSVardan Mikayelyan ret = dwc2_backup_device_registers(hsotg); 4948c5c403dcSVardan Mikayelyan if (ret) { 4949c5c403dcSVardan Mikayelyan dev_err(hsotg->dev, "%s: failed to backup device registers\n", 4950c5c403dcSVardan Mikayelyan __func__); 4951c5c403dcSVardan Mikayelyan return ret; 4952c5c403dcSVardan Mikayelyan } 4953c5c403dcSVardan Mikayelyan 4954c5c403dcSVardan Mikayelyan gpwrdn = GPWRDN_PWRDNRSTN; 4955c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_PMUACTV; 4956c5c403dcSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 4957c5c403dcSVardan Mikayelyan udelay(10); 4958c5c403dcSVardan Mikayelyan 4959c5c403dcSVardan Mikayelyan /* Set flag to indicate that we are in hibernation */ 4960c5c403dcSVardan Mikayelyan hsotg->hibernated = 1; 4961c5c403dcSVardan Mikayelyan 4962c5c403dcSVardan Mikayelyan /* Enable interrupts from wake up logic */ 4963c5c403dcSVardan Mikayelyan gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 4964c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_PMUINTSEL; 4965c5c403dcSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 4966c5c403dcSVardan Mikayelyan udelay(10); 4967c5c403dcSVardan Mikayelyan 4968c5c403dcSVardan Mikayelyan /* Unmask device mode interrupts in GPWRDN */ 4969c5c403dcSVardan Mikayelyan gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 4970c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_RST_DET_MSK; 4971c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_LNSTSCHG_MSK; 4972c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_STS_CHGINT_MSK; 4973c5c403dcSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 4974c5c403dcSVardan Mikayelyan udelay(10); 4975c5c403dcSVardan Mikayelyan 4976c5c403dcSVardan Mikayelyan /* Enable Power Down Clamp */ 4977c5c403dcSVardan Mikayelyan gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 4978c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_PWRDNCLMP; 4979c5c403dcSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 4980c5c403dcSVardan Mikayelyan udelay(10); 4981c5c403dcSVardan Mikayelyan 4982c5c403dcSVardan Mikayelyan /* Switch off VDD */ 4983c5c403dcSVardan Mikayelyan gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 4984c5c403dcSVardan Mikayelyan gpwrdn |= GPWRDN_PWRDNSWTCH; 4985c5c403dcSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 4986c5c403dcSVardan Mikayelyan udelay(10); 4987c5c403dcSVardan Mikayelyan 4988c5c403dcSVardan Mikayelyan /* Save gpwrdn register for further usage if stschng interrupt */ 4989c5c403dcSVardan Mikayelyan hsotg->gr_backup.gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 4990c5c403dcSVardan Mikayelyan dev_dbg(hsotg->dev, "Hibernation completed\n"); 4991c5c403dcSVardan Mikayelyan 4992c5c403dcSVardan Mikayelyan return ret; 4993c5c403dcSVardan Mikayelyan } 4994c5c403dcSVardan Mikayelyan 4995c5c403dcSVardan Mikayelyan /** 4996c5c403dcSVardan Mikayelyan * dwc2_gadget_exit_hibernation() 4997c5c403dcSVardan Mikayelyan * This function is for exiting from Device mode hibernation by host initiated 4998c5c403dcSVardan Mikayelyan * resume/reset and device initiated remote-wakeup. 4999c5c403dcSVardan Mikayelyan * 5000c5c403dcSVardan Mikayelyan * @hsotg: Programming view of the DWC_otg controller 5001c5c403dcSVardan Mikayelyan * @rem_wakeup: indicates whether resume is initiated by Device or Host. 5002c5c403dcSVardan Mikayelyan * @param reset: indicates whether resume is initiated by Reset. 5003c5c403dcSVardan Mikayelyan * 5004c5c403dcSVardan Mikayelyan * Return non-zero if failed to exit from hibernation. 5005c5c403dcSVardan Mikayelyan */ 5006c5c403dcSVardan Mikayelyan int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, 5007c5c403dcSVardan Mikayelyan int rem_wakeup, int reset) 5008c5c403dcSVardan Mikayelyan { 5009c5c403dcSVardan Mikayelyan u32 pcgcctl; 5010c5c403dcSVardan Mikayelyan u32 gpwrdn; 5011c5c403dcSVardan Mikayelyan u32 dctl; 5012c5c403dcSVardan Mikayelyan int ret = 0; 5013c5c403dcSVardan Mikayelyan struct dwc2_gregs_backup *gr; 5014c5c403dcSVardan Mikayelyan struct dwc2_dregs_backup *dr; 5015c5c403dcSVardan Mikayelyan 5016c5c403dcSVardan Mikayelyan gr = &hsotg->gr_backup; 5017c5c403dcSVardan Mikayelyan dr = &hsotg->dr_backup; 5018c5c403dcSVardan Mikayelyan 5019c5c403dcSVardan Mikayelyan if (!hsotg->hibernated) { 5020c5c403dcSVardan Mikayelyan dev_dbg(hsotg->dev, "Already exited from Hibernation\n"); 5021c5c403dcSVardan Mikayelyan return 1; 5022c5c403dcSVardan Mikayelyan } 5023c5c403dcSVardan Mikayelyan dev_dbg(hsotg->dev, 5024c5c403dcSVardan Mikayelyan "%s: called with rem_wakeup = %d reset = %d\n", 5025c5c403dcSVardan Mikayelyan __func__, rem_wakeup, reset); 5026c5c403dcSVardan Mikayelyan 5027c5c403dcSVardan Mikayelyan dwc2_hib_restore_common(hsotg, rem_wakeup, 0); 5028c5c403dcSVardan Mikayelyan 5029c5c403dcSVardan Mikayelyan if (!reset) { 5030c5c403dcSVardan Mikayelyan /* Clear all pending interupts */ 5031c5c403dcSVardan Mikayelyan dwc2_writel(0xffffffff, hsotg->regs + GINTSTS); 5032c5c403dcSVardan Mikayelyan } 5033c5c403dcSVardan Mikayelyan 5034c5c403dcSVardan Mikayelyan /* De-assert Restore */ 5035c5c403dcSVardan Mikayelyan gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 5036c5c403dcSVardan Mikayelyan gpwrdn &= ~GPWRDN_RESTORE; 5037c5c403dcSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 5038c5c403dcSVardan Mikayelyan udelay(10); 5039c5c403dcSVardan Mikayelyan 5040c5c403dcSVardan Mikayelyan if (!rem_wakeup) { 5041c5c403dcSVardan Mikayelyan pcgcctl = dwc2_readl(hsotg->regs + PCGCTL); 5042c5c403dcSVardan Mikayelyan pcgcctl &= ~PCGCTL_RSTPDWNMODULE; 5043c5c403dcSVardan Mikayelyan dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); 5044c5c403dcSVardan Mikayelyan } 5045c5c403dcSVardan Mikayelyan 5046c5c403dcSVardan Mikayelyan /* Restore GUSBCFG, DCFG and DCTL */ 5047c5c403dcSVardan Mikayelyan dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG); 5048c5c403dcSVardan Mikayelyan dwc2_writel(dr->dcfg, hsotg->regs + DCFG); 5049c5c403dcSVardan Mikayelyan dwc2_writel(dr->dctl, hsotg->regs + DCTL); 5050c5c403dcSVardan Mikayelyan 5051c5c403dcSVardan Mikayelyan /* De-assert Wakeup Logic */ 5052c5c403dcSVardan Mikayelyan gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 5053c5c403dcSVardan Mikayelyan gpwrdn &= ~GPWRDN_PMUACTV; 5054c5c403dcSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 5055c5c403dcSVardan Mikayelyan 5056c5c403dcSVardan Mikayelyan if (rem_wakeup) { 5057c5c403dcSVardan Mikayelyan udelay(10); 5058c5c403dcSVardan Mikayelyan /* Start Remote Wakeup Signaling */ 5059c5c403dcSVardan Mikayelyan dwc2_writel(dr->dctl | DCTL_RMTWKUPSIG, hsotg->regs + DCTL); 5060c5c403dcSVardan Mikayelyan } else { 5061c5c403dcSVardan Mikayelyan udelay(50); 5062c5c403dcSVardan Mikayelyan /* Set Device programming done bit */ 5063c5c403dcSVardan Mikayelyan dctl = dwc2_readl(hsotg->regs + DCTL); 5064c5c403dcSVardan Mikayelyan dctl |= DCTL_PWRONPRGDONE; 5065c5c403dcSVardan Mikayelyan dwc2_writel(dctl, hsotg->regs + DCTL); 5066c5c403dcSVardan Mikayelyan } 5067c5c403dcSVardan Mikayelyan /* Wait for interrupts which must be cleared */ 5068c5c403dcSVardan Mikayelyan mdelay(2); 5069c5c403dcSVardan Mikayelyan /* Clear all pending interupts */ 5070c5c403dcSVardan Mikayelyan dwc2_writel(0xffffffff, hsotg->regs + GINTSTS); 5071c5c403dcSVardan Mikayelyan 5072c5c403dcSVardan Mikayelyan /* Restore global registers */ 5073c5c403dcSVardan Mikayelyan ret = dwc2_restore_global_registers(hsotg); 5074c5c403dcSVardan Mikayelyan if (ret) { 5075c5c403dcSVardan Mikayelyan dev_err(hsotg->dev, "%s: failed to restore registers\n", 5076c5c403dcSVardan Mikayelyan __func__); 5077c5c403dcSVardan Mikayelyan return ret; 5078c5c403dcSVardan Mikayelyan } 5079c5c403dcSVardan Mikayelyan 5080c5c403dcSVardan Mikayelyan /* Restore device registers */ 5081c5c403dcSVardan Mikayelyan ret = dwc2_restore_device_registers(hsotg, rem_wakeup); 5082c5c403dcSVardan Mikayelyan if (ret) { 5083c5c403dcSVardan Mikayelyan dev_err(hsotg->dev, "%s: failed to restore device registers\n", 5084c5c403dcSVardan Mikayelyan __func__); 5085c5c403dcSVardan Mikayelyan return ret; 5086c5c403dcSVardan Mikayelyan } 5087c5c403dcSVardan Mikayelyan 5088c5c403dcSVardan Mikayelyan if (rem_wakeup) { 5089c5c403dcSVardan Mikayelyan mdelay(10); 5090c5c403dcSVardan Mikayelyan dctl = dwc2_readl(hsotg->regs + DCTL); 5091c5c403dcSVardan Mikayelyan dctl &= ~DCTL_RMTWKUPSIG; 5092c5c403dcSVardan Mikayelyan dwc2_writel(dctl, hsotg->regs + DCTL); 5093c5c403dcSVardan Mikayelyan } 5094c5c403dcSVardan Mikayelyan 5095c5c403dcSVardan Mikayelyan hsotg->hibernated = 0; 5096c5c403dcSVardan Mikayelyan hsotg->lx_state = DWC2_L0; 5097c5c403dcSVardan Mikayelyan dev_dbg(hsotg->dev, "Hibernation recovery completes here\n"); 5098c5c403dcSVardan Mikayelyan 5099c5c403dcSVardan Mikayelyan return ret; 5100c5c403dcSVardan Mikayelyan } 5101