147a1685fSDinh Nguyen /** 247a1685fSDinh Nguyen * Copyright (c) 2011 Samsung Electronics Co., Ltd. 347a1685fSDinh Nguyen * http://www.samsung.com 447a1685fSDinh Nguyen * 547a1685fSDinh Nguyen * Copyright 2008 Openmoko, Inc. 647a1685fSDinh Nguyen * Copyright 2008 Simtec Electronics 747a1685fSDinh Nguyen * Ben Dooks <ben@simtec.co.uk> 847a1685fSDinh Nguyen * http://armlinux.simtec.co.uk/ 947a1685fSDinh Nguyen * 1047a1685fSDinh Nguyen * S3C USB2.0 High-speed / OtG driver 1147a1685fSDinh Nguyen * 1247a1685fSDinh Nguyen * This program is free software; you can redistribute it and/or modify 1347a1685fSDinh Nguyen * it under the terms of the GNU General Public License version 2 as 1447a1685fSDinh Nguyen * published by the Free Software Foundation. 1547a1685fSDinh Nguyen */ 1647a1685fSDinh Nguyen 1747a1685fSDinh Nguyen #include <linux/kernel.h> 1847a1685fSDinh Nguyen #include <linux/module.h> 1947a1685fSDinh Nguyen #include <linux/spinlock.h> 2047a1685fSDinh Nguyen #include <linux/interrupt.h> 2147a1685fSDinh Nguyen #include <linux/platform_device.h> 2247a1685fSDinh Nguyen #include <linux/dma-mapping.h> 237ad8096eSMarek Szyprowski #include <linux/mutex.h> 2447a1685fSDinh Nguyen #include <linux/seq_file.h> 2547a1685fSDinh Nguyen #include <linux/delay.h> 2647a1685fSDinh Nguyen #include <linux/io.h> 2747a1685fSDinh Nguyen #include <linux/slab.h> 2847a1685fSDinh Nguyen #include <linux/of_platform.h> 2947a1685fSDinh Nguyen 3047a1685fSDinh Nguyen #include <linux/usb/ch9.h> 3147a1685fSDinh Nguyen #include <linux/usb/gadget.h> 3247a1685fSDinh Nguyen #include <linux/usb/phy.h> 3347a1685fSDinh Nguyen 34f7c0b143SDinh Nguyen #include "core.h" 35941fcce4SDinh Nguyen #include "hw.h" 3647a1685fSDinh Nguyen 3747a1685fSDinh Nguyen /* conversion functions */ 381f91b4ccSFelipe Balbi static inline struct dwc2_hsotg_req *our_req(struct usb_request *req) 3947a1685fSDinh Nguyen { 401f91b4ccSFelipe Balbi return container_of(req, struct dwc2_hsotg_req, req); 4147a1685fSDinh Nguyen } 4247a1685fSDinh Nguyen 431f91b4ccSFelipe Balbi static inline struct dwc2_hsotg_ep *our_ep(struct usb_ep *ep) 4447a1685fSDinh Nguyen { 451f91b4ccSFelipe Balbi return container_of(ep, struct dwc2_hsotg_ep, ep); 4647a1685fSDinh Nguyen } 4747a1685fSDinh Nguyen 48941fcce4SDinh Nguyen static inline struct dwc2_hsotg *to_hsotg(struct usb_gadget *gadget) 4947a1685fSDinh Nguyen { 50941fcce4SDinh Nguyen return container_of(gadget, struct dwc2_hsotg, gadget); 5147a1685fSDinh Nguyen } 5247a1685fSDinh Nguyen 5347a1685fSDinh Nguyen static inline void __orr32(void __iomem *ptr, u32 val) 5447a1685fSDinh Nguyen { 5595c8bc36SAntti Seppälä dwc2_writel(dwc2_readl(ptr) | val, ptr); 5647a1685fSDinh Nguyen } 5747a1685fSDinh Nguyen 5847a1685fSDinh Nguyen static inline void __bic32(void __iomem *ptr, u32 val) 5947a1685fSDinh Nguyen { 6095c8bc36SAntti Seppälä dwc2_writel(dwc2_readl(ptr) & ~val, ptr); 6147a1685fSDinh Nguyen } 6247a1685fSDinh Nguyen 631f91b4ccSFelipe Balbi static inline struct dwc2_hsotg_ep *index_to_ep(struct dwc2_hsotg *hsotg, 64c6f5c050SMian Yousaf Kaukab u32 ep_index, u32 dir_in) 65c6f5c050SMian Yousaf Kaukab { 66c6f5c050SMian Yousaf Kaukab if (dir_in) 67c6f5c050SMian Yousaf Kaukab return hsotg->eps_in[ep_index]; 68c6f5c050SMian Yousaf Kaukab else 69c6f5c050SMian Yousaf Kaukab return hsotg->eps_out[ep_index]; 70c6f5c050SMian Yousaf Kaukab } 71c6f5c050SMian Yousaf Kaukab 72997f4f81SMickael Maison /* forward declaration of functions */ 731f91b4ccSFelipe Balbi static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg); 7447a1685fSDinh Nguyen 7547a1685fSDinh Nguyen /** 7647a1685fSDinh Nguyen * using_dma - return the DMA status of the driver. 7747a1685fSDinh Nguyen * @hsotg: The driver state. 7847a1685fSDinh Nguyen * 7947a1685fSDinh Nguyen * Return true if we're using DMA. 8047a1685fSDinh Nguyen * 8147a1685fSDinh Nguyen * Currently, we have the DMA support code worked into everywhere 8247a1685fSDinh Nguyen * that needs it, but the AMBA DMA implementation in the hardware can 8347a1685fSDinh Nguyen * only DMA from 32bit aligned addresses. This means that gadgets such 8447a1685fSDinh Nguyen * as the CDC Ethernet cannot work as they often pass packets which are 8547a1685fSDinh Nguyen * not 32bit aligned. 8647a1685fSDinh Nguyen * 8747a1685fSDinh Nguyen * Unfortunately the choice to use DMA or not is global to the controller 8847a1685fSDinh Nguyen * and seems to be only settable when the controller is being put through 8947a1685fSDinh Nguyen * a core reset. This means we either need to fix the gadgets to take 9047a1685fSDinh Nguyen * account of DMA alignment, or add bounce buffers (yuerk). 9147a1685fSDinh Nguyen * 92edd74be8SGregory Herrero * g_using_dma is set depending on dts flag. 9347a1685fSDinh Nguyen */ 94941fcce4SDinh Nguyen static inline bool using_dma(struct dwc2_hsotg *hsotg) 9547a1685fSDinh Nguyen { 9605ee799fSJohn Youn return hsotg->params.g_dma; 9747a1685fSDinh Nguyen } 9847a1685fSDinh Nguyen 99dec4b556SVahram Aharonyan /* 100dec4b556SVahram Aharonyan * using_desc_dma - return the descriptor DMA status of the driver. 101dec4b556SVahram Aharonyan * @hsotg: The driver state. 102dec4b556SVahram Aharonyan * 103dec4b556SVahram Aharonyan * Return true if we're using descriptor DMA. 104dec4b556SVahram Aharonyan */ 105dec4b556SVahram Aharonyan static inline bool using_desc_dma(struct dwc2_hsotg *hsotg) 106dec4b556SVahram Aharonyan { 107dec4b556SVahram Aharonyan return hsotg->params.g_dma_desc; 108dec4b556SVahram Aharonyan } 109dec4b556SVahram Aharonyan 11047a1685fSDinh Nguyen /** 11192d1635dSVardan Mikayelyan * dwc2_gadget_incr_frame_num - Increments the targeted frame number. 11292d1635dSVardan Mikayelyan * @hs_ep: The endpoint 11392d1635dSVardan Mikayelyan * @increment: The value to increment by 11492d1635dSVardan Mikayelyan * 11592d1635dSVardan Mikayelyan * This function will also check if the frame number overruns DSTS_SOFFN_LIMIT. 11692d1635dSVardan Mikayelyan * If an overrun occurs it will wrap the value and set the frame_overrun flag. 11792d1635dSVardan Mikayelyan */ 11892d1635dSVardan Mikayelyan static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep) 11992d1635dSVardan Mikayelyan { 12092d1635dSVardan Mikayelyan hs_ep->target_frame += hs_ep->interval; 12192d1635dSVardan Mikayelyan if (hs_ep->target_frame > DSTS_SOFFN_LIMIT) { 12292d1635dSVardan Mikayelyan hs_ep->frame_overrun = 1; 12392d1635dSVardan Mikayelyan hs_ep->target_frame &= DSTS_SOFFN_LIMIT; 12492d1635dSVardan Mikayelyan } else { 12592d1635dSVardan Mikayelyan hs_ep->frame_overrun = 0; 12692d1635dSVardan Mikayelyan } 12792d1635dSVardan Mikayelyan } 12892d1635dSVardan Mikayelyan 12992d1635dSVardan Mikayelyan /** 1301f91b4ccSFelipe Balbi * dwc2_hsotg_en_gsint - enable one or more of the general interrupt 13147a1685fSDinh Nguyen * @hsotg: The device state 13247a1685fSDinh Nguyen * @ints: A bitmask of the interrupts to enable 13347a1685fSDinh Nguyen */ 1341f91b4ccSFelipe Balbi static void dwc2_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints) 13547a1685fSDinh Nguyen { 13695c8bc36SAntti Seppälä u32 gsintmsk = dwc2_readl(hsotg->regs + GINTMSK); 13747a1685fSDinh Nguyen u32 new_gsintmsk; 13847a1685fSDinh Nguyen 13947a1685fSDinh Nguyen new_gsintmsk = gsintmsk | ints; 14047a1685fSDinh Nguyen 14147a1685fSDinh Nguyen if (new_gsintmsk != gsintmsk) { 14247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); 14395c8bc36SAntti Seppälä dwc2_writel(new_gsintmsk, hsotg->regs + GINTMSK); 14447a1685fSDinh Nguyen } 14547a1685fSDinh Nguyen } 14647a1685fSDinh Nguyen 14747a1685fSDinh Nguyen /** 1481f91b4ccSFelipe Balbi * dwc2_hsotg_disable_gsint - disable one or more of the general interrupt 14947a1685fSDinh Nguyen * @hsotg: The device state 15047a1685fSDinh Nguyen * @ints: A bitmask of the interrupts to enable 15147a1685fSDinh Nguyen */ 1521f91b4ccSFelipe Balbi static void dwc2_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints) 15347a1685fSDinh Nguyen { 15495c8bc36SAntti Seppälä u32 gsintmsk = dwc2_readl(hsotg->regs + GINTMSK); 15547a1685fSDinh Nguyen u32 new_gsintmsk; 15647a1685fSDinh Nguyen 15747a1685fSDinh Nguyen new_gsintmsk = gsintmsk & ~ints; 15847a1685fSDinh Nguyen 15947a1685fSDinh Nguyen if (new_gsintmsk != gsintmsk) 16095c8bc36SAntti Seppälä dwc2_writel(new_gsintmsk, hsotg->regs + GINTMSK); 16147a1685fSDinh Nguyen } 16247a1685fSDinh Nguyen 16347a1685fSDinh Nguyen /** 1641f91b4ccSFelipe Balbi * dwc2_hsotg_ctrl_epint - enable/disable an endpoint irq 16547a1685fSDinh Nguyen * @hsotg: The device state 16647a1685fSDinh Nguyen * @ep: The endpoint index 16747a1685fSDinh Nguyen * @dir_in: True if direction is in. 16847a1685fSDinh Nguyen * @en: The enable value, true to enable 16947a1685fSDinh Nguyen * 17047a1685fSDinh Nguyen * Set or clear the mask for an individual endpoint's interrupt 17147a1685fSDinh Nguyen * request. 17247a1685fSDinh Nguyen */ 1731f91b4ccSFelipe Balbi static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, 17447a1685fSDinh Nguyen unsigned int ep, unsigned int dir_in, 17547a1685fSDinh Nguyen unsigned int en) 17647a1685fSDinh Nguyen { 17747a1685fSDinh Nguyen unsigned long flags; 17847a1685fSDinh Nguyen u32 bit = 1 << ep; 17947a1685fSDinh Nguyen u32 daint; 18047a1685fSDinh Nguyen 18147a1685fSDinh Nguyen if (!dir_in) 18247a1685fSDinh Nguyen bit <<= 16; 18347a1685fSDinh Nguyen 18447a1685fSDinh Nguyen local_irq_save(flags); 18595c8bc36SAntti Seppälä daint = dwc2_readl(hsotg->regs + DAINTMSK); 18647a1685fSDinh Nguyen if (en) 18747a1685fSDinh Nguyen daint |= bit; 18847a1685fSDinh Nguyen else 18947a1685fSDinh Nguyen daint &= ~bit; 19095c8bc36SAntti Seppälä dwc2_writel(daint, hsotg->regs + DAINTMSK); 19147a1685fSDinh Nguyen local_irq_restore(flags); 19247a1685fSDinh Nguyen } 19347a1685fSDinh Nguyen 19447a1685fSDinh Nguyen /** 1951f91b4ccSFelipe Balbi * dwc2_hsotg_init_fifo - initialise non-periodic FIFOs 19647a1685fSDinh Nguyen * @hsotg: The device instance. 19747a1685fSDinh Nguyen */ 1981f91b4ccSFelipe Balbi static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) 19947a1685fSDinh Nguyen { 2002317eacdSJohn Youn unsigned int ep; 20147a1685fSDinh Nguyen unsigned int addr; 20247a1685fSDinh Nguyen int timeout; 20347a1685fSDinh Nguyen u32 val; 20405ee799fSJohn Youn u32 *txfsz = hsotg->params.g_tx_fifo_size; 20547a1685fSDinh Nguyen 2067fcbc95cSGregory Herrero /* Reset fifo map if not correctly cleared during previous session */ 2077fcbc95cSGregory Herrero WARN_ON(hsotg->fifo_map); 2087fcbc95cSGregory Herrero hsotg->fifo_map = 0; 2097fcbc95cSGregory Herrero 2100a176279SGregory Herrero /* set RX/NPTX FIFO sizes */ 21105ee799fSJohn Youn dwc2_writel(hsotg->params.g_rx_fifo_size, hsotg->regs + GRXFSIZ); 21205ee799fSJohn Youn dwc2_writel((hsotg->params.g_rx_fifo_size << FIFOSIZE_STARTADDR_SHIFT) | 21305ee799fSJohn Youn (hsotg->params.g_np_tx_fifo_size << FIFOSIZE_DEPTH_SHIFT), 2140a176279SGregory Herrero hsotg->regs + GNPTXFSIZ); 21547a1685fSDinh Nguyen 21647a1685fSDinh Nguyen /* 21747a1685fSDinh Nguyen * arange all the rest of the TX FIFOs, as some versions of this 21847a1685fSDinh Nguyen * block have overlapping default addresses. This also ensures 21947a1685fSDinh Nguyen * that if the settings have been changed, then they are set to 22047a1685fSDinh Nguyen * known values. 22147a1685fSDinh Nguyen */ 22247a1685fSDinh Nguyen 22347a1685fSDinh Nguyen /* start at the end of the GNPTXFSIZ, rounded up */ 22405ee799fSJohn Youn addr = hsotg->params.g_rx_fifo_size + hsotg->params.g_np_tx_fifo_size; 22547a1685fSDinh Nguyen 22647a1685fSDinh Nguyen /* 2270a176279SGregory Herrero * Configure fifos sizes from provided configuration and assign 228b203d0a2SRobert Baldyga * them to endpoints dynamically according to maxpacket size value of 229b203d0a2SRobert Baldyga * given endpoint. 23047a1685fSDinh Nguyen */ 2312317eacdSJohn Youn for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) { 23205ee799fSJohn Youn if (!txfsz[ep]) 2333fa95385SJohn Youn continue; 2343fa95385SJohn Youn val = addr; 23505ee799fSJohn Youn val |= txfsz[ep] << FIFOSIZE_DEPTH_SHIFT; 23605ee799fSJohn Youn WARN_ONCE(addr + txfsz[ep] > hsotg->fifo_mem, 2373fa95385SJohn Youn "insufficient fifo memory"); 23805ee799fSJohn Youn addr += txfsz[ep]; 23947a1685fSDinh Nguyen 2402317eacdSJohn Youn dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep)); 24105ee799fSJohn Youn val = dwc2_readl(hsotg->regs + DPTXFSIZN(ep)); 24247a1685fSDinh Nguyen } 24347a1685fSDinh Nguyen 24447a1685fSDinh Nguyen /* 24547a1685fSDinh Nguyen * according to p428 of the design guide, we need to ensure that 24647a1685fSDinh Nguyen * all fifos are flushed before continuing 24747a1685fSDinh Nguyen */ 24847a1685fSDinh Nguyen 24995c8bc36SAntti Seppälä dwc2_writel(GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | 25047a1685fSDinh Nguyen GRSTCTL_RXFFLSH, hsotg->regs + GRSTCTL); 25147a1685fSDinh Nguyen 25247a1685fSDinh Nguyen /* wait until the fifos are both flushed */ 25347a1685fSDinh Nguyen timeout = 100; 25447a1685fSDinh Nguyen while (1) { 25595c8bc36SAntti Seppälä val = dwc2_readl(hsotg->regs + GRSTCTL); 25647a1685fSDinh Nguyen 25747a1685fSDinh Nguyen if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0) 25847a1685fSDinh Nguyen break; 25947a1685fSDinh Nguyen 26047a1685fSDinh Nguyen if (--timeout == 0) { 26147a1685fSDinh Nguyen dev_err(hsotg->dev, 26247a1685fSDinh Nguyen "%s: timeout flushing fifos (GRSTCTL=%08x)\n", 26347a1685fSDinh Nguyen __func__, val); 26448b20bcbSGregory Herrero break; 26547a1685fSDinh Nguyen } 26647a1685fSDinh Nguyen 26747a1685fSDinh Nguyen udelay(1); 26847a1685fSDinh Nguyen } 26947a1685fSDinh Nguyen 27047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); 27147a1685fSDinh Nguyen } 27247a1685fSDinh Nguyen 27347a1685fSDinh Nguyen /** 27447a1685fSDinh Nguyen * @ep: USB endpoint to allocate request for. 27547a1685fSDinh Nguyen * @flags: Allocation flags 27647a1685fSDinh Nguyen * 27747a1685fSDinh Nguyen * Allocate a new USB request structure appropriate for the specified endpoint 27847a1685fSDinh Nguyen */ 2791f91b4ccSFelipe Balbi static struct usb_request *dwc2_hsotg_ep_alloc_request(struct usb_ep *ep, 28047a1685fSDinh Nguyen gfp_t flags) 28147a1685fSDinh Nguyen { 2821f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req; 28347a1685fSDinh Nguyen 2841f91b4ccSFelipe Balbi req = kzalloc(sizeof(struct dwc2_hsotg_req), flags); 28547a1685fSDinh Nguyen if (!req) 28647a1685fSDinh Nguyen return NULL; 28747a1685fSDinh Nguyen 28847a1685fSDinh Nguyen INIT_LIST_HEAD(&req->queue); 28947a1685fSDinh Nguyen 29047a1685fSDinh Nguyen return &req->req; 29147a1685fSDinh Nguyen } 29247a1685fSDinh Nguyen 29347a1685fSDinh Nguyen /** 29447a1685fSDinh Nguyen * is_ep_periodic - return true if the endpoint is in periodic mode. 29547a1685fSDinh Nguyen * @hs_ep: The endpoint to query. 29647a1685fSDinh Nguyen * 29747a1685fSDinh Nguyen * Returns true if the endpoint is in periodic mode, meaning it is being 29847a1685fSDinh Nguyen * used for an Interrupt or ISO transfer. 29947a1685fSDinh Nguyen */ 3001f91b4ccSFelipe Balbi static inline int is_ep_periodic(struct dwc2_hsotg_ep *hs_ep) 30147a1685fSDinh Nguyen { 30247a1685fSDinh Nguyen return hs_ep->periodic; 30347a1685fSDinh Nguyen } 30447a1685fSDinh Nguyen 30547a1685fSDinh Nguyen /** 3061f91b4ccSFelipe Balbi * dwc2_hsotg_unmap_dma - unmap the DMA memory being used for the request 30747a1685fSDinh Nguyen * @hsotg: The device state. 30847a1685fSDinh Nguyen * @hs_ep: The endpoint for the request 30947a1685fSDinh Nguyen * @hs_req: The request being processed. 31047a1685fSDinh Nguyen * 3111f91b4ccSFelipe Balbi * This is the reverse of dwc2_hsotg_map_dma(), called for the completion 31247a1685fSDinh Nguyen * of a request to ensure the buffer is ready for access by the caller. 31347a1685fSDinh Nguyen */ 3141f91b4ccSFelipe Balbi static void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg, 3151f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 3161f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req) 31747a1685fSDinh Nguyen { 31847a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 3199da51974SJohn Youn 32047a1685fSDinh Nguyen usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); 32147a1685fSDinh Nguyen } 32247a1685fSDinh Nguyen 3230f6b80c0SVahram Aharonyan /* 3240f6b80c0SVahram Aharonyan * dwc2_gadget_alloc_ctrl_desc_chains - allocate DMA descriptor chains 3250f6b80c0SVahram Aharonyan * for Control endpoint 3260f6b80c0SVahram Aharonyan * @hsotg: The device state. 3270f6b80c0SVahram Aharonyan * 3280f6b80c0SVahram Aharonyan * This function will allocate 4 descriptor chains for EP 0: 2 for 3290f6b80c0SVahram Aharonyan * Setup stage, per one for IN and OUT data/status transactions. 3300f6b80c0SVahram Aharonyan */ 3310f6b80c0SVahram Aharonyan static int dwc2_gadget_alloc_ctrl_desc_chains(struct dwc2_hsotg *hsotg) 3320f6b80c0SVahram Aharonyan { 3330f6b80c0SVahram Aharonyan hsotg->setup_desc[0] = 3340f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 3350f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 3360f6b80c0SVahram Aharonyan &hsotg->setup_desc_dma[0], 3370f6b80c0SVahram Aharonyan GFP_KERNEL); 3380f6b80c0SVahram Aharonyan if (!hsotg->setup_desc[0]) 3390f6b80c0SVahram Aharonyan goto fail; 3400f6b80c0SVahram Aharonyan 3410f6b80c0SVahram Aharonyan hsotg->setup_desc[1] = 3420f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 3430f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 3440f6b80c0SVahram Aharonyan &hsotg->setup_desc_dma[1], 3450f6b80c0SVahram Aharonyan GFP_KERNEL); 3460f6b80c0SVahram Aharonyan if (!hsotg->setup_desc[1]) 3470f6b80c0SVahram Aharonyan goto fail; 3480f6b80c0SVahram Aharonyan 3490f6b80c0SVahram Aharonyan hsotg->ctrl_in_desc = 3500f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 3510f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 3520f6b80c0SVahram Aharonyan &hsotg->ctrl_in_desc_dma, 3530f6b80c0SVahram Aharonyan GFP_KERNEL); 3540f6b80c0SVahram Aharonyan if (!hsotg->ctrl_in_desc) 3550f6b80c0SVahram Aharonyan goto fail; 3560f6b80c0SVahram Aharonyan 3570f6b80c0SVahram Aharonyan hsotg->ctrl_out_desc = 3580f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 3590f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 3600f6b80c0SVahram Aharonyan &hsotg->ctrl_out_desc_dma, 3610f6b80c0SVahram Aharonyan GFP_KERNEL); 3620f6b80c0SVahram Aharonyan if (!hsotg->ctrl_out_desc) 3630f6b80c0SVahram Aharonyan goto fail; 3640f6b80c0SVahram Aharonyan 3650f6b80c0SVahram Aharonyan return 0; 3660f6b80c0SVahram Aharonyan 3670f6b80c0SVahram Aharonyan fail: 3680f6b80c0SVahram Aharonyan return -ENOMEM; 3690f6b80c0SVahram Aharonyan } 3700f6b80c0SVahram Aharonyan 37147a1685fSDinh Nguyen /** 3721f91b4ccSFelipe Balbi * dwc2_hsotg_write_fifo - write packet Data to the TxFIFO 37347a1685fSDinh Nguyen * @hsotg: The controller state. 37447a1685fSDinh Nguyen * @hs_ep: The endpoint we're going to write for. 37547a1685fSDinh Nguyen * @hs_req: The request to write data for. 37647a1685fSDinh Nguyen * 37747a1685fSDinh Nguyen * This is called when the TxFIFO has some space in it to hold a new 37847a1685fSDinh Nguyen * transmission and we have something to give it. The actual setup of 37947a1685fSDinh Nguyen * the data size is done elsewhere, so all we have to do is to actually 38047a1685fSDinh Nguyen * write the data. 38147a1685fSDinh Nguyen * 38247a1685fSDinh Nguyen * The return value is zero if there is more space (or nothing was done) 38347a1685fSDinh Nguyen * otherwise -ENOSPC is returned if the FIFO space was used up. 38447a1685fSDinh Nguyen * 38547a1685fSDinh Nguyen * This routine is only needed for PIO 38647a1685fSDinh Nguyen */ 3871f91b4ccSFelipe Balbi static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, 3881f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 3891f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req) 39047a1685fSDinh Nguyen { 39147a1685fSDinh Nguyen bool periodic = is_ep_periodic(hs_ep); 39295c8bc36SAntti Seppälä u32 gnptxsts = dwc2_readl(hsotg->regs + GNPTXSTS); 39347a1685fSDinh Nguyen int buf_pos = hs_req->req.actual; 39447a1685fSDinh Nguyen int to_write = hs_ep->size_loaded; 39547a1685fSDinh Nguyen void *data; 39647a1685fSDinh Nguyen int can_write; 39747a1685fSDinh Nguyen int pkt_round; 39847a1685fSDinh Nguyen int max_transfer; 39947a1685fSDinh Nguyen 40047a1685fSDinh Nguyen to_write -= (buf_pos - hs_ep->last_load); 40147a1685fSDinh Nguyen 40247a1685fSDinh Nguyen /* if there's nothing to write, get out early */ 40347a1685fSDinh Nguyen if (to_write == 0) 40447a1685fSDinh Nguyen return 0; 40547a1685fSDinh Nguyen 40647a1685fSDinh Nguyen if (periodic && !hsotg->dedicated_fifos) { 40795c8bc36SAntti Seppälä u32 epsize = dwc2_readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); 40847a1685fSDinh Nguyen int size_left; 40947a1685fSDinh Nguyen int size_done; 41047a1685fSDinh Nguyen 41147a1685fSDinh Nguyen /* 41247a1685fSDinh Nguyen * work out how much data was loaded so we can calculate 41347a1685fSDinh Nguyen * how much data is left in the fifo. 41447a1685fSDinh Nguyen */ 41547a1685fSDinh Nguyen 41647a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 41747a1685fSDinh Nguyen 41847a1685fSDinh Nguyen /* 41947a1685fSDinh Nguyen * if shared fifo, we cannot write anything until the 42047a1685fSDinh Nguyen * previous data has been completely sent. 42147a1685fSDinh Nguyen */ 42247a1685fSDinh Nguyen if (hs_ep->fifo_load != 0) { 4231f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 42447a1685fSDinh Nguyen return -ENOSPC; 42547a1685fSDinh Nguyen } 42647a1685fSDinh Nguyen 42747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", 42847a1685fSDinh Nguyen __func__, size_left, 42947a1685fSDinh Nguyen hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); 43047a1685fSDinh Nguyen 43147a1685fSDinh Nguyen /* how much of the data has moved */ 43247a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 43347a1685fSDinh Nguyen 43447a1685fSDinh Nguyen /* how much data is left in the fifo */ 43547a1685fSDinh Nguyen can_write = hs_ep->fifo_load - size_done; 43647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", 43747a1685fSDinh Nguyen __func__, can_write); 43847a1685fSDinh Nguyen 43947a1685fSDinh Nguyen can_write = hs_ep->fifo_size - can_write; 44047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", 44147a1685fSDinh Nguyen __func__, can_write); 44247a1685fSDinh Nguyen 44347a1685fSDinh Nguyen if (can_write <= 0) { 4441f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 44547a1685fSDinh Nguyen return -ENOSPC; 44647a1685fSDinh Nguyen } 44747a1685fSDinh Nguyen } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { 448ad674a15SRobert Baldyga can_write = dwc2_readl(hsotg->regs + 449ad674a15SRobert Baldyga DTXFSTS(hs_ep->fifo_index)); 45047a1685fSDinh Nguyen 45147a1685fSDinh Nguyen can_write &= 0xffff; 45247a1685fSDinh Nguyen can_write *= 4; 45347a1685fSDinh Nguyen } else { 45447a1685fSDinh Nguyen if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) { 45547a1685fSDinh Nguyen dev_dbg(hsotg->dev, 45647a1685fSDinh Nguyen "%s: no queue slots available (0x%08x)\n", 45747a1685fSDinh Nguyen __func__, gnptxsts); 45847a1685fSDinh Nguyen 4591f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP); 46047a1685fSDinh Nguyen return -ENOSPC; 46147a1685fSDinh Nguyen } 46247a1685fSDinh Nguyen 46347a1685fSDinh Nguyen can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts); 46447a1685fSDinh Nguyen can_write *= 4; /* fifo size is in 32bit quantities. */ 46547a1685fSDinh Nguyen } 46647a1685fSDinh Nguyen 46747a1685fSDinh Nguyen max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; 46847a1685fSDinh Nguyen 46947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", 47047a1685fSDinh Nguyen __func__, gnptxsts, can_write, to_write, max_transfer); 47147a1685fSDinh Nguyen 47247a1685fSDinh Nguyen /* 47347a1685fSDinh Nguyen * limit to 512 bytes of data, it seems at least on the non-periodic 47447a1685fSDinh Nguyen * FIFO, requests of >512 cause the endpoint to get stuck with a 47547a1685fSDinh Nguyen * fragment of the end of the transfer in it. 47647a1685fSDinh Nguyen */ 47747a1685fSDinh Nguyen if (can_write > 512 && !periodic) 47847a1685fSDinh Nguyen can_write = 512; 47947a1685fSDinh Nguyen 48047a1685fSDinh Nguyen /* 48147a1685fSDinh Nguyen * limit the write to one max-packet size worth of data, but allow 48247a1685fSDinh Nguyen * the transfer to return that it did not run out of fifo space 48347a1685fSDinh Nguyen * doing it. 48447a1685fSDinh Nguyen */ 48547a1685fSDinh Nguyen if (to_write > max_transfer) { 48647a1685fSDinh Nguyen to_write = max_transfer; 48747a1685fSDinh Nguyen 48847a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 48947a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 4901f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, 49147a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 49247a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 49347a1685fSDinh Nguyen } 49447a1685fSDinh Nguyen 49547a1685fSDinh Nguyen /* see if we can write data */ 49647a1685fSDinh Nguyen 49747a1685fSDinh Nguyen if (to_write > can_write) { 49847a1685fSDinh Nguyen to_write = can_write; 49947a1685fSDinh Nguyen pkt_round = to_write % max_transfer; 50047a1685fSDinh Nguyen 50147a1685fSDinh Nguyen /* 50247a1685fSDinh Nguyen * Round the write down to an 50347a1685fSDinh Nguyen * exact number of packets. 50447a1685fSDinh Nguyen * 50547a1685fSDinh Nguyen * Note, we do not currently check to see if we can ever 50647a1685fSDinh Nguyen * write a full packet or not to the FIFO. 50747a1685fSDinh Nguyen */ 50847a1685fSDinh Nguyen 50947a1685fSDinh Nguyen if (pkt_round) 51047a1685fSDinh Nguyen to_write -= pkt_round; 51147a1685fSDinh Nguyen 51247a1685fSDinh Nguyen /* 51347a1685fSDinh Nguyen * enable correct FIFO interrupt to alert us when there 51447a1685fSDinh Nguyen * is more room left. 51547a1685fSDinh Nguyen */ 51647a1685fSDinh Nguyen 51747a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 51847a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 5191f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, 52047a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 52147a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 52247a1685fSDinh Nguyen } 52347a1685fSDinh Nguyen 52447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", 52547a1685fSDinh Nguyen to_write, hs_req->req.length, can_write, buf_pos); 52647a1685fSDinh Nguyen 52747a1685fSDinh Nguyen if (to_write <= 0) 52847a1685fSDinh Nguyen return -ENOSPC; 52947a1685fSDinh Nguyen 53047a1685fSDinh Nguyen hs_req->req.actual = buf_pos + to_write; 53147a1685fSDinh Nguyen hs_ep->total_data += to_write; 53247a1685fSDinh Nguyen 53347a1685fSDinh Nguyen if (periodic) 53447a1685fSDinh Nguyen hs_ep->fifo_load += to_write; 53547a1685fSDinh Nguyen 53647a1685fSDinh Nguyen to_write = DIV_ROUND_UP(to_write, 4); 53747a1685fSDinh Nguyen data = hs_req->req.buf + buf_pos; 53847a1685fSDinh Nguyen 53947a1685fSDinh Nguyen iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); 54047a1685fSDinh Nguyen 54147a1685fSDinh Nguyen return (to_write >= can_write) ? -ENOSPC : 0; 54247a1685fSDinh Nguyen } 54347a1685fSDinh Nguyen 54447a1685fSDinh Nguyen /** 54547a1685fSDinh Nguyen * get_ep_limit - get the maximum data legnth for this endpoint 54647a1685fSDinh Nguyen * @hs_ep: The endpoint 54747a1685fSDinh Nguyen * 54847a1685fSDinh Nguyen * Return the maximum data that can be queued in one go on a given endpoint 54947a1685fSDinh Nguyen * so that transfers that are too long can be split. 55047a1685fSDinh Nguyen */ 5519da51974SJohn Youn static unsigned int get_ep_limit(struct dwc2_hsotg_ep *hs_ep) 55247a1685fSDinh Nguyen { 55347a1685fSDinh Nguyen int index = hs_ep->index; 5549da51974SJohn Youn unsigned int maxsize; 5559da51974SJohn Youn unsigned int maxpkt; 55647a1685fSDinh Nguyen 55747a1685fSDinh Nguyen if (index != 0) { 55847a1685fSDinh Nguyen maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; 55947a1685fSDinh Nguyen maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; 56047a1685fSDinh Nguyen } else { 56147a1685fSDinh Nguyen maxsize = 64 + 64; 56247a1685fSDinh Nguyen if (hs_ep->dir_in) 56347a1685fSDinh Nguyen maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; 56447a1685fSDinh Nguyen else 56547a1685fSDinh Nguyen maxpkt = 2; 56647a1685fSDinh Nguyen } 56747a1685fSDinh Nguyen 56847a1685fSDinh Nguyen /* we made the constant loading easier above by using +1 */ 56947a1685fSDinh Nguyen maxpkt--; 57047a1685fSDinh Nguyen maxsize--; 57147a1685fSDinh Nguyen 57247a1685fSDinh Nguyen /* 57347a1685fSDinh Nguyen * constrain by packet count if maxpkts*pktsize is greater 57447a1685fSDinh Nguyen * than the length register size. 57547a1685fSDinh Nguyen */ 57647a1685fSDinh Nguyen 57747a1685fSDinh Nguyen if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) 57847a1685fSDinh Nguyen maxsize = maxpkt * hs_ep->ep.maxpacket; 57947a1685fSDinh Nguyen 58047a1685fSDinh Nguyen return maxsize; 58147a1685fSDinh Nguyen } 58247a1685fSDinh Nguyen 58347a1685fSDinh Nguyen /** 584381fc8f8SVardan Mikayelyan * dwc2_hsotg_read_frameno - read current frame number 585381fc8f8SVardan Mikayelyan * @hsotg: The device instance 586381fc8f8SVardan Mikayelyan * 587381fc8f8SVardan Mikayelyan * Return the current frame number 588381fc8f8SVardan Mikayelyan */ 589381fc8f8SVardan Mikayelyan static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg) 590381fc8f8SVardan Mikayelyan { 591381fc8f8SVardan Mikayelyan u32 dsts; 592381fc8f8SVardan Mikayelyan 593381fc8f8SVardan Mikayelyan dsts = dwc2_readl(hsotg->regs + DSTS); 594381fc8f8SVardan Mikayelyan dsts &= DSTS_SOFFN_MASK; 595381fc8f8SVardan Mikayelyan dsts >>= DSTS_SOFFN_SHIFT; 596381fc8f8SVardan Mikayelyan 597381fc8f8SVardan Mikayelyan return dsts; 598381fc8f8SVardan Mikayelyan } 599381fc8f8SVardan Mikayelyan 600381fc8f8SVardan Mikayelyan /** 601cf77b5fbSVahram Aharonyan * dwc2_gadget_get_chain_limit - get the maximum data payload value of the 602cf77b5fbSVahram Aharonyan * DMA descriptor chain prepared for specific endpoint 603cf77b5fbSVahram Aharonyan * @hs_ep: The endpoint 604cf77b5fbSVahram Aharonyan * 605cf77b5fbSVahram Aharonyan * Return the maximum data that can be queued in one go on a given endpoint 606cf77b5fbSVahram Aharonyan * depending on its descriptor chain capacity so that transfers that 607cf77b5fbSVahram Aharonyan * are too long can be split. 608cf77b5fbSVahram Aharonyan */ 609cf77b5fbSVahram Aharonyan static unsigned int dwc2_gadget_get_chain_limit(struct dwc2_hsotg_ep *hs_ep) 610cf77b5fbSVahram Aharonyan { 611cf77b5fbSVahram Aharonyan int is_isoc = hs_ep->isochronous; 612cf77b5fbSVahram Aharonyan unsigned int maxsize; 613cf77b5fbSVahram Aharonyan 614cf77b5fbSVahram Aharonyan if (is_isoc) 615cf77b5fbSVahram Aharonyan maxsize = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_LIMIT : 616cf77b5fbSVahram Aharonyan DEV_DMA_ISOC_RX_NBYTES_LIMIT; 617cf77b5fbSVahram Aharonyan else 618cf77b5fbSVahram Aharonyan maxsize = DEV_DMA_NBYTES_LIMIT; 619cf77b5fbSVahram Aharonyan 620cf77b5fbSVahram Aharonyan /* Above size of one descriptor was chosen, multiple it */ 621cf77b5fbSVahram Aharonyan maxsize *= MAX_DMA_DESC_NUM_GENERIC; 622cf77b5fbSVahram Aharonyan 623cf77b5fbSVahram Aharonyan return maxsize; 624cf77b5fbSVahram Aharonyan } 625cf77b5fbSVahram Aharonyan 626e02f9aa6SVahram Aharonyan /* 627e02f9aa6SVahram Aharonyan * dwc2_gadget_get_desc_params - get DMA descriptor parameters. 628e02f9aa6SVahram Aharonyan * @hs_ep: The endpoint 629e02f9aa6SVahram Aharonyan * @mask: RX/TX bytes mask to be defined 630e02f9aa6SVahram Aharonyan * 631e02f9aa6SVahram Aharonyan * Returns maximum data payload for one descriptor after analyzing endpoint 632e02f9aa6SVahram Aharonyan * characteristics. 633e02f9aa6SVahram Aharonyan * DMA descriptor transfer bytes limit depends on EP type: 634e02f9aa6SVahram Aharonyan * Control out - MPS, 635e02f9aa6SVahram Aharonyan * Isochronous - descriptor rx/tx bytes bitfield limit, 636e02f9aa6SVahram Aharonyan * Control In/Bulk/Interrupt - multiple of mps. This will allow to not 637e02f9aa6SVahram Aharonyan * have concatenations from various descriptors within one packet. 638e02f9aa6SVahram Aharonyan * 639e02f9aa6SVahram Aharonyan * Selects corresponding mask for RX/TX bytes as well. 640e02f9aa6SVahram Aharonyan */ 641e02f9aa6SVahram Aharonyan static u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask) 642e02f9aa6SVahram Aharonyan { 643e02f9aa6SVahram Aharonyan u32 mps = hs_ep->ep.maxpacket; 644e02f9aa6SVahram Aharonyan int dir_in = hs_ep->dir_in; 645e02f9aa6SVahram Aharonyan u32 desc_size = 0; 646e02f9aa6SVahram Aharonyan 647e02f9aa6SVahram Aharonyan if (!hs_ep->index && !dir_in) { 648e02f9aa6SVahram Aharonyan desc_size = mps; 649e02f9aa6SVahram Aharonyan *mask = DEV_DMA_NBYTES_MASK; 650e02f9aa6SVahram Aharonyan } else if (hs_ep->isochronous) { 651e02f9aa6SVahram Aharonyan if (dir_in) { 652e02f9aa6SVahram Aharonyan desc_size = DEV_DMA_ISOC_TX_NBYTES_LIMIT; 653e02f9aa6SVahram Aharonyan *mask = DEV_DMA_ISOC_TX_NBYTES_MASK; 654e02f9aa6SVahram Aharonyan } else { 655e02f9aa6SVahram Aharonyan desc_size = DEV_DMA_ISOC_RX_NBYTES_LIMIT; 656e02f9aa6SVahram Aharonyan *mask = DEV_DMA_ISOC_RX_NBYTES_MASK; 657e02f9aa6SVahram Aharonyan } 658e02f9aa6SVahram Aharonyan } else { 659e02f9aa6SVahram Aharonyan desc_size = DEV_DMA_NBYTES_LIMIT; 660e02f9aa6SVahram Aharonyan *mask = DEV_DMA_NBYTES_MASK; 661e02f9aa6SVahram Aharonyan 662e02f9aa6SVahram Aharonyan /* Round down desc_size to be mps multiple */ 663e02f9aa6SVahram Aharonyan desc_size -= desc_size % mps; 664e02f9aa6SVahram Aharonyan } 665e02f9aa6SVahram Aharonyan 666e02f9aa6SVahram Aharonyan return desc_size; 667e02f9aa6SVahram Aharonyan } 668e02f9aa6SVahram Aharonyan 669e02f9aa6SVahram Aharonyan /* 670e02f9aa6SVahram Aharonyan * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. 671e02f9aa6SVahram Aharonyan * @hs_ep: The endpoint 672e02f9aa6SVahram Aharonyan * @dma_buff: DMA address to use 673e02f9aa6SVahram Aharonyan * @len: Length of the transfer 674e02f9aa6SVahram Aharonyan * 675e02f9aa6SVahram Aharonyan * This function will iterate over descriptor chain and fill its entries 676e02f9aa6SVahram Aharonyan * with corresponding information based on transfer data. 677e02f9aa6SVahram Aharonyan */ 678e02f9aa6SVahram Aharonyan static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, 679e02f9aa6SVahram Aharonyan dma_addr_t dma_buff, 680e02f9aa6SVahram Aharonyan unsigned int len) 681e02f9aa6SVahram Aharonyan { 682e02f9aa6SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 683e02f9aa6SVahram Aharonyan int dir_in = hs_ep->dir_in; 684e02f9aa6SVahram Aharonyan struct dwc2_dma_desc *desc = hs_ep->desc_list; 685e02f9aa6SVahram Aharonyan u32 mps = hs_ep->ep.maxpacket; 686e02f9aa6SVahram Aharonyan u32 maxsize = 0; 687e02f9aa6SVahram Aharonyan u32 offset = 0; 688e02f9aa6SVahram Aharonyan u32 mask = 0; 689e02f9aa6SVahram Aharonyan int i; 690e02f9aa6SVahram Aharonyan 691e02f9aa6SVahram Aharonyan maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); 692e02f9aa6SVahram Aharonyan 693e02f9aa6SVahram Aharonyan hs_ep->desc_count = (len / maxsize) + 694e02f9aa6SVahram Aharonyan ((len % maxsize) ? 1 : 0); 695e02f9aa6SVahram Aharonyan if (len == 0) 696e02f9aa6SVahram Aharonyan hs_ep->desc_count = 1; 697e02f9aa6SVahram Aharonyan 698e02f9aa6SVahram Aharonyan for (i = 0; i < hs_ep->desc_count; ++i) { 699e02f9aa6SVahram Aharonyan desc->status = 0; 700e02f9aa6SVahram Aharonyan desc->status |= (DEV_DMA_BUFF_STS_HBUSY 701e02f9aa6SVahram Aharonyan << DEV_DMA_BUFF_STS_SHIFT); 702e02f9aa6SVahram Aharonyan 703e02f9aa6SVahram Aharonyan if (len > maxsize) { 704e02f9aa6SVahram Aharonyan if (!hs_ep->index && !dir_in) 705e02f9aa6SVahram Aharonyan desc->status |= (DEV_DMA_L | DEV_DMA_IOC); 706e02f9aa6SVahram Aharonyan 707e02f9aa6SVahram Aharonyan desc->status |= (maxsize << 708e02f9aa6SVahram Aharonyan DEV_DMA_NBYTES_SHIFT & mask); 709e02f9aa6SVahram Aharonyan desc->buf = dma_buff + offset; 710e02f9aa6SVahram Aharonyan 711e02f9aa6SVahram Aharonyan len -= maxsize; 712e02f9aa6SVahram Aharonyan offset += maxsize; 713e02f9aa6SVahram Aharonyan } else { 714e02f9aa6SVahram Aharonyan desc->status |= (DEV_DMA_L | DEV_DMA_IOC); 715e02f9aa6SVahram Aharonyan 716e02f9aa6SVahram Aharonyan if (dir_in) 717e02f9aa6SVahram Aharonyan desc->status |= (len % mps) ? DEV_DMA_SHORT : 718e02f9aa6SVahram Aharonyan ((hs_ep->send_zlp) ? DEV_DMA_SHORT : 0); 719e02f9aa6SVahram Aharonyan if (len > maxsize) 720e02f9aa6SVahram Aharonyan dev_err(hsotg->dev, "wrong len %d\n", len); 721e02f9aa6SVahram Aharonyan 722e02f9aa6SVahram Aharonyan desc->status |= 723e02f9aa6SVahram Aharonyan len << DEV_DMA_NBYTES_SHIFT & mask; 724e02f9aa6SVahram Aharonyan desc->buf = dma_buff + offset; 725e02f9aa6SVahram Aharonyan } 726e02f9aa6SVahram Aharonyan 727e02f9aa6SVahram Aharonyan desc->status &= ~DEV_DMA_BUFF_STS_MASK; 728e02f9aa6SVahram Aharonyan desc->status |= (DEV_DMA_BUFF_STS_HREADY 729e02f9aa6SVahram Aharonyan << DEV_DMA_BUFF_STS_SHIFT); 730e02f9aa6SVahram Aharonyan desc++; 731e02f9aa6SVahram Aharonyan } 732e02f9aa6SVahram Aharonyan } 733e02f9aa6SVahram Aharonyan 734540ccba0SVahram Aharonyan /* 735540ccba0SVahram Aharonyan * dwc2_gadget_fill_isoc_desc - fills next isochronous descriptor in chain. 736540ccba0SVahram Aharonyan * @hs_ep: The isochronous endpoint. 737540ccba0SVahram Aharonyan * @dma_buff: usb requests dma buffer. 738540ccba0SVahram Aharonyan * @len: usb request transfer length. 739540ccba0SVahram Aharonyan * 740540ccba0SVahram Aharonyan * Finds out index of first free entry either in the bottom or up half of 741540ccba0SVahram Aharonyan * descriptor chain depend on which is under SW control and not processed 742540ccba0SVahram Aharonyan * by HW. Then fills that descriptor with the data of the arrived usb request, 743540ccba0SVahram Aharonyan * frame info, sets Last and IOC bits increments next_desc. If filled 744540ccba0SVahram Aharonyan * descriptor is not the first one, removes L bit from the previous descriptor 745540ccba0SVahram Aharonyan * status. 746540ccba0SVahram Aharonyan */ 747540ccba0SVahram Aharonyan static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, 748540ccba0SVahram Aharonyan dma_addr_t dma_buff, unsigned int len) 749540ccba0SVahram Aharonyan { 750540ccba0SVahram Aharonyan struct dwc2_dma_desc *desc; 751540ccba0SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 752540ccba0SVahram Aharonyan u32 index; 753540ccba0SVahram Aharonyan u32 maxsize = 0; 754540ccba0SVahram Aharonyan u32 mask = 0; 755540ccba0SVahram Aharonyan 756540ccba0SVahram Aharonyan maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); 757540ccba0SVahram Aharonyan if (len > maxsize) { 758540ccba0SVahram Aharonyan dev_err(hsotg->dev, "wrong len %d\n", len); 759540ccba0SVahram Aharonyan return -EINVAL; 760540ccba0SVahram Aharonyan } 761540ccba0SVahram Aharonyan 762540ccba0SVahram Aharonyan /* 763540ccba0SVahram Aharonyan * If SW has already filled half of chain, then return and wait for 764540ccba0SVahram Aharonyan * the other chain to be processed by HW. 765540ccba0SVahram Aharonyan */ 766540ccba0SVahram Aharonyan if (hs_ep->next_desc == MAX_DMA_DESC_NUM_GENERIC / 2) 767540ccba0SVahram Aharonyan return -EBUSY; 768540ccba0SVahram Aharonyan 769540ccba0SVahram Aharonyan /* Increment frame number by interval for IN */ 770540ccba0SVahram Aharonyan if (hs_ep->dir_in) 771540ccba0SVahram Aharonyan dwc2_gadget_incr_frame_num(hs_ep); 772540ccba0SVahram Aharonyan 773540ccba0SVahram Aharonyan index = (MAX_DMA_DESC_NUM_GENERIC / 2) * hs_ep->isoc_chain_num + 774540ccba0SVahram Aharonyan hs_ep->next_desc; 775540ccba0SVahram Aharonyan 776540ccba0SVahram Aharonyan /* Sanity check of calculated index */ 777540ccba0SVahram Aharonyan if ((hs_ep->isoc_chain_num && index > MAX_DMA_DESC_NUM_GENERIC) || 778540ccba0SVahram Aharonyan (!hs_ep->isoc_chain_num && index > MAX_DMA_DESC_NUM_GENERIC / 2)) { 779540ccba0SVahram Aharonyan dev_err(hsotg->dev, "wrong index %d for iso chain\n", index); 780540ccba0SVahram Aharonyan return -EINVAL; 781540ccba0SVahram Aharonyan } 782540ccba0SVahram Aharonyan 783540ccba0SVahram Aharonyan desc = &hs_ep->desc_list[index]; 784540ccba0SVahram Aharonyan 785540ccba0SVahram Aharonyan /* Clear L bit of previous desc if more than one entries in the chain */ 786540ccba0SVahram Aharonyan if (hs_ep->next_desc) 787540ccba0SVahram Aharonyan hs_ep->desc_list[index - 1].status &= ~DEV_DMA_L; 788540ccba0SVahram Aharonyan 789540ccba0SVahram Aharonyan dev_dbg(hsotg->dev, "%s: Filling ep %d, dir %s isoc desc # %d\n", 790540ccba0SVahram Aharonyan __func__, hs_ep->index, hs_ep->dir_in ? "in" : "out", index); 791540ccba0SVahram Aharonyan 792540ccba0SVahram Aharonyan desc->status = 0; 793540ccba0SVahram Aharonyan desc->status |= (DEV_DMA_BUFF_STS_HBUSY << DEV_DMA_BUFF_STS_SHIFT); 794540ccba0SVahram Aharonyan 795540ccba0SVahram Aharonyan desc->buf = dma_buff; 796540ccba0SVahram Aharonyan desc->status |= (DEV_DMA_L | DEV_DMA_IOC | 797540ccba0SVahram Aharonyan ((len << DEV_DMA_NBYTES_SHIFT) & mask)); 798540ccba0SVahram Aharonyan 799540ccba0SVahram Aharonyan if (hs_ep->dir_in) { 800540ccba0SVahram Aharonyan desc->status |= ((hs_ep->mc << DEV_DMA_ISOC_PID_SHIFT) & 801540ccba0SVahram Aharonyan DEV_DMA_ISOC_PID_MASK) | 802540ccba0SVahram Aharonyan ((len % hs_ep->ep.maxpacket) ? 803540ccba0SVahram Aharonyan DEV_DMA_SHORT : 0) | 804540ccba0SVahram Aharonyan ((hs_ep->target_frame << 805540ccba0SVahram Aharonyan DEV_DMA_ISOC_FRNUM_SHIFT) & 806540ccba0SVahram Aharonyan DEV_DMA_ISOC_FRNUM_MASK); 807540ccba0SVahram Aharonyan } 808540ccba0SVahram Aharonyan 809540ccba0SVahram Aharonyan desc->status &= ~DEV_DMA_BUFF_STS_MASK; 810540ccba0SVahram Aharonyan desc->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT); 811540ccba0SVahram Aharonyan 812540ccba0SVahram Aharonyan /* Update index of last configured entry in the chain */ 813540ccba0SVahram Aharonyan hs_ep->next_desc++; 814540ccba0SVahram Aharonyan 815540ccba0SVahram Aharonyan return 0; 816540ccba0SVahram Aharonyan } 817540ccba0SVahram Aharonyan 818540ccba0SVahram Aharonyan /* 819540ccba0SVahram Aharonyan * dwc2_gadget_start_isoc_ddma - start isochronous transfer in DDMA 820540ccba0SVahram Aharonyan * @hs_ep: The isochronous endpoint. 821540ccba0SVahram Aharonyan * 822540ccba0SVahram Aharonyan * Prepare first descriptor chain for isochronous endpoints. Afterwards 823540ccba0SVahram Aharonyan * write DMA address to HW and enable the endpoint. 824540ccba0SVahram Aharonyan * 825540ccba0SVahram Aharonyan * Switch between descriptor chains via isoc_chain_num to give SW opportunity 826540ccba0SVahram Aharonyan * to prepare second descriptor chain while first one is being processed by HW. 827540ccba0SVahram Aharonyan */ 828540ccba0SVahram Aharonyan static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) 829540ccba0SVahram Aharonyan { 830540ccba0SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 831540ccba0SVahram Aharonyan struct dwc2_hsotg_req *hs_req, *treq; 832540ccba0SVahram Aharonyan int index = hs_ep->index; 833540ccba0SVahram Aharonyan int ret; 834540ccba0SVahram Aharonyan u32 dma_reg; 835540ccba0SVahram Aharonyan u32 depctl; 836540ccba0SVahram Aharonyan u32 ctrl; 837540ccba0SVahram Aharonyan 838540ccba0SVahram Aharonyan if (list_empty(&hs_ep->queue)) { 839540ccba0SVahram Aharonyan dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__); 840540ccba0SVahram Aharonyan return; 841540ccba0SVahram Aharonyan } 842540ccba0SVahram Aharonyan 843540ccba0SVahram Aharonyan list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) { 844540ccba0SVahram Aharonyan ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, 845540ccba0SVahram Aharonyan hs_req->req.length); 846540ccba0SVahram Aharonyan if (ret) { 847540ccba0SVahram Aharonyan dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__); 848540ccba0SVahram Aharonyan break; 849540ccba0SVahram Aharonyan } 850540ccba0SVahram Aharonyan } 851540ccba0SVahram Aharonyan 852540ccba0SVahram Aharonyan depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 853540ccba0SVahram Aharonyan dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index); 854540ccba0SVahram Aharonyan 855540ccba0SVahram Aharonyan /* write descriptor chain address to control register */ 856540ccba0SVahram Aharonyan dwc2_writel(hs_ep->desc_list_dma, hsotg->regs + dma_reg); 857540ccba0SVahram Aharonyan 858540ccba0SVahram Aharonyan ctrl = dwc2_readl(hsotg->regs + depctl); 859540ccba0SVahram Aharonyan ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK; 860540ccba0SVahram Aharonyan dwc2_writel(ctrl, hsotg->regs + depctl); 861540ccba0SVahram Aharonyan 862540ccba0SVahram Aharonyan /* Switch ISOC descriptor chain number being processed by SW*/ 863540ccba0SVahram Aharonyan hs_ep->isoc_chain_num = (hs_ep->isoc_chain_num ^ 1) & 0x1; 864540ccba0SVahram Aharonyan hs_ep->next_desc = 0; 865540ccba0SVahram Aharonyan } 866540ccba0SVahram Aharonyan 867cf77b5fbSVahram Aharonyan /** 8681f91b4ccSFelipe Balbi * dwc2_hsotg_start_req - start a USB request from an endpoint's queue 86947a1685fSDinh Nguyen * @hsotg: The controller state. 87047a1685fSDinh Nguyen * @hs_ep: The endpoint to process a request for 87147a1685fSDinh Nguyen * @hs_req: The request to start. 87247a1685fSDinh Nguyen * @continuing: True if we are doing more for the current request. 87347a1685fSDinh Nguyen * 87447a1685fSDinh Nguyen * Start the given request running by setting the endpoint registers 87547a1685fSDinh Nguyen * appropriately, and writing any data to the FIFOs. 87647a1685fSDinh Nguyen */ 8771f91b4ccSFelipe Balbi static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, 8781f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 8791f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req, 88047a1685fSDinh Nguyen bool continuing) 88147a1685fSDinh Nguyen { 88247a1685fSDinh Nguyen struct usb_request *ureq = &hs_req->req; 88347a1685fSDinh Nguyen int index = hs_ep->index; 88447a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 88547a1685fSDinh Nguyen u32 epctrl_reg; 88647a1685fSDinh Nguyen u32 epsize_reg; 88747a1685fSDinh Nguyen u32 epsize; 88847a1685fSDinh Nguyen u32 ctrl; 8899da51974SJohn Youn unsigned int length; 8909da51974SJohn Youn unsigned int packets; 8919da51974SJohn Youn unsigned int maxreq; 892aa3e8bc8SVahram Aharonyan unsigned int dma_reg; 89347a1685fSDinh Nguyen 89447a1685fSDinh Nguyen if (index != 0) { 89547a1685fSDinh Nguyen if (hs_ep->req && !continuing) { 89647a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: active request\n", __func__); 89747a1685fSDinh Nguyen WARN_ON(1); 89847a1685fSDinh Nguyen return; 89947a1685fSDinh Nguyen } else if (hs_ep->req != hs_req && continuing) { 90047a1685fSDinh Nguyen dev_err(hsotg->dev, 90147a1685fSDinh Nguyen "%s: continue different req\n", __func__); 90247a1685fSDinh Nguyen WARN_ON(1); 90347a1685fSDinh Nguyen return; 90447a1685fSDinh Nguyen } 90547a1685fSDinh Nguyen } 90647a1685fSDinh Nguyen 907aa3e8bc8SVahram Aharonyan dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); 90847a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 90947a1685fSDinh Nguyen epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 91047a1685fSDinh Nguyen 91147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", 91295c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctrl_reg), index, 91347a1685fSDinh Nguyen hs_ep->dir_in ? "in" : "out"); 91447a1685fSDinh Nguyen 91547a1685fSDinh Nguyen /* If endpoint is stalled, we will restart request later */ 91695c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctrl_reg); 91747a1685fSDinh Nguyen 918b2d4c54eSMian Yousaf Kaukab if (index && ctrl & DXEPCTL_STALL) { 91947a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); 92047a1685fSDinh Nguyen return; 92147a1685fSDinh Nguyen } 92247a1685fSDinh Nguyen 92347a1685fSDinh Nguyen length = ureq->length - ureq->actual; 92447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", 92547a1685fSDinh Nguyen ureq->length, ureq->actual); 92647a1685fSDinh Nguyen 927cf77b5fbSVahram Aharonyan if (!using_desc_dma(hsotg)) 92847a1685fSDinh Nguyen maxreq = get_ep_limit(hs_ep); 929cf77b5fbSVahram Aharonyan else 930cf77b5fbSVahram Aharonyan maxreq = dwc2_gadget_get_chain_limit(hs_ep); 931cf77b5fbSVahram Aharonyan 93247a1685fSDinh Nguyen if (length > maxreq) { 93347a1685fSDinh Nguyen int round = maxreq % hs_ep->ep.maxpacket; 93447a1685fSDinh Nguyen 93547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", 93647a1685fSDinh Nguyen __func__, length, maxreq, round); 93747a1685fSDinh Nguyen 93847a1685fSDinh Nguyen /* round down to multiple of packets */ 93947a1685fSDinh Nguyen if (round) 94047a1685fSDinh Nguyen maxreq -= round; 94147a1685fSDinh Nguyen 94247a1685fSDinh Nguyen length = maxreq; 94347a1685fSDinh Nguyen } 94447a1685fSDinh Nguyen 94547a1685fSDinh Nguyen if (length) 94647a1685fSDinh Nguyen packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); 94747a1685fSDinh Nguyen else 94847a1685fSDinh Nguyen packets = 1; /* send one packet if length is zero. */ 94947a1685fSDinh Nguyen 95047a1685fSDinh Nguyen if (hs_ep->isochronous && length > (hs_ep->mc * hs_ep->ep.maxpacket)) { 95147a1685fSDinh Nguyen dev_err(hsotg->dev, "req length > maxpacket*mc\n"); 95247a1685fSDinh Nguyen return; 95347a1685fSDinh Nguyen } 95447a1685fSDinh Nguyen 95547a1685fSDinh Nguyen if (dir_in && index != 0) 95647a1685fSDinh Nguyen if (hs_ep->isochronous) 95747a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(packets); 95847a1685fSDinh Nguyen else 95947a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(1); 96047a1685fSDinh Nguyen else 96147a1685fSDinh Nguyen epsize = 0; 96247a1685fSDinh Nguyen 96347a1685fSDinh Nguyen /* 964f71b5e25SMian Yousaf Kaukab * zero length packet should be programmed on its own and should not 965f71b5e25SMian Yousaf Kaukab * be counted in DIEPTSIZ.PktCnt with other packets. 96647a1685fSDinh Nguyen */ 967f71b5e25SMian Yousaf Kaukab if (dir_in && ureq->zero && !continuing) { 968f71b5e25SMian Yousaf Kaukab /* Test if zlp is actually required. */ 969f71b5e25SMian Yousaf Kaukab if ((ureq->length >= hs_ep->ep.maxpacket) && 970f71b5e25SMian Yousaf Kaukab !(ureq->length % hs_ep->ep.maxpacket)) 9718a20fa45SMian Yousaf Kaukab hs_ep->send_zlp = 1; 97247a1685fSDinh Nguyen } 97347a1685fSDinh Nguyen 97447a1685fSDinh Nguyen epsize |= DXEPTSIZ_PKTCNT(packets); 97547a1685fSDinh Nguyen epsize |= DXEPTSIZ_XFERSIZE(length); 97647a1685fSDinh Nguyen 97747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", 97847a1685fSDinh Nguyen __func__, packets, length, ureq->length, epsize, epsize_reg); 97947a1685fSDinh Nguyen 98047a1685fSDinh Nguyen /* store the request as the current one we're doing */ 98147a1685fSDinh Nguyen hs_ep->req = hs_req; 98247a1685fSDinh Nguyen 983aa3e8bc8SVahram Aharonyan if (using_desc_dma(hsotg)) { 984aa3e8bc8SVahram Aharonyan u32 offset = 0; 985aa3e8bc8SVahram Aharonyan u32 mps = hs_ep->ep.maxpacket; 986aa3e8bc8SVahram Aharonyan 987aa3e8bc8SVahram Aharonyan /* Adjust length: EP0 - MPS, other OUT EPs - multiple of MPS */ 988aa3e8bc8SVahram Aharonyan if (!dir_in) { 989aa3e8bc8SVahram Aharonyan if (!index) 990aa3e8bc8SVahram Aharonyan length = mps; 991aa3e8bc8SVahram Aharonyan else if (length % mps) 992aa3e8bc8SVahram Aharonyan length += (mps - (length % mps)); 993aa3e8bc8SVahram Aharonyan } 994aa3e8bc8SVahram Aharonyan 995aa3e8bc8SVahram Aharonyan /* 996aa3e8bc8SVahram Aharonyan * If more data to send, adjust DMA for EP0 out data stage. 997aa3e8bc8SVahram Aharonyan * ureq->dma stays unchanged, hence increment it by already 998aa3e8bc8SVahram Aharonyan * passed passed data count before starting new transaction. 999aa3e8bc8SVahram Aharonyan */ 1000aa3e8bc8SVahram Aharonyan if (!index && hsotg->ep0_state == DWC2_EP0_DATA_OUT && 1001aa3e8bc8SVahram Aharonyan continuing) 1002aa3e8bc8SVahram Aharonyan offset = ureq->actual; 1003aa3e8bc8SVahram Aharonyan 1004aa3e8bc8SVahram Aharonyan /* Fill DDMA chain entries */ 1005aa3e8bc8SVahram Aharonyan dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq->dma + offset, 1006aa3e8bc8SVahram Aharonyan length); 1007aa3e8bc8SVahram Aharonyan 1008aa3e8bc8SVahram Aharonyan /* write descriptor chain address to control register */ 1009aa3e8bc8SVahram Aharonyan dwc2_writel(hs_ep->desc_list_dma, hsotg->regs + dma_reg); 1010aa3e8bc8SVahram Aharonyan 1011aa3e8bc8SVahram Aharonyan dev_dbg(hsotg->dev, "%s: %08x pad => 0x%08x\n", 1012aa3e8bc8SVahram Aharonyan __func__, (u32)hs_ep->desc_list_dma, dma_reg); 1013aa3e8bc8SVahram Aharonyan } else { 101447a1685fSDinh Nguyen /* write size / packets */ 101595c8bc36SAntti Seppälä dwc2_writel(epsize, hsotg->regs + epsize_reg); 101647a1685fSDinh Nguyen 1017729e6574SRazmik Karapetyan if (using_dma(hsotg) && !continuing && (length != 0)) { 101847a1685fSDinh Nguyen /* 1019aa3e8bc8SVahram Aharonyan * write DMA address to control register, buffer 1020aa3e8bc8SVahram Aharonyan * already synced by dwc2_hsotg_ep_queue(). 102147a1685fSDinh Nguyen */ 102247a1685fSDinh Nguyen 102395c8bc36SAntti Seppälä dwc2_writel(ureq->dma, hsotg->regs + dma_reg); 102447a1685fSDinh Nguyen 10250cc4cf6fSFabio Estevam dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n", 102647a1685fSDinh Nguyen __func__, &ureq->dma, dma_reg); 102747a1685fSDinh Nguyen } 1028aa3e8bc8SVahram Aharonyan } 102947a1685fSDinh Nguyen 1030837e9f00SVardan Mikayelyan if (hs_ep->isochronous && hs_ep->interval == 1) { 1031837e9f00SVardan Mikayelyan hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg); 1032837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 1033837e9f00SVardan Mikayelyan 1034837e9f00SVardan Mikayelyan if (hs_ep->target_frame & 0x1) 1035837e9f00SVardan Mikayelyan ctrl |= DXEPCTL_SETODDFR; 1036837e9f00SVardan Mikayelyan else 1037837e9f00SVardan Mikayelyan ctrl |= DXEPCTL_SETEVENFR; 1038837e9f00SVardan Mikayelyan } 1039837e9f00SVardan Mikayelyan 104047a1685fSDinh Nguyen ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 104147a1685fSDinh Nguyen 1042fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state); 104347a1685fSDinh Nguyen 104447a1685fSDinh Nguyen /* For Setup request do not clear NAK */ 1045fe0b94abSMian Yousaf Kaukab if (!(index == 0 && hsotg->ep0_state == DWC2_EP0_SETUP)) 104647a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 104747a1685fSDinh Nguyen 104847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 104995c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + epctrl_reg); 105047a1685fSDinh Nguyen 105147a1685fSDinh Nguyen /* 105247a1685fSDinh Nguyen * set these, it seems that DMA support increments past the end 105347a1685fSDinh Nguyen * of the packet buffer so we need to calculate the length from 105447a1685fSDinh Nguyen * this information. 105547a1685fSDinh Nguyen */ 105647a1685fSDinh Nguyen hs_ep->size_loaded = length; 105747a1685fSDinh Nguyen hs_ep->last_load = ureq->actual; 105847a1685fSDinh Nguyen 105947a1685fSDinh Nguyen if (dir_in && !using_dma(hsotg)) { 106047a1685fSDinh Nguyen /* set these anyway, we may need them for non-periodic in */ 106147a1685fSDinh Nguyen hs_ep->fifo_load = 0; 106247a1685fSDinh Nguyen 10631f91b4ccSFelipe Balbi dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 106447a1685fSDinh Nguyen } 106547a1685fSDinh Nguyen 106647a1685fSDinh Nguyen /* 106747a1685fSDinh Nguyen * Note, trying to clear the NAK here causes problems with transmit 106847a1685fSDinh Nguyen * on the S3C6400 ending up with the TXFIFO becoming full. 106947a1685fSDinh Nguyen */ 107047a1685fSDinh Nguyen 107147a1685fSDinh Nguyen /* check ep is enabled */ 107295c8bc36SAntti Seppälä if (!(dwc2_readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA)) 10731a0ed863SMian Yousaf Kaukab dev_dbg(hsotg->dev, 107447a1685fSDinh Nguyen "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", 107595c8bc36SAntti Seppälä index, dwc2_readl(hsotg->regs + epctrl_reg)); 107647a1685fSDinh Nguyen 107747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", 107895c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctrl_reg)); 107947a1685fSDinh Nguyen 108047a1685fSDinh Nguyen /* enable ep interrupts */ 10811f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1); 108247a1685fSDinh Nguyen } 108347a1685fSDinh Nguyen 108447a1685fSDinh Nguyen /** 10851f91b4ccSFelipe Balbi * dwc2_hsotg_map_dma - map the DMA memory being used for the request 108647a1685fSDinh Nguyen * @hsotg: The device state. 108747a1685fSDinh Nguyen * @hs_ep: The endpoint the request is on. 108847a1685fSDinh Nguyen * @req: The request being processed. 108947a1685fSDinh Nguyen * 109047a1685fSDinh Nguyen * We've been asked to queue a request, so ensure that the memory buffer 109147a1685fSDinh Nguyen * is correctly setup for DMA. If we've been passed an extant DMA address 109247a1685fSDinh Nguyen * then ensure the buffer has been synced to memory. If our buffer has no 109347a1685fSDinh Nguyen * DMA memory, then we map the memory and mark our request to allow us to 109447a1685fSDinh Nguyen * cleanup on completion. 109547a1685fSDinh Nguyen */ 10961f91b4ccSFelipe Balbi static int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg, 10971f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 109847a1685fSDinh Nguyen struct usb_request *req) 109947a1685fSDinh Nguyen { 110047a1685fSDinh Nguyen int ret; 110147a1685fSDinh Nguyen 110247a1685fSDinh Nguyen ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); 110347a1685fSDinh Nguyen if (ret) 110447a1685fSDinh Nguyen goto dma_error; 110547a1685fSDinh Nguyen 110647a1685fSDinh Nguyen return 0; 110747a1685fSDinh Nguyen 110847a1685fSDinh Nguyen dma_error: 110947a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", 111047a1685fSDinh Nguyen __func__, req->buf, req->length); 111147a1685fSDinh Nguyen 111247a1685fSDinh Nguyen return -EIO; 111347a1685fSDinh Nguyen } 111447a1685fSDinh Nguyen 11151f91b4ccSFelipe Balbi static int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, 1116*b98866c2SJohn Youn struct dwc2_hsotg_ep *hs_ep, 1117*b98866c2SJohn Youn struct dwc2_hsotg_req *hs_req) 11187d24c1b5SMian Yousaf Kaukab { 11197d24c1b5SMian Yousaf Kaukab void *req_buf = hs_req->req.buf; 11207d24c1b5SMian Yousaf Kaukab 11217d24c1b5SMian Yousaf Kaukab /* If dma is not being used or buffer is aligned */ 11227d24c1b5SMian Yousaf Kaukab if (!using_dma(hsotg) || !((long)req_buf & 3)) 11237d24c1b5SMian Yousaf Kaukab return 0; 11247d24c1b5SMian Yousaf Kaukab 11257d24c1b5SMian Yousaf Kaukab WARN_ON(hs_req->saved_req_buf); 11267d24c1b5SMian Yousaf Kaukab 11277d24c1b5SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__, 11287d24c1b5SMian Yousaf Kaukab hs_ep->ep.name, req_buf, hs_req->req.length); 11297d24c1b5SMian Yousaf Kaukab 11307d24c1b5SMian Yousaf Kaukab hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC); 11317d24c1b5SMian Yousaf Kaukab if (!hs_req->req.buf) { 11327d24c1b5SMian Yousaf Kaukab hs_req->req.buf = req_buf; 11337d24c1b5SMian Yousaf Kaukab dev_err(hsotg->dev, 11347d24c1b5SMian Yousaf Kaukab "%s: unable to allocate memory for bounce buffer\n", 11357d24c1b5SMian Yousaf Kaukab __func__); 11367d24c1b5SMian Yousaf Kaukab return -ENOMEM; 11377d24c1b5SMian Yousaf Kaukab } 11387d24c1b5SMian Yousaf Kaukab 11397d24c1b5SMian Yousaf Kaukab /* Save actual buffer */ 11407d24c1b5SMian Yousaf Kaukab hs_req->saved_req_buf = req_buf; 11417d24c1b5SMian Yousaf Kaukab 11427d24c1b5SMian Yousaf Kaukab if (hs_ep->dir_in) 11437d24c1b5SMian Yousaf Kaukab memcpy(hs_req->req.buf, req_buf, hs_req->req.length); 11447d24c1b5SMian Yousaf Kaukab return 0; 11457d24c1b5SMian Yousaf Kaukab } 11467d24c1b5SMian Yousaf Kaukab 1147*b98866c2SJohn Youn static void 1148*b98866c2SJohn Youn dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, 1149*b98866c2SJohn Youn struct dwc2_hsotg_ep *hs_ep, 1150*b98866c2SJohn Youn struct dwc2_hsotg_req *hs_req) 11517d24c1b5SMian Yousaf Kaukab { 11527d24c1b5SMian Yousaf Kaukab /* If dma is not being used or buffer was aligned */ 11537d24c1b5SMian Yousaf Kaukab if (!using_dma(hsotg) || !hs_req->saved_req_buf) 11547d24c1b5SMian Yousaf Kaukab return; 11557d24c1b5SMian Yousaf Kaukab 11567d24c1b5SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: %s: status=%d actual-length=%d\n", __func__, 11577d24c1b5SMian Yousaf Kaukab hs_ep->ep.name, hs_req->req.status, hs_req->req.actual); 11587d24c1b5SMian Yousaf Kaukab 11597d24c1b5SMian Yousaf Kaukab /* Copy data from bounce buffer on successful out transfer */ 11607d24c1b5SMian Yousaf Kaukab if (!hs_ep->dir_in && !hs_req->req.status) 11617d24c1b5SMian Yousaf Kaukab memcpy(hs_req->saved_req_buf, hs_req->req.buf, 11627d24c1b5SMian Yousaf Kaukab hs_req->req.actual); 11637d24c1b5SMian Yousaf Kaukab 11647d24c1b5SMian Yousaf Kaukab /* Free bounce buffer */ 11657d24c1b5SMian Yousaf Kaukab kfree(hs_req->req.buf); 11667d24c1b5SMian Yousaf Kaukab 11677d24c1b5SMian Yousaf Kaukab hs_req->req.buf = hs_req->saved_req_buf; 11687d24c1b5SMian Yousaf Kaukab hs_req->saved_req_buf = NULL; 11697d24c1b5SMian Yousaf Kaukab } 11707d24c1b5SMian Yousaf Kaukab 1171381fc8f8SVardan Mikayelyan /** 1172381fc8f8SVardan Mikayelyan * dwc2_gadget_target_frame_elapsed - Checks target frame 1173381fc8f8SVardan Mikayelyan * @hs_ep: The driver endpoint to check 1174381fc8f8SVardan Mikayelyan * 1175381fc8f8SVardan Mikayelyan * Returns 1 if targeted frame elapsed. If returned 1 then we need to drop 1176381fc8f8SVardan Mikayelyan * corresponding transfer. 1177381fc8f8SVardan Mikayelyan */ 1178381fc8f8SVardan Mikayelyan static bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep) 1179381fc8f8SVardan Mikayelyan { 1180381fc8f8SVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 1181381fc8f8SVardan Mikayelyan u32 target_frame = hs_ep->target_frame; 1182381fc8f8SVardan Mikayelyan u32 current_frame = dwc2_hsotg_read_frameno(hsotg); 1183381fc8f8SVardan Mikayelyan bool frame_overrun = hs_ep->frame_overrun; 1184381fc8f8SVardan Mikayelyan 1185381fc8f8SVardan Mikayelyan if (!frame_overrun && current_frame >= target_frame) 1186381fc8f8SVardan Mikayelyan return true; 1187381fc8f8SVardan Mikayelyan 1188381fc8f8SVardan Mikayelyan if (frame_overrun && current_frame >= target_frame && 1189381fc8f8SVardan Mikayelyan ((current_frame - target_frame) < DSTS_SOFFN_LIMIT / 2)) 1190381fc8f8SVardan Mikayelyan return true; 1191381fc8f8SVardan Mikayelyan 1192381fc8f8SVardan Mikayelyan return false; 1193381fc8f8SVardan Mikayelyan } 1194381fc8f8SVardan Mikayelyan 1195e02f9aa6SVahram Aharonyan /* 1196e02f9aa6SVahram Aharonyan * dwc2_gadget_set_ep0_desc_chain - Set EP's desc chain pointers 1197e02f9aa6SVahram Aharonyan * @hsotg: The driver state 1198e02f9aa6SVahram Aharonyan * @hs_ep: the ep descriptor chain is for 1199e02f9aa6SVahram Aharonyan * 1200e02f9aa6SVahram Aharonyan * Called to update EP0 structure's pointers depend on stage of 1201e02f9aa6SVahram Aharonyan * control transfer. 1202e02f9aa6SVahram Aharonyan */ 1203e02f9aa6SVahram Aharonyan static int dwc2_gadget_set_ep0_desc_chain(struct dwc2_hsotg *hsotg, 1204e02f9aa6SVahram Aharonyan struct dwc2_hsotg_ep *hs_ep) 1205e02f9aa6SVahram Aharonyan { 1206e02f9aa6SVahram Aharonyan switch (hsotg->ep0_state) { 1207e02f9aa6SVahram Aharonyan case DWC2_EP0_SETUP: 1208e02f9aa6SVahram Aharonyan case DWC2_EP0_STATUS_OUT: 1209e02f9aa6SVahram Aharonyan hs_ep->desc_list = hsotg->setup_desc[0]; 1210e02f9aa6SVahram Aharonyan hs_ep->desc_list_dma = hsotg->setup_desc_dma[0]; 1211e02f9aa6SVahram Aharonyan break; 1212e02f9aa6SVahram Aharonyan case DWC2_EP0_DATA_IN: 1213e02f9aa6SVahram Aharonyan case DWC2_EP0_STATUS_IN: 1214e02f9aa6SVahram Aharonyan hs_ep->desc_list = hsotg->ctrl_in_desc; 1215e02f9aa6SVahram Aharonyan hs_ep->desc_list_dma = hsotg->ctrl_in_desc_dma; 1216e02f9aa6SVahram Aharonyan break; 1217e02f9aa6SVahram Aharonyan case DWC2_EP0_DATA_OUT: 1218e02f9aa6SVahram Aharonyan hs_ep->desc_list = hsotg->ctrl_out_desc; 1219e02f9aa6SVahram Aharonyan hs_ep->desc_list_dma = hsotg->ctrl_out_desc_dma; 1220e02f9aa6SVahram Aharonyan break; 1221e02f9aa6SVahram Aharonyan default: 1222e02f9aa6SVahram Aharonyan dev_err(hsotg->dev, "invalid EP 0 state in queue %d\n", 1223e02f9aa6SVahram Aharonyan hsotg->ep0_state); 1224e02f9aa6SVahram Aharonyan return -EINVAL; 1225e02f9aa6SVahram Aharonyan } 1226e02f9aa6SVahram Aharonyan 1227e02f9aa6SVahram Aharonyan return 0; 1228e02f9aa6SVahram Aharonyan } 1229e02f9aa6SVahram Aharonyan 12301f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, 123147a1685fSDinh Nguyen gfp_t gfp_flags) 123247a1685fSDinh Nguyen { 12331f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 12341f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1235941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 123647a1685fSDinh Nguyen bool first; 12377d24c1b5SMian Yousaf Kaukab int ret; 123847a1685fSDinh Nguyen 123947a1685fSDinh Nguyen dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", 124047a1685fSDinh Nguyen ep->name, req, req->length, req->buf, req->no_interrupt, 124147a1685fSDinh Nguyen req->zero, req->short_not_ok); 124247a1685fSDinh Nguyen 12437ababa92SGregory Herrero /* Prevent new request submission when controller is suspended */ 12447ababa92SGregory Herrero if (hs->lx_state == DWC2_L2) { 12457ababa92SGregory Herrero dev_dbg(hs->dev, "%s: don't submit request while suspended\n", 12467ababa92SGregory Herrero __func__); 12477ababa92SGregory Herrero return -EAGAIN; 12487ababa92SGregory Herrero } 12497ababa92SGregory Herrero 125047a1685fSDinh Nguyen /* initialise status of the request */ 125147a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_req->queue); 125247a1685fSDinh Nguyen req->actual = 0; 125347a1685fSDinh Nguyen req->status = -EINPROGRESS; 125447a1685fSDinh Nguyen 12551f91b4ccSFelipe Balbi ret = dwc2_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req); 12567d24c1b5SMian Yousaf Kaukab if (ret) 12577d24c1b5SMian Yousaf Kaukab return ret; 12587d24c1b5SMian Yousaf Kaukab 125947a1685fSDinh Nguyen /* if we're using DMA, sync the buffers as necessary */ 126047a1685fSDinh Nguyen if (using_dma(hs)) { 12611f91b4ccSFelipe Balbi ret = dwc2_hsotg_map_dma(hs, hs_ep, req); 126247a1685fSDinh Nguyen if (ret) 126347a1685fSDinh Nguyen return ret; 126447a1685fSDinh Nguyen } 1265e02f9aa6SVahram Aharonyan /* If using descriptor DMA configure EP0 descriptor chain pointers */ 1266e02f9aa6SVahram Aharonyan if (using_desc_dma(hs) && !hs_ep->index) { 1267e02f9aa6SVahram Aharonyan ret = dwc2_gadget_set_ep0_desc_chain(hs, hs_ep); 1268e02f9aa6SVahram Aharonyan if (ret) 1269e02f9aa6SVahram Aharonyan return ret; 1270e02f9aa6SVahram Aharonyan } 127147a1685fSDinh Nguyen 127247a1685fSDinh Nguyen first = list_empty(&hs_ep->queue); 127347a1685fSDinh Nguyen list_add_tail(&hs_req->queue, &hs_ep->queue); 127447a1685fSDinh Nguyen 1275540ccba0SVahram Aharonyan /* 1276540ccba0SVahram Aharonyan * Handle DDMA isochronous transfers separately - just add new entry 1277540ccba0SVahram Aharonyan * to the half of descriptor chain that is not processed by HW. 1278540ccba0SVahram Aharonyan * Transfer will be started once SW gets either one of NAK or 1279540ccba0SVahram Aharonyan * OutTknEpDis interrupts. 1280540ccba0SVahram Aharonyan */ 1281540ccba0SVahram Aharonyan if (using_desc_dma(hs) && hs_ep->isochronous && 1282540ccba0SVahram Aharonyan hs_ep->target_frame != TARGET_FRAME_INITIAL) { 1283540ccba0SVahram Aharonyan ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, 1284540ccba0SVahram Aharonyan hs_req->req.length); 1285540ccba0SVahram Aharonyan if (ret) 1286540ccba0SVahram Aharonyan dev_dbg(hs->dev, "%s: ISO desc chain full\n", __func__); 1287540ccba0SVahram Aharonyan 1288540ccba0SVahram Aharonyan return 0; 1289540ccba0SVahram Aharonyan } 1290540ccba0SVahram Aharonyan 1291837e9f00SVardan Mikayelyan if (first) { 1292837e9f00SVardan Mikayelyan if (!hs_ep->isochronous) { 12931f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 1294837e9f00SVardan Mikayelyan return 0; 1295837e9f00SVardan Mikayelyan } 129647a1685fSDinh Nguyen 1297837e9f00SVardan Mikayelyan while (dwc2_gadget_target_frame_elapsed(hs_ep)) 1298837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 1299837e9f00SVardan Mikayelyan 1300837e9f00SVardan Mikayelyan if (hs_ep->target_frame != TARGET_FRAME_INITIAL) 1301837e9f00SVardan Mikayelyan dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 1302837e9f00SVardan Mikayelyan } 130347a1685fSDinh Nguyen return 0; 130447a1685fSDinh Nguyen } 130547a1685fSDinh Nguyen 13061f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, 130747a1685fSDinh Nguyen gfp_t gfp_flags) 130847a1685fSDinh Nguyen { 13091f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1310941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 131147a1685fSDinh Nguyen unsigned long flags = 0; 131247a1685fSDinh Nguyen int ret = 0; 131347a1685fSDinh Nguyen 131447a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 13151f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(ep, req, gfp_flags); 131647a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 131747a1685fSDinh Nguyen 131847a1685fSDinh Nguyen return ret; 131947a1685fSDinh Nguyen } 132047a1685fSDinh Nguyen 13211f91b4ccSFelipe Balbi static void dwc2_hsotg_ep_free_request(struct usb_ep *ep, 132247a1685fSDinh Nguyen struct usb_request *req) 132347a1685fSDinh Nguyen { 13241f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 132547a1685fSDinh Nguyen 132647a1685fSDinh Nguyen kfree(hs_req); 132747a1685fSDinh Nguyen } 132847a1685fSDinh Nguyen 132947a1685fSDinh Nguyen /** 13301f91b4ccSFelipe Balbi * dwc2_hsotg_complete_oursetup - setup completion callback 133147a1685fSDinh Nguyen * @ep: The endpoint the request was on. 133247a1685fSDinh Nguyen * @req: The request completed. 133347a1685fSDinh Nguyen * 133447a1685fSDinh Nguyen * Called on completion of any requests the driver itself 133547a1685fSDinh Nguyen * submitted that need cleaning up. 133647a1685fSDinh Nguyen */ 13371f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_oursetup(struct usb_ep *ep, 133847a1685fSDinh Nguyen struct usb_request *req) 133947a1685fSDinh Nguyen { 13401f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1341941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 134247a1685fSDinh Nguyen 134347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); 134447a1685fSDinh Nguyen 13451f91b4ccSFelipe Balbi dwc2_hsotg_ep_free_request(ep, req); 134647a1685fSDinh Nguyen } 134747a1685fSDinh Nguyen 134847a1685fSDinh Nguyen /** 134947a1685fSDinh Nguyen * ep_from_windex - convert control wIndex value to endpoint 135047a1685fSDinh Nguyen * @hsotg: The driver state. 135147a1685fSDinh Nguyen * @windex: The control request wIndex field (in host order). 135247a1685fSDinh Nguyen * 135347a1685fSDinh Nguyen * Convert the given wIndex into a pointer to an driver endpoint 135447a1685fSDinh Nguyen * structure, or return NULL if it is not a valid endpoint. 135547a1685fSDinh Nguyen */ 13561f91b4ccSFelipe Balbi static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, 135747a1685fSDinh Nguyen u32 windex) 135847a1685fSDinh Nguyen { 13591f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 136047a1685fSDinh Nguyen int dir = (windex & USB_DIR_IN) ? 1 : 0; 136147a1685fSDinh Nguyen int idx = windex & 0x7F; 136247a1685fSDinh Nguyen 136347a1685fSDinh Nguyen if (windex >= 0x100) 136447a1685fSDinh Nguyen return NULL; 136547a1685fSDinh Nguyen 136647a1685fSDinh Nguyen if (idx > hsotg->num_of_eps) 136747a1685fSDinh Nguyen return NULL; 136847a1685fSDinh Nguyen 1369c6f5c050SMian Yousaf Kaukab ep = index_to_ep(hsotg, idx, dir); 1370c6f5c050SMian Yousaf Kaukab 137147a1685fSDinh Nguyen if (idx && ep->dir_in != dir) 137247a1685fSDinh Nguyen return NULL; 137347a1685fSDinh Nguyen 137447a1685fSDinh Nguyen return ep; 137547a1685fSDinh Nguyen } 137647a1685fSDinh Nguyen 137747a1685fSDinh Nguyen /** 13781f91b4ccSFelipe Balbi * dwc2_hsotg_set_test_mode - Enable usb Test Modes 13799e14d0a5SGregory Herrero * @hsotg: The driver state. 13809e14d0a5SGregory Herrero * @testmode: requested usb test mode 13819e14d0a5SGregory Herrero * Enable usb Test Mode requested by the Host. 13829e14d0a5SGregory Herrero */ 13831f91b4ccSFelipe Balbi int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode) 13849e14d0a5SGregory Herrero { 138595c8bc36SAntti Seppälä int dctl = dwc2_readl(hsotg->regs + DCTL); 13869e14d0a5SGregory Herrero 13879e14d0a5SGregory Herrero dctl &= ~DCTL_TSTCTL_MASK; 13889e14d0a5SGregory Herrero switch (testmode) { 13899e14d0a5SGregory Herrero case TEST_J: 13909e14d0a5SGregory Herrero case TEST_K: 13919e14d0a5SGregory Herrero case TEST_SE0_NAK: 13929e14d0a5SGregory Herrero case TEST_PACKET: 13939e14d0a5SGregory Herrero case TEST_FORCE_EN: 13949e14d0a5SGregory Herrero dctl |= testmode << DCTL_TSTCTL_SHIFT; 13959e14d0a5SGregory Herrero break; 13969e14d0a5SGregory Herrero default: 13979e14d0a5SGregory Herrero return -EINVAL; 13989e14d0a5SGregory Herrero } 139995c8bc36SAntti Seppälä dwc2_writel(dctl, hsotg->regs + DCTL); 14009e14d0a5SGregory Herrero return 0; 14019e14d0a5SGregory Herrero } 14029e14d0a5SGregory Herrero 14039e14d0a5SGregory Herrero /** 14041f91b4ccSFelipe Balbi * dwc2_hsotg_send_reply - send reply to control request 140547a1685fSDinh Nguyen * @hsotg: The device state 140647a1685fSDinh Nguyen * @ep: Endpoint 0 140747a1685fSDinh Nguyen * @buff: Buffer for request 140847a1685fSDinh Nguyen * @length: Length of reply. 140947a1685fSDinh Nguyen * 141047a1685fSDinh Nguyen * Create a request and queue it on the given endpoint. This is useful as 141147a1685fSDinh Nguyen * an internal method of sending replies to certain control requests, etc. 141247a1685fSDinh Nguyen */ 14131f91b4ccSFelipe Balbi static int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg, 14141f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep, 141547a1685fSDinh Nguyen void *buff, 141647a1685fSDinh Nguyen int length) 141747a1685fSDinh Nguyen { 141847a1685fSDinh Nguyen struct usb_request *req; 141947a1685fSDinh Nguyen int ret; 142047a1685fSDinh Nguyen 142147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); 142247a1685fSDinh Nguyen 14231f91b4ccSFelipe Balbi req = dwc2_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); 142447a1685fSDinh Nguyen hsotg->ep0_reply = req; 142547a1685fSDinh Nguyen if (!req) { 142647a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); 142747a1685fSDinh Nguyen return -ENOMEM; 142847a1685fSDinh Nguyen } 142947a1685fSDinh Nguyen 143047a1685fSDinh Nguyen req->buf = hsotg->ep0_buff; 143147a1685fSDinh Nguyen req->length = length; 1432f71b5e25SMian Yousaf Kaukab /* 1433f71b5e25SMian Yousaf Kaukab * zero flag is for sending zlp in DATA IN stage. It has no impact on 1434f71b5e25SMian Yousaf Kaukab * STATUS stage. 1435f71b5e25SMian Yousaf Kaukab */ 1436f71b5e25SMian Yousaf Kaukab req->zero = 0; 14371f91b4ccSFelipe Balbi req->complete = dwc2_hsotg_complete_oursetup; 143847a1685fSDinh Nguyen 143947a1685fSDinh Nguyen if (length) 144047a1685fSDinh Nguyen memcpy(req->buf, buff, length); 144147a1685fSDinh Nguyen 14421f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); 144347a1685fSDinh Nguyen if (ret) { 144447a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); 144547a1685fSDinh Nguyen return ret; 144647a1685fSDinh Nguyen } 144747a1685fSDinh Nguyen 144847a1685fSDinh Nguyen return 0; 144947a1685fSDinh Nguyen } 145047a1685fSDinh Nguyen 145147a1685fSDinh Nguyen /** 14521f91b4ccSFelipe Balbi * dwc2_hsotg_process_req_status - process request GET_STATUS 145347a1685fSDinh Nguyen * @hsotg: The device state 145447a1685fSDinh Nguyen * @ctrl: USB control request 145547a1685fSDinh Nguyen */ 14561f91b4ccSFelipe Balbi static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, 145747a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 145847a1685fSDinh Nguyen { 14591f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 14601f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 146147a1685fSDinh Nguyen __le16 reply; 146247a1685fSDinh Nguyen int ret; 146347a1685fSDinh Nguyen 146447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); 146547a1685fSDinh Nguyen 146647a1685fSDinh Nguyen if (!ep0->dir_in) { 146747a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: direction out?\n", __func__); 146847a1685fSDinh Nguyen return -EINVAL; 146947a1685fSDinh Nguyen } 147047a1685fSDinh Nguyen 147147a1685fSDinh Nguyen switch (ctrl->bRequestType & USB_RECIP_MASK) { 147247a1685fSDinh Nguyen case USB_RECIP_DEVICE: 147338beaec6SJohn Youn /* 147438beaec6SJohn Youn * bit 0 => self powered 147538beaec6SJohn Youn * bit 1 => remote wakeup 147638beaec6SJohn Youn */ 147738beaec6SJohn Youn reply = cpu_to_le16(0); 147847a1685fSDinh Nguyen break; 147947a1685fSDinh Nguyen 148047a1685fSDinh Nguyen case USB_RECIP_INTERFACE: 148147a1685fSDinh Nguyen /* currently, the data result should be zero */ 148247a1685fSDinh Nguyen reply = cpu_to_le16(0); 148347a1685fSDinh Nguyen break; 148447a1685fSDinh Nguyen 148547a1685fSDinh Nguyen case USB_RECIP_ENDPOINT: 148647a1685fSDinh Nguyen ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); 148747a1685fSDinh Nguyen if (!ep) 148847a1685fSDinh Nguyen return -ENOENT; 148947a1685fSDinh Nguyen 149047a1685fSDinh Nguyen reply = cpu_to_le16(ep->halted ? 1 : 0); 149147a1685fSDinh Nguyen break; 149247a1685fSDinh Nguyen 149347a1685fSDinh Nguyen default: 149447a1685fSDinh Nguyen return 0; 149547a1685fSDinh Nguyen } 149647a1685fSDinh Nguyen 149747a1685fSDinh Nguyen if (le16_to_cpu(ctrl->wLength) != 2) 149847a1685fSDinh Nguyen return -EINVAL; 149947a1685fSDinh Nguyen 15001f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, &reply, 2); 150147a1685fSDinh Nguyen if (ret) { 150247a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); 150347a1685fSDinh Nguyen return ret; 150447a1685fSDinh Nguyen } 150547a1685fSDinh Nguyen 150647a1685fSDinh Nguyen return 1; 150747a1685fSDinh Nguyen } 150847a1685fSDinh Nguyen 150951da43b5SVahram Aharonyan static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now); 151047a1685fSDinh Nguyen 151147a1685fSDinh Nguyen /** 151247a1685fSDinh Nguyen * get_ep_head - return the first request on the endpoint 151347a1685fSDinh Nguyen * @hs_ep: The controller endpoint to get 151447a1685fSDinh Nguyen * 151547a1685fSDinh Nguyen * Get the first request on the endpoint. 151647a1685fSDinh Nguyen */ 15171f91b4ccSFelipe Balbi static struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep) 151847a1685fSDinh Nguyen { 1519ffc4b406SMasahiro Yamada return list_first_entry_or_null(&hs_ep->queue, struct dwc2_hsotg_req, 1520ffc4b406SMasahiro Yamada queue); 152147a1685fSDinh Nguyen } 152247a1685fSDinh Nguyen 152347a1685fSDinh Nguyen /** 152441cc4cd2SVardan Mikayelyan * dwc2_gadget_start_next_request - Starts next request from ep queue 152541cc4cd2SVardan Mikayelyan * @hs_ep: Endpoint structure 152641cc4cd2SVardan Mikayelyan * 152741cc4cd2SVardan Mikayelyan * If queue is empty and EP is ISOC-OUT - unmasks OUTTKNEPDIS which is masked 152841cc4cd2SVardan Mikayelyan * in its handler. Hence we need to unmask it here to be able to do 152941cc4cd2SVardan Mikayelyan * resynchronization. 153041cc4cd2SVardan Mikayelyan */ 153141cc4cd2SVardan Mikayelyan static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep) 153241cc4cd2SVardan Mikayelyan { 153341cc4cd2SVardan Mikayelyan u32 mask; 153441cc4cd2SVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 153541cc4cd2SVardan Mikayelyan int dir_in = hs_ep->dir_in; 153641cc4cd2SVardan Mikayelyan struct dwc2_hsotg_req *hs_req; 153741cc4cd2SVardan Mikayelyan u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; 153841cc4cd2SVardan Mikayelyan 153941cc4cd2SVardan Mikayelyan if (!list_empty(&hs_ep->queue)) { 154041cc4cd2SVardan Mikayelyan hs_req = get_ep_head(hs_ep); 154141cc4cd2SVardan Mikayelyan dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false); 154241cc4cd2SVardan Mikayelyan return; 154341cc4cd2SVardan Mikayelyan } 154441cc4cd2SVardan Mikayelyan if (!hs_ep->isochronous) 154541cc4cd2SVardan Mikayelyan return; 154641cc4cd2SVardan Mikayelyan 154741cc4cd2SVardan Mikayelyan if (dir_in) { 154841cc4cd2SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: No more ISOC-IN requests\n", 154941cc4cd2SVardan Mikayelyan __func__); 155041cc4cd2SVardan Mikayelyan } else { 155141cc4cd2SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: No more ISOC-OUT requests\n", 155241cc4cd2SVardan Mikayelyan __func__); 155341cc4cd2SVardan Mikayelyan mask = dwc2_readl(hsotg->regs + epmsk_reg); 155441cc4cd2SVardan Mikayelyan mask |= DOEPMSK_OUTTKNEPDISMSK; 155541cc4cd2SVardan Mikayelyan dwc2_writel(mask, hsotg->regs + epmsk_reg); 155641cc4cd2SVardan Mikayelyan } 155741cc4cd2SVardan Mikayelyan } 155841cc4cd2SVardan Mikayelyan 155941cc4cd2SVardan Mikayelyan /** 15601f91b4ccSFelipe Balbi * dwc2_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE 156147a1685fSDinh Nguyen * @hsotg: The device state 156247a1685fSDinh Nguyen * @ctrl: USB control request 156347a1685fSDinh Nguyen */ 15641f91b4ccSFelipe Balbi static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, 156547a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 156647a1685fSDinh Nguyen { 15671f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 15681f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req; 156947a1685fSDinh Nguyen bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); 15701f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 157147a1685fSDinh Nguyen int ret; 157247a1685fSDinh Nguyen bool halted; 15739e14d0a5SGregory Herrero u32 recip; 15749e14d0a5SGregory Herrero u32 wValue; 15759e14d0a5SGregory Herrero u32 wIndex; 157647a1685fSDinh Nguyen 157747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", 157847a1685fSDinh Nguyen __func__, set ? "SET" : "CLEAR"); 157947a1685fSDinh Nguyen 15809e14d0a5SGregory Herrero wValue = le16_to_cpu(ctrl->wValue); 15819e14d0a5SGregory Herrero wIndex = le16_to_cpu(ctrl->wIndex); 15829e14d0a5SGregory Herrero recip = ctrl->bRequestType & USB_RECIP_MASK; 15839e14d0a5SGregory Herrero 15849e14d0a5SGregory Herrero switch (recip) { 15859e14d0a5SGregory Herrero case USB_RECIP_DEVICE: 15869e14d0a5SGregory Herrero switch (wValue) { 15879e14d0a5SGregory Herrero case USB_DEVICE_TEST_MODE: 15889e14d0a5SGregory Herrero if ((wIndex & 0xff) != 0) 15899e14d0a5SGregory Herrero return -EINVAL; 15909e14d0a5SGregory Herrero if (!set) 15919e14d0a5SGregory Herrero return -EINVAL; 15929e14d0a5SGregory Herrero 15939e14d0a5SGregory Herrero hsotg->test_mode = wIndex >> 8; 15941f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 15959e14d0a5SGregory Herrero if (ret) { 15969e14d0a5SGregory Herrero dev_err(hsotg->dev, 15979e14d0a5SGregory Herrero "%s: failed to send reply\n", __func__); 15989e14d0a5SGregory Herrero return ret; 15999e14d0a5SGregory Herrero } 16009e14d0a5SGregory Herrero break; 16019e14d0a5SGregory Herrero default: 16029e14d0a5SGregory Herrero return -ENOENT; 16039e14d0a5SGregory Herrero } 16049e14d0a5SGregory Herrero break; 16059e14d0a5SGregory Herrero 16069e14d0a5SGregory Herrero case USB_RECIP_ENDPOINT: 16079e14d0a5SGregory Herrero ep = ep_from_windex(hsotg, wIndex); 160847a1685fSDinh Nguyen if (!ep) { 160947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", 16109e14d0a5SGregory Herrero __func__, wIndex); 161147a1685fSDinh Nguyen return -ENOENT; 161247a1685fSDinh Nguyen } 161347a1685fSDinh Nguyen 16149e14d0a5SGregory Herrero switch (wValue) { 161547a1685fSDinh Nguyen case USB_ENDPOINT_HALT: 161647a1685fSDinh Nguyen halted = ep->halted; 161747a1685fSDinh Nguyen 161851da43b5SVahram Aharonyan dwc2_hsotg_ep_sethalt(&ep->ep, set, true); 161947a1685fSDinh Nguyen 16201f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 162147a1685fSDinh Nguyen if (ret) { 162247a1685fSDinh Nguyen dev_err(hsotg->dev, 162347a1685fSDinh Nguyen "%s: failed to send reply\n", __func__); 162447a1685fSDinh Nguyen return ret; 162547a1685fSDinh Nguyen } 162647a1685fSDinh Nguyen 162747a1685fSDinh Nguyen /* 162847a1685fSDinh Nguyen * we have to complete all requests for ep if it was 162947a1685fSDinh Nguyen * halted, and the halt was cleared by CLEAR_FEATURE 163047a1685fSDinh Nguyen */ 163147a1685fSDinh Nguyen 163247a1685fSDinh Nguyen if (!set && halted) { 163347a1685fSDinh Nguyen /* 163447a1685fSDinh Nguyen * If we have request in progress, 163547a1685fSDinh Nguyen * then complete it 163647a1685fSDinh Nguyen */ 163747a1685fSDinh Nguyen if (ep->req) { 163847a1685fSDinh Nguyen hs_req = ep->req; 163947a1685fSDinh Nguyen ep->req = NULL; 164047a1685fSDinh Nguyen list_del_init(&hs_req->queue); 1641c00dd4a6SGregory Herrero if (hs_req->req.complete) { 1642c00dd4a6SGregory Herrero spin_unlock(&hsotg->lock); 1643c00dd4a6SGregory Herrero usb_gadget_giveback_request( 1644c00dd4a6SGregory Herrero &ep->ep, &hs_req->req); 1645c00dd4a6SGregory Herrero spin_lock(&hsotg->lock); 1646c00dd4a6SGregory Herrero } 164747a1685fSDinh Nguyen } 164847a1685fSDinh Nguyen 164947a1685fSDinh Nguyen /* If we have pending request, then start it */ 165034c0887fSJohn Youn if (!ep->req) 165141cc4cd2SVardan Mikayelyan dwc2_gadget_start_next_request(ep); 165247a1685fSDinh Nguyen } 165347a1685fSDinh Nguyen 165447a1685fSDinh Nguyen break; 165547a1685fSDinh Nguyen 165647a1685fSDinh Nguyen default: 165747a1685fSDinh Nguyen return -ENOENT; 165847a1685fSDinh Nguyen } 16599e14d0a5SGregory Herrero break; 16609e14d0a5SGregory Herrero default: 16619e14d0a5SGregory Herrero return -ENOENT; 16629e14d0a5SGregory Herrero } 166347a1685fSDinh Nguyen return 1; 166447a1685fSDinh Nguyen } 166547a1685fSDinh Nguyen 16661f91b4ccSFelipe Balbi static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg); 166747a1685fSDinh Nguyen 166847a1685fSDinh Nguyen /** 16691f91b4ccSFelipe Balbi * dwc2_hsotg_stall_ep0 - stall ep0 167047a1685fSDinh Nguyen * @hsotg: The device state 167147a1685fSDinh Nguyen * 167247a1685fSDinh Nguyen * Set stall for ep0 as response for setup request. 167347a1685fSDinh Nguyen */ 16741f91b4ccSFelipe Balbi static void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg) 1675e9ebe7c3SJingoo Han { 16761f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 167747a1685fSDinh Nguyen u32 reg; 167847a1685fSDinh Nguyen u32 ctrl; 167947a1685fSDinh Nguyen 168047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); 168147a1685fSDinh Nguyen reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; 168247a1685fSDinh Nguyen 168347a1685fSDinh Nguyen /* 168447a1685fSDinh Nguyen * DxEPCTL_Stall will be cleared by EP once it has 168547a1685fSDinh Nguyen * taken effect, so no need to clear later. 168647a1685fSDinh Nguyen */ 168747a1685fSDinh Nguyen 168895c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + reg); 168947a1685fSDinh Nguyen ctrl |= DXEPCTL_STALL; 169047a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; 169195c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + reg); 169247a1685fSDinh Nguyen 169347a1685fSDinh Nguyen dev_dbg(hsotg->dev, 169447a1685fSDinh Nguyen "written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n", 169595c8bc36SAntti Seppälä ctrl, reg, dwc2_readl(hsotg->regs + reg)); 169647a1685fSDinh Nguyen 169747a1685fSDinh Nguyen /* 169847a1685fSDinh Nguyen * complete won't be called, so we enqueue 169947a1685fSDinh Nguyen * setup request here 170047a1685fSDinh Nguyen */ 17011f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 170247a1685fSDinh Nguyen } 170347a1685fSDinh Nguyen 170447a1685fSDinh Nguyen /** 17051f91b4ccSFelipe Balbi * dwc2_hsotg_process_control - process a control request 170647a1685fSDinh Nguyen * @hsotg: The device state 170747a1685fSDinh Nguyen * @ctrl: The control request received 170847a1685fSDinh Nguyen * 170947a1685fSDinh Nguyen * The controller has received the SETUP phase of a control request, and 171047a1685fSDinh Nguyen * needs to work out what to do next (and whether to pass it on to the 171147a1685fSDinh Nguyen * gadget driver). 171247a1685fSDinh Nguyen */ 17131f91b4ccSFelipe Balbi static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, 171447a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 171547a1685fSDinh Nguyen { 17161f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 171747a1685fSDinh Nguyen int ret = 0; 171847a1685fSDinh Nguyen u32 dcfg; 171947a1685fSDinh Nguyen 1720e525e743SMian Yousaf Kaukab dev_dbg(hsotg->dev, 1721e525e743SMian Yousaf Kaukab "ctrl Type=%02x, Req=%02x, V=%04x, I=%04x, L=%04x\n", 1722e525e743SMian Yousaf Kaukab ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, 1723e525e743SMian Yousaf Kaukab ctrl->wIndex, ctrl->wLength); 172447a1685fSDinh Nguyen 1725fe0b94abSMian Yousaf Kaukab if (ctrl->wLength == 0) { 172647a1685fSDinh Nguyen ep0->dir_in = 1; 1727fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_STATUS_IN; 1728fe0b94abSMian Yousaf Kaukab } else if (ctrl->bRequestType & USB_DIR_IN) { 1729fe0b94abSMian Yousaf Kaukab ep0->dir_in = 1; 1730fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_DATA_IN; 1731fe0b94abSMian Yousaf Kaukab } else { 1732fe0b94abSMian Yousaf Kaukab ep0->dir_in = 0; 1733fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_DATA_OUT; 1734fe0b94abSMian Yousaf Kaukab } 173547a1685fSDinh Nguyen 173647a1685fSDinh Nguyen if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 173747a1685fSDinh Nguyen switch (ctrl->bRequest) { 173847a1685fSDinh Nguyen case USB_REQ_SET_ADDRESS: 17396d713c15SMian Yousaf Kaukab hsotg->connected = 1; 174095c8bc36SAntti Seppälä dcfg = dwc2_readl(hsotg->regs + DCFG); 174147a1685fSDinh Nguyen dcfg &= ~DCFG_DEVADDR_MASK; 1742d5dbd3f7SPaul Zimmerman dcfg |= (le16_to_cpu(ctrl->wValue) << 1743d5dbd3f7SPaul Zimmerman DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK; 174495c8bc36SAntti Seppälä dwc2_writel(dcfg, hsotg->regs + DCFG); 174547a1685fSDinh Nguyen 174647a1685fSDinh Nguyen dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); 174747a1685fSDinh Nguyen 17481f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 174947a1685fSDinh Nguyen return; 175047a1685fSDinh Nguyen 175147a1685fSDinh Nguyen case USB_REQ_GET_STATUS: 17521f91b4ccSFelipe Balbi ret = dwc2_hsotg_process_req_status(hsotg, ctrl); 175347a1685fSDinh Nguyen break; 175447a1685fSDinh Nguyen 175547a1685fSDinh Nguyen case USB_REQ_CLEAR_FEATURE: 175647a1685fSDinh Nguyen case USB_REQ_SET_FEATURE: 17571f91b4ccSFelipe Balbi ret = dwc2_hsotg_process_req_feature(hsotg, ctrl); 175847a1685fSDinh Nguyen break; 175947a1685fSDinh Nguyen } 176047a1685fSDinh Nguyen } 176147a1685fSDinh Nguyen 176247a1685fSDinh Nguyen /* as a fallback, try delivering it to the driver to deal with */ 176347a1685fSDinh Nguyen 176447a1685fSDinh Nguyen if (ret == 0 && hsotg->driver) { 176547a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 176647a1685fSDinh Nguyen ret = hsotg->driver->setup(&hsotg->gadget, ctrl); 176747a1685fSDinh Nguyen spin_lock(&hsotg->lock); 176847a1685fSDinh Nguyen if (ret < 0) 176947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); 177047a1685fSDinh Nguyen } 177147a1685fSDinh Nguyen 177247a1685fSDinh Nguyen /* 177347a1685fSDinh Nguyen * the request is either unhandlable, or is not formatted correctly 177447a1685fSDinh Nguyen * so respond with a STALL for the status stage to indicate failure. 177547a1685fSDinh Nguyen */ 177647a1685fSDinh Nguyen 177747a1685fSDinh Nguyen if (ret < 0) 17781f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hsotg); 177947a1685fSDinh Nguyen } 178047a1685fSDinh Nguyen 178147a1685fSDinh Nguyen /** 17821f91b4ccSFelipe Balbi * dwc2_hsotg_complete_setup - completion of a setup transfer 178347a1685fSDinh Nguyen * @ep: The endpoint the request was on. 178447a1685fSDinh Nguyen * @req: The request completed. 178547a1685fSDinh Nguyen * 178647a1685fSDinh Nguyen * Called on completion of any requests the driver itself submitted for 178747a1685fSDinh Nguyen * EP0 setup packets 178847a1685fSDinh Nguyen */ 17891f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_setup(struct usb_ep *ep, 179047a1685fSDinh Nguyen struct usb_request *req) 179147a1685fSDinh Nguyen { 17921f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1793941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 179447a1685fSDinh Nguyen 179547a1685fSDinh Nguyen if (req->status < 0) { 179647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); 179747a1685fSDinh Nguyen return; 179847a1685fSDinh Nguyen } 179947a1685fSDinh Nguyen 180047a1685fSDinh Nguyen spin_lock(&hsotg->lock); 180147a1685fSDinh Nguyen if (req->actual == 0) 18021f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 180347a1685fSDinh Nguyen else 18041f91b4ccSFelipe Balbi dwc2_hsotg_process_control(hsotg, req->buf); 180547a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 180647a1685fSDinh Nguyen } 180747a1685fSDinh Nguyen 180847a1685fSDinh Nguyen /** 18091f91b4ccSFelipe Balbi * dwc2_hsotg_enqueue_setup - start a request for EP0 packets 181047a1685fSDinh Nguyen * @hsotg: The device state. 181147a1685fSDinh Nguyen * 181247a1685fSDinh Nguyen * Enqueue a request on EP0 if necessary to received any SETUP packets 181347a1685fSDinh Nguyen * received from the host. 181447a1685fSDinh Nguyen */ 18151f91b4ccSFelipe Balbi static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg) 181647a1685fSDinh Nguyen { 181747a1685fSDinh Nguyen struct usb_request *req = hsotg->ctrl_req; 18181f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 181947a1685fSDinh Nguyen int ret; 182047a1685fSDinh Nguyen 182147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); 182247a1685fSDinh Nguyen 182347a1685fSDinh Nguyen req->zero = 0; 182447a1685fSDinh Nguyen req->length = 8; 182547a1685fSDinh Nguyen req->buf = hsotg->ctrl_buff; 18261f91b4ccSFelipe Balbi req->complete = dwc2_hsotg_complete_setup; 182747a1685fSDinh Nguyen 182847a1685fSDinh Nguyen if (!list_empty(&hs_req->queue)) { 182947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s already queued???\n", __func__); 183047a1685fSDinh Nguyen return; 183147a1685fSDinh Nguyen } 183247a1685fSDinh Nguyen 1833c6f5c050SMian Yousaf Kaukab hsotg->eps_out[0]->dir_in = 0; 18348a20fa45SMian Yousaf Kaukab hsotg->eps_out[0]->send_zlp = 0; 1835fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_SETUP; 183647a1685fSDinh Nguyen 18371f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(&hsotg->eps_out[0]->ep, req, GFP_ATOMIC); 183847a1685fSDinh Nguyen if (ret < 0) { 183947a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); 184047a1685fSDinh Nguyen /* 184147a1685fSDinh Nguyen * Don't think there's much we can do other than watch the 184247a1685fSDinh Nguyen * driver fail. 184347a1685fSDinh Nguyen */ 184447a1685fSDinh Nguyen } 184547a1685fSDinh Nguyen } 184647a1685fSDinh Nguyen 18471f91b4ccSFelipe Balbi static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, 18481f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 1849fe0b94abSMian Yousaf Kaukab { 1850fe0b94abSMian Yousaf Kaukab u32 ctrl; 1851fe0b94abSMian Yousaf Kaukab u8 index = hs_ep->index; 1852fe0b94abSMian Yousaf Kaukab u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 1853fe0b94abSMian Yousaf Kaukab u32 epsiz_reg = hs_ep->dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 1854fe0b94abSMian Yousaf Kaukab 1855ccb34a91SMian Yousaf Kaukab if (hs_ep->dir_in) 1856ccb34a91SMian Yousaf Kaukab dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n", 1857ccb34a91SMian Yousaf Kaukab index); 1858ccb34a91SMian Yousaf Kaukab else 1859ccb34a91SMian Yousaf Kaukab dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n", 1860ccb34a91SMian Yousaf Kaukab index); 1861e02f9aa6SVahram Aharonyan if (using_desc_dma(hsotg)) { 1862e02f9aa6SVahram Aharonyan /* Not specific buffer needed for ep0 ZLP */ 1863e02f9aa6SVahram Aharonyan dma_addr_t dma = hs_ep->desc_list_dma; 1864fe0b94abSMian Yousaf Kaukab 1865e02f9aa6SVahram Aharonyan dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep); 1866e02f9aa6SVahram Aharonyan dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0); 1867e02f9aa6SVahram Aharonyan } else { 186895c8bc36SAntti Seppälä dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 1869fe0b94abSMian Yousaf Kaukab DXEPTSIZ_XFERSIZE(0), hsotg->regs + 1870fe0b94abSMian Yousaf Kaukab epsiz_reg); 1871e02f9aa6SVahram Aharonyan } 1872fe0b94abSMian Yousaf Kaukab 187395c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctl_reg); 1874fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 1875fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 1876fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_USBACTEP; 187795c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + epctl_reg); 1878fe0b94abSMian Yousaf Kaukab } 1879fe0b94abSMian Yousaf Kaukab 188047a1685fSDinh Nguyen /** 18811f91b4ccSFelipe Balbi * dwc2_hsotg_complete_request - complete a request given to us 188247a1685fSDinh Nguyen * @hsotg: The device state. 188347a1685fSDinh Nguyen * @hs_ep: The endpoint the request was on. 188447a1685fSDinh Nguyen * @hs_req: The request to complete. 188547a1685fSDinh Nguyen * @result: The result code (0 => Ok, otherwise errno) 188647a1685fSDinh Nguyen * 188747a1685fSDinh Nguyen * The given request has finished, so call the necessary completion 188847a1685fSDinh Nguyen * if it has one and then look to see if we can start a new request 188947a1685fSDinh Nguyen * on the endpoint. 189047a1685fSDinh Nguyen * 189147a1685fSDinh Nguyen * Note, expects the ep to already be locked as appropriate. 189247a1685fSDinh Nguyen */ 18931f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, 18941f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 18951f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req, 189647a1685fSDinh Nguyen int result) 189747a1685fSDinh Nguyen { 189847a1685fSDinh Nguyen if (!hs_req) { 189947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); 190047a1685fSDinh Nguyen return; 190147a1685fSDinh Nguyen } 190247a1685fSDinh Nguyen 190347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", 190447a1685fSDinh Nguyen hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); 190547a1685fSDinh Nguyen 190647a1685fSDinh Nguyen /* 190747a1685fSDinh Nguyen * only replace the status if we've not already set an error 190847a1685fSDinh Nguyen * from a previous transaction 190947a1685fSDinh Nguyen */ 191047a1685fSDinh Nguyen 191147a1685fSDinh Nguyen if (hs_req->req.status == -EINPROGRESS) 191247a1685fSDinh Nguyen hs_req->req.status = result; 191347a1685fSDinh Nguyen 191444583fecSYunzhi Li if (using_dma(hsotg)) 191544583fecSYunzhi Li dwc2_hsotg_unmap_dma(hsotg, hs_ep, hs_req); 191644583fecSYunzhi Li 19171f91b4ccSFelipe Balbi dwc2_hsotg_handle_unaligned_buf_complete(hsotg, hs_ep, hs_req); 19187d24c1b5SMian Yousaf Kaukab 191947a1685fSDinh Nguyen hs_ep->req = NULL; 192047a1685fSDinh Nguyen list_del_init(&hs_req->queue); 192147a1685fSDinh Nguyen 192247a1685fSDinh Nguyen /* 192347a1685fSDinh Nguyen * call the complete request with the locks off, just in case the 192447a1685fSDinh Nguyen * request tries to queue more work for this endpoint. 192547a1685fSDinh Nguyen */ 192647a1685fSDinh Nguyen 192747a1685fSDinh Nguyen if (hs_req->req.complete) { 192847a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 1929304f7e5eSMichal Sojka usb_gadget_giveback_request(&hs_ep->ep, &hs_req->req); 193047a1685fSDinh Nguyen spin_lock(&hsotg->lock); 193147a1685fSDinh Nguyen } 193247a1685fSDinh Nguyen 1933540ccba0SVahram Aharonyan /* In DDMA don't need to proceed to starting of next ISOC request */ 1934540ccba0SVahram Aharonyan if (using_desc_dma(hsotg) && hs_ep->isochronous) 1935540ccba0SVahram Aharonyan return; 1936540ccba0SVahram Aharonyan 193747a1685fSDinh Nguyen /* 193847a1685fSDinh Nguyen * Look to see if there is anything else to do. Note, the completion 193947a1685fSDinh Nguyen * of the previous request may have caused a new request to be started 194047a1685fSDinh Nguyen * so be careful when doing this. 194147a1685fSDinh Nguyen */ 194247a1685fSDinh Nguyen 194334c0887fSJohn Youn if (!hs_ep->req && result >= 0) 194441cc4cd2SVardan Mikayelyan dwc2_gadget_start_next_request(hs_ep); 194547a1685fSDinh Nguyen } 194647a1685fSDinh Nguyen 1947540ccba0SVahram Aharonyan /* 1948540ccba0SVahram Aharonyan * dwc2_gadget_complete_isoc_request_ddma - complete an isoc request in DDMA 1949540ccba0SVahram Aharonyan * @hs_ep: The endpoint the request was on. 1950540ccba0SVahram Aharonyan * 1951540ccba0SVahram Aharonyan * Get first request from the ep queue, determine descriptor on which complete 1952540ccba0SVahram Aharonyan * happened. SW based on isoc_chain_num discovers which half of the descriptor 1953540ccba0SVahram Aharonyan * chain is currently in use by HW, adjusts dma_address and calculates index 1954540ccba0SVahram Aharonyan * of completed descriptor based on the value of DEPDMA register. Update actual 1955540ccba0SVahram Aharonyan * length of request, giveback to gadget. 1956540ccba0SVahram Aharonyan */ 1957540ccba0SVahram Aharonyan static void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep) 1958540ccba0SVahram Aharonyan { 1959540ccba0SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 1960540ccba0SVahram Aharonyan struct dwc2_hsotg_req *hs_req; 1961540ccba0SVahram Aharonyan struct usb_request *ureq; 1962540ccba0SVahram Aharonyan int index; 1963540ccba0SVahram Aharonyan dma_addr_t dma_addr; 1964540ccba0SVahram Aharonyan u32 dma_reg; 1965540ccba0SVahram Aharonyan u32 depdma; 1966540ccba0SVahram Aharonyan u32 desc_sts; 1967540ccba0SVahram Aharonyan u32 mask; 1968540ccba0SVahram Aharonyan 1969540ccba0SVahram Aharonyan hs_req = get_ep_head(hs_ep); 1970540ccba0SVahram Aharonyan if (!hs_req) { 1971540ccba0SVahram Aharonyan dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n", __func__); 1972540ccba0SVahram Aharonyan return; 1973540ccba0SVahram Aharonyan } 1974540ccba0SVahram Aharonyan ureq = &hs_req->req; 1975540ccba0SVahram Aharonyan 1976540ccba0SVahram Aharonyan dma_addr = hs_ep->desc_list_dma; 1977540ccba0SVahram Aharonyan 1978540ccba0SVahram Aharonyan /* 1979540ccba0SVahram Aharonyan * If lower half of descriptor chain is currently use by SW, 1980540ccba0SVahram Aharonyan * that means higher half is being processed by HW, so shift 1981540ccba0SVahram Aharonyan * DMA address to higher half of descriptor chain. 1982540ccba0SVahram Aharonyan */ 1983540ccba0SVahram Aharonyan if (!hs_ep->isoc_chain_num) 1984540ccba0SVahram Aharonyan dma_addr += sizeof(struct dwc2_dma_desc) * 1985540ccba0SVahram Aharonyan (MAX_DMA_DESC_NUM_GENERIC / 2); 1986540ccba0SVahram Aharonyan 1987540ccba0SVahram Aharonyan dma_reg = hs_ep->dir_in ? DIEPDMA(hs_ep->index) : DOEPDMA(hs_ep->index); 1988540ccba0SVahram Aharonyan depdma = dwc2_readl(hsotg->regs + dma_reg); 1989540ccba0SVahram Aharonyan 1990540ccba0SVahram Aharonyan index = (depdma - dma_addr) / sizeof(struct dwc2_dma_desc) - 1; 1991540ccba0SVahram Aharonyan desc_sts = hs_ep->desc_list[index].status; 1992540ccba0SVahram Aharonyan 1993540ccba0SVahram Aharonyan mask = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_MASK : 1994540ccba0SVahram Aharonyan DEV_DMA_ISOC_RX_NBYTES_MASK; 1995540ccba0SVahram Aharonyan ureq->actual = ureq->length - 1996540ccba0SVahram Aharonyan ((desc_sts & mask) >> DEV_DMA_ISOC_NBYTES_SHIFT); 1997540ccba0SVahram Aharonyan 199895d2b037SVahram Aharonyan /* Adjust actual length for ISOC Out if length is not align of 4 */ 199995d2b037SVahram Aharonyan if (!hs_ep->dir_in && ureq->length & 0x3) 200095d2b037SVahram Aharonyan ureq->actual += 4 - (ureq->length & 0x3); 200195d2b037SVahram Aharonyan 2002540ccba0SVahram Aharonyan dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 2003540ccba0SVahram Aharonyan } 2004540ccba0SVahram Aharonyan 2005540ccba0SVahram Aharonyan /* 2006540ccba0SVahram Aharonyan * dwc2_gadget_start_next_isoc_ddma - start next isoc request, if any. 2007540ccba0SVahram Aharonyan * @hs_ep: The isochronous endpoint to be re-enabled. 2008540ccba0SVahram Aharonyan * 2009540ccba0SVahram Aharonyan * If ep has been disabled due to last descriptor servicing (IN endpoint) or 2010540ccba0SVahram Aharonyan * BNA (OUT endpoint) check the status of other half of descriptor chain that 2011540ccba0SVahram Aharonyan * was under SW control till HW was busy and restart the endpoint if needed. 2012540ccba0SVahram Aharonyan */ 2013540ccba0SVahram Aharonyan static void dwc2_gadget_start_next_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) 2014540ccba0SVahram Aharonyan { 2015540ccba0SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 2016540ccba0SVahram Aharonyan u32 depctl; 2017540ccba0SVahram Aharonyan u32 dma_reg; 2018540ccba0SVahram Aharonyan u32 ctrl; 2019540ccba0SVahram Aharonyan u32 dma_addr = hs_ep->desc_list_dma; 2020540ccba0SVahram Aharonyan unsigned char index = hs_ep->index; 2021540ccba0SVahram Aharonyan 2022540ccba0SVahram Aharonyan dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index); 2023540ccba0SVahram Aharonyan depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 2024540ccba0SVahram Aharonyan 2025540ccba0SVahram Aharonyan ctrl = dwc2_readl(hsotg->regs + depctl); 2026540ccba0SVahram Aharonyan 2027540ccba0SVahram Aharonyan /* 2028540ccba0SVahram Aharonyan * EP was disabled if HW has processed last descriptor or BNA was set. 2029540ccba0SVahram Aharonyan * So restart ep if SW has prepared new descriptor chain in ep_queue 2030540ccba0SVahram Aharonyan * routine while HW was busy. 2031540ccba0SVahram Aharonyan */ 2032540ccba0SVahram Aharonyan if (!(ctrl & DXEPCTL_EPENA)) { 2033540ccba0SVahram Aharonyan if (!hs_ep->next_desc) { 2034540ccba0SVahram Aharonyan dev_dbg(hsotg->dev, "%s: No more ISOC requests\n", 2035540ccba0SVahram Aharonyan __func__); 2036540ccba0SVahram Aharonyan return; 2037540ccba0SVahram Aharonyan } 2038540ccba0SVahram Aharonyan 2039540ccba0SVahram Aharonyan dma_addr += sizeof(struct dwc2_dma_desc) * 2040540ccba0SVahram Aharonyan (MAX_DMA_DESC_NUM_GENERIC / 2) * 2041540ccba0SVahram Aharonyan hs_ep->isoc_chain_num; 2042540ccba0SVahram Aharonyan dwc2_writel(dma_addr, hsotg->regs + dma_reg); 2043540ccba0SVahram Aharonyan 2044540ccba0SVahram Aharonyan ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK; 2045540ccba0SVahram Aharonyan dwc2_writel(ctrl, hsotg->regs + depctl); 2046540ccba0SVahram Aharonyan 2047540ccba0SVahram Aharonyan /* Switch ISOC descriptor chain number being processed by SW*/ 2048540ccba0SVahram Aharonyan hs_ep->isoc_chain_num = (hs_ep->isoc_chain_num ^ 1) & 0x1; 2049540ccba0SVahram Aharonyan hs_ep->next_desc = 0; 2050540ccba0SVahram Aharonyan 2051540ccba0SVahram Aharonyan dev_dbg(hsotg->dev, "%s: Restarted isochronous endpoint\n", 2052540ccba0SVahram Aharonyan __func__); 2053540ccba0SVahram Aharonyan } 2054540ccba0SVahram Aharonyan } 2055540ccba0SVahram Aharonyan 205647a1685fSDinh Nguyen /** 20571f91b4ccSFelipe Balbi * dwc2_hsotg_rx_data - receive data from the FIFO for an endpoint 205847a1685fSDinh Nguyen * @hsotg: The device state. 205947a1685fSDinh Nguyen * @ep_idx: The endpoint index for the data 206047a1685fSDinh Nguyen * @size: The size of data in the fifo, in bytes 206147a1685fSDinh Nguyen * 206247a1685fSDinh Nguyen * The FIFO status shows there is data to read from the FIFO for a given 206347a1685fSDinh Nguyen * endpoint, so sort out whether we need to read the data into a request 206447a1685fSDinh Nguyen * that has been made for that endpoint. 206547a1685fSDinh Nguyen */ 20661f91b4ccSFelipe Balbi static void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size) 206747a1685fSDinh Nguyen { 20681f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[ep_idx]; 20691f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 207047a1685fSDinh Nguyen void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx); 207147a1685fSDinh Nguyen int to_read; 207247a1685fSDinh Nguyen int max_req; 207347a1685fSDinh Nguyen int read_ptr; 207447a1685fSDinh Nguyen 207547a1685fSDinh Nguyen if (!hs_req) { 207695c8bc36SAntti Seppälä u32 epctl = dwc2_readl(hsotg->regs + DOEPCTL(ep_idx)); 207747a1685fSDinh Nguyen int ptr; 207847a1685fSDinh Nguyen 20796b448af4SRobert Baldyga dev_dbg(hsotg->dev, 208047a1685fSDinh Nguyen "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", 208147a1685fSDinh Nguyen __func__, size, ep_idx, epctl); 208247a1685fSDinh Nguyen 208347a1685fSDinh Nguyen /* dump the data from the FIFO, we've nothing we can do */ 208447a1685fSDinh Nguyen for (ptr = 0; ptr < size; ptr += 4) 208595c8bc36SAntti Seppälä (void)dwc2_readl(fifo); 208647a1685fSDinh Nguyen 208747a1685fSDinh Nguyen return; 208847a1685fSDinh Nguyen } 208947a1685fSDinh Nguyen 209047a1685fSDinh Nguyen to_read = size; 209147a1685fSDinh Nguyen read_ptr = hs_req->req.actual; 209247a1685fSDinh Nguyen max_req = hs_req->req.length - read_ptr; 209347a1685fSDinh Nguyen 209447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", 209547a1685fSDinh Nguyen __func__, to_read, max_req, read_ptr, hs_req->req.length); 209647a1685fSDinh Nguyen 209747a1685fSDinh Nguyen if (to_read > max_req) { 209847a1685fSDinh Nguyen /* 209947a1685fSDinh Nguyen * more data appeared than we where willing 210047a1685fSDinh Nguyen * to deal with in this request. 210147a1685fSDinh Nguyen */ 210247a1685fSDinh Nguyen 210347a1685fSDinh Nguyen /* currently we don't deal this */ 210447a1685fSDinh Nguyen WARN_ON_ONCE(1); 210547a1685fSDinh Nguyen } 210647a1685fSDinh Nguyen 210747a1685fSDinh Nguyen hs_ep->total_data += to_read; 210847a1685fSDinh Nguyen hs_req->req.actual += to_read; 210947a1685fSDinh Nguyen to_read = DIV_ROUND_UP(to_read, 4); 211047a1685fSDinh Nguyen 211147a1685fSDinh Nguyen /* 211247a1685fSDinh Nguyen * note, we might over-write the buffer end by 3 bytes depending on 211347a1685fSDinh Nguyen * alignment of the data. 211447a1685fSDinh Nguyen */ 211547a1685fSDinh Nguyen ioread32_rep(fifo, hs_req->req.buf + read_ptr, to_read); 211647a1685fSDinh Nguyen } 211747a1685fSDinh Nguyen 211847a1685fSDinh Nguyen /** 21191f91b4ccSFelipe Balbi * dwc2_hsotg_ep0_zlp - send/receive zero-length packet on control endpoint 212047a1685fSDinh Nguyen * @hsotg: The device instance 2121fe0b94abSMian Yousaf Kaukab * @dir_in: If IN zlp 212247a1685fSDinh Nguyen * 212347a1685fSDinh Nguyen * Generate a zero-length IN packet request for terminating a SETUP 212447a1685fSDinh Nguyen * transaction. 212547a1685fSDinh Nguyen * 212647a1685fSDinh Nguyen * Note, since we don't write any data to the TxFIFO, then it is 212747a1685fSDinh Nguyen * currently believed that we do not need to wait for any space in 212847a1685fSDinh Nguyen * the TxFIFO. 212947a1685fSDinh Nguyen */ 21301f91b4ccSFelipe Balbi static void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in) 213147a1685fSDinh Nguyen { 2132c6f5c050SMian Yousaf Kaukab /* eps_out[0] is used in both directions */ 2133fe0b94abSMian Yousaf Kaukab hsotg->eps_out[0]->dir_in = dir_in; 2134fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = dir_in ? DWC2_EP0_STATUS_IN : DWC2_EP0_STATUS_OUT; 213547a1685fSDinh Nguyen 21361f91b4ccSFelipe Balbi dwc2_hsotg_program_zlp(hsotg, hsotg->eps_out[0]); 213747a1685fSDinh Nguyen } 213847a1685fSDinh Nguyen 2139ec1f9d9fSRoman Bacik static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg, 2140ec1f9d9fSRoman Bacik u32 epctl_reg) 2141ec1f9d9fSRoman Bacik { 2142ec1f9d9fSRoman Bacik u32 ctrl; 2143ec1f9d9fSRoman Bacik 2144ec1f9d9fSRoman Bacik ctrl = dwc2_readl(hsotg->regs + epctl_reg); 2145ec1f9d9fSRoman Bacik if (ctrl & DXEPCTL_EOFRNUM) 2146ec1f9d9fSRoman Bacik ctrl |= DXEPCTL_SETEVENFR; 2147ec1f9d9fSRoman Bacik else 2148ec1f9d9fSRoman Bacik ctrl |= DXEPCTL_SETODDFR; 2149ec1f9d9fSRoman Bacik dwc2_writel(ctrl, hsotg->regs + epctl_reg); 2150ec1f9d9fSRoman Bacik } 2151ec1f9d9fSRoman Bacik 2152aa3e8bc8SVahram Aharonyan /* 2153aa3e8bc8SVahram Aharonyan * dwc2_gadget_get_xfersize_ddma - get transferred bytes amount from desc 2154aa3e8bc8SVahram Aharonyan * @hs_ep - The endpoint on which transfer went 2155aa3e8bc8SVahram Aharonyan * 2156aa3e8bc8SVahram Aharonyan * Iterate over endpoints descriptor chain and get info on bytes remained 2157aa3e8bc8SVahram Aharonyan * in DMA descriptors after transfer has completed. Used for non isoc EPs. 2158aa3e8bc8SVahram Aharonyan */ 2159aa3e8bc8SVahram Aharonyan static unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep) 2160aa3e8bc8SVahram Aharonyan { 2161aa3e8bc8SVahram Aharonyan struct dwc2_hsotg *hsotg = hs_ep->parent; 2162aa3e8bc8SVahram Aharonyan unsigned int bytes_rem = 0; 2163aa3e8bc8SVahram Aharonyan struct dwc2_dma_desc *desc = hs_ep->desc_list; 2164aa3e8bc8SVahram Aharonyan int i; 2165aa3e8bc8SVahram Aharonyan u32 status; 2166aa3e8bc8SVahram Aharonyan 2167aa3e8bc8SVahram Aharonyan if (!desc) 2168aa3e8bc8SVahram Aharonyan return -EINVAL; 2169aa3e8bc8SVahram Aharonyan 2170aa3e8bc8SVahram Aharonyan for (i = 0; i < hs_ep->desc_count; ++i) { 2171aa3e8bc8SVahram Aharonyan status = desc->status; 2172aa3e8bc8SVahram Aharonyan bytes_rem += status & DEV_DMA_NBYTES_MASK; 2173aa3e8bc8SVahram Aharonyan 2174aa3e8bc8SVahram Aharonyan if (status & DEV_DMA_STS_MASK) 2175aa3e8bc8SVahram Aharonyan dev_err(hsotg->dev, "descriptor %d closed with %x\n", 2176aa3e8bc8SVahram Aharonyan i, status & DEV_DMA_STS_MASK); 2177aa3e8bc8SVahram Aharonyan } 2178aa3e8bc8SVahram Aharonyan 2179aa3e8bc8SVahram Aharonyan return bytes_rem; 2180aa3e8bc8SVahram Aharonyan } 2181aa3e8bc8SVahram Aharonyan 218247a1685fSDinh Nguyen /** 21831f91b4ccSFelipe Balbi * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO 218447a1685fSDinh Nguyen * @hsotg: The device instance 218547a1685fSDinh Nguyen * @epnum: The endpoint received from 218647a1685fSDinh Nguyen * 218747a1685fSDinh Nguyen * The RXFIFO has delivered an OutDone event, which means that the data 218847a1685fSDinh Nguyen * transfer for an OUT endpoint has been completed, either by a short 218947a1685fSDinh Nguyen * packet or by the finish of a transfer. 219047a1685fSDinh Nguyen */ 21911f91b4ccSFelipe Balbi static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) 219247a1685fSDinh Nguyen { 219395c8bc36SAntti Seppälä u32 epsize = dwc2_readl(hsotg->regs + DOEPTSIZ(epnum)); 21941f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[epnum]; 21951f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 219647a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 21979da51974SJohn Youn unsigned int size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 219847a1685fSDinh Nguyen int result = 0; 219947a1685fSDinh Nguyen 220047a1685fSDinh Nguyen if (!hs_req) { 220147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no request active\n", __func__); 220247a1685fSDinh Nguyen return; 220347a1685fSDinh Nguyen } 220447a1685fSDinh Nguyen 2205fe0b94abSMian Yousaf Kaukab if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_OUT) { 2206fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "zlp packet received\n"); 22071f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 22081f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 2209fe0b94abSMian Yousaf Kaukab return; 2210fe0b94abSMian Yousaf Kaukab } 2211fe0b94abSMian Yousaf Kaukab 2212aa3e8bc8SVahram Aharonyan if (using_desc_dma(hsotg)) 2213aa3e8bc8SVahram Aharonyan size_left = dwc2_gadget_get_xfersize_ddma(hs_ep); 2214aa3e8bc8SVahram Aharonyan 221547a1685fSDinh Nguyen if (using_dma(hsotg)) { 22169da51974SJohn Youn unsigned int size_done; 221747a1685fSDinh Nguyen 221847a1685fSDinh Nguyen /* 221947a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much 222047a1685fSDinh Nguyen * is left in the endpoint size register and then working it 222147a1685fSDinh Nguyen * out from the amount we loaded for the transfer. 222247a1685fSDinh Nguyen * 222347a1685fSDinh Nguyen * We need to do this as DMA pointers are always 32bit aligned 222447a1685fSDinh Nguyen * so may overshoot/undershoot the transfer. 222547a1685fSDinh Nguyen */ 222647a1685fSDinh Nguyen 222747a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 222847a1685fSDinh Nguyen size_done += hs_ep->last_load; 222947a1685fSDinh Nguyen 223047a1685fSDinh Nguyen req->actual = size_done; 223147a1685fSDinh Nguyen } 223247a1685fSDinh Nguyen 223347a1685fSDinh Nguyen /* if there is more request to do, schedule new transfer */ 223447a1685fSDinh Nguyen if (req->actual < req->length && size_left == 0) { 22351f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 223647a1685fSDinh Nguyen return; 223747a1685fSDinh Nguyen } 223847a1685fSDinh Nguyen 223947a1685fSDinh Nguyen if (req->actual < req->length && req->short_not_ok) { 224047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", 224147a1685fSDinh Nguyen __func__, req->actual, req->length); 224247a1685fSDinh Nguyen 224347a1685fSDinh Nguyen /* 224447a1685fSDinh Nguyen * todo - what should we return here? there's no one else 224547a1685fSDinh Nguyen * even bothering to check the status. 224647a1685fSDinh Nguyen */ 224747a1685fSDinh Nguyen } 224847a1685fSDinh Nguyen 2249ef750c71SVahram Aharonyan /* DDMA IN status phase will start from StsPhseRcvd interrupt */ 2250ef750c71SVahram Aharonyan if (!using_desc_dma(hsotg) && epnum == 0 && 2251ef750c71SVahram Aharonyan hsotg->ep0_state == DWC2_EP0_DATA_OUT) { 2252fe0b94abSMian Yousaf Kaukab /* Move to STATUS IN */ 22531f91b4ccSFelipe Balbi dwc2_hsotg_ep0_zlp(hsotg, true); 2254fe0b94abSMian Yousaf Kaukab return; 225547a1685fSDinh Nguyen } 225647a1685fSDinh Nguyen 2257ec1f9d9fSRoman Bacik /* 2258ec1f9d9fSRoman Bacik * Slave mode OUT transfers do not go through XferComplete so 2259ec1f9d9fSRoman Bacik * adjust the ISOC parity here. 2260ec1f9d9fSRoman Bacik */ 2261ec1f9d9fSRoman Bacik if (!using_dma(hsotg)) { 2262ec1f9d9fSRoman Bacik if (hs_ep->isochronous && hs_ep->interval == 1) 2263ec1f9d9fSRoman Bacik dwc2_hsotg_change_ep_iso_parity(hsotg, DOEPCTL(epnum)); 2264837e9f00SVardan Mikayelyan else if (hs_ep->isochronous && hs_ep->interval > 1) 2265837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 2266ec1f9d9fSRoman Bacik } 2267ec1f9d9fSRoman Bacik 22681f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result); 226947a1685fSDinh Nguyen } 227047a1685fSDinh Nguyen 227147a1685fSDinh Nguyen /** 22721f91b4ccSFelipe Balbi * dwc2_hsotg_handle_rx - RX FIFO has data 227347a1685fSDinh Nguyen * @hsotg: The device instance 227447a1685fSDinh Nguyen * 227547a1685fSDinh Nguyen * The IRQ handler has detected that the RX FIFO has some data in it 227647a1685fSDinh Nguyen * that requires processing, so find out what is in there and do the 227747a1685fSDinh Nguyen * appropriate read. 227847a1685fSDinh Nguyen * 227947a1685fSDinh Nguyen * The RXFIFO is a true FIFO, the packets coming out are still in packet 228047a1685fSDinh Nguyen * chunks, so if you have x packets received on an endpoint you'll get x 228147a1685fSDinh Nguyen * FIFO events delivered, each with a packet's worth of data in it. 228247a1685fSDinh Nguyen * 228347a1685fSDinh Nguyen * When using DMA, we should not be processing events from the RXFIFO 228447a1685fSDinh Nguyen * as the actual data should be sent to the memory directly and we turn 228547a1685fSDinh Nguyen * on the completion interrupts to get notifications of transfer completion. 228647a1685fSDinh Nguyen */ 22871f91b4ccSFelipe Balbi static void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg) 228847a1685fSDinh Nguyen { 228995c8bc36SAntti Seppälä u32 grxstsr = dwc2_readl(hsotg->regs + GRXSTSP); 229047a1685fSDinh Nguyen u32 epnum, status, size; 229147a1685fSDinh Nguyen 229247a1685fSDinh Nguyen WARN_ON(using_dma(hsotg)); 229347a1685fSDinh Nguyen 229447a1685fSDinh Nguyen epnum = grxstsr & GRXSTS_EPNUM_MASK; 229547a1685fSDinh Nguyen status = grxstsr & GRXSTS_PKTSTS_MASK; 229647a1685fSDinh Nguyen 229747a1685fSDinh Nguyen size = grxstsr & GRXSTS_BYTECNT_MASK; 229847a1685fSDinh Nguyen size >>= GRXSTS_BYTECNT_SHIFT; 229947a1685fSDinh Nguyen 230047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", 230147a1685fSDinh Nguyen __func__, grxstsr, size, epnum); 230247a1685fSDinh Nguyen 230347a1685fSDinh Nguyen switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { 230447a1685fSDinh Nguyen case GRXSTS_PKTSTS_GLOBALOUTNAK: 230547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GLOBALOUTNAK\n"); 230647a1685fSDinh Nguyen break; 230747a1685fSDinh Nguyen 230847a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTDONE: 230947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", 23101f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg)); 231147a1685fSDinh Nguyen 231247a1685fSDinh Nguyen if (!using_dma(hsotg)) 23131f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, epnum); 231447a1685fSDinh Nguyen break; 231547a1685fSDinh Nguyen 231647a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPDONE: 231747a1685fSDinh Nguyen dev_dbg(hsotg->dev, 231847a1685fSDinh Nguyen "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 23191f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg), 232095c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL(0))); 2321fe0b94abSMian Yousaf Kaukab /* 23221f91b4ccSFelipe Balbi * Call dwc2_hsotg_handle_outdone here if it was not called from 2323fe0b94abSMian Yousaf Kaukab * GRXSTS_PKTSTS_OUTDONE. That is, if the core didn't 2324fe0b94abSMian Yousaf Kaukab * generate GRXSTS_PKTSTS_OUTDONE for setup packet. 2325fe0b94abSMian Yousaf Kaukab */ 2326fe0b94abSMian Yousaf Kaukab if (hsotg->ep0_state == DWC2_EP0_SETUP) 23271f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, epnum); 232847a1685fSDinh Nguyen break; 232947a1685fSDinh Nguyen 233047a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTRX: 23311f91b4ccSFelipe Balbi dwc2_hsotg_rx_data(hsotg, epnum, size); 233247a1685fSDinh Nguyen break; 233347a1685fSDinh Nguyen 233447a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPRX: 233547a1685fSDinh Nguyen dev_dbg(hsotg->dev, 233647a1685fSDinh Nguyen "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 23371f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg), 233895c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL(0))); 233947a1685fSDinh Nguyen 2340fe0b94abSMian Yousaf Kaukab WARN_ON(hsotg->ep0_state != DWC2_EP0_SETUP); 2341fe0b94abSMian Yousaf Kaukab 23421f91b4ccSFelipe Balbi dwc2_hsotg_rx_data(hsotg, epnum, size); 234347a1685fSDinh Nguyen break; 234447a1685fSDinh Nguyen 234547a1685fSDinh Nguyen default: 234647a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: unknown status %08x\n", 234747a1685fSDinh Nguyen __func__, grxstsr); 234847a1685fSDinh Nguyen 23491f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 235047a1685fSDinh Nguyen break; 235147a1685fSDinh Nguyen } 235247a1685fSDinh Nguyen } 235347a1685fSDinh Nguyen 235447a1685fSDinh Nguyen /** 23551f91b4ccSFelipe Balbi * dwc2_hsotg_ep0_mps - turn max packet size into register setting 235647a1685fSDinh Nguyen * @mps: The maximum packet size in bytes. 235747a1685fSDinh Nguyen */ 23581f91b4ccSFelipe Balbi static u32 dwc2_hsotg_ep0_mps(unsigned int mps) 235947a1685fSDinh Nguyen { 236047a1685fSDinh Nguyen switch (mps) { 236147a1685fSDinh Nguyen case 64: 236247a1685fSDinh Nguyen return D0EPCTL_MPS_64; 236347a1685fSDinh Nguyen case 32: 236447a1685fSDinh Nguyen return D0EPCTL_MPS_32; 236547a1685fSDinh Nguyen case 16: 236647a1685fSDinh Nguyen return D0EPCTL_MPS_16; 236747a1685fSDinh Nguyen case 8: 236847a1685fSDinh Nguyen return D0EPCTL_MPS_8; 236947a1685fSDinh Nguyen } 237047a1685fSDinh Nguyen 237147a1685fSDinh Nguyen /* bad max packet size, warn and return invalid result */ 237247a1685fSDinh Nguyen WARN_ON(1); 237347a1685fSDinh Nguyen return (u32)-1; 237447a1685fSDinh Nguyen } 237547a1685fSDinh Nguyen 237647a1685fSDinh Nguyen /** 23771f91b4ccSFelipe Balbi * dwc2_hsotg_set_ep_maxpacket - set endpoint's max-packet field 237847a1685fSDinh Nguyen * @hsotg: The driver state. 237947a1685fSDinh Nguyen * @ep: The index number of the endpoint 238047a1685fSDinh Nguyen * @mps: The maximum packet size in bytes 2381ee2c40deSVardan Mikayelyan * @mc: The multicount value 238247a1685fSDinh Nguyen * 238347a1685fSDinh Nguyen * Configure the maximum packet size for the given endpoint, updating 238447a1685fSDinh Nguyen * the hardware control registers to reflect this. 238547a1685fSDinh Nguyen */ 23861f91b4ccSFelipe Balbi static void dwc2_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg, 2387ee2c40deSVardan Mikayelyan unsigned int ep, unsigned int mps, 2388ee2c40deSVardan Mikayelyan unsigned int mc, unsigned int dir_in) 238947a1685fSDinh Nguyen { 23901f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep; 239147a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 239247a1685fSDinh Nguyen u32 reg; 239347a1685fSDinh Nguyen 2394c6f5c050SMian Yousaf Kaukab hs_ep = index_to_ep(hsotg, ep, dir_in); 2395c6f5c050SMian Yousaf Kaukab if (!hs_ep) 2396c6f5c050SMian Yousaf Kaukab return; 2397c6f5c050SMian Yousaf Kaukab 239847a1685fSDinh Nguyen if (ep == 0) { 2399ee2c40deSVardan Mikayelyan u32 mps_bytes = mps; 2400ee2c40deSVardan Mikayelyan 240147a1685fSDinh Nguyen /* EP0 is a special case */ 2402ee2c40deSVardan Mikayelyan mps = dwc2_hsotg_ep0_mps(mps_bytes); 2403ee2c40deSVardan Mikayelyan if (mps > 3) 240447a1685fSDinh Nguyen goto bad_mps; 2405ee2c40deSVardan Mikayelyan hs_ep->ep.maxpacket = mps_bytes; 240647a1685fSDinh Nguyen hs_ep->mc = 1; 240747a1685fSDinh Nguyen } else { 2408ee2c40deSVardan Mikayelyan if (mps > 1024) 240947a1685fSDinh Nguyen goto bad_mps; 2410ee2c40deSVardan Mikayelyan hs_ep->mc = mc; 2411ee2c40deSVardan Mikayelyan if (mc > 3) 241247a1685fSDinh Nguyen goto bad_mps; 2413ee2c40deSVardan Mikayelyan hs_ep->ep.maxpacket = mps; 241447a1685fSDinh Nguyen } 241547a1685fSDinh Nguyen 2416c6f5c050SMian Yousaf Kaukab if (dir_in) { 241795c8bc36SAntti Seppälä reg = dwc2_readl(regs + DIEPCTL(ep)); 241847a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 2419ee2c40deSVardan Mikayelyan reg |= mps; 242095c8bc36SAntti Seppälä dwc2_writel(reg, regs + DIEPCTL(ep)); 2421c6f5c050SMian Yousaf Kaukab } else { 242295c8bc36SAntti Seppälä reg = dwc2_readl(regs + DOEPCTL(ep)); 242347a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 2424ee2c40deSVardan Mikayelyan reg |= mps; 242595c8bc36SAntti Seppälä dwc2_writel(reg, regs + DOEPCTL(ep)); 242647a1685fSDinh Nguyen } 242747a1685fSDinh Nguyen 242847a1685fSDinh Nguyen return; 242947a1685fSDinh Nguyen 243047a1685fSDinh Nguyen bad_mps: 243147a1685fSDinh Nguyen dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); 243247a1685fSDinh Nguyen } 243347a1685fSDinh Nguyen 243447a1685fSDinh Nguyen /** 24351f91b4ccSFelipe Balbi * dwc2_hsotg_txfifo_flush - flush Tx FIFO 243647a1685fSDinh Nguyen * @hsotg: The driver state 243747a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 243847a1685fSDinh Nguyen */ 24391f91b4ccSFelipe Balbi static void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx) 244047a1685fSDinh Nguyen { 244147a1685fSDinh Nguyen int timeout; 244247a1685fSDinh Nguyen int val; 244347a1685fSDinh Nguyen 244495c8bc36SAntti Seppälä dwc2_writel(GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH, 244547a1685fSDinh Nguyen hsotg->regs + GRSTCTL); 244647a1685fSDinh Nguyen 244747a1685fSDinh Nguyen /* wait until the fifo is flushed */ 244847a1685fSDinh Nguyen timeout = 100; 244947a1685fSDinh Nguyen 245047a1685fSDinh Nguyen while (1) { 245195c8bc36SAntti Seppälä val = dwc2_readl(hsotg->regs + GRSTCTL); 245247a1685fSDinh Nguyen 245347a1685fSDinh Nguyen if ((val & (GRSTCTL_TXFFLSH)) == 0) 245447a1685fSDinh Nguyen break; 245547a1685fSDinh Nguyen 245647a1685fSDinh Nguyen if (--timeout == 0) { 245747a1685fSDinh Nguyen dev_err(hsotg->dev, 245847a1685fSDinh Nguyen "%s: timeout flushing fifo (GRSTCTL=%08x)\n", 245947a1685fSDinh Nguyen __func__, val); 2460e0cbe595SMarek Szyprowski break; 246147a1685fSDinh Nguyen } 246247a1685fSDinh Nguyen 246347a1685fSDinh Nguyen udelay(1); 246447a1685fSDinh Nguyen } 246547a1685fSDinh Nguyen } 246647a1685fSDinh Nguyen 246747a1685fSDinh Nguyen /** 24681f91b4ccSFelipe Balbi * dwc2_hsotg_trytx - check to see if anything needs transmitting 246947a1685fSDinh Nguyen * @hsotg: The driver state 247047a1685fSDinh Nguyen * @hs_ep: The driver endpoint to check. 247147a1685fSDinh Nguyen * 247247a1685fSDinh Nguyen * Check to see if there is a request that has data to send, and if so 247347a1685fSDinh Nguyen * make an attempt to write data into the FIFO. 247447a1685fSDinh Nguyen */ 24751f91b4ccSFelipe Balbi static int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, 24761f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 247747a1685fSDinh Nguyen { 24781f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 247947a1685fSDinh Nguyen 248047a1685fSDinh Nguyen if (!hs_ep->dir_in || !hs_req) { 248147a1685fSDinh Nguyen /** 248247a1685fSDinh Nguyen * if request is not enqueued, we disable interrupts 248347a1685fSDinh Nguyen * for endpoints, excepting ep0 248447a1685fSDinh Nguyen */ 248547a1685fSDinh Nguyen if (hs_ep->index != 0) 24861f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, 248747a1685fSDinh Nguyen hs_ep->dir_in, 0); 248847a1685fSDinh Nguyen return 0; 248947a1685fSDinh Nguyen } 249047a1685fSDinh Nguyen 249147a1685fSDinh Nguyen if (hs_req->req.actual < hs_req->req.length) { 249247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "trying to write more for ep%d\n", 249347a1685fSDinh Nguyen hs_ep->index); 24941f91b4ccSFelipe Balbi return dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 249547a1685fSDinh Nguyen } 249647a1685fSDinh Nguyen 249747a1685fSDinh Nguyen return 0; 249847a1685fSDinh Nguyen } 249947a1685fSDinh Nguyen 250047a1685fSDinh Nguyen /** 25011f91b4ccSFelipe Balbi * dwc2_hsotg_complete_in - complete IN transfer 250247a1685fSDinh Nguyen * @hsotg: The device state. 250347a1685fSDinh Nguyen * @hs_ep: The endpoint that has just completed. 250447a1685fSDinh Nguyen * 250547a1685fSDinh Nguyen * An IN transfer has been completed, update the transfer's state and then 250647a1685fSDinh Nguyen * call the relevant completion routines. 250747a1685fSDinh Nguyen */ 25081f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, 25091f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 251047a1685fSDinh Nguyen { 25111f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 251295c8bc36SAntti Seppälä u32 epsize = dwc2_readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); 251347a1685fSDinh Nguyen int size_left, size_done; 251447a1685fSDinh Nguyen 251547a1685fSDinh Nguyen if (!hs_req) { 251647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "XferCompl but no req\n"); 251747a1685fSDinh Nguyen return; 251847a1685fSDinh Nguyen } 251947a1685fSDinh Nguyen 252047a1685fSDinh Nguyen /* Finish ZLP handling for IN EP0 transactions */ 2521fe0b94abSMian Yousaf Kaukab if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) { 2522fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "zlp packet sent\n"); 2523c3b22fe2SRazmik Karapetyan 2524c3b22fe2SRazmik Karapetyan /* 2525c3b22fe2SRazmik Karapetyan * While send zlp for DWC2_EP0_STATUS_IN EP direction was 2526c3b22fe2SRazmik Karapetyan * changed to IN. Change back to complete OUT transfer request 2527c3b22fe2SRazmik Karapetyan */ 2528c3b22fe2SRazmik Karapetyan hs_ep->dir_in = 0; 2529c3b22fe2SRazmik Karapetyan 25301f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 25319e14d0a5SGregory Herrero if (hsotg->test_mode) { 25329e14d0a5SGregory Herrero int ret; 25339e14d0a5SGregory Herrero 25341f91b4ccSFelipe Balbi ret = dwc2_hsotg_set_test_mode(hsotg, hsotg->test_mode); 25359e14d0a5SGregory Herrero if (ret < 0) { 25369e14d0a5SGregory Herrero dev_dbg(hsotg->dev, "Invalid Test #%d\n", 25379e14d0a5SGregory Herrero hsotg->test_mode); 25381f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hsotg); 25399e14d0a5SGregory Herrero return; 25409e14d0a5SGregory Herrero } 25419e14d0a5SGregory Herrero } 25421f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 254347a1685fSDinh Nguyen return; 254447a1685fSDinh Nguyen } 254547a1685fSDinh Nguyen 254647a1685fSDinh Nguyen /* 254747a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much is left 254847a1685fSDinh Nguyen * in the endpoint size register and then working it out from 254947a1685fSDinh Nguyen * the amount we loaded for the transfer. 255047a1685fSDinh Nguyen * 255147a1685fSDinh Nguyen * We do this even for DMA, as the transfer may have incremented 255247a1685fSDinh Nguyen * past the end of the buffer (DMA transfers are always 32bit 255347a1685fSDinh Nguyen * aligned). 255447a1685fSDinh Nguyen */ 2555aa3e8bc8SVahram Aharonyan if (using_desc_dma(hsotg)) { 2556aa3e8bc8SVahram Aharonyan size_left = dwc2_gadget_get_xfersize_ddma(hs_ep); 2557aa3e8bc8SVahram Aharonyan if (size_left < 0) 2558aa3e8bc8SVahram Aharonyan dev_err(hsotg->dev, "error parsing DDMA results %d\n", 2559aa3e8bc8SVahram Aharonyan size_left); 2560aa3e8bc8SVahram Aharonyan } else { 256147a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 2562aa3e8bc8SVahram Aharonyan } 256347a1685fSDinh Nguyen 256447a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 256547a1685fSDinh Nguyen size_done += hs_ep->last_load; 256647a1685fSDinh Nguyen 256747a1685fSDinh Nguyen if (hs_req->req.actual != size_done) 256847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", 256947a1685fSDinh Nguyen __func__, hs_req->req.actual, size_done); 257047a1685fSDinh Nguyen 257147a1685fSDinh Nguyen hs_req->req.actual = size_done; 257247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", 257347a1685fSDinh Nguyen hs_req->req.length, hs_req->req.actual, hs_req->req.zero); 257447a1685fSDinh Nguyen 257547a1685fSDinh Nguyen if (!size_left && hs_req->req.actual < hs_req->req.length) { 257647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); 25771f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 2578fe0b94abSMian Yousaf Kaukab return; 2579fe0b94abSMian Yousaf Kaukab } 2580fe0b94abSMian Yousaf Kaukab 2581f71b5e25SMian Yousaf Kaukab /* Zlp for all endpoints, for ep0 only in DATA IN stage */ 25828a20fa45SMian Yousaf Kaukab if (hs_ep->send_zlp) { 25831f91b4ccSFelipe Balbi dwc2_hsotg_program_zlp(hsotg, hs_ep); 25848a20fa45SMian Yousaf Kaukab hs_ep->send_zlp = 0; 2585f71b5e25SMian Yousaf Kaukab /* transfer will be completed on next complete interrupt */ 2586f71b5e25SMian Yousaf Kaukab return; 2587f71b5e25SMian Yousaf Kaukab } 2588f71b5e25SMian Yousaf Kaukab 2589fe0b94abSMian Yousaf Kaukab if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_DATA_IN) { 2590fe0b94abSMian Yousaf Kaukab /* Move to STATUS OUT */ 25911f91b4ccSFelipe Balbi dwc2_hsotg_ep0_zlp(hsotg, false); 2592fe0b94abSMian Yousaf Kaukab return; 2593fe0b94abSMian Yousaf Kaukab } 2594fe0b94abSMian Yousaf Kaukab 25951f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 259647a1685fSDinh Nguyen } 259747a1685fSDinh Nguyen 259847a1685fSDinh Nguyen /** 259932601588SVardan Mikayelyan * dwc2_gadget_read_ep_interrupts - reads interrupts for given ep 260032601588SVardan Mikayelyan * @hsotg: The device state. 260132601588SVardan Mikayelyan * @idx: Index of ep. 260232601588SVardan Mikayelyan * @dir_in: Endpoint direction 1-in 0-out. 260332601588SVardan Mikayelyan * 260432601588SVardan Mikayelyan * Reads for endpoint with given index and direction, by masking 260532601588SVardan Mikayelyan * epint_reg with coresponding mask. 260632601588SVardan Mikayelyan */ 260732601588SVardan Mikayelyan static u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg, 260832601588SVardan Mikayelyan unsigned int idx, int dir_in) 260932601588SVardan Mikayelyan { 261032601588SVardan Mikayelyan u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; 261132601588SVardan Mikayelyan u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 261232601588SVardan Mikayelyan u32 ints; 261332601588SVardan Mikayelyan u32 mask; 261432601588SVardan Mikayelyan u32 diepempmsk; 261532601588SVardan Mikayelyan 261632601588SVardan Mikayelyan mask = dwc2_readl(hsotg->regs + epmsk_reg); 261732601588SVardan Mikayelyan diepempmsk = dwc2_readl(hsotg->regs + DIEPEMPMSK); 261832601588SVardan Mikayelyan mask |= ((diepempmsk >> idx) & 0x1) ? DIEPMSK_TXFIFOEMPTY : 0; 261932601588SVardan Mikayelyan mask |= DXEPINT_SETUP_RCVD; 262032601588SVardan Mikayelyan 262132601588SVardan Mikayelyan ints = dwc2_readl(hsotg->regs + epint_reg); 262232601588SVardan Mikayelyan ints &= mask; 262332601588SVardan Mikayelyan return ints; 262432601588SVardan Mikayelyan } 262532601588SVardan Mikayelyan 262632601588SVardan Mikayelyan /** 2627bd9971f0SVardan Mikayelyan * dwc2_gadget_handle_ep_disabled - handle DXEPINT_EPDISBLD 2628bd9971f0SVardan Mikayelyan * @hs_ep: The endpoint on which interrupt is asserted. 2629bd9971f0SVardan Mikayelyan * 2630bd9971f0SVardan Mikayelyan * This interrupt indicates that the endpoint has been disabled per the 2631bd9971f0SVardan Mikayelyan * application's request. 2632bd9971f0SVardan Mikayelyan * 2633bd9971f0SVardan Mikayelyan * For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK, 2634bd9971f0SVardan Mikayelyan * in case of ISOC completes current request. 2635bd9971f0SVardan Mikayelyan * 2636bd9971f0SVardan Mikayelyan * For ISOC-OUT endpoints completes expired requests. If there is remaining 2637bd9971f0SVardan Mikayelyan * request starts it. 2638bd9971f0SVardan Mikayelyan */ 2639bd9971f0SVardan Mikayelyan static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) 2640bd9971f0SVardan Mikayelyan { 2641bd9971f0SVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 2642bd9971f0SVardan Mikayelyan struct dwc2_hsotg_req *hs_req; 2643bd9971f0SVardan Mikayelyan unsigned char idx = hs_ep->index; 2644bd9971f0SVardan Mikayelyan int dir_in = hs_ep->dir_in; 2645bd9971f0SVardan Mikayelyan u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 2646bd9971f0SVardan Mikayelyan int dctl = dwc2_readl(hsotg->regs + DCTL); 2647bd9971f0SVardan Mikayelyan 2648bd9971f0SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); 2649bd9971f0SVardan Mikayelyan 2650bd9971f0SVardan Mikayelyan if (dir_in) { 2651bd9971f0SVardan Mikayelyan int epctl = dwc2_readl(hsotg->regs + epctl_reg); 2652bd9971f0SVardan Mikayelyan 2653bd9971f0SVardan Mikayelyan dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); 2654bd9971f0SVardan Mikayelyan 2655bd9971f0SVardan Mikayelyan if (hs_ep->isochronous) { 2656bd9971f0SVardan Mikayelyan dwc2_hsotg_complete_in(hsotg, hs_ep); 2657bd9971f0SVardan Mikayelyan return; 2658bd9971f0SVardan Mikayelyan } 2659bd9971f0SVardan Mikayelyan 2660bd9971f0SVardan Mikayelyan if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) { 2661bd9971f0SVardan Mikayelyan int dctl = dwc2_readl(hsotg->regs + DCTL); 2662bd9971f0SVardan Mikayelyan 2663bd9971f0SVardan Mikayelyan dctl |= DCTL_CGNPINNAK; 2664bd9971f0SVardan Mikayelyan dwc2_writel(dctl, hsotg->regs + DCTL); 2665bd9971f0SVardan Mikayelyan } 2666bd9971f0SVardan Mikayelyan return; 2667bd9971f0SVardan Mikayelyan } 2668bd9971f0SVardan Mikayelyan 2669bd9971f0SVardan Mikayelyan if (dctl & DCTL_GOUTNAKSTS) { 2670bd9971f0SVardan Mikayelyan dctl |= DCTL_CGOUTNAK; 2671bd9971f0SVardan Mikayelyan dwc2_writel(dctl, hsotg->regs + DCTL); 2672bd9971f0SVardan Mikayelyan } 2673bd9971f0SVardan Mikayelyan 2674bd9971f0SVardan Mikayelyan if (!hs_ep->isochronous) 2675bd9971f0SVardan Mikayelyan return; 2676bd9971f0SVardan Mikayelyan 2677bd9971f0SVardan Mikayelyan if (list_empty(&hs_ep->queue)) { 2678bd9971f0SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: complete_ep 0x%p, ep->queue empty!\n", 2679bd9971f0SVardan Mikayelyan __func__, hs_ep); 2680bd9971f0SVardan Mikayelyan return; 2681bd9971f0SVardan Mikayelyan } 2682bd9971f0SVardan Mikayelyan 2683bd9971f0SVardan Mikayelyan do { 2684bd9971f0SVardan Mikayelyan hs_req = get_ep_head(hs_ep); 2685bd9971f0SVardan Mikayelyan if (hs_req) 2686bd9971f0SVardan Mikayelyan dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 2687bd9971f0SVardan Mikayelyan -ENODATA); 2688bd9971f0SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 2689bd9971f0SVardan Mikayelyan } while (dwc2_gadget_target_frame_elapsed(hs_ep)); 2690bd9971f0SVardan Mikayelyan 2691bd9971f0SVardan Mikayelyan dwc2_gadget_start_next_request(hs_ep); 2692bd9971f0SVardan Mikayelyan } 2693bd9971f0SVardan Mikayelyan 2694bd9971f0SVardan Mikayelyan /** 26955321922cSVardan Mikayelyan * dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS 26965321922cSVardan Mikayelyan * @hs_ep: The endpoint on which interrupt is asserted. 26975321922cSVardan Mikayelyan * 26985321922cSVardan Mikayelyan * This is starting point for ISOC-OUT transfer, synchronization done with 26995321922cSVardan Mikayelyan * first out token received from host while corresponding EP is disabled. 27005321922cSVardan Mikayelyan * 27015321922cSVardan Mikayelyan * Device does not know initial frame in which out token will come. For this 27025321922cSVardan Mikayelyan * HW generates OUTTKNEPDIS - out token is received while EP is disabled. Upon 27035321922cSVardan Mikayelyan * getting this interrupt SW starts calculation for next transfer frame. 27045321922cSVardan Mikayelyan */ 27055321922cSVardan Mikayelyan static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) 27065321922cSVardan Mikayelyan { 27075321922cSVardan Mikayelyan struct dwc2_hsotg *hsotg = ep->parent; 27085321922cSVardan Mikayelyan int dir_in = ep->dir_in; 27095321922cSVardan Mikayelyan u32 doepmsk; 2710540ccba0SVahram Aharonyan u32 tmp; 27115321922cSVardan Mikayelyan 27125321922cSVardan Mikayelyan if (dir_in || !ep->isochronous) 27135321922cSVardan Mikayelyan return; 27145321922cSVardan Mikayelyan 2715540ccba0SVahram Aharonyan /* 2716540ccba0SVahram Aharonyan * Store frame in which irq was asserted here, as 2717540ccba0SVahram Aharonyan * it can change while completing request below. 2718540ccba0SVahram Aharonyan */ 2719540ccba0SVahram Aharonyan tmp = dwc2_hsotg_read_frameno(hsotg); 2720540ccba0SVahram Aharonyan 27215321922cSVardan Mikayelyan dwc2_hsotg_complete_request(hsotg, ep, get_ep_head(ep), -ENODATA); 27225321922cSVardan Mikayelyan 2723540ccba0SVahram Aharonyan if (using_desc_dma(hsotg)) { 2724540ccba0SVahram Aharonyan if (ep->target_frame == TARGET_FRAME_INITIAL) { 2725540ccba0SVahram Aharonyan /* Start first ISO Out */ 2726540ccba0SVahram Aharonyan ep->target_frame = tmp; 2727540ccba0SVahram Aharonyan dwc2_gadget_start_isoc_ddma(ep); 2728540ccba0SVahram Aharonyan } 2729540ccba0SVahram Aharonyan return; 2730540ccba0SVahram Aharonyan } 2731540ccba0SVahram Aharonyan 27325321922cSVardan Mikayelyan if (ep->interval > 1 && 27335321922cSVardan Mikayelyan ep->target_frame == TARGET_FRAME_INITIAL) { 27345321922cSVardan Mikayelyan u32 dsts; 27355321922cSVardan Mikayelyan u32 ctrl; 27365321922cSVardan Mikayelyan 27375321922cSVardan Mikayelyan dsts = dwc2_readl(hsotg->regs + DSTS); 27385321922cSVardan Mikayelyan ep->target_frame = dwc2_hsotg_read_frameno(hsotg); 27395321922cSVardan Mikayelyan dwc2_gadget_incr_frame_num(ep); 27405321922cSVardan Mikayelyan 27415321922cSVardan Mikayelyan ctrl = dwc2_readl(hsotg->regs + DOEPCTL(ep->index)); 27425321922cSVardan Mikayelyan if (ep->target_frame & 0x1) 27435321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETODDFR; 27445321922cSVardan Mikayelyan else 27455321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETEVENFR; 27465321922cSVardan Mikayelyan 27475321922cSVardan Mikayelyan dwc2_writel(ctrl, hsotg->regs + DOEPCTL(ep->index)); 27485321922cSVardan Mikayelyan } 27495321922cSVardan Mikayelyan 27505321922cSVardan Mikayelyan dwc2_gadget_start_next_request(ep); 27515321922cSVardan Mikayelyan doepmsk = dwc2_readl(hsotg->regs + DOEPMSK); 27525321922cSVardan Mikayelyan doepmsk &= ~DOEPMSK_OUTTKNEPDISMSK; 27535321922cSVardan Mikayelyan dwc2_writel(doepmsk, hsotg->regs + DOEPMSK); 27545321922cSVardan Mikayelyan } 27555321922cSVardan Mikayelyan 27565321922cSVardan Mikayelyan /** 27575321922cSVardan Mikayelyan * dwc2_gadget_handle_nak - handle NAK interrupt 27585321922cSVardan Mikayelyan * @hs_ep: The endpoint on which interrupt is asserted. 27595321922cSVardan Mikayelyan * 27605321922cSVardan Mikayelyan * This is starting point for ISOC-IN transfer, synchronization done with 27615321922cSVardan Mikayelyan * first IN token received from host while corresponding EP is disabled. 27625321922cSVardan Mikayelyan * 27635321922cSVardan Mikayelyan * Device does not know when first one token will arrive from host. On first 27645321922cSVardan Mikayelyan * token arrival HW generates 2 interrupts: 'in token received while FIFO empty' 27655321922cSVardan Mikayelyan * and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was 27665321922cSVardan Mikayelyan * sent in response to that as there was no data in FIFO. SW is basing on this 27675321922cSVardan Mikayelyan * interrupt to obtain frame in which token has come and then based on the 27685321922cSVardan Mikayelyan * interval calculates next frame for transfer. 27695321922cSVardan Mikayelyan */ 27705321922cSVardan Mikayelyan static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) 27715321922cSVardan Mikayelyan { 27725321922cSVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 27735321922cSVardan Mikayelyan int dir_in = hs_ep->dir_in; 27745321922cSVardan Mikayelyan 27755321922cSVardan Mikayelyan if (!dir_in || !hs_ep->isochronous) 27765321922cSVardan Mikayelyan return; 27775321922cSVardan Mikayelyan 27785321922cSVardan Mikayelyan if (hs_ep->target_frame == TARGET_FRAME_INITIAL) { 27795321922cSVardan Mikayelyan hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg); 2780540ccba0SVahram Aharonyan 2781540ccba0SVahram Aharonyan if (using_desc_dma(hsotg)) { 2782540ccba0SVahram Aharonyan dwc2_gadget_start_isoc_ddma(hs_ep); 2783540ccba0SVahram Aharonyan return; 2784540ccba0SVahram Aharonyan } 2785540ccba0SVahram Aharonyan 27865321922cSVardan Mikayelyan if (hs_ep->interval > 1) { 27875321922cSVardan Mikayelyan u32 ctrl = dwc2_readl(hsotg->regs + 27885321922cSVardan Mikayelyan DIEPCTL(hs_ep->index)); 27895321922cSVardan Mikayelyan if (hs_ep->target_frame & 0x1) 27905321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETODDFR; 27915321922cSVardan Mikayelyan else 27925321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETEVENFR; 27935321922cSVardan Mikayelyan 27945321922cSVardan Mikayelyan dwc2_writel(ctrl, hsotg->regs + DIEPCTL(hs_ep->index)); 27955321922cSVardan Mikayelyan } 27965321922cSVardan Mikayelyan 27975321922cSVardan Mikayelyan dwc2_hsotg_complete_request(hsotg, hs_ep, 27985321922cSVardan Mikayelyan get_ep_head(hs_ep), 0); 27995321922cSVardan Mikayelyan } 28005321922cSVardan Mikayelyan 28015321922cSVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 28025321922cSVardan Mikayelyan } 28035321922cSVardan Mikayelyan 28045321922cSVardan Mikayelyan /** 28051f91b4ccSFelipe Balbi * dwc2_hsotg_epint - handle an in/out endpoint interrupt 280647a1685fSDinh Nguyen * @hsotg: The driver state 280747a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 280847a1685fSDinh Nguyen * @dir_in: Set if this is an IN endpoint 280947a1685fSDinh Nguyen * 281047a1685fSDinh Nguyen * Process and clear any interrupt pending for an individual endpoint 281147a1685fSDinh Nguyen */ 28121f91b4ccSFelipe Balbi static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, 281347a1685fSDinh Nguyen int dir_in) 281447a1685fSDinh Nguyen { 28151f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in); 281647a1685fSDinh Nguyen u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 281747a1685fSDinh Nguyen u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 281847a1685fSDinh Nguyen u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); 281947a1685fSDinh Nguyen u32 ints; 282047a1685fSDinh Nguyen u32 ctrl; 282147a1685fSDinh Nguyen 282232601588SVardan Mikayelyan ints = dwc2_gadget_read_ep_interrupts(hsotg, idx, dir_in); 282395c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctl_reg); 282447a1685fSDinh Nguyen 282547a1685fSDinh Nguyen /* Clear endpoint interrupts */ 282695c8bc36SAntti Seppälä dwc2_writel(ints, hsotg->regs + epint_reg); 282747a1685fSDinh Nguyen 2828c6f5c050SMian Yousaf Kaukab if (!hs_ep) { 2829c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n", 2830c6f5c050SMian Yousaf Kaukab __func__, idx, dir_in ? "in" : "out"); 2831c6f5c050SMian Yousaf Kaukab return; 2832c6f5c050SMian Yousaf Kaukab } 2833c6f5c050SMian Yousaf Kaukab 283447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", 283547a1685fSDinh Nguyen __func__, idx, dir_in ? "in" : "out", ints); 283647a1685fSDinh Nguyen 2837b787d755SMian Yousaf Kaukab /* Don't process XferCompl interrupt if it is a setup packet */ 2838b787d755SMian Yousaf Kaukab if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD))) 2839b787d755SMian Yousaf Kaukab ints &= ~DXEPINT_XFERCOMPL; 2840b787d755SMian Yousaf Kaukab 2841f0afdb42SVahram Aharonyan /* 2842f0afdb42SVahram Aharonyan * Don't process XferCompl interrupt in DDMA if EP0 is still in SETUP 2843f0afdb42SVahram Aharonyan * stage and xfercomplete was generated without SETUP phase done 2844f0afdb42SVahram Aharonyan * interrupt. SW should parse received setup packet only after host's 2845f0afdb42SVahram Aharonyan * exit from setup phase of control transfer. 2846f0afdb42SVahram Aharonyan */ 2847f0afdb42SVahram Aharonyan if (using_desc_dma(hsotg) && idx == 0 && !hs_ep->dir_in && 2848f0afdb42SVahram Aharonyan hsotg->ep0_state == DWC2_EP0_SETUP && !(ints & DXEPINT_SETUP)) 2849f0afdb42SVahram Aharonyan ints &= ~DXEPINT_XFERCOMPL; 2850f0afdb42SVahram Aharonyan 2851837e9f00SVardan Mikayelyan if (ints & DXEPINT_XFERCOMPL) { 285247a1685fSDinh Nguyen dev_dbg(hsotg->dev, 285347a1685fSDinh Nguyen "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", 285495c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctl_reg), 285595c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + epsiz_reg)); 285647a1685fSDinh Nguyen 2857540ccba0SVahram Aharonyan /* In DDMA handle isochronous requests separately */ 2858540ccba0SVahram Aharonyan if (using_desc_dma(hsotg) && hs_ep->isochronous) { 2859540ccba0SVahram Aharonyan dwc2_gadget_complete_isoc_request_ddma(hs_ep); 2860540ccba0SVahram Aharonyan /* Try to start next isoc request */ 2861540ccba0SVahram Aharonyan dwc2_gadget_start_next_isoc_ddma(hs_ep); 2862540ccba0SVahram Aharonyan } else if (dir_in) { 286347a1685fSDinh Nguyen /* 2864540ccba0SVahram Aharonyan * We get OutDone from the FIFO, so we only 2865540ccba0SVahram Aharonyan * need to look at completing IN requests here 2866540ccba0SVahram Aharonyan * if operating slave mode 286747a1685fSDinh Nguyen */ 2868837e9f00SVardan Mikayelyan if (hs_ep->isochronous && hs_ep->interval > 1) 2869837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 2870837e9f00SVardan Mikayelyan 28711f91b4ccSFelipe Balbi dwc2_hsotg_complete_in(hsotg, hs_ep); 2872837e9f00SVardan Mikayelyan if (ints & DXEPINT_NAKINTRPT) 2873837e9f00SVardan Mikayelyan ints &= ~DXEPINT_NAKINTRPT; 287447a1685fSDinh Nguyen 287547a1685fSDinh Nguyen if (idx == 0 && !hs_ep->req) 28761f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 287747a1685fSDinh Nguyen } else if (using_dma(hsotg)) { 287847a1685fSDinh Nguyen /* 287947a1685fSDinh Nguyen * We're using DMA, we need to fire an OutDone here 288047a1685fSDinh Nguyen * as we ignore the RXFIFO. 288147a1685fSDinh Nguyen */ 2882837e9f00SVardan Mikayelyan if (hs_ep->isochronous && hs_ep->interval > 1) 2883837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 288447a1685fSDinh Nguyen 28851f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, idx); 288647a1685fSDinh Nguyen } 288747a1685fSDinh Nguyen } 288847a1685fSDinh Nguyen 2889bd9971f0SVardan Mikayelyan if (ints & DXEPINT_EPDISBLD) 2890bd9971f0SVardan Mikayelyan dwc2_gadget_handle_ep_disabled(hs_ep); 289147a1685fSDinh Nguyen 28925321922cSVardan Mikayelyan if (ints & DXEPINT_OUTTKNEPDIS) 28935321922cSVardan Mikayelyan dwc2_gadget_handle_out_token_ep_disabled(hs_ep); 28945321922cSVardan Mikayelyan 28955321922cSVardan Mikayelyan if (ints & DXEPINT_NAKINTRPT) 28965321922cSVardan Mikayelyan dwc2_gadget_handle_nak(hs_ep); 28975321922cSVardan Mikayelyan 289847a1685fSDinh Nguyen if (ints & DXEPINT_AHBERR) 289947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); 290047a1685fSDinh Nguyen 290147a1685fSDinh Nguyen if (ints & DXEPINT_SETUP) { /* Setup or Timeout */ 290247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); 290347a1685fSDinh Nguyen 290447a1685fSDinh Nguyen if (using_dma(hsotg) && idx == 0) { 290547a1685fSDinh Nguyen /* 290647a1685fSDinh Nguyen * this is the notification we've received a 290747a1685fSDinh Nguyen * setup packet. In non-DMA mode we'd get this 290847a1685fSDinh Nguyen * from the RXFIFO, instead we need to process 290947a1685fSDinh Nguyen * the setup here. 291047a1685fSDinh Nguyen */ 291147a1685fSDinh Nguyen 291247a1685fSDinh Nguyen if (dir_in) 291347a1685fSDinh Nguyen WARN_ON_ONCE(1); 291447a1685fSDinh Nguyen else 29151f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, 0); 291647a1685fSDinh Nguyen } 291747a1685fSDinh Nguyen } 291847a1685fSDinh Nguyen 2919ef750c71SVahram Aharonyan if (ints & DXEPINT_STSPHSERCVD) { 29209d9a6b07SVahram Aharonyan dev_dbg(hsotg->dev, "%s: StsPhseRcvd\n", __func__); 29219d9a6b07SVahram Aharonyan 2922ef750c71SVahram Aharonyan /* Move to STATUS IN for DDMA */ 2923ef750c71SVahram Aharonyan if (using_desc_dma(hsotg)) 2924ef750c71SVahram Aharonyan dwc2_hsotg_ep0_zlp(hsotg, true); 2925ef750c71SVahram Aharonyan } 2926ef750c71SVahram Aharonyan 292747a1685fSDinh Nguyen if (ints & DXEPINT_BACK2BACKSETUP) 292847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); 292947a1685fSDinh Nguyen 2930540ccba0SVahram Aharonyan if (ints & DXEPINT_BNAINTR) { 2931540ccba0SVahram Aharonyan dev_dbg(hsotg->dev, "%s: BNA interrupt\n", __func__); 2932540ccba0SVahram Aharonyan 2933540ccba0SVahram Aharonyan /* 2934540ccba0SVahram Aharonyan * Try to start next isoc request, if any. 2935540ccba0SVahram Aharonyan * Sometimes the endpoint remains enabled after BNA interrupt 2936540ccba0SVahram Aharonyan * assertion, which is not expected, hence we can enter here 2937540ccba0SVahram Aharonyan * couple of times. 2938540ccba0SVahram Aharonyan */ 2939540ccba0SVahram Aharonyan if (hs_ep->isochronous) 2940540ccba0SVahram Aharonyan dwc2_gadget_start_next_isoc_ddma(hs_ep); 2941540ccba0SVahram Aharonyan } 2942540ccba0SVahram Aharonyan 294347a1685fSDinh Nguyen if (dir_in && !hs_ep->isochronous) { 294447a1685fSDinh Nguyen /* not sure if this is important, but we'll clear it anyway */ 294526ddef5dSVardan Mikayelyan if (ints & DXEPINT_INTKNTXFEMP) { 294647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", 294747a1685fSDinh Nguyen __func__, idx); 294847a1685fSDinh Nguyen } 294947a1685fSDinh Nguyen 295047a1685fSDinh Nguyen /* this probably means something bad is happening */ 295126ddef5dSVardan Mikayelyan if (ints & DXEPINT_INTKNEPMIS) { 295247a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", 295347a1685fSDinh Nguyen __func__, idx); 295447a1685fSDinh Nguyen } 295547a1685fSDinh Nguyen 295647a1685fSDinh Nguyen /* FIFO has space or is empty (see GAHBCFG) */ 295747a1685fSDinh Nguyen if (hsotg->dedicated_fifos && 295826ddef5dSVardan Mikayelyan ints & DXEPINT_TXFEMP) { 295947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", 296047a1685fSDinh Nguyen __func__, idx); 296147a1685fSDinh Nguyen if (!using_dma(hsotg)) 29621f91b4ccSFelipe Balbi dwc2_hsotg_trytx(hsotg, hs_ep); 296347a1685fSDinh Nguyen } 296447a1685fSDinh Nguyen } 296547a1685fSDinh Nguyen } 296647a1685fSDinh Nguyen 296747a1685fSDinh Nguyen /** 29681f91b4ccSFelipe Balbi * dwc2_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) 296947a1685fSDinh Nguyen * @hsotg: The device state. 297047a1685fSDinh Nguyen * 297147a1685fSDinh Nguyen * Handle updating the device settings after the enumeration phase has 297247a1685fSDinh Nguyen * been completed. 297347a1685fSDinh Nguyen */ 29741f91b4ccSFelipe Balbi static void dwc2_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg) 297547a1685fSDinh Nguyen { 297695c8bc36SAntti Seppälä u32 dsts = dwc2_readl(hsotg->regs + DSTS); 29779b2667f1SJingoo Han int ep0_mps = 0, ep_mps = 8; 297847a1685fSDinh Nguyen 297947a1685fSDinh Nguyen /* 298047a1685fSDinh Nguyen * This should signal the finish of the enumeration phase 298147a1685fSDinh Nguyen * of the USB handshaking, so we should now know what rate 298247a1685fSDinh Nguyen * we connected at. 298347a1685fSDinh Nguyen */ 298447a1685fSDinh Nguyen 298547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); 298647a1685fSDinh Nguyen 298747a1685fSDinh Nguyen /* 298847a1685fSDinh Nguyen * note, since we're limited by the size of transfer on EP0, and 298947a1685fSDinh Nguyen * it seems IN transfers must be a even number of packets we do 299047a1685fSDinh Nguyen * not advertise a 64byte MPS on EP0. 299147a1685fSDinh Nguyen */ 299247a1685fSDinh Nguyen 299347a1685fSDinh Nguyen /* catch both EnumSpd_FS and EnumSpd_FS48 */ 29946d76c92cSMarek Vasut switch ((dsts & DSTS_ENUMSPD_MASK) >> DSTS_ENUMSPD_SHIFT) { 299547a1685fSDinh Nguyen case DSTS_ENUMSPD_FS: 299647a1685fSDinh Nguyen case DSTS_ENUMSPD_FS48: 299747a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_FULL; 299847a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 299947a1685fSDinh Nguyen ep_mps = 1023; 300047a1685fSDinh Nguyen break; 300147a1685fSDinh Nguyen 300247a1685fSDinh Nguyen case DSTS_ENUMSPD_HS: 300347a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_HIGH; 300447a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 300547a1685fSDinh Nguyen ep_mps = 1024; 300647a1685fSDinh Nguyen break; 300747a1685fSDinh Nguyen 300847a1685fSDinh Nguyen case DSTS_ENUMSPD_LS: 300947a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_LOW; 3010552d940fSVardan Mikayelyan ep0_mps = 8; 3011552d940fSVardan Mikayelyan ep_mps = 8; 301247a1685fSDinh Nguyen /* 301347a1685fSDinh Nguyen * note, we don't actually support LS in this driver at the 301447a1685fSDinh Nguyen * moment, and the documentation seems to imply that it isn't 301547a1685fSDinh Nguyen * supported by the PHYs on some of the devices. 301647a1685fSDinh Nguyen */ 301747a1685fSDinh Nguyen break; 301847a1685fSDinh Nguyen } 301947a1685fSDinh Nguyen dev_info(hsotg->dev, "new device is %s\n", 302047a1685fSDinh Nguyen usb_speed_string(hsotg->gadget.speed)); 302147a1685fSDinh Nguyen 302247a1685fSDinh Nguyen /* 302347a1685fSDinh Nguyen * we should now know the maximum packet size for an 302447a1685fSDinh Nguyen * endpoint, so set the endpoints to a default value. 302547a1685fSDinh Nguyen */ 302647a1685fSDinh Nguyen 302747a1685fSDinh Nguyen if (ep0_mps) { 302847a1685fSDinh Nguyen int i; 3029c6f5c050SMian Yousaf Kaukab /* Initialize ep0 for both in and out directions */ 3030ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 1); 3031ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 0); 3032c6f5c050SMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; i++) { 3033c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[i]) 3034ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 3035ee2c40deSVardan Mikayelyan 0, 1); 3036c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[i]) 3037ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 3038ee2c40deSVardan Mikayelyan 0, 0); 3039c6f5c050SMian Yousaf Kaukab } 304047a1685fSDinh Nguyen } 304147a1685fSDinh Nguyen 304247a1685fSDinh Nguyen /* ensure after enumeration our EP0 is active */ 304347a1685fSDinh Nguyen 30441f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 304547a1685fSDinh Nguyen 304647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 304795c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DIEPCTL0), 304895c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL0)); 304947a1685fSDinh Nguyen } 305047a1685fSDinh Nguyen 305147a1685fSDinh Nguyen /** 305247a1685fSDinh Nguyen * kill_all_requests - remove all requests from the endpoint's queue 305347a1685fSDinh Nguyen * @hsotg: The device state. 305447a1685fSDinh Nguyen * @ep: The endpoint the requests may be on. 305547a1685fSDinh Nguyen * @result: The result code to use. 305647a1685fSDinh Nguyen * 305747a1685fSDinh Nguyen * Go through the requests on the given endpoint and mark them 305847a1685fSDinh Nguyen * completed with the given result code. 305947a1685fSDinh Nguyen */ 3060941fcce4SDinh Nguyen static void kill_all_requests(struct dwc2_hsotg *hsotg, 30611f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep, 30626b448af4SRobert Baldyga int result) 306347a1685fSDinh Nguyen { 30641f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req, *treq; 30659da51974SJohn Youn unsigned int size; 306647a1685fSDinh Nguyen 30676b448af4SRobert Baldyga ep->req = NULL; 306847a1685fSDinh Nguyen 30696b448af4SRobert Baldyga list_for_each_entry_safe(req, treq, &ep->queue, queue) 30701f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, ep, req, 307147a1685fSDinh Nguyen result); 30726b448af4SRobert Baldyga 3073b203d0a2SRobert Baldyga if (!hsotg->dedicated_fifos) 3074b203d0a2SRobert Baldyga return; 3075ad674a15SRobert Baldyga size = (dwc2_readl(hsotg->regs + DTXFSTS(ep->fifo_index)) & 0xffff) * 4; 3076b203d0a2SRobert Baldyga if (size < ep->fifo_size) 30771f91b4ccSFelipe Balbi dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); 307847a1685fSDinh Nguyen } 307947a1685fSDinh Nguyen 308047a1685fSDinh Nguyen /** 30811f91b4ccSFelipe Balbi * dwc2_hsotg_disconnect - disconnect service 308247a1685fSDinh Nguyen * @hsotg: The device state. 308347a1685fSDinh Nguyen * 308447a1685fSDinh Nguyen * The device has been disconnected. Remove all current 308547a1685fSDinh Nguyen * transactions and signal the gadget driver that this 308647a1685fSDinh Nguyen * has happened. 308747a1685fSDinh Nguyen */ 30881f91b4ccSFelipe Balbi void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) 308947a1685fSDinh Nguyen { 30909da51974SJohn Youn unsigned int ep; 309147a1685fSDinh Nguyen 30924ace06e8SMarek Szyprowski if (!hsotg->connected) 30934ace06e8SMarek Szyprowski return; 30944ace06e8SMarek Szyprowski 30954ace06e8SMarek Szyprowski hsotg->connected = 0; 30969e14d0a5SGregory Herrero hsotg->test_mode = 0; 3097c6f5c050SMian Yousaf Kaukab 3098c6f5c050SMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps; ep++) { 3099c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 3100c6f5c050SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_in[ep], 3101c6f5c050SMian Yousaf Kaukab -ESHUTDOWN); 3102c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 3103c6f5c050SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_out[ep], 3104c6f5c050SMian Yousaf Kaukab -ESHUTDOWN); 3105c6f5c050SMian Yousaf Kaukab } 310647a1685fSDinh Nguyen 310747a1685fSDinh Nguyen call_gadget(hsotg, disconnect); 3108065d3931SGregory Herrero hsotg->lx_state = DWC2_L3; 310947a1685fSDinh Nguyen } 311047a1685fSDinh Nguyen 311147a1685fSDinh Nguyen /** 31121f91b4ccSFelipe Balbi * dwc2_hsotg_irq_fifoempty - TX FIFO empty interrupt handler 311347a1685fSDinh Nguyen * @hsotg: The device state: 311447a1685fSDinh Nguyen * @periodic: True if this is a periodic FIFO interrupt 311547a1685fSDinh Nguyen */ 31161f91b4ccSFelipe Balbi static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) 311747a1685fSDinh Nguyen { 31181f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 311947a1685fSDinh Nguyen int epno, ret; 312047a1685fSDinh Nguyen 312147a1685fSDinh Nguyen /* look through for any more data to transmit */ 312247a1685fSDinh Nguyen for (epno = 0; epno < hsotg->num_of_eps; epno++) { 3123c6f5c050SMian Yousaf Kaukab ep = index_to_ep(hsotg, epno, 1); 3124c6f5c050SMian Yousaf Kaukab 3125c6f5c050SMian Yousaf Kaukab if (!ep) 3126c6f5c050SMian Yousaf Kaukab continue; 312747a1685fSDinh Nguyen 312847a1685fSDinh Nguyen if (!ep->dir_in) 312947a1685fSDinh Nguyen continue; 313047a1685fSDinh Nguyen 313147a1685fSDinh Nguyen if ((periodic && !ep->periodic) || 313247a1685fSDinh Nguyen (!periodic && ep->periodic)) 313347a1685fSDinh Nguyen continue; 313447a1685fSDinh Nguyen 31351f91b4ccSFelipe Balbi ret = dwc2_hsotg_trytx(hsotg, ep); 313647a1685fSDinh Nguyen if (ret < 0) 313747a1685fSDinh Nguyen break; 313847a1685fSDinh Nguyen } 313947a1685fSDinh Nguyen } 314047a1685fSDinh Nguyen 314147a1685fSDinh Nguyen /* IRQ flags which will trigger a retry around the IRQ loop */ 314247a1685fSDinh Nguyen #define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ 314347a1685fSDinh Nguyen GINTSTS_PTXFEMP | \ 314447a1685fSDinh Nguyen GINTSTS_RXFLVL) 314547a1685fSDinh Nguyen 314647a1685fSDinh Nguyen /** 31471f91b4ccSFelipe Balbi * dwc2_hsotg_core_init - issue softreset to the core 314847a1685fSDinh Nguyen * @hsotg: The device state 314947a1685fSDinh Nguyen * 315047a1685fSDinh Nguyen * Issue a soft reset to the core, and await the core finishing it. 315147a1685fSDinh Nguyen */ 31521f91b4ccSFelipe Balbi void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, 3153643cc4deSGregory Herrero bool is_usb_reset) 315447a1685fSDinh Nguyen { 31551ee6903bSGregory Herrero u32 intmsk; 3156643cc4deSGregory Herrero u32 val; 3157ecd9a7adSPrzemek Rudy u32 usbcfg; 315879c3b5bbSVahram Aharonyan u32 dcfg = 0; 3159643cc4deSGregory Herrero 31605390d438SMian Yousaf Kaukab /* Kill any ep0 requests as controller will be reinitialized */ 31615390d438SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); 31625390d438SMian Yousaf Kaukab 3163643cc4deSGregory Herrero if (!is_usb_reset) 3164241729baSJohn Youn if (dwc2_core_reset(hsotg)) 316586de4895SGregory Herrero return; 316647a1685fSDinh Nguyen 316747a1685fSDinh Nguyen /* 316847a1685fSDinh Nguyen * we must now enable ep0 ready for host detection and then 316947a1685fSDinh Nguyen * set configuration. 317047a1685fSDinh Nguyen */ 317147a1685fSDinh Nguyen 3172ecd9a7adSPrzemek Rudy /* keep other bits untouched (so e.g. forced modes are not lost) */ 3173ecd9a7adSPrzemek Rudy usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); 3174ecd9a7adSPrzemek Rudy usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP | 3175ecd9a7adSPrzemek Rudy GUSBCFG_HNPCAP); 3176ecd9a7adSPrzemek Rudy 317779c3b5bbSVahram Aharonyan if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS && 317838e9002bSVardan Mikayelyan (hsotg->params.speed == DWC2_SPEED_PARAM_FULL || 317938e9002bSVardan Mikayelyan hsotg->params.speed == DWC2_SPEED_PARAM_LOW)) { 318079c3b5bbSVahram Aharonyan /* FS/LS Dedicated Transceiver Interface */ 318179c3b5bbSVahram Aharonyan usbcfg |= GUSBCFG_PHYSEL; 318279c3b5bbSVahram Aharonyan } else { 318347a1685fSDinh Nguyen /* set the PLL on, remove the HNP/SRP and set the PHY */ 3184fa4a8d72SMian Yousaf Kaukab val = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5; 3185ecd9a7adSPrzemek Rudy usbcfg |= hsotg->phyif | GUSBCFG_TOUTCAL(7) | 3186ecd9a7adSPrzemek Rudy (val << GUSBCFG_USBTRDTIM_SHIFT); 318779c3b5bbSVahram Aharonyan } 3188ecd9a7adSPrzemek Rudy dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); 318947a1685fSDinh Nguyen 31901f91b4ccSFelipe Balbi dwc2_hsotg_init_fifo(hsotg); 319147a1685fSDinh Nguyen 3192643cc4deSGregory Herrero if (!is_usb_reset) 319347a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 319447a1685fSDinh Nguyen 319579c3b5bbSVahram Aharonyan dcfg |= DCFG_EPMISCNT(1); 319638e9002bSVardan Mikayelyan 319738e9002bSVardan Mikayelyan switch (hsotg->params.speed) { 319838e9002bSVardan Mikayelyan case DWC2_SPEED_PARAM_LOW: 319938e9002bSVardan Mikayelyan dcfg |= DCFG_DEVSPD_LS; 320038e9002bSVardan Mikayelyan break; 320138e9002bSVardan Mikayelyan case DWC2_SPEED_PARAM_FULL: 320279c3b5bbSVahram Aharonyan if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) 320379c3b5bbSVahram Aharonyan dcfg |= DCFG_DEVSPD_FS48; 320479c3b5bbSVahram Aharonyan else 320579c3b5bbSVahram Aharonyan dcfg |= DCFG_DEVSPD_FS; 320638e9002bSVardan Mikayelyan break; 320738e9002bSVardan Mikayelyan default: 320879c3b5bbSVahram Aharonyan dcfg |= DCFG_DEVSPD_HS; 320979c3b5bbSVahram Aharonyan } 321038e9002bSVardan Mikayelyan 321179c3b5bbSVahram Aharonyan dwc2_writel(dcfg, hsotg->regs + DCFG); 321247a1685fSDinh Nguyen 321347a1685fSDinh Nguyen /* Clear any pending OTG interrupts */ 321495c8bc36SAntti Seppälä dwc2_writel(0xffffffff, hsotg->regs + GOTGINT); 321547a1685fSDinh Nguyen 321647a1685fSDinh Nguyen /* Clear any pending interrupts */ 321795c8bc36SAntti Seppälä dwc2_writel(0xffffffff, hsotg->regs + GINTSTS); 32181ee6903bSGregory Herrero intmsk = GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT | 321947a1685fSDinh Nguyen GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | 32201ee6903bSGregory Herrero GINTSTS_USBRST | GINTSTS_RESETDET | 32211ee6903bSGregory Herrero GINTSTS_ENUMDONE | GINTSTS_OTGINT | 3222f4736701SVahram Aharonyan GINTSTS_USBSUSP | GINTSTS_WKUPINT; 3223f4736701SVahram Aharonyan 3224f4736701SVahram Aharonyan if (!using_desc_dma(hsotg)) 3225f4736701SVahram Aharonyan intmsk |= GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT; 32261ee6903bSGregory Herrero 3227bea8e86cSJohn Youn if (hsotg->params.external_id_pin_ctl <= 0) 32281ee6903bSGregory Herrero intmsk |= GINTSTS_CONIDSTSCHNG; 32291ee6903bSGregory Herrero 32301ee6903bSGregory Herrero dwc2_writel(intmsk, hsotg->regs + GINTMSK); 323147a1685fSDinh Nguyen 3232a5c18f11SVahram Aharonyan if (using_dma(hsotg)) { 323395c8bc36SAntti Seppälä dwc2_writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN | 32345f05048eSGregory Herrero (GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT), 323547a1685fSDinh Nguyen hsotg->regs + GAHBCFG); 3236a5c18f11SVahram Aharonyan 3237a5c18f11SVahram Aharonyan /* Set DDMA mode support in the core if needed */ 3238a5c18f11SVahram Aharonyan if (using_desc_dma(hsotg)) 3239a5c18f11SVahram Aharonyan __orr32(hsotg->regs + DCFG, DCFG_DESCDMA_EN); 3240a5c18f11SVahram Aharonyan 3241a5c18f11SVahram Aharonyan } else { 324295c8bc36SAntti Seppälä dwc2_writel(((hsotg->dedicated_fifos) ? 324395c8bc36SAntti Seppälä (GAHBCFG_NP_TXF_EMP_LVL | 324447a1685fSDinh Nguyen GAHBCFG_P_TXF_EMP_LVL) : 0) | 324595c8bc36SAntti Seppälä GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG); 3246a5c18f11SVahram Aharonyan } 324747a1685fSDinh Nguyen 324847a1685fSDinh Nguyen /* 324947a1685fSDinh Nguyen * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts 325047a1685fSDinh Nguyen * when we have no data to transfer. Otherwise we get being flooded by 325147a1685fSDinh Nguyen * interrupts. 325247a1685fSDinh Nguyen */ 325347a1685fSDinh Nguyen 325495c8bc36SAntti Seppälä dwc2_writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ? 32556ff2e832SMian Yousaf Kaukab DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) | 325647a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | 3257837e9f00SVardan Mikayelyan DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK, 325847a1685fSDinh Nguyen hsotg->regs + DIEPMSK); 325947a1685fSDinh Nguyen 326047a1685fSDinh Nguyen /* 326147a1685fSDinh Nguyen * don't need XferCompl, we get that from RXFIFO in slave mode. In 32629d9a6b07SVahram Aharonyan * DMA mode we may need this and StsPhseRcvd. 326347a1685fSDinh Nguyen */ 32649d9a6b07SVahram Aharonyan dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK | 32659d9a6b07SVahram Aharonyan DOEPMSK_STSPHSERCVDMSK) : 0) | 326647a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | 32679d9a6b07SVahram Aharonyan DOEPMSK_SETUPMSK, 326847a1685fSDinh Nguyen hsotg->regs + DOEPMSK); 326947a1685fSDinh Nguyen 3270ec01f0b2SVahram Aharonyan /* Enable BNA interrupt for DDMA */ 3271ec01f0b2SVahram Aharonyan if (using_desc_dma(hsotg)) 3272ec01f0b2SVahram Aharonyan __orr32(hsotg->regs + DOEPMSK, DOEPMSK_BNAMSK); 3273ec01f0b2SVahram Aharonyan 327495c8bc36SAntti Seppälä dwc2_writel(0, hsotg->regs + DAINTMSK); 327547a1685fSDinh Nguyen 327647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 327795c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DIEPCTL0), 327895c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL0)); 327947a1685fSDinh Nguyen 328047a1685fSDinh Nguyen /* enable in and out endpoint interrupts */ 32811f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT); 328247a1685fSDinh Nguyen 328347a1685fSDinh Nguyen /* 328447a1685fSDinh Nguyen * Enable the RXFIFO when in slave mode, as this is how we collect 328547a1685fSDinh Nguyen * the data. In DMA mode, we get events from the FIFO but also 328647a1685fSDinh Nguyen * things we cannot process, so do not use it. 328747a1685fSDinh Nguyen */ 328847a1685fSDinh Nguyen if (!using_dma(hsotg)) 32891f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL); 329047a1685fSDinh Nguyen 329147a1685fSDinh Nguyen /* Enable interrupts for EP0 in and out */ 32921f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, 0, 0, 1); 32931f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, 0, 1, 1); 329447a1685fSDinh Nguyen 3295643cc4deSGregory Herrero if (!is_usb_reset) { 329647a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); 329747a1685fSDinh Nguyen udelay(10); /* see openiboot */ 329847a1685fSDinh Nguyen __bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); 3299643cc4deSGregory Herrero } 330047a1685fSDinh Nguyen 330195c8bc36SAntti Seppälä dev_dbg(hsotg->dev, "DCTL=0x%08x\n", dwc2_readl(hsotg->regs + DCTL)); 330247a1685fSDinh Nguyen 330347a1685fSDinh Nguyen /* 330447a1685fSDinh Nguyen * DxEPCTL_USBActEp says RO in manual, but seems to be set by 330547a1685fSDinh Nguyen * writing to the EPCTL register.. 330647a1685fSDinh Nguyen */ 330747a1685fSDinh Nguyen 330847a1685fSDinh Nguyen /* set to read 1 8byte packet */ 330995c8bc36SAntti Seppälä dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 331047a1685fSDinh Nguyen DXEPTSIZ_XFERSIZE(8), hsotg->regs + DOEPTSIZ0); 331147a1685fSDinh Nguyen 331295c8bc36SAntti Seppälä dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 331347a1685fSDinh Nguyen DXEPCTL_CNAK | DXEPCTL_EPENA | 331447a1685fSDinh Nguyen DXEPCTL_USBACTEP, 331547a1685fSDinh Nguyen hsotg->regs + DOEPCTL0); 331647a1685fSDinh Nguyen 331747a1685fSDinh Nguyen /* enable, but don't activate EP0in */ 331895c8bc36SAntti Seppälä dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 331947a1685fSDinh Nguyen DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0); 332047a1685fSDinh Nguyen 33211f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 332247a1685fSDinh Nguyen 332347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 332495c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DIEPCTL0), 332595c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL0)); 332647a1685fSDinh Nguyen 332747a1685fSDinh Nguyen /* clear global NAKs */ 3328643cc4deSGregory Herrero val = DCTL_CGOUTNAK | DCTL_CGNPINNAK; 3329643cc4deSGregory Herrero if (!is_usb_reset) 3330643cc4deSGregory Herrero val |= DCTL_SFTDISCON; 3331643cc4deSGregory Herrero __orr32(hsotg->regs + DCTL, val); 333247a1685fSDinh Nguyen 333347a1685fSDinh Nguyen /* must be at-least 3ms to allow bus to see disconnect */ 333447a1685fSDinh Nguyen mdelay(3); 333547a1685fSDinh Nguyen 3336065d3931SGregory Herrero hsotg->lx_state = DWC2_L0; 3337ad38dc5dSMarek Szyprowski } 3338ac3c81f3SMarek Szyprowski 33391f91b4ccSFelipe Balbi static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) 3340ad38dc5dSMarek Szyprowski { 3341ad38dc5dSMarek Szyprowski /* set the soft-disconnect bit */ 3342ad38dc5dSMarek Szyprowski __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 3343ad38dc5dSMarek Szyprowski } 3344ad38dc5dSMarek Szyprowski 33451f91b4ccSFelipe Balbi void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) 3346ad38dc5dSMarek Szyprowski { 334747a1685fSDinh Nguyen /* remove the soft-disconnect and let's go */ 334847a1685fSDinh Nguyen __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON); 334947a1685fSDinh Nguyen } 335047a1685fSDinh Nguyen 335147a1685fSDinh Nguyen /** 3352381fc8f8SVardan Mikayelyan * dwc2_gadget_handle_incomplete_isoc_in - handle incomplete ISO IN Interrupt. 3353381fc8f8SVardan Mikayelyan * @hsotg: The device state: 3354381fc8f8SVardan Mikayelyan * 3355381fc8f8SVardan Mikayelyan * This interrupt indicates one of the following conditions occurred while 3356381fc8f8SVardan Mikayelyan * transmitting an ISOC transaction. 3357381fc8f8SVardan Mikayelyan * - Corrupted IN Token for ISOC EP. 3358381fc8f8SVardan Mikayelyan * - Packet not complete in FIFO. 3359381fc8f8SVardan Mikayelyan * 3360381fc8f8SVardan Mikayelyan * The following actions will be taken: 3361381fc8f8SVardan Mikayelyan * - Determine the EP 3362381fc8f8SVardan Mikayelyan * - Disable EP; when 'Endpoint Disabled' interrupt is received Flush FIFO 3363381fc8f8SVardan Mikayelyan */ 3364381fc8f8SVardan Mikayelyan static void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg) 3365381fc8f8SVardan Mikayelyan { 3366381fc8f8SVardan Mikayelyan struct dwc2_hsotg_ep *hs_ep; 3367381fc8f8SVardan Mikayelyan u32 epctrl; 3368381fc8f8SVardan Mikayelyan u32 idx; 3369381fc8f8SVardan Mikayelyan 3370381fc8f8SVardan Mikayelyan dev_dbg(hsotg->dev, "Incomplete isoc in interrupt received:\n"); 3371381fc8f8SVardan Mikayelyan 3372381fc8f8SVardan Mikayelyan for (idx = 1; idx <= hsotg->num_of_eps; idx++) { 3373381fc8f8SVardan Mikayelyan hs_ep = hsotg->eps_in[idx]; 3374381fc8f8SVardan Mikayelyan epctrl = dwc2_readl(hsotg->regs + DIEPCTL(idx)); 3375381fc8f8SVardan Mikayelyan if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous && 3376381fc8f8SVardan Mikayelyan dwc2_gadget_target_frame_elapsed(hs_ep)) { 3377381fc8f8SVardan Mikayelyan epctrl |= DXEPCTL_SNAK; 3378381fc8f8SVardan Mikayelyan epctrl |= DXEPCTL_EPDIS; 3379381fc8f8SVardan Mikayelyan dwc2_writel(epctrl, hsotg->regs + DIEPCTL(idx)); 3380381fc8f8SVardan Mikayelyan } 3381381fc8f8SVardan Mikayelyan } 3382381fc8f8SVardan Mikayelyan 3383381fc8f8SVardan Mikayelyan /* Clear interrupt */ 3384381fc8f8SVardan Mikayelyan dwc2_writel(GINTSTS_INCOMPL_SOIN, hsotg->regs + GINTSTS); 3385381fc8f8SVardan Mikayelyan } 3386381fc8f8SVardan Mikayelyan 3387381fc8f8SVardan Mikayelyan /** 3388381fc8f8SVardan Mikayelyan * dwc2_gadget_handle_incomplete_isoc_out - handle incomplete ISO OUT Interrupt 3389381fc8f8SVardan Mikayelyan * @hsotg: The device state: 3390381fc8f8SVardan Mikayelyan * 3391381fc8f8SVardan Mikayelyan * This interrupt indicates one of the following conditions occurred while 3392381fc8f8SVardan Mikayelyan * transmitting an ISOC transaction. 3393381fc8f8SVardan Mikayelyan * - Corrupted OUT Token for ISOC EP. 3394381fc8f8SVardan Mikayelyan * - Packet not complete in FIFO. 3395381fc8f8SVardan Mikayelyan * 3396381fc8f8SVardan Mikayelyan * The following actions will be taken: 3397381fc8f8SVardan Mikayelyan * - Determine the EP 3398381fc8f8SVardan Mikayelyan * - Set DCTL_SGOUTNAK and unmask GOUTNAKEFF if target frame elapsed. 3399381fc8f8SVardan Mikayelyan */ 3400381fc8f8SVardan Mikayelyan static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg) 3401381fc8f8SVardan Mikayelyan { 3402381fc8f8SVardan Mikayelyan u32 gintsts; 3403381fc8f8SVardan Mikayelyan u32 gintmsk; 3404381fc8f8SVardan Mikayelyan u32 epctrl; 3405381fc8f8SVardan Mikayelyan struct dwc2_hsotg_ep *hs_ep; 3406381fc8f8SVardan Mikayelyan int idx; 3407381fc8f8SVardan Mikayelyan 3408381fc8f8SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__); 3409381fc8f8SVardan Mikayelyan 3410381fc8f8SVardan Mikayelyan for (idx = 1; idx <= hsotg->num_of_eps; idx++) { 3411381fc8f8SVardan Mikayelyan hs_ep = hsotg->eps_out[idx]; 3412381fc8f8SVardan Mikayelyan epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx)); 3413381fc8f8SVardan Mikayelyan if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous && 3414381fc8f8SVardan Mikayelyan dwc2_gadget_target_frame_elapsed(hs_ep)) { 3415381fc8f8SVardan Mikayelyan /* Unmask GOUTNAKEFF interrupt */ 3416381fc8f8SVardan Mikayelyan gintmsk = dwc2_readl(hsotg->regs + GINTMSK); 3417381fc8f8SVardan Mikayelyan gintmsk |= GINTSTS_GOUTNAKEFF; 3418381fc8f8SVardan Mikayelyan dwc2_writel(gintmsk, hsotg->regs + GINTMSK); 3419381fc8f8SVardan Mikayelyan 3420381fc8f8SVardan Mikayelyan gintsts = dwc2_readl(hsotg->regs + GINTSTS); 3421381fc8f8SVardan Mikayelyan if (!(gintsts & GINTSTS_GOUTNAKEFF)) 3422381fc8f8SVardan Mikayelyan __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK); 3423381fc8f8SVardan Mikayelyan } 3424381fc8f8SVardan Mikayelyan } 3425381fc8f8SVardan Mikayelyan 3426381fc8f8SVardan Mikayelyan /* Clear interrupt */ 3427381fc8f8SVardan Mikayelyan dwc2_writel(GINTSTS_INCOMPL_SOOUT, hsotg->regs + GINTSTS); 3428381fc8f8SVardan Mikayelyan } 3429381fc8f8SVardan Mikayelyan 3430381fc8f8SVardan Mikayelyan /** 34311f91b4ccSFelipe Balbi * dwc2_hsotg_irq - handle device interrupt 343247a1685fSDinh Nguyen * @irq: The IRQ number triggered 343347a1685fSDinh Nguyen * @pw: The pw value when registered the handler. 343447a1685fSDinh Nguyen */ 34351f91b4ccSFelipe Balbi static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) 343647a1685fSDinh Nguyen { 3437941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = pw; 343847a1685fSDinh Nguyen int retry_count = 8; 343947a1685fSDinh Nguyen u32 gintsts; 344047a1685fSDinh Nguyen u32 gintmsk; 344147a1685fSDinh Nguyen 3442ee3de8d7SVardan Mikayelyan if (!dwc2_is_device_mode(hsotg)) 3443ee3de8d7SVardan Mikayelyan return IRQ_NONE; 3444ee3de8d7SVardan Mikayelyan 344547a1685fSDinh Nguyen spin_lock(&hsotg->lock); 344647a1685fSDinh Nguyen irq_retry: 344795c8bc36SAntti Seppälä gintsts = dwc2_readl(hsotg->regs + GINTSTS); 344895c8bc36SAntti Seppälä gintmsk = dwc2_readl(hsotg->regs + GINTMSK); 344947a1685fSDinh Nguyen 345047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", 345147a1685fSDinh Nguyen __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); 345247a1685fSDinh Nguyen 345347a1685fSDinh Nguyen gintsts &= gintmsk; 345447a1685fSDinh Nguyen 34558fc37b82SMian Yousaf Kaukab if (gintsts & GINTSTS_RESETDET) { 34568fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: USBRstDet\n", __func__); 34578fc37b82SMian Yousaf Kaukab 34588fc37b82SMian Yousaf Kaukab dwc2_writel(GINTSTS_RESETDET, hsotg->regs + GINTSTS); 34598fc37b82SMian Yousaf Kaukab 34608fc37b82SMian Yousaf Kaukab /* This event must be used only if controller is suspended */ 34618fc37b82SMian Yousaf Kaukab if (hsotg->lx_state == DWC2_L2) { 34628fc37b82SMian Yousaf Kaukab dwc2_exit_hibernation(hsotg, true); 34638fc37b82SMian Yousaf Kaukab hsotg->lx_state = DWC2_L0; 34648fc37b82SMian Yousaf Kaukab } 34658fc37b82SMian Yousaf Kaukab } 34668fc37b82SMian Yousaf Kaukab 34678fc37b82SMian Yousaf Kaukab if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) { 34688fc37b82SMian Yousaf Kaukab u32 usb_status = dwc2_readl(hsotg->regs + GOTGCTL); 34698fc37b82SMian Yousaf Kaukab u32 connected = hsotg->connected; 34708fc37b82SMian Yousaf Kaukab 34718fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: USBRst\n", __func__); 34728fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", 34738fc37b82SMian Yousaf Kaukab dwc2_readl(hsotg->regs + GNPTXSTS)); 34748fc37b82SMian Yousaf Kaukab 34758fc37b82SMian Yousaf Kaukab dwc2_writel(GINTSTS_USBRST, hsotg->regs + GINTSTS); 34768fc37b82SMian Yousaf Kaukab 34778fc37b82SMian Yousaf Kaukab /* Report disconnection if it is not already done. */ 34788fc37b82SMian Yousaf Kaukab dwc2_hsotg_disconnect(hsotg); 34798fc37b82SMian Yousaf Kaukab 34808fc37b82SMian Yousaf Kaukab if (usb_status & GOTGCTL_BSESVLD && connected) 34818fc37b82SMian Yousaf Kaukab dwc2_hsotg_core_init_disconnected(hsotg, true); 34828fc37b82SMian Yousaf Kaukab } 34838fc37b82SMian Yousaf Kaukab 348447a1685fSDinh Nguyen if (gintsts & GINTSTS_ENUMDONE) { 348595c8bc36SAntti Seppälä dwc2_writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); 348647a1685fSDinh Nguyen 34871f91b4ccSFelipe Balbi dwc2_hsotg_irq_enumdone(hsotg); 348847a1685fSDinh Nguyen } 348947a1685fSDinh Nguyen 349047a1685fSDinh Nguyen if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { 349195c8bc36SAntti Seppälä u32 daint = dwc2_readl(hsotg->regs + DAINT); 349295c8bc36SAntti Seppälä u32 daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); 349347a1685fSDinh Nguyen u32 daint_out, daint_in; 349447a1685fSDinh Nguyen int ep; 349547a1685fSDinh Nguyen 349647a1685fSDinh Nguyen daint &= daintmsk; 349747a1685fSDinh Nguyen daint_out = daint >> DAINT_OUTEP_SHIFT; 349847a1685fSDinh Nguyen daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); 349947a1685fSDinh Nguyen 350047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); 350147a1685fSDinh Nguyen 3502cec87f1dSMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps && daint_out; 3503cec87f1dSMian Yousaf Kaukab ep++, daint_out >>= 1) { 350447a1685fSDinh Nguyen if (daint_out & 1) 35051f91b4ccSFelipe Balbi dwc2_hsotg_epint(hsotg, ep, 0); 350647a1685fSDinh Nguyen } 350747a1685fSDinh Nguyen 3508cec87f1dSMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps && daint_in; 3509cec87f1dSMian Yousaf Kaukab ep++, daint_in >>= 1) { 351047a1685fSDinh Nguyen if (daint_in & 1) 35111f91b4ccSFelipe Balbi dwc2_hsotg_epint(hsotg, ep, 1); 351247a1685fSDinh Nguyen } 351347a1685fSDinh Nguyen } 351447a1685fSDinh Nguyen 351547a1685fSDinh Nguyen /* check both FIFOs */ 351647a1685fSDinh Nguyen 351747a1685fSDinh Nguyen if (gintsts & GINTSTS_NPTXFEMP) { 351847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "NPTxFEmp\n"); 351947a1685fSDinh Nguyen 352047a1685fSDinh Nguyen /* 352147a1685fSDinh Nguyen * Disable the interrupt to stop it happening again 352247a1685fSDinh Nguyen * unless one of these endpoint routines decides that 352347a1685fSDinh Nguyen * it needs re-enabling 352447a1685fSDinh Nguyen */ 352547a1685fSDinh Nguyen 35261f91b4ccSFelipe Balbi dwc2_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); 35271f91b4ccSFelipe Balbi dwc2_hsotg_irq_fifoempty(hsotg, false); 352847a1685fSDinh Nguyen } 352947a1685fSDinh Nguyen 353047a1685fSDinh Nguyen if (gintsts & GINTSTS_PTXFEMP) { 353147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "PTxFEmp\n"); 353247a1685fSDinh Nguyen 353347a1685fSDinh Nguyen /* See note in GINTSTS_NPTxFEmp */ 353447a1685fSDinh Nguyen 35351f91b4ccSFelipe Balbi dwc2_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); 35361f91b4ccSFelipe Balbi dwc2_hsotg_irq_fifoempty(hsotg, true); 353747a1685fSDinh Nguyen } 353847a1685fSDinh Nguyen 353947a1685fSDinh Nguyen if (gintsts & GINTSTS_RXFLVL) { 354047a1685fSDinh Nguyen /* 354147a1685fSDinh Nguyen * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, 35421f91b4ccSFelipe Balbi * we need to retry dwc2_hsotg_handle_rx if this is still 354347a1685fSDinh Nguyen * set. 354447a1685fSDinh Nguyen */ 354547a1685fSDinh Nguyen 35461f91b4ccSFelipe Balbi dwc2_hsotg_handle_rx(hsotg); 354747a1685fSDinh Nguyen } 354847a1685fSDinh Nguyen 354947a1685fSDinh Nguyen if (gintsts & GINTSTS_ERLYSUSP) { 355047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); 355195c8bc36SAntti Seppälä dwc2_writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS); 355247a1685fSDinh Nguyen } 355347a1685fSDinh Nguyen 355447a1685fSDinh Nguyen /* 355547a1685fSDinh Nguyen * these next two seem to crop-up occasionally causing the core 355647a1685fSDinh Nguyen * to shutdown the USB transfer, so try clearing them and logging 355747a1685fSDinh Nguyen * the occurrence. 355847a1685fSDinh Nguyen */ 355947a1685fSDinh Nguyen 356047a1685fSDinh Nguyen if (gintsts & GINTSTS_GOUTNAKEFF) { 3561837e9f00SVardan Mikayelyan u8 idx; 3562837e9f00SVardan Mikayelyan u32 epctrl; 3563837e9f00SVardan Mikayelyan u32 gintmsk; 3564837e9f00SVardan Mikayelyan struct dwc2_hsotg_ep *hs_ep; 356547a1685fSDinh Nguyen 3566837e9f00SVardan Mikayelyan /* Mask this interrupt */ 3567837e9f00SVardan Mikayelyan gintmsk = dwc2_readl(hsotg->regs + GINTMSK); 3568837e9f00SVardan Mikayelyan gintmsk &= ~GINTSTS_GOUTNAKEFF; 3569837e9f00SVardan Mikayelyan dwc2_writel(gintmsk, hsotg->regs + GINTMSK); 357047a1685fSDinh Nguyen 3571837e9f00SVardan Mikayelyan dev_dbg(hsotg->dev, "GOUTNakEff triggered\n"); 3572837e9f00SVardan Mikayelyan for (idx = 1; idx <= hsotg->num_of_eps; idx++) { 3573837e9f00SVardan Mikayelyan hs_ep = hsotg->eps_out[idx]; 3574837e9f00SVardan Mikayelyan epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx)); 3575837e9f00SVardan Mikayelyan 3576837e9f00SVardan Mikayelyan if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous) { 3577837e9f00SVardan Mikayelyan epctrl |= DXEPCTL_SNAK; 3578837e9f00SVardan Mikayelyan epctrl |= DXEPCTL_EPDIS; 3579837e9f00SVardan Mikayelyan dwc2_writel(epctrl, hsotg->regs + DOEPCTL(idx)); 3580837e9f00SVardan Mikayelyan } 3581837e9f00SVardan Mikayelyan } 3582837e9f00SVardan Mikayelyan 3583837e9f00SVardan Mikayelyan /* This interrupt bit is cleared in DXEPINT_EPDISBLD handler */ 358447a1685fSDinh Nguyen } 358547a1685fSDinh Nguyen 358647a1685fSDinh Nguyen if (gintsts & GINTSTS_GINNAKEFF) { 358747a1685fSDinh Nguyen dev_info(hsotg->dev, "GINNakEff triggered\n"); 358847a1685fSDinh Nguyen 35893be99cd0SGregory Herrero __orr32(hsotg->regs + DCTL, DCTL_CGNPINNAK); 359047a1685fSDinh Nguyen 35911f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 359247a1685fSDinh Nguyen } 359347a1685fSDinh Nguyen 3594381fc8f8SVardan Mikayelyan if (gintsts & GINTSTS_INCOMPL_SOIN) 3595381fc8f8SVardan Mikayelyan dwc2_gadget_handle_incomplete_isoc_in(hsotg); 3596ec1f9d9fSRoman Bacik 3597381fc8f8SVardan Mikayelyan if (gintsts & GINTSTS_INCOMPL_SOOUT) 3598381fc8f8SVardan Mikayelyan dwc2_gadget_handle_incomplete_isoc_out(hsotg); 3599ec1f9d9fSRoman Bacik 360047a1685fSDinh Nguyen /* 360147a1685fSDinh Nguyen * if we've had fifo events, we should try and go around the 360247a1685fSDinh Nguyen * loop again to see if there's any point in returning yet. 360347a1685fSDinh Nguyen */ 360447a1685fSDinh Nguyen 360547a1685fSDinh Nguyen if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) 360647a1685fSDinh Nguyen goto irq_retry; 360747a1685fSDinh Nguyen 360847a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 360947a1685fSDinh Nguyen 361047a1685fSDinh Nguyen return IRQ_HANDLED; 361147a1685fSDinh Nguyen } 361247a1685fSDinh Nguyen 3613a4f82771SVahram Aharonyan static int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hs_otg, u32 reg, 3614a4f82771SVahram Aharonyan u32 bit, u32 timeout) 3615a4f82771SVahram Aharonyan { 3616a4f82771SVahram Aharonyan u32 i; 3617a4f82771SVahram Aharonyan 3618a4f82771SVahram Aharonyan for (i = 0; i < timeout; i++) { 3619a4f82771SVahram Aharonyan if (dwc2_readl(hs_otg->regs + reg) & bit) 3620a4f82771SVahram Aharonyan return 0; 3621a4f82771SVahram Aharonyan udelay(1); 3622a4f82771SVahram Aharonyan } 3623a4f82771SVahram Aharonyan 3624a4f82771SVahram Aharonyan return -ETIMEDOUT; 3625a4f82771SVahram Aharonyan } 3626a4f82771SVahram Aharonyan 3627a4f82771SVahram Aharonyan static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, 3628a4f82771SVahram Aharonyan struct dwc2_hsotg_ep *hs_ep) 3629a4f82771SVahram Aharonyan { 3630a4f82771SVahram Aharonyan u32 epctrl_reg; 3631a4f82771SVahram Aharonyan u32 epint_reg; 3632a4f82771SVahram Aharonyan 3633a4f82771SVahram Aharonyan epctrl_reg = hs_ep->dir_in ? DIEPCTL(hs_ep->index) : 3634a4f82771SVahram Aharonyan DOEPCTL(hs_ep->index); 3635a4f82771SVahram Aharonyan epint_reg = hs_ep->dir_in ? DIEPINT(hs_ep->index) : 3636a4f82771SVahram Aharonyan DOEPINT(hs_ep->index); 3637a4f82771SVahram Aharonyan 3638a4f82771SVahram Aharonyan dev_dbg(hsotg->dev, "%s: stopping transfer on %s\n", __func__, 3639a4f82771SVahram Aharonyan hs_ep->name); 3640a4f82771SVahram Aharonyan 3641a4f82771SVahram Aharonyan if (hs_ep->dir_in) { 3642a4f82771SVahram Aharonyan if (hsotg->dedicated_fifos || hs_ep->periodic) { 3643a4f82771SVahram Aharonyan __orr32(hsotg->regs + epctrl_reg, DXEPCTL_SNAK); 3644a4f82771SVahram Aharonyan /* Wait for Nak effect */ 3645a4f82771SVahram Aharonyan if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, 3646a4f82771SVahram Aharonyan DXEPINT_INEPNAKEFF, 100)) 3647a4f82771SVahram Aharonyan dev_warn(hsotg->dev, 3648a4f82771SVahram Aharonyan "%s: timeout DIEPINT.NAKEFF\n", 3649a4f82771SVahram Aharonyan __func__); 3650a4f82771SVahram Aharonyan } else { 3651a4f82771SVahram Aharonyan __orr32(hsotg->regs + DCTL, DCTL_SGNPINNAK); 3652a4f82771SVahram Aharonyan /* Wait for Nak effect */ 3653a4f82771SVahram Aharonyan if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 3654a4f82771SVahram Aharonyan GINTSTS_GINNAKEFF, 100)) 3655a4f82771SVahram Aharonyan dev_warn(hsotg->dev, 3656a4f82771SVahram Aharonyan "%s: timeout GINTSTS.GINNAKEFF\n", 3657a4f82771SVahram Aharonyan __func__); 3658a4f82771SVahram Aharonyan } 3659a4f82771SVahram Aharonyan } else { 3660a4f82771SVahram Aharonyan if (!(dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_GOUTNAKEFF)) 3661a4f82771SVahram Aharonyan __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK); 3662a4f82771SVahram Aharonyan 3663a4f82771SVahram Aharonyan /* Wait for global nak to take effect */ 3664a4f82771SVahram Aharonyan if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 3665a4f82771SVahram Aharonyan GINTSTS_GOUTNAKEFF, 100)) 3666a4f82771SVahram Aharonyan dev_warn(hsotg->dev, "%s: timeout GINTSTS.GOUTNAKEFF\n", 3667a4f82771SVahram Aharonyan __func__); 3668a4f82771SVahram Aharonyan } 3669a4f82771SVahram Aharonyan 3670a4f82771SVahram Aharonyan /* Disable ep */ 3671a4f82771SVahram Aharonyan __orr32(hsotg->regs + epctrl_reg, DXEPCTL_EPDIS | DXEPCTL_SNAK); 3672a4f82771SVahram Aharonyan 3673a4f82771SVahram Aharonyan /* Wait for ep to be disabled */ 3674a4f82771SVahram Aharonyan if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, DXEPINT_EPDISBLD, 100)) 3675a4f82771SVahram Aharonyan dev_warn(hsotg->dev, 3676a4f82771SVahram Aharonyan "%s: timeout DOEPCTL.EPDisable\n", __func__); 3677a4f82771SVahram Aharonyan 3678a4f82771SVahram Aharonyan /* Clear EPDISBLD interrupt */ 3679a4f82771SVahram Aharonyan __orr32(hsotg->regs + epint_reg, DXEPINT_EPDISBLD); 3680a4f82771SVahram Aharonyan 3681a4f82771SVahram Aharonyan if (hs_ep->dir_in) { 3682a4f82771SVahram Aharonyan unsigned short fifo_index; 3683a4f82771SVahram Aharonyan 3684a4f82771SVahram Aharonyan if (hsotg->dedicated_fifos || hs_ep->periodic) 3685a4f82771SVahram Aharonyan fifo_index = hs_ep->fifo_index; 3686a4f82771SVahram Aharonyan else 3687a4f82771SVahram Aharonyan fifo_index = 0; 3688a4f82771SVahram Aharonyan 3689a4f82771SVahram Aharonyan /* Flush TX FIFO */ 3690a4f82771SVahram Aharonyan dwc2_flush_tx_fifo(hsotg, fifo_index); 3691a4f82771SVahram Aharonyan 3692a4f82771SVahram Aharonyan /* Clear Global In NP NAK in Shared FIFO for non periodic ep */ 3693a4f82771SVahram Aharonyan if (!hsotg->dedicated_fifos && !hs_ep->periodic) 3694a4f82771SVahram Aharonyan __orr32(hsotg->regs + DCTL, DCTL_CGNPINNAK); 3695a4f82771SVahram Aharonyan 3696a4f82771SVahram Aharonyan } else { 3697a4f82771SVahram Aharonyan /* Remove global NAKs */ 3698a4f82771SVahram Aharonyan __orr32(hsotg->regs + DCTL, DCTL_CGOUTNAK); 3699a4f82771SVahram Aharonyan } 3700a4f82771SVahram Aharonyan } 3701a4f82771SVahram Aharonyan 370247a1685fSDinh Nguyen /** 37031f91b4ccSFelipe Balbi * dwc2_hsotg_ep_enable - enable the given endpoint 370447a1685fSDinh Nguyen * @ep: The USB endpint to configure 370547a1685fSDinh Nguyen * @desc: The USB endpoint descriptor to configure with. 370647a1685fSDinh Nguyen * 370747a1685fSDinh Nguyen * This is called from the USB gadget code's usb_ep_enable(). 370847a1685fSDinh Nguyen */ 37091f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_enable(struct usb_ep *ep, 371047a1685fSDinh Nguyen const struct usb_endpoint_descriptor *desc) 371147a1685fSDinh Nguyen { 37121f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 3713941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 371447a1685fSDinh Nguyen unsigned long flags; 3715ca4c55adSMian Yousaf Kaukab unsigned int index = hs_ep->index; 371647a1685fSDinh Nguyen u32 epctrl_reg; 371747a1685fSDinh Nguyen u32 epctrl; 371847a1685fSDinh Nguyen u32 mps; 3719ee2c40deSVardan Mikayelyan u32 mc; 3720837e9f00SVardan Mikayelyan u32 mask; 3721ca4c55adSMian Yousaf Kaukab unsigned int dir_in; 3722ca4c55adSMian Yousaf Kaukab unsigned int i, val, size; 372347a1685fSDinh Nguyen int ret = 0; 372447a1685fSDinh Nguyen 372547a1685fSDinh Nguyen dev_dbg(hsotg->dev, 372647a1685fSDinh Nguyen "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", 372747a1685fSDinh Nguyen __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, 372847a1685fSDinh Nguyen desc->wMaxPacketSize, desc->bInterval); 372947a1685fSDinh Nguyen 373047a1685fSDinh Nguyen /* not to be called for EP0 */ 37318c3d6092SVahram Aharonyan if (index == 0) { 37328c3d6092SVahram Aharonyan dev_err(hsotg->dev, "%s: called for EP 0\n", __func__); 37338c3d6092SVahram Aharonyan return -EINVAL; 37348c3d6092SVahram Aharonyan } 373547a1685fSDinh Nguyen 373647a1685fSDinh Nguyen dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; 373747a1685fSDinh Nguyen if (dir_in != hs_ep->dir_in) { 373847a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); 373947a1685fSDinh Nguyen return -EINVAL; 374047a1685fSDinh Nguyen } 374147a1685fSDinh Nguyen 374247a1685fSDinh Nguyen mps = usb_endpoint_maxp(desc); 3743ee2c40deSVardan Mikayelyan mc = usb_endpoint_maxp_mult(desc); 374447a1685fSDinh Nguyen 37451f91b4ccSFelipe Balbi /* note, we handle this here instead of dwc2_hsotg_set_ep_maxpacket */ 374647a1685fSDinh Nguyen 374747a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 374895c8bc36SAntti Seppälä epctrl = dwc2_readl(hsotg->regs + epctrl_reg); 374947a1685fSDinh Nguyen 375047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", 375147a1685fSDinh Nguyen __func__, epctrl, epctrl_reg); 375247a1685fSDinh Nguyen 37535f54c54bSVahram Aharonyan /* Allocate DMA descriptor chain for non-ctrl endpoints */ 37545f54c54bSVahram Aharonyan if (using_desc_dma(hsotg)) { 37555f54c54bSVahram Aharonyan hs_ep->desc_list = dma_alloc_coherent(hsotg->dev, 37565f54c54bSVahram Aharonyan MAX_DMA_DESC_NUM_GENERIC * 37575f54c54bSVahram Aharonyan sizeof(struct dwc2_dma_desc), 375886e881e7SMarek Szyprowski &hs_ep->desc_list_dma, GFP_ATOMIC); 37595f54c54bSVahram Aharonyan if (!hs_ep->desc_list) { 37605f54c54bSVahram Aharonyan ret = -ENOMEM; 37615f54c54bSVahram Aharonyan goto error2; 37625f54c54bSVahram Aharonyan } 37635f54c54bSVahram Aharonyan } 37645f54c54bSVahram Aharonyan 376547a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 376647a1685fSDinh Nguyen 376747a1685fSDinh Nguyen epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK); 376847a1685fSDinh Nguyen epctrl |= DXEPCTL_MPS(mps); 376947a1685fSDinh Nguyen 377047a1685fSDinh Nguyen /* 377147a1685fSDinh Nguyen * mark the endpoint as active, otherwise the core may ignore 377247a1685fSDinh Nguyen * transactions entirely for this endpoint 377347a1685fSDinh Nguyen */ 377447a1685fSDinh Nguyen epctrl |= DXEPCTL_USBACTEP; 377547a1685fSDinh Nguyen 377647a1685fSDinh Nguyen /* update the endpoint state */ 3777ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, mc, dir_in); 377847a1685fSDinh Nguyen 377947a1685fSDinh Nguyen /* default, set to non-periodic */ 378047a1685fSDinh Nguyen hs_ep->isochronous = 0; 378147a1685fSDinh Nguyen hs_ep->periodic = 0; 378247a1685fSDinh Nguyen hs_ep->halted = 0; 378347a1685fSDinh Nguyen hs_ep->interval = desc->bInterval; 378447a1685fSDinh Nguyen 378547a1685fSDinh Nguyen switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { 378647a1685fSDinh Nguyen case USB_ENDPOINT_XFER_ISOC: 378747a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_ISO; 378847a1685fSDinh Nguyen epctrl |= DXEPCTL_SETEVENFR; 378947a1685fSDinh Nguyen hs_ep->isochronous = 1; 3790142bd33fSVardan Mikayelyan hs_ep->interval = 1 << (desc->bInterval - 1); 3791837e9f00SVardan Mikayelyan hs_ep->target_frame = TARGET_FRAME_INITIAL; 3792ab7d2192SVahram Aharonyan hs_ep->isoc_chain_num = 0; 3793ab7d2192SVahram Aharonyan hs_ep->next_desc = 0; 3794837e9f00SVardan Mikayelyan if (dir_in) { 379547a1685fSDinh Nguyen hs_ep->periodic = 1; 3796837e9f00SVardan Mikayelyan mask = dwc2_readl(hsotg->regs + DIEPMSK); 3797837e9f00SVardan Mikayelyan mask |= DIEPMSK_NAKMSK; 3798837e9f00SVardan Mikayelyan dwc2_writel(mask, hsotg->regs + DIEPMSK); 3799837e9f00SVardan Mikayelyan } else { 3800837e9f00SVardan Mikayelyan mask = dwc2_readl(hsotg->regs + DOEPMSK); 3801837e9f00SVardan Mikayelyan mask |= DOEPMSK_OUTTKNEPDISMSK; 3802837e9f00SVardan Mikayelyan dwc2_writel(mask, hsotg->regs + DOEPMSK); 3803837e9f00SVardan Mikayelyan } 380447a1685fSDinh Nguyen break; 380547a1685fSDinh Nguyen 380647a1685fSDinh Nguyen case USB_ENDPOINT_XFER_BULK: 380747a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_BULK; 380847a1685fSDinh Nguyen break; 380947a1685fSDinh Nguyen 381047a1685fSDinh Nguyen case USB_ENDPOINT_XFER_INT: 3811b203d0a2SRobert Baldyga if (dir_in) 381247a1685fSDinh Nguyen hs_ep->periodic = 1; 381347a1685fSDinh Nguyen 3814142bd33fSVardan Mikayelyan if (hsotg->gadget.speed == USB_SPEED_HIGH) 3815142bd33fSVardan Mikayelyan hs_ep->interval = 1 << (desc->bInterval - 1); 3816142bd33fSVardan Mikayelyan 381747a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_INTERRUPT; 381847a1685fSDinh Nguyen break; 381947a1685fSDinh Nguyen 382047a1685fSDinh Nguyen case USB_ENDPOINT_XFER_CONTROL: 382147a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_CONTROL; 382247a1685fSDinh Nguyen break; 382347a1685fSDinh Nguyen } 382447a1685fSDinh Nguyen 382547a1685fSDinh Nguyen /* 382647a1685fSDinh Nguyen * if the hardware has dedicated fifos, we must give each IN EP 382747a1685fSDinh Nguyen * a unique tx-fifo even if it is non-periodic. 382847a1685fSDinh Nguyen */ 382921f3bb52SRobert Baldyga if (dir_in && hsotg->dedicated_fifos) { 3830ca4c55adSMian Yousaf Kaukab u32 fifo_index = 0; 3831ca4c55adSMian Yousaf Kaukab u32 fifo_size = UINT_MAX; 38329da51974SJohn Youn 3833b203d0a2SRobert Baldyga size = hs_ep->ep.maxpacket * hs_ep->mc; 38345f2196bdSMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; ++i) { 3835b203d0a2SRobert Baldyga if (hsotg->fifo_map & (1 << i)) 3836b203d0a2SRobert Baldyga continue; 383795c8bc36SAntti Seppälä val = dwc2_readl(hsotg->regs + DPTXFSIZN(i)); 3838b203d0a2SRobert Baldyga val = (val >> FIFOSIZE_DEPTH_SHIFT) * 4; 3839b203d0a2SRobert Baldyga if (val < size) 3840b203d0a2SRobert Baldyga continue; 3841ca4c55adSMian Yousaf Kaukab /* Search for smallest acceptable fifo */ 3842ca4c55adSMian Yousaf Kaukab if (val < fifo_size) { 3843ca4c55adSMian Yousaf Kaukab fifo_size = val; 3844ca4c55adSMian Yousaf Kaukab fifo_index = i; 3845b203d0a2SRobert Baldyga } 3846ca4c55adSMian Yousaf Kaukab } 3847ca4c55adSMian Yousaf Kaukab if (!fifo_index) { 38485f2196bdSMian Yousaf Kaukab dev_err(hsotg->dev, 38495f2196bdSMian Yousaf Kaukab "%s: No suitable fifo found\n", __func__); 3850b585a48bSSudip Mukherjee ret = -ENOMEM; 38515f54c54bSVahram Aharonyan goto error1; 3852b585a48bSSudip Mukherjee } 3853ca4c55adSMian Yousaf Kaukab hsotg->fifo_map |= 1 << fifo_index; 3854ca4c55adSMian Yousaf Kaukab epctrl |= DXEPCTL_TXFNUM(fifo_index); 3855ca4c55adSMian Yousaf Kaukab hs_ep->fifo_index = fifo_index; 3856ca4c55adSMian Yousaf Kaukab hs_ep->fifo_size = fifo_size; 3857b203d0a2SRobert Baldyga } 385847a1685fSDinh Nguyen 385947a1685fSDinh Nguyen /* for non control endpoints, set PID to D0 */ 3860837e9f00SVardan Mikayelyan if (index && !hs_ep->isochronous) 386147a1685fSDinh Nguyen epctrl |= DXEPCTL_SETD0PID; 386247a1685fSDinh Nguyen 386347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", 386447a1685fSDinh Nguyen __func__, epctrl); 386547a1685fSDinh Nguyen 386695c8bc36SAntti Seppälä dwc2_writel(epctrl, hsotg->regs + epctrl_reg); 386747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", 386895c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctrl_reg)); 386947a1685fSDinh Nguyen 387047a1685fSDinh Nguyen /* enable the endpoint interrupt */ 38711f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, index, dir_in, 1); 387247a1685fSDinh Nguyen 38735f54c54bSVahram Aharonyan error1: 387447a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 38755f54c54bSVahram Aharonyan 38765f54c54bSVahram Aharonyan error2: 38775f54c54bSVahram Aharonyan if (ret && using_desc_dma(hsotg) && hs_ep->desc_list) { 38785f54c54bSVahram Aharonyan dma_free_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC * 38795f54c54bSVahram Aharonyan sizeof(struct dwc2_dma_desc), 38805f54c54bSVahram Aharonyan hs_ep->desc_list, hs_ep->desc_list_dma); 38815f54c54bSVahram Aharonyan hs_ep->desc_list = NULL; 38825f54c54bSVahram Aharonyan } 38835f54c54bSVahram Aharonyan 388447a1685fSDinh Nguyen return ret; 388547a1685fSDinh Nguyen } 388647a1685fSDinh Nguyen 388747a1685fSDinh Nguyen /** 38881f91b4ccSFelipe Balbi * dwc2_hsotg_ep_disable - disable given endpoint 388947a1685fSDinh Nguyen * @ep: The endpoint to disable. 389047a1685fSDinh Nguyen */ 38911f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_disable(struct usb_ep *ep) 389247a1685fSDinh Nguyen { 38931f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 3894941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 389547a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 389647a1685fSDinh Nguyen int index = hs_ep->index; 389747a1685fSDinh Nguyen unsigned long flags; 389847a1685fSDinh Nguyen u32 epctrl_reg; 389947a1685fSDinh Nguyen u32 ctrl; 390047a1685fSDinh Nguyen 39011e011293SMarek Szyprowski dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); 390247a1685fSDinh Nguyen 3903c6f5c050SMian Yousaf Kaukab if (ep == &hsotg->eps_out[0]->ep) { 390447a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: called for ep0\n", __func__); 390547a1685fSDinh Nguyen return -EINVAL; 390647a1685fSDinh Nguyen } 390747a1685fSDinh Nguyen 39085f54c54bSVahram Aharonyan /* Remove DMA memory allocated for non-control Endpoints */ 39095f54c54bSVahram Aharonyan if (using_desc_dma(hsotg)) { 39105f54c54bSVahram Aharonyan dma_free_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC * 39115f54c54bSVahram Aharonyan sizeof(struct dwc2_dma_desc), 39125f54c54bSVahram Aharonyan hs_ep->desc_list, hs_ep->desc_list_dma); 39135f54c54bSVahram Aharonyan hs_ep->desc_list = NULL; 39145f54c54bSVahram Aharonyan } 39155f54c54bSVahram Aharonyan 391647a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 391747a1685fSDinh Nguyen 391847a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 391947a1685fSDinh Nguyen 392095c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctrl_reg); 3921a4f82771SVahram Aharonyan 3922a4f82771SVahram Aharonyan if (ctrl & DXEPCTL_EPENA) 3923a4f82771SVahram Aharonyan dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep); 3924a4f82771SVahram Aharonyan 392547a1685fSDinh Nguyen ctrl &= ~DXEPCTL_EPENA; 392647a1685fSDinh Nguyen ctrl &= ~DXEPCTL_USBACTEP; 392747a1685fSDinh Nguyen ctrl |= DXEPCTL_SNAK; 392847a1685fSDinh Nguyen 392947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 393095c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + epctrl_reg); 393147a1685fSDinh Nguyen 393247a1685fSDinh Nguyen /* disable endpoint interrupts */ 39331f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); 393447a1685fSDinh Nguyen 39351141ea01SMian Yousaf Kaukab /* terminate all requests with shutdown */ 39361141ea01SMian Yousaf Kaukab kill_all_requests(hsotg, hs_ep, -ESHUTDOWN); 39371141ea01SMian Yousaf Kaukab 39381c07b20eSRobert Baldyga hsotg->fifo_map &= ~(1 << hs_ep->fifo_index); 39391c07b20eSRobert Baldyga hs_ep->fifo_index = 0; 39401c07b20eSRobert Baldyga hs_ep->fifo_size = 0; 39411c07b20eSRobert Baldyga 394247a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 394347a1685fSDinh Nguyen return 0; 394447a1685fSDinh Nguyen } 394547a1685fSDinh Nguyen 394647a1685fSDinh Nguyen /** 394747a1685fSDinh Nguyen * on_list - check request is on the given endpoint 394847a1685fSDinh Nguyen * @ep: The endpoint to check. 394947a1685fSDinh Nguyen * @test: The request to test if it is on the endpoint. 395047a1685fSDinh Nguyen */ 39511f91b4ccSFelipe Balbi static bool on_list(struct dwc2_hsotg_ep *ep, struct dwc2_hsotg_req *test) 395247a1685fSDinh Nguyen { 39531f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req, *treq; 395447a1685fSDinh Nguyen 395547a1685fSDinh Nguyen list_for_each_entry_safe(req, treq, &ep->queue, queue) { 395647a1685fSDinh Nguyen if (req == test) 395747a1685fSDinh Nguyen return true; 395847a1685fSDinh Nguyen } 395947a1685fSDinh Nguyen 396047a1685fSDinh Nguyen return false; 396147a1685fSDinh Nguyen } 396247a1685fSDinh Nguyen 396347a1685fSDinh Nguyen /** 39641f91b4ccSFelipe Balbi * dwc2_hsotg_ep_dequeue - dequeue given endpoint 396547a1685fSDinh Nguyen * @ep: The endpoint to dequeue. 396647a1685fSDinh Nguyen * @req: The request to be removed from a queue. 396747a1685fSDinh Nguyen */ 39681f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) 396947a1685fSDinh Nguyen { 39701f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 39711f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 3972941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 397347a1685fSDinh Nguyen unsigned long flags; 397447a1685fSDinh Nguyen 39751e011293SMarek Szyprowski dev_dbg(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); 397647a1685fSDinh Nguyen 397747a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 397847a1685fSDinh Nguyen 397947a1685fSDinh Nguyen if (!on_list(hs_ep, hs_req)) { 398047a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 398147a1685fSDinh Nguyen return -EINVAL; 398247a1685fSDinh Nguyen } 398347a1685fSDinh Nguyen 3984c524dd5fSMian Yousaf Kaukab /* Dequeue already started request */ 3985c524dd5fSMian Yousaf Kaukab if (req == &hs_ep->req->req) 3986c524dd5fSMian Yousaf Kaukab dwc2_hsotg_ep_stop_xfr(hs, hs_ep); 3987c524dd5fSMian Yousaf Kaukab 39881f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); 398947a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 399047a1685fSDinh Nguyen 399147a1685fSDinh Nguyen return 0; 399247a1685fSDinh Nguyen } 399347a1685fSDinh Nguyen 399447a1685fSDinh Nguyen /** 39951f91b4ccSFelipe Balbi * dwc2_hsotg_ep_sethalt - set halt on a given endpoint 399647a1685fSDinh Nguyen * @ep: The endpoint to set halt. 399747a1685fSDinh Nguyen * @value: Set or unset the halt. 399851da43b5SVahram Aharonyan * @now: If true, stall the endpoint now. Otherwise return -EAGAIN if 399951da43b5SVahram Aharonyan * the endpoint is busy processing requests. 400051da43b5SVahram Aharonyan * 400151da43b5SVahram Aharonyan * We need to stall the endpoint immediately if request comes from set_feature 400251da43b5SVahram Aharonyan * protocol command handler. 400347a1685fSDinh Nguyen */ 400451da43b5SVahram Aharonyan static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now) 400547a1685fSDinh Nguyen { 40061f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 4007941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 400847a1685fSDinh Nguyen int index = hs_ep->index; 400947a1685fSDinh Nguyen u32 epreg; 401047a1685fSDinh Nguyen u32 epctl; 401147a1685fSDinh Nguyen u32 xfertype; 401247a1685fSDinh Nguyen 401347a1685fSDinh Nguyen dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); 401447a1685fSDinh Nguyen 401547a1685fSDinh Nguyen if (index == 0) { 401647a1685fSDinh Nguyen if (value) 40171f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hs); 401847a1685fSDinh Nguyen else 401947a1685fSDinh Nguyen dev_warn(hs->dev, 402047a1685fSDinh Nguyen "%s: can't clear halt on ep0\n", __func__); 402147a1685fSDinh Nguyen return 0; 402247a1685fSDinh Nguyen } 402347a1685fSDinh Nguyen 402415186f10SVahram Aharonyan if (hs_ep->isochronous) { 402515186f10SVahram Aharonyan dev_err(hs->dev, "%s is Isochronous Endpoint\n", ep->name); 402615186f10SVahram Aharonyan return -EINVAL; 402715186f10SVahram Aharonyan } 402815186f10SVahram Aharonyan 402951da43b5SVahram Aharonyan if (!now && value && !list_empty(&hs_ep->queue)) { 403051da43b5SVahram Aharonyan dev_dbg(hs->dev, "%s request is pending, cannot halt\n", 403151da43b5SVahram Aharonyan ep->name); 403251da43b5SVahram Aharonyan return -EAGAIN; 403351da43b5SVahram Aharonyan } 403451da43b5SVahram Aharonyan 4035c6f5c050SMian Yousaf Kaukab if (hs_ep->dir_in) { 403647a1685fSDinh Nguyen epreg = DIEPCTL(index); 403795c8bc36SAntti Seppälä epctl = dwc2_readl(hs->regs + epreg); 403847a1685fSDinh Nguyen 403947a1685fSDinh Nguyen if (value) { 40405a350d53SFelipe Balbi epctl |= DXEPCTL_STALL | DXEPCTL_SNAK; 404147a1685fSDinh Nguyen if (epctl & DXEPCTL_EPENA) 404247a1685fSDinh Nguyen epctl |= DXEPCTL_EPDIS; 404347a1685fSDinh Nguyen } else { 404447a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 404547a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 404647a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 404747a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 404847a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 404947a1685fSDinh Nguyen } 405095c8bc36SAntti Seppälä dwc2_writel(epctl, hs->regs + epreg); 4051c6f5c050SMian Yousaf Kaukab } else { 405247a1685fSDinh Nguyen epreg = DOEPCTL(index); 405395c8bc36SAntti Seppälä epctl = dwc2_readl(hs->regs + epreg); 405447a1685fSDinh Nguyen 405534c0887fSJohn Youn if (value) { 405647a1685fSDinh Nguyen epctl |= DXEPCTL_STALL; 405734c0887fSJohn Youn } else { 405847a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 405947a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 406047a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 406147a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 406247a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 406347a1685fSDinh Nguyen } 406495c8bc36SAntti Seppälä dwc2_writel(epctl, hs->regs + epreg); 4065c6f5c050SMian Yousaf Kaukab } 406647a1685fSDinh Nguyen 406747a1685fSDinh Nguyen hs_ep->halted = value; 406847a1685fSDinh Nguyen 406947a1685fSDinh Nguyen return 0; 407047a1685fSDinh Nguyen } 407147a1685fSDinh Nguyen 407247a1685fSDinh Nguyen /** 40731f91b4ccSFelipe Balbi * dwc2_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held 407447a1685fSDinh Nguyen * @ep: The endpoint to set halt. 407547a1685fSDinh Nguyen * @value: Set or unset the halt. 407647a1685fSDinh Nguyen */ 40771f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) 407847a1685fSDinh Nguyen { 40791f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 4080941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 408147a1685fSDinh Nguyen unsigned long flags = 0; 408247a1685fSDinh Nguyen int ret = 0; 408347a1685fSDinh Nguyen 408447a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 408551da43b5SVahram Aharonyan ret = dwc2_hsotg_ep_sethalt(ep, value, false); 408647a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 408747a1685fSDinh Nguyen 408847a1685fSDinh Nguyen return ret; 408947a1685fSDinh Nguyen } 409047a1685fSDinh Nguyen 40911f91b4ccSFelipe Balbi static struct usb_ep_ops dwc2_hsotg_ep_ops = { 40921f91b4ccSFelipe Balbi .enable = dwc2_hsotg_ep_enable, 40931f91b4ccSFelipe Balbi .disable = dwc2_hsotg_ep_disable, 40941f91b4ccSFelipe Balbi .alloc_request = dwc2_hsotg_ep_alloc_request, 40951f91b4ccSFelipe Balbi .free_request = dwc2_hsotg_ep_free_request, 40961f91b4ccSFelipe Balbi .queue = dwc2_hsotg_ep_queue_lock, 40971f91b4ccSFelipe Balbi .dequeue = dwc2_hsotg_ep_dequeue, 40981f91b4ccSFelipe Balbi .set_halt = dwc2_hsotg_ep_sethalt_lock, 409947a1685fSDinh Nguyen /* note, don't believe we have any call for the fifo routines */ 410047a1685fSDinh Nguyen }; 410147a1685fSDinh Nguyen 410247a1685fSDinh Nguyen /** 41039da51974SJohn Youn * dwc2_hsotg_init - initialize the usb core 410447a1685fSDinh Nguyen * @hsotg: The driver state 410547a1685fSDinh Nguyen */ 41061f91b4ccSFelipe Balbi static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) 410747a1685fSDinh Nguyen { 4108fa4a8d72SMian Yousaf Kaukab u32 trdtim; 4109ecd9a7adSPrzemek Rudy u32 usbcfg; 411047a1685fSDinh Nguyen /* unmask subset of endpoint interrupts */ 411147a1685fSDinh Nguyen 411295c8bc36SAntti Seppälä dwc2_writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | 411347a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK, 411447a1685fSDinh Nguyen hsotg->regs + DIEPMSK); 411547a1685fSDinh Nguyen 411695c8bc36SAntti Seppälä dwc2_writel(DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | 411747a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK, 411847a1685fSDinh Nguyen hsotg->regs + DOEPMSK); 411947a1685fSDinh Nguyen 412095c8bc36SAntti Seppälä dwc2_writel(0, hsotg->regs + DAINTMSK); 412147a1685fSDinh Nguyen 412247a1685fSDinh Nguyen /* Be in disconnected state until gadget is registered */ 412347a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 412447a1685fSDinh Nguyen 412547a1685fSDinh Nguyen /* setup fifos */ 412647a1685fSDinh Nguyen 412747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 412895c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + GRXFSIZ), 412995c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + GNPTXFSIZ)); 413047a1685fSDinh Nguyen 41311f91b4ccSFelipe Balbi dwc2_hsotg_init_fifo(hsotg); 413247a1685fSDinh Nguyen 4133ecd9a7adSPrzemek Rudy /* keep other bits untouched (so e.g. forced modes are not lost) */ 4134ecd9a7adSPrzemek Rudy usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); 4135ecd9a7adSPrzemek Rudy usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP | 4136ecd9a7adSPrzemek Rudy GUSBCFG_HNPCAP); 4137ecd9a7adSPrzemek Rudy 413847a1685fSDinh Nguyen /* set the PLL on, remove the HNP/SRP and set the PHY */ 4139fa4a8d72SMian Yousaf Kaukab trdtim = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5; 4140ecd9a7adSPrzemek Rudy usbcfg |= hsotg->phyif | GUSBCFG_TOUTCAL(7) | 4141ecd9a7adSPrzemek Rudy (trdtim << GUSBCFG_USBTRDTIM_SHIFT); 4142ecd9a7adSPrzemek Rudy dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); 414347a1685fSDinh Nguyen 4144f5090044SGregory Herrero if (using_dma(hsotg)) 4145f5090044SGregory Herrero __orr32(hsotg->regs + GAHBCFG, GAHBCFG_DMA_EN); 414647a1685fSDinh Nguyen } 414747a1685fSDinh Nguyen 414847a1685fSDinh Nguyen /** 41491f91b4ccSFelipe Balbi * dwc2_hsotg_udc_start - prepare the udc for work 415047a1685fSDinh Nguyen * @gadget: The usb gadget state 415147a1685fSDinh Nguyen * @driver: The usb gadget driver 415247a1685fSDinh Nguyen * 415347a1685fSDinh Nguyen * Perform initialization to prepare udc device and driver 415447a1685fSDinh Nguyen * to work. 415547a1685fSDinh Nguyen */ 41561f91b4ccSFelipe Balbi static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, 415747a1685fSDinh Nguyen struct usb_gadget_driver *driver) 415847a1685fSDinh Nguyen { 4159941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 41605b9451f8SMarek Szyprowski unsigned long flags; 416147a1685fSDinh Nguyen int ret; 416247a1685fSDinh Nguyen 416347a1685fSDinh Nguyen if (!hsotg) { 416447a1685fSDinh Nguyen pr_err("%s: called with no device\n", __func__); 416547a1685fSDinh Nguyen return -ENODEV; 416647a1685fSDinh Nguyen } 416747a1685fSDinh Nguyen 416847a1685fSDinh Nguyen if (!driver) { 416947a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: no driver\n", __func__); 417047a1685fSDinh Nguyen return -EINVAL; 417147a1685fSDinh Nguyen } 417247a1685fSDinh Nguyen 417347a1685fSDinh Nguyen if (driver->max_speed < USB_SPEED_FULL) 417447a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: bad speed\n", __func__); 417547a1685fSDinh Nguyen 417647a1685fSDinh Nguyen if (!driver->setup) { 417747a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: missing entry points\n", __func__); 417847a1685fSDinh Nguyen return -EINVAL; 417947a1685fSDinh Nguyen } 418047a1685fSDinh Nguyen 418147a1685fSDinh Nguyen WARN_ON(hsotg->driver); 418247a1685fSDinh Nguyen 418347a1685fSDinh Nguyen driver->driver.bus = NULL; 418447a1685fSDinh Nguyen hsotg->driver = driver; 418547a1685fSDinh Nguyen hsotg->gadget.dev.of_node = hsotg->dev->of_node; 418647a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 418747a1685fSDinh Nguyen 418809a75e85SMarek Szyprowski if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) { 418909a75e85SMarek Szyprowski ret = dwc2_lowlevel_hw_enable(hsotg); 419009a75e85SMarek Szyprowski if (ret) 419147a1685fSDinh Nguyen goto err; 419247a1685fSDinh Nguyen } 419347a1685fSDinh Nguyen 4194f6c01592SGregory Herrero if (!IS_ERR_OR_NULL(hsotg->uphy)) 4195f6c01592SGregory Herrero otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget); 4196c816c47fSMarek Szyprowski 41975b9451f8SMarek Szyprowski spin_lock_irqsave(&hsotg->lock, flags); 4198d0f0ac56SJohn Youn if (dwc2_hw_is_device(hsotg)) { 41991f91b4ccSFelipe Balbi dwc2_hsotg_init(hsotg); 42001f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 4201d0f0ac56SJohn Youn } 4202d0f0ac56SJohn Youn 4203dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 42045b9451f8SMarek Szyprowski spin_unlock_irqrestore(&hsotg->lock, flags); 42055b9451f8SMarek Szyprowski 420647a1685fSDinh Nguyen dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); 42075b9451f8SMarek Szyprowski 420847a1685fSDinh Nguyen return 0; 420947a1685fSDinh Nguyen 421047a1685fSDinh Nguyen err: 421147a1685fSDinh Nguyen hsotg->driver = NULL; 421247a1685fSDinh Nguyen return ret; 421347a1685fSDinh Nguyen } 421447a1685fSDinh Nguyen 421547a1685fSDinh Nguyen /** 42161f91b4ccSFelipe Balbi * dwc2_hsotg_udc_stop - stop the udc 421747a1685fSDinh Nguyen * @gadget: The usb gadget state 421847a1685fSDinh Nguyen * @driver: The usb gadget driver 421947a1685fSDinh Nguyen * 422047a1685fSDinh Nguyen * Stop udc hw block and stay tunned for future transmissions 422147a1685fSDinh Nguyen */ 42221f91b4ccSFelipe Balbi static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) 422347a1685fSDinh Nguyen { 4224941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 422547a1685fSDinh Nguyen unsigned long flags = 0; 422647a1685fSDinh Nguyen int ep; 422747a1685fSDinh Nguyen 422847a1685fSDinh Nguyen if (!hsotg) 422947a1685fSDinh Nguyen return -ENODEV; 423047a1685fSDinh Nguyen 423147a1685fSDinh Nguyen /* all endpoints should be shutdown */ 4232c6f5c050SMian Yousaf Kaukab for (ep = 1; ep < hsotg->num_of_eps; ep++) { 4233c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 42341f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 4235c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 42361f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 4237c6f5c050SMian Yousaf Kaukab } 423847a1685fSDinh Nguyen 423947a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 424047a1685fSDinh Nguyen 424147a1685fSDinh Nguyen hsotg->driver = NULL; 424247a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 4243dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 424447a1685fSDinh Nguyen 424547a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 424647a1685fSDinh Nguyen 4247f6c01592SGregory Herrero if (!IS_ERR_OR_NULL(hsotg->uphy)) 4248f6c01592SGregory Herrero otg_set_peripheral(hsotg->uphy->otg, NULL); 4249c816c47fSMarek Szyprowski 425009a75e85SMarek Szyprowski if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 425109a75e85SMarek Szyprowski dwc2_lowlevel_hw_disable(hsotg); 425247a1685fSDinh Nguyen 425347a1685fSDinh Nguyen return 0; 425447a1685fSDinh Nguyen } 425547a1685fSDinh Nguyen 425647a1685fSDinh Nguyen /** 42571f91b4ccSFelipe Balbi * dwc2_hsotg_gadget_getframe - read the frame number 425847a1685fSDinh Nguyen * @gadget: The usb gadget state 425947a1685fSDinh Nguyen * 426047a1685fSDinh Nguyen * Read the {micro} frame number 426147a1685fSDinh Nguyen */ 42621f91b4ccSFelipe Balbi static int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget) 426347a1685fSDinh Nguyen { 42641f91b4ccSFelipe Balbi return dwc2_hsotg_read_frameno(to_hsotg(gadget)); 426547a1685fSDinh Nguyen } 426647a1685fSDinh Nguyen 426747a1685fSDinh Nguyen /** 42681f91b4ccSFelipe Balbi * dwc2_hsotg_pullup - connect/disconnect the USB PHY 426947a1685fSDinh Nguyen * @gadget: The usb gadget state 427047a1685fSDinh Nguyen * @is_on: Current state of the USB PHY 427147a1685fSDinh Nguyen * 427247a1685fSDinh Nguyen * Connect/Disconnect the USB PHY pullup 427347a1685fSDinh Nguyen */ 42741f91b4ccSFelipe Balbi static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) 427547a1685fSDinh Nguyen { 4276941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 427747a1685fSDinh Nguyen unsigned long flags = 0; 427847a1685fSDinh Nguyen 427977ba9119SGregory Herrero dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on, 428077ba9119SGregory Herrero hsotg->op_state); 428177ba9119SGregory Herrero 428277ba9119SGregory Herrero /* Don't modify pullup state while in host mode */ 428377ba9119SGregory Herrero if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { 428477ba9119SGregory Herrero hsotg->enabled = is_on; 428577ba9119SGregory Herrero return 0; 428677ba9119SGregory Herrero } 428747a1685fSDinh Nguyen 428847a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 428947a1685fSDinh Nguyen if (is_on) { 4290dc6e69e6SMarek Szyprowski hsotg->enabled = 1; 42911f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 42921f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 429347a1685fSDinh Nguyen } else { 42941f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 42951f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 4296dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 429747a1685fSDinh Nguyen } 429847a1685fSDinh Nguyen 429947a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 430047a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 430147a1685fSDinh Nguyen 430247a1685fSDinh Nguyen return 0; 430347a1685fSDinh Nguyen } 430447a1685fSDinh Nguyen 43051f91b4ccSFelipe Balbi static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) 430683d98223SGregory Herrero { 430783d98223SGregory Herrero struct dwc2_hsotg *hsotg = to_hsotg(gadget); 430883d98223SGregory Herrero unsigned long flags; 430983d98223SGregory Herrero 431083d98223SGregory Herrero dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active); 431183d98223SGregory Herrero spin_lock_irqsave(&hsotg->lock, flags); 431283d98223SGregory Herrero 431318b2b37cSGregory Herrero /* 431418b2b37cSGregory Herrero * If controller is hibernated, it must exit from hibernation 431561f7223bSGregory Herrero * before being initialized / de-initialized 431618b2b37cSGregory Herrero */ 4317065d3931SGregory Herrero if (hsotg->lx_state == DWC2_L2) 431818b2b37cSGregory Herrero dwc2_exit_hibernation(hsotg, false); 4319065d3931SGregory Herrero 432061f7223bSGregory Herrero if (is_active) { 432161f7223bSGregory Herrero hsotg->op_state = OTG_STATE_B_PERIPHERAL; 432261f7223bSGregory Herrero 43231f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 432483d98223SGregory Herrero if (hsotg->enabled) 43251f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 432683d98223SGregory Herrero } else { 43271f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 43281f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 432983d98223SGregory Herrero } 433083d98223SGregory Herrero 433183d98223SGregory Herrero spin_unlock_irqrestore(&hsotg->lock, flags); 433283d98223SGregory Herrero return 0; 433383d98223SGregory Herrero } 433483d98223SGregory Herrero 4335596d696aSGregory Herrero /** 43361f91b4ccSFelipe Balbi * dwc2_hsotg_vbus_draw - report bMaxPower field 4337596d696aSGregory Herrero * @gadget: The usb gadget state 4338596d696aSGregory Herrero * @mA: Amount of current 4339596d696aSGregory Herrero * 4340596d696aSGregory Herrero * Report how much power the device may consume to the phy. 4341596d696aSGregory Herrero */ 43429da51974SJohn Youn static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA) 4343596d696aSGregory Herrero { 4344596d696aSGregory Herrero struct dwc2_hsotg *hsotg = to_hsotg(gadget); 4345596d696aSGregory Herrero 4346596d696aSGregory Herrero if (IS_ERR_OR_NULL(hsotg->uphy)) 4347596d696aSGregory Herrero return -ENOTSUPP; 4348596d696aSGregory Herrero return usb_phy_set_power(hsotg->uphy, mA); 4349596d696aSGregory Herrero } 4350596d696aSGregory Herrero 43511f91b4ccSFelipe Balbi static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { 43521f91b4ccSFelipe Balbi .get_frame = dwc2_hsotg_gadget_getframe, 43531f91b4ccSFelipe Balbi .udc_start = dwc2_hsotg_udc_start, 43541f91b4ccSFelipe Balbi .udc_stop = dwc2_hsotg_udc_stop, 43551f91b4ccSFelipe Balbi .pullup = dwc2_hsotg_pullup, 43561f91b4ccSFelipe Balbi .vbus_session = dwc2_hsotg_vbus_session, 43571f91b4ccSFelipe Balbi .vbus_draw = dwc2_hsotg_vbus_draw, 435847a1685fSDinh Nguyen }; 435947a1685fSDinh Nguyen 436047a1685fSDinh Nguyen /** 43611f91b4ccSFelipe Balbi * dwc2_hsotg_initep - initialise a single endpoint 436247a1685fSDinh Nguyen * @hsotg: The device state. 436347a1685fSDinh Nguyen * @hs_ep: The endpoint to be initialised. 436447a1685fSDinh Nguyen * @epnum: The endpoint number 436547a1685fSDinh Nguyen * 436647a1685fSDinh Nguyen * Initialise the given endpoint (as part of the probe and device state 436747a1685fSDinh Nguyen * creation) to give to the gadget driver. Setup the endpoint name, any 436847a1685fSDinh Nguyen * direction information and other state that may be required. 436947a1685fSDinh Nguyen */ 43701f91b4ccSFelipe Balbi static void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, 43711f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 4372c6f5c050SMian Yousaf Kaukab int epnum, 4373c6f5c050SMian Yousaf Kaukab bool dir_in) 437447a1685fSDinh Nguyen { 437547a1685fSDinh Nguyen char *dir; 437647a1685fSDinh Nguyen 437747a1685fSDinh Nguyen if (epnum == 0) 437847a1685fSDinh Nguyen dir = ""; 4379c6f5c050SMian Yousaf Kaukab else if (dir_in) 438047a1685fSDinh Nguyen dir = "in"; 4381c6f5c050SMian Yousaf Kaukab else 4382c6f5c050SMian Yousaf Kaukab dir = "out"; 438347a1685fSDinh Nguyen 4384c6f5c050SMian Yousaf Kaukab hs_ep->dir_in = dir_in; 438547a1685fSDinh Nguyen hs_ep->index = epnum; 438647a1685fSDinh Nguyen 438747a1685fSDinh Nguyen snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); 438847a1685fSDinh Nguyen 438947a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->queue); 439047a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->ep.ep_list); 439147a1685fSDinh Nguyen 439247a1685fSDinh Nguyen /* add to the list of endpoints known by the gadget driver */ 439347a1685fSDinh Nguyen if (epnum) 439447a1685fSDinh Nguyen list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); 439547a1685fSDinh Nguyen 439647a1685fSDinh Nguyen hs_ep->parent = hsotg; 439747a1685fSDinh Nguyen hs_ep->ep.name = hs_ep->name; 439838e9002bSVardan Mikayelyan 439938e9002bSVardan Mikayelyan if (hsotg->params.speed == DWC2_SPEED_PARAM_LOW) 440038e9002bSVardan Mikayelyan usb_ep_set_maxpacket_limit(&hs_ep->ep, 8); 440138e9002bSVardan Mikayelyan else 440238e9002bSVardan Mikayelyan usb_ep_set_maxpacket_limit(&hs_ep->ep, 440338e9002bSVardan Mikayelyan epnum ? 1024 : EP0_MPS_LIMIT); 44041f91b4ccSFelipe Balbi hs_ep->ep.ops = &dwc2_hsotg_ep_ops; 440547a1685fSDinh Nguyen 44062954522fSRobert Baldyga if (epnum == 0) { 44072954522fSRobert Baldyga hs_ep->ep.caps.type_control = true; 44082954522fSRobert Baldyga } else { 440938e9002bSVardan Mikayelyan if (hsotg->params.speed != DWC2_SPEED_PARAM_LOW) { 44102954522fSRobert Baldyga hs_ep->ep.caps.type_iso = true; 44112954522fSRobert Baldyga hs_ep->ep.caps.type_bulk = true; 441238e9002bSVardan Mikayelyan } 44132954522fSRobert Baldyga hs_ep->ep.caps.type_int = true; 44142954522fSRobert Baldyga } 44152954522fSRobert Baldyga 44162954522fSRobert Baldyga if (dir_in) 44172954522fSRobert Baldyga hs_ep->ep.caps.dir_in = true; 44182954522fSRobert Baldyga else 44192954522fSRobert Baldyga hs_ep->ep.caps.dir_out = true; 44202954522fSRobert Baldyga 442147a1685fSDinh Nguyen /* 442247a1685fSDinh Nguyen * if we're using dma, we need to set the next-endpoint pointer 442347a1685fSDinh Nguyen * to be something valid. 442447a1685fSDinh Nguyen */ 442547a1685fSDinh Nguyen 442647a1685fSDinh Nguyen if (using_dma(hsotg)) { 442747a1685fSDinh Nguyen u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); 44289da51974SJohn Youn 4429c6f5c050SMian Yousaf Kaukab if (dir_in) 443095c8bc36SAntti Seppälä dwc2_writel(next, hsotg->regs + DIEPCTL(epnum)); 4431c6f5c050SMian Yousaf Kaukab else 443295c8bc36SAntti Seppälä dwc2_writel(next, hsotg->regs + DOEPCTL(epnum)); 443347a1685fSDinh Nguyen } 443447a1685fSDinh Nguyen } 443547a1685fSDinh Nguyen 443647a1685fSDinh Nguyen /** 44371f91b4ccSFelipe Balbi * dwc2_hsotg_hw_cfg - read HW configuration registers 443847a1685fSDinh Nguyen * @param: The device state 443947a1685fSDinh Nguyen * 444047a1685fSDinh Nguyen * Read the USB core HW configuration registers 444147a1685fSDinh Nguyen */ 44421f91b4ccSFelipe Balbi static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) 444347a1685fSDinh Nguyen { 4444c6f5c050SMian Yousaf Kaukab u32 cfg; 4445c6f5c050SMian Yousaf Kaukab u32 ep_type; 4446c6f5c050SMian Yousaf Kaukab u32 i; 4447c6f5c050SMian Yousaf Kaukab 444847a1685fSDinh Nguyen /* check hardware configuration */ 444947a1685fSDinh Nguyen 445043e90349SJohn Youn hsotg->num_of_eps = hsotg->hw_params.num_dev_ep; 445143e90349SJohn Youn 4452c6f5c050SMian Yousaf Kaukab /* Add ep0 */ 4453c6f5c050SMian Yousaf Kaukab hsotg->num_of_eps++; 445447a1685fSDinh Nguyen 4455*b98866c2SJohn Youn hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, 4456*b98866c2SJohn Youn sizeof(struct dwc2_hsotg_ep), 4457c6f5c050SMian Yousaf Kaukab GFP_KERNEL); 4458c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_in[0]) 4459c6f5c050SMian Yousaf Kaukab return -ENOMEM; 44601f91b4ccSFelipe Balbi /* Same dwc2_hsotg_ep is used in both directions for ep0 */ 4461c6f5c050SMian Yousaf Kaukab hsotg->eps_out[0] = hsotg->eps_in[0]; 446247a1685fSDinh Nguyen 446343e90349SJohn Youn cfg = hsotg->hw_params.dev_ep_dirs; 4464251a17f5SRoshan Pius for (i = 1, cfg >>= 2; i < hsotg->num_of_eps; i++, cfg >>= 2) { 4465c6f5c050SMian Yousaf Kaukab ep_type = cfg & 3; 4466c6f5c050SMian Yousaf Kaukab /* Direction in or both */ 4467c6f5c050SMian Yousaf Kaukab if (!(ep_type & 2)) { 4468c6f5c050SMian Yousaf Kaukab hsotg->eps_in[i] = devm_kzalloc(hsotg->dev, 44691f91b4ccSFelipe Balbi sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 4470c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_in[i]) 4471c6f5c050SMian Yousaf Kaukab return -ENOMEM; 4472c6f5c050SMian Yousaf Kaukab } 4473c6f5c050SMian Yousaf Kaukab /* Direction out or both */ 4474c6f5c050SMian Yousaf Kaukab if (!(ep_type & 1)) { 4475c6f5c050SMian Yousaf Kaukab hsotg->eps_out[i] = devm_kzalloc(hsotg->dev, 44761f91b4ccSFelipe Balbi sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 4477c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_out[i]) 4478c6f5c050SMian Yousaf Kaukab return -ENOMEM; 4479c6f5c050SMian Yousaf Kaukab } 4480c6f5c050SMian Yousaf Kaukab } 4481c6f5c050SMian Yousaf Kaukab 448243e90349SJohn Youn hsotg->fifo_mem = hsotg->hw_params.total_fifo_size; 448343e90349SJohn Youn hsotg->dedicated_fifos = hsotg->hw_params.en_multiple_tx_fifo; 448447a1685fSDinh Nguyen 4485cff9eb75SMarek Szyprowski dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n", 4486cff9eb75SMarek Szyprowski hsotg->num_of_eps, 4487cff9eb75SMarek Szyprowski hsotg->dedicated_fifos ? "dedicated" : "shared", 4488cff9eb75SMarek Szyprowski hsotg->fifo_mem); 4489c6f5c050SMian Yousaf Kaukab return 0; 449047a1685fSDinh Nguyen } 449147a1685fSDinh Nguyen 449247a1685fSDinh Nguyen /** 44931f91b4ccSFelipe Balbi * dwc2_hsotg_dump - dump state of the udc 449447a1685fSDinh Nguyen * @param: The device state 449547a1685fSDinh Nguyen */ 44961f91b4ccSFelipe Balbi static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) 449747a1685fSDinh Nguyen { 449847a1685fSDinh Nguyen #ifdef DEBUG 449947a1685fSDinh Nguyen struct device *dev = hsotg->dev; 450047a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 450147a1685fSDinh Nguyen u32 val; 450247a1685fSDinh Nguyen int idx; 450347a1685fSDinh Nguyen 450447a1685fSDinh Nguyen dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", 450595c8bc36SAntti Seppälä dwc2_readl(regs + DCFG), dwc2_readl(regs + DCTL), 450695c8bc36SAntti Seppälä dwc2_readl(regs + DIEPMSK)); 450747a1685fSDinh Nguyen 4508f889f23dSMian Yousaf Kaukab dev_info(dev, "GAHBCFG=0x%08x, GHWCFG1=0x%08x\n", 450995c8bc36SAntti Seppälä dwc2_readl(regs + GAHBCFG), dwc2_readl(regs + GHWCFG1)); 451047a1685fSDinh Nguyen 451147a1685fSDinh Nguyen dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 451295c8bc36SAntti Seppälä dwc2_readl(regs + GRXFSIZ), dwc2_readl(regs + GNPTXFSIZ)); 451347a1685fSDinh Nguyen 451447a1685fSDinh Nguyen /* show periodic fifo settings */ 451547a1685fSDinh Nguyen 4516364f8e93SMian Yousaf Kaukab for (idx = 1; idx < hsotg->num_of_eps; idx++) { 451795c8bc36SAntti Seppälä val = dwc2_readl(regs + DPTXFSIZN(idx)); 451847a1685fSDinh Nguyen dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, 451947a1685fSDinh Nguyen val >> FIFOSIZE_DEPTH_SHIFT, 452047a1685fSDinh Nguyen val & FIFOSIZE_STARTADDR_MASK); 452147a1685fSDinh Nguyen } 452247a1685fSDinh Nguyen 4523364f8e93SMian Yousaf Kaukab for (idx = 0; idx < hsotg->num_of_eps; idx++) { 452447a1685fSDinh Nguyen dev_info(dev, 452547a1685fSDinh Nguyen "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, 452695c8bc36SAntti Seppälä dwc2_readl(regs + DIEPCTL(idx)), 452795c8bc36SAntti Seppälä dwc2_readl(regs + DIEPTSIZ(idx)), 452895c8bc36SAntti Seppälä dwc2_readl(regs + DIEPDMA(idx))); 452947a1685fSDinh Nguyen 453095c8bc36SAntti Seppälä val = dwc2_readl(regs + DOEPCTL(idx)); 453147a1685fSDinh Nguyen dev_info(dev, 453247a1685fSDinh Nguyen "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", 453395c8bc36SAntti Seppälä idx, dwc2_readl(regs + DOEPCTL(idx)), 453495c8bc36SAntti Seppälä dwc2_readl(regs + DOEPTSIZ(idx)), 453595c8bc36SAntti Seppälä dwc2_readl(regs + DOEPDMA(idx))); 453647a1685fSDinh Nguyen } 453747a1685fSDinh Nguyen 453847a1685fSDinh Nguyen dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", 453995c8bc36SAntti Seppälä dwc2_readl(regs + DVBUSDIS), dwc2_readl(regs + DVBUSPULSE)); 454047a1685fSDinh Nguyen #endif 454147a1685fSDinh Nguyen } 454247a1685fSDinh Nguyen 454347a1685fSDinh Nguyen /** 4544117777b2SDinh Nguyen * dwc2_gadget_init - init function for gadget 4545117777b2SDinh Nguyen * @dwc2: The data structure for the DWC2 driver. 4546117777b2SDinh Nguyen * @irq: The IRQ number for the controller. 454747a1685fSDinh Nguyen */ 4548117777b2SDinh Nguyen int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) 454947a1685fSDinh Nguyen { 4550117777b2SDinh Nguyen struct device *dev = hsotg->dev; 455147a1685fSDinh Nguyen int epnum; 455247a1685fSDinh Nguyen int ret; 455343e90349SJohn Youn 45540a176279SGregory Herrero /* Dump fifo information */ 45550a176279SGregory Herrero dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n", 455605ee799fSJohn Youn hsotg->params.g_np_tx_fifo_size); 455705ee799fSJohn Youn dev_dbg(dev, "RXFIFO size: %d\n", hsotg->params.g_rx_fifo_size); 455847a1685fSDinh Nguyen 455947a1685fSDinh Nguyen hsotg->gadget.max_speed = USB_SPEED_HIGH; 45601f91b4ccSFelipe Balbi hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; 456147a1685fSDinh Nguyen hsotg->gadget.name = dev_name(dev); 4562097ee662SGregory Herrero if (hsotg->dr_mode == USB_DR_MODE_OTG) 4563097ee662SGregory Herrero hsotg->gadget.is_otg = 1; 4564ec4cc657SMian Yousaf Kaukab else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 4565ec4cc657SMian Yousaf Kaukab hsotg->op_state = OTG_STATE_B_PERIPHERAL; 456647a1685fSDinh Nguyen 45671f91b4ccSFelipe Balbi ret = dwc2_hsotg_hw_cfg(hsotg); 4568c6f5c050SMian Yousaf Kaukab if (ret) { 4569c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret); 457009a75e85SMarek Szyprowski return ret; 4571c6f5c050SMian Yousaf Kaukab } 4572c6f5c050SMian Yousaf Kaukab 45733f95001dSMian Yousaf Kaukab hsotg->ctrl_buff = devm_kzalloc(hsotg->dev, 45743f95001dSMian Yousaf Kaukab DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 45758bae0f8cSWolfram Sang if (!hsotg->ctrl_buff) 457609a75e85SMarek Szyprowski return -ENOMEM; 45773f95001dSMian Yousaf Kaukab 45783f95001dSMian Yousaf Kaukab hsotg->ep0_buff = devm_kzalloc(hsotg->dev, 45793f95001dSMian Yousaf Kaukab DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 45808bae0f8cSWolfram Sang if (!hsotg->ep0_buff) 458109a75e85SMarek Szyprowski return -ENOMEM; 45823f95001dSMian Yousaf Kaukab 45830f6b80c0SVahram Aharonyan if (using_desc_dma(hsotg)) { 45840f6b80c0SVahram Aharonyan ret = dwc2_gadget_alloc_ctrl_desc_chains(hsotg); 45850f6b80c0SVahram Aharonyan if (ret < 0) 45860f6b80c0SVahram Aharonyan return ret; 45870f6b80c0SVahram Aharonyan } 45880f6b80c0SVahram Aharonyan 45891f91b4ccSFelipe Balbi ret = devm_request_irq(hsotg->dev, irq, dwc2_hsotg_irq, IRQF_SHARED, 4590db8178c3SDinh Nguyen dev_name(hsotg->dev), hsotg); 4591eb3c56c5SMarek Szyprowski if (ret < 0) { 4592db8178c3SDinh Nguyen dev_err(dev, "cannot claim IRQ for gadget\n"); 459309a75e85SMarek Szyprowski return ret; 4594eb3c56c5SMarek Szyprowski } 4595eb3c56c5SMarek Szyprowski 459647a1685fSDinh Nguyen /* hsotg->num_of_eps holds number of EPs other than ep0 */ 459747a1685fSDinh Nguyen 459847a1685fSDinh Nguyen if (hsotg->num_of_eps == 0) { 459947a1685fSDinh Nguyen dev_err(dev, "wrong number of EPs (zero)\n"); 460009a75e85SMarek Szyprowski return -EINVAL; 460147a1685fSDinh Nguyen } 460247a1685fSDinh Nguyen 460347a1685fSDinh Nguyen /* setup endpoint information */ 460447a1685fSDinh Nguyen 460547a1685fSDinh Nguyen INIT_LIST_HEAD(&hsotg->gadget.ep_list); 4606c6f5c050SMian Yousaf Kaukab hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep; 460747a1685fSDinh Nguyen 460847a1685fSDinh Nguyen /* allocate EP0 request */ 460947a1685fSDinh Nguyen 46101f91b4ccSFelipe Balbi hsotg->ctrl_req = dwc2_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep, 461147a1685fSDinh Nguyen GFP_KERNEL); 461247a1685fSDinh Nguyen if (!hsotg->ctrl_req) { 461347a1685fSDinh Nguyen dev_err(dev, "failed to allocate ctrl req\n"); 461409a75e85SMarek Szyprowski return -ENOMEM; 461547a1685fSDinh Nguyen } 461647a1685fSDinh Nguyen 461747a1685fSDinh Nguyen /* initialise the endpoints now the core has been initialised */ 4618c6f5c050SMian Yousaf Kaukab for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) { 4619c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[epnum]) 46201f91b4ccSFelipe Balbi dwc2_hsotg_initep(hsotg, hsotg->eps_in[epnum], 4621c6f5c050SMian Yousaf Kaukab epnum, 1); 4622c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[epnum]) 46231f91b4ccSFelipe Balbi dwc2_hsotg_initep(hsotg, hsotg->eps_out[epnum], 4624c6f5c050SMian Yousaf Kaukab epnum, 0); 4625c6f5c050SMian Yousaf Kaukab } 462647a1685fSDinh Nguyen 4627117777b2SDinh Nguyen ret = usb_add_gadget_udc(dev, &hsotg->gadget); 462847a1685fSDinh Nguyen if (ret) 462909a75e85SMarek Szyprowski return ret; 463047a1685fSDinh Nguyen 46311f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 463247a1685fSDinh Nguyen 463347a1685fSDinh Nguyen return 0; 463447a1685fSDinh Nguyen } 463547a1685fSDinh Nguyen 463647a1685fSDinh Nguyen /** 46371f91b4ccSFelipe Balbi * dwc2_hsotg_remove - remove function for hsotg driver 463847a1685fSDinh Nguyen * @pdev: The platform information for the driver 463947a1685fSDinh Nguyen */ 46401f91b4ccSFelipe Balbi int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg) 464147a1685fSDinh Nguyen { 464247a1685fSDinh Nguyen usb_del_gadget_udc(&hsotg->gadget); 464347a1685fSDinh Nguyen 464447a1685fSDinh Nguyen return 0; 464547a1685fSDinh Nguyen } 464647a1685fSDinh Nguyen 46471f91b4ccSFelipe Balbi int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) 464847a1685fSDinh Nguyen { 464947a1685fSDinh Nguyen unsigned long flags; 465047a1685fSDinh Nguyen 46519e779778SGregory Herrero if (hsotg->lx_state != DWC2_L0) 465209a75e85SMarek Szyprowski return 0; 46539e779778SGregory Herrero 4654dc6e69e6SMarek Szyprowski if (hsotg->driver) { 4655dc6e69e6SMarek Szyprowski int ep; 4656dc6e69e6SMarek Szyprowski 465747a1685fSDinh Nguyen dev_info(hsotg->dev, "suspending usb gadget %s\n", 465847a1685fSDinh Nguyen hsotg->driver->driver.name); 465947a1685fSDinh Nguyen 466047a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 4661dc6e69e6SMarek Szyprowski if (hsotg->enabled) 46621f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 46631f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 466447a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 466547a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 466647a1685fSDinh Nguyen 4667c6f5c050SMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps; ep++) { 4668c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 46691f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 4670c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 46711f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 4672c6f5c050SMian Yousaf Kaukab } 467347a1685fSDinh Nguyen } 467447a1685fSDinh Nguyen 467509a75e85SMarek Szyprowski return 0; 467647a1685fSDinh Nguyen } 467747a1685fSDinh Nguyen 46781f91b4ccSFelipe Balbi int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg) 467947a1685fSDinh Nguyen { 468047a1685fSDinh Nguyen unsigned long flags; 468147a1685fSDinh Nguyen 46829e779778SGregory Herrero if (hsotg->lx_state == DWC2_L2) 468309a75e85SMarek Szyprowski return 0; 46849e779778SGregory Herrero 468547a1685fSDinh Nguyen if (hsotg->driver) { 468647a1685fSDinh Nguyen dev_info(hsotg->dev, "resuming usb gadget %s\n", 468747a1685fSDinh Nguyen hsotg->driver->driver.name); 4688d00b4142SRobert Baldyga 468947a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 46901f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 4691dc6e69e6SMarek Szyprowski if (hsotg->enabled) 46921f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 469347a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 4694dc6e69e6SMarek Szyprowski } 469547a1685fSDinh Nguyen 469609a75e85SMarek Szyprowski return 0; 469747a1685fSDinh Nguyen } 469858e52ff6SJohn Youn 469958e52ff6SJohn Youn /** 470058e52ff6SJohn Youn * dwc2_backup_device_registers() - Backup controller device registers. 470158e52ff6SJohn Youn * When suspending usb bus, registers needs to be backuped 470258e52ff6SJohn Youn * if controller power is disabled once suspended. 470358e52ff6SJohn Youn * 470458e52ff6SJohn Youn * @hsotg: Programming view of the DWC_otg controller 470558e52ff6SJohn Youn */ 470658e52ff6SJohn Youn int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg) 470758e52ff6SJohn Youn { 470858e52ff6SJohn Youn struct dwc2_dregs_backup *dr; 470958e52ff6SJohn Youn int i; 471058e52ff6SJohn Youn 471158e52ff6SJohn Youn dev_dbg(hsotg->dev, "%s\n", __func__); 471258e52ff6SJohn Youn 471358e52ff6SJohn Youn /* Backup dev regs */ 471458e52ff6SJohn Youn dr = &hsotg->dr_backup; 471558e52ff6SJohn Youn 471658e52ff6SJohn Youn dr->dcfg = dwc2_readl(hsotg->regs + DCFG); 471758e52ff6SJohn Youn dr->dctl = dwc2_readl(hsotg->regs + DCTL); 471858e52ff6SJohn Youn dr->daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); 471958e52ff6SJohn Youn dr->diepmsk = dwc2_readl(hsotg->regs + DIEPMSK); 472058e52ff6SJohn Youn dr->doepmsk = dwc2_readl(hsotg->regs + DOEPMSK); 472158e52ff6SJohn Youn 472258e52ff6SJohn Youn for (i = 0; i < hsotg->num_of_eps; i++) { 472358e52ff6SJohn Youn /* Backup IN EPs */ 472458e52ff6SJohn Youn dr->diepctl[i] = dwc2_readl(hsotg->regs + DIEPCTL(i)); 472558e52ff6SJohn Youn 472658e52ff6SJohn Youn /* Ensure DATA PID is correctly configured */ 472758e52ff6SJohn Youn if (dr->diepctl[i] & DXEPCTL_DPID) 472858e52ff6SJohn Youn dr->diepctl[i] |= DXEPCTL_SETD1PID; 472958e52ff6SJohn Youn else 473058e52ff6SJohn Youn dr->diepctl[i] |= DXEPCTL_SETD0PID; 473158e52ff6SJohn Youn 473258e52ff6SJohn Youn dr->dieptsiz[i] = dwc2_readl(hsotg->regs + DIEPTSIZ(i)); 473358e52ff6SJohn Youn dr->diepdma[i] = dwc2_readl(hsotg->regs + DIEPDMA(i)); 473458e52ff6SJohn Youn 473558e52ff6SJohn Youn /* Backup OUT EPs */ 473658e52ff6SJohn Youn dr->doepctl[i] = dwc2_readl(hsotg->regs + DOEPCTL(i)); 473758e52ff6SJohn Youn 473858e52ff6SJohn Youn /* Ensure DATA PID is correctly configured */ 473958e52ff6SJohn Youn if (dr->doepctl[i] & DXEPCTL_DPID) 474058e52ff6SJohn Youn dr->doepctl[i] |= DXEPCTL_SETD1PID; 474158e52ff6SJohn Youn else 474258e52ff6SJohn Youn dr->doepctl[i] |= DXEPCTL_SETD0PID; 474358e52ff6SJohn Youn 474458e52ff6SJohn Youn dr->doeptsiz[i] = dwc2_readl(hsotg->regs + DOEPTSIZ(i)); 474558e52ff6SJohn Youn dr->doepdma[i] = dwc2_readl(hsotg->regs + DOEPDMA(i)); 474658e52ff6SJohn Youn } 474758e52ff6SJohn Youn dr->valid = true; 474858e52ff6SJohn Youn return 0; 474958e52ff6SJohn Youn } 475058e52ff6SJohn Youn 475158e52ff6SJohn Youn /** 475258e52ff6SJohn Youn * dwc2_restore_device_registers() - Restore controller device registers. 475358e52ff6SJohn Youn * When resuming usb bus, device registers needs to be restored 475458e52ff6SJohn Youn * if controller power were disabled. 475558e52ff6SJohn Youn * 475658e52ff6SJohn Youn * @hsotg: Programming view of the DWC_otg controller 475758e52ff6SJohn Youn */ 475858e52ff6SJohn Youn int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg) 475958e52ff6SJohn Youn { 476058e52ff6SJohn Youn struct dwc2_dregs_backup *dr; 476158e52ff6SJohn Youn u32 dctl; 476258e52ff6SJohn Youn int i; 476358e52ff6SJohn Youn 476458e52ff6SJohn Youn dev_dbg(hsotg->dev, "%s\n", __func__); 476558e52ff6SJohn Youn 476658e52ff6SJohn Youn /* Restore dev regs */ 476758e52ff6SJohn Youn dr = &hsotg->dr_backup; 476858e52ff6SJohn Youn if (!dr->valid) { 476958e52ff6SJohn Youn dev_err(hsotg->dev, "%s: no device registers to restore\n", 477058e52ff6SJohn Youn __func__); 477158e52ff6SJohn Youn return -EINVAL; 477258e52ff6SJohn Youn } 477358e52ff6SJohn Youn dr->valid = false; 477458e52ff6SJohn Youn 477558e52ff6SJohn Youn dwc2_writel(dr->dcfg, hsotg->regs + DCFG); 477658e52ff6SJohn Youn dwc2_writel(dr->dctl, hsotg->regs + DCTL); 477758e52ff6SJohn Youn dwc2_writel(dr->daintmsk, hsotg->regs + DAINTMSK); 477858e52ff6SJohn Youn dwc2_writel(dr->diepmsk, hsotg->regs + DIEPMSK); 477958e52ff6SJohn Youn dwc2_writel(dr->doepmsk, hsotg->regs + DOEPMSK); 478058e52ff6SJohn Youn 478158e52ff6SJohn Youn for (i = 0; i < hsotg->num_of_eps; i++) { 478258e52ff6SJohn Youn /* Restore IN EPs */ 478358e52ff6SJohn Youn dwc2_writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i)); 478458e52ff6SJohn Youn dwc2_writel(dr->dieptsiz[i], hsotg->regs + DIEPTSIZ(i)); 478558e52ff6SJohn Youn dwc2_writel(dr->diepdma[i], hsotg->regs + DIEPDMA(i)); 478658e52ff6SJohn Youn 478758e52ff6SJohn Youn /* Restore OUT EPs */ 478858e52ff6SJohn Youn dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i)); 478958e52ff6SJohn Youn dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i)); 479058e52ff6SJohn Youn dwc2_writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i)); 479158e52ff6SJohn Youn } 479258e52ff6SJohn Youn 479358e52ff6SJohn Youn /* Set the Power-On Programming done bit */ 479458e52ff6SJohn Youn dctl = dwc2_readl(hsotg->regs + DCTL); 479558e52ff6SJohn Youn dctl |= DCTL_PWRONPRGDONE; 479658e52ff6SJohn Youn dwc2_writel(dctl, hsotg->regs + DCTL); 479758e52ff6SJohn Youn 479858e52ff6SJohn Youn return 0; 479958e52ff6SJohn Youn } 4800