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; 31947a1685fSDinh Nguyen 32047a1685fSDinh Nguyen /* ignore this if we're not moving any data */ 32147a1685fSDinh Nguyen if (hs_req->req.length == 0) 32247a1685fSDinh Nguyen return; 32347a1685fSDinh Nguyen 32447a1685fSDinh Nguyen usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); 32547a1685fSDinh Nguyen } 32647a1685fSDinh Nguyen 327*0f6b80c0SVahram Aharonyan /* 328*0f6b80c0SVahram Aharonyan * dwc2_gadget_alloc_ctrl_desc_chains - allocate DMA descriptor chains 329*0f6b80c0SVahram Aharonyan * for Control endpoint 330*0f6b80c0SVahram Aharonyan * @hsotg: The device state. 331*0f6b80c0SVahram Aharonyan * 332*0f6b80c0SVahram Aharonyan * This function will allocate 4 descriptor chains for EP 0: 2 for 333*0f6b80c0SVahram Aharonyan * Setup stage, per one for IN and OUT data/status transactions. 334*0f6b80c0SVahram Aharonyan */ 335*0f6b80c0SVahram Aharonyan static int dwc2_gadget_alloc_ctrl_desc_chains(struct dwc2_hsotg *hsotg) 336*0f6b80c0SVahram Aharonyan { 337*0f6b80c0SVahram Aharonyan hsotg->setup_desc[0] = 338*0f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 339*0f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 340*0f6b80c0SVahram Aharonyan &hsotg->setup_desc_dma[0], 341*0f6b80c0SVahram Aharonyan GFP_KERNEL); 342*0f6b80c0SVahram Aharonyan if (!hsotg->setup_desc[0]) 343*0f6b80c0SVahram Aharonyan goto fail; 344*0f6b80c0SVahram Aharonyan 345*0f6b80c0SVahram Aharonyan hsotg->setup_desc[1] = 346*0f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 347*0f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 348*0f6b80c0SVahram Aharonyan &hsotg->setup_desc_dma[1], 349*0f6b80c0SVahram Aharonyan GFP_KERNEL); 350*0f6b80c0SVahram Aharonyan if (!hsotg->setup_desc[1]) 351*0f6b80c0SVahram Aharonyan goto fail; 352*0f6b80c0SVahram Aharonyan 353*0f6b80c0SVahram Aharonyan hsotg->ctrl_in_desc = 354*0f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 355*0f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 356*0f6b80c0SVahram Aharonyan &hsotg->ctrl_in_desc_dma, 357*0f6b80c0SVahram Aharonyan GFP_KERNEL); 358*0f6b80c0SVahram Aharonyan if (!hsotg->ctrl_in_desc) 359*0f6b80c0SVahram Aharonyan goto fail; 360*0f6b80c0SVahram Aharonyan 361*0f6b80c0SVahram Aharonyan hsotg->ctrl_out_desc = 362*0f6b80c0SVahram Aharonyan dmam_alloc_coherent(hsotg->dev, 363*0f6b80c0SVahram Aharonyan sizeof(struct dwc2_dma_desc), 364*0f6b80c0SVahram Aharonyan &hsotg->ctrl_out_desc_dma, 365*0f6b80c0SVahram Aharonyan GFP_KERNEL); 366*0f6b80c0SVahram Aharonyan if (!hsotg->ctrl_out_desc) 367*0f6b80c0SVahram Aharonyan goto fail; 368*0f6b80c0SVahram Aharonyan 369*0f6b80c0SVahram Aharonyan return 0; 370*0f6b80c0SVahram Aharonyan 371*0f6b80c0SVahram Aharonyan fail: 372*0f6b80c0SVahram Aharonyan return -ENOMEM; 373*0f6b80c0SVahram Aharonyan } 374*0f6b80c0SVahram Aharonyan 37547a1685fSDinh Nguyen /** 3761f91b4ccSFelipe Balbi * dwc2_hsotg_write_fifo - write packet Data to the TxFIFO 37747a1685fSDinh Nguyen * @hsotg: The controller state. 37847a1685fSDinh Nguyen * @hs_ep: The endpoint we're going to write for. 37947a1685fSDinh Nguyen * @hs_req: The request to write data for. 38047a1685fSDinh Nguyen * 38147a1685fSDinh Nguyen * This is called when the TxFIFO has some space in it to hold a new 38247a1685fSDinh Nguyen * transmission and we have something to give it. The actual setup of 38347a1685fSDinh Nguyen * the data size is done elsewhere, so all we have to do is to actually 38447a1685fSDinh Nguyen * write the data. 38547a1685fSDinh Nguyen * 38647a1685fSDinh Nguyen * The return value is zero if there is more space (or nothing was done) 38747a1685fSDinh Nguyen * otherwise -ENOSPC is returned if the FIFO space was used up. 38847a1685fSDinh Nguyen * 38947a1685fSDinh Nguyen * This routine is only needed for PIO 39047a1685fSDinh Nguyen */ 3911f91b4ccSFelipe Balbi static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, 3921f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 3931f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req) 39447a1685fSDinh Nguyen { 39547a1685fSDinh Nguyen bool periodic = is_ep_periodic(hs_ep); 39695c8bc36SAntti Seppälä u32 gnptxsts = dwc2_readl(hsotg->regs + GNPTXSTS); 39747a1685fSDinh Nguyen int buf_pos = hs_req->req.actual; 39847a1685fSDinh Nguyen int to_write = hs_ep->size_loaded; 39947a1685fSDinh Nguyen void *data; 40047a1685fSDinh Nguyen int can_write; 40147a1685fSDinh Nguyen int pkt_round; 40247a1685fSDinh Nguyen int max_transfer; 40347a1685fSDinh Nguyen 40447a1685fSDinh Nguyen to_write -= (buf_pos - hs_ep->last_load); 40547a1685fSDinh Nguyen 40647a1685fSDinh Nguyen /* if there's nothing to write, get out early */ 40747a1685fSDinh Nguyen if (to_write == 0) 40847a1685fSDinh Nguyen return 0; 40947a1685fSDinh Nguyen 41047a1685fSDinh Nguyen if (periodic && !hsotg->dedicated_fifos) { 41195c8bc36SAntti Seppälä u32 epsize = dwc2_readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); 41247a1685fSDinh Nguyen int size_left; 41347a1685fSDinh Nguyen int size_done; 41447a1685fSDinh Nguyen 41547a1685fSDinh Nguyen /* 41647a1685fSDinh Nguyen * work out how much data was loaded so we can calculate 41747a1685fSDinh Nguyen * how much data is left in the fifo. 41847a1685fSDinh Nguyen */ 41947a1685fSDinh Nguyen 42047a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 42147a1685fSDinh Nguyen 42247a1685fSDinh Nguyen /* 42347a1685fSDinh Nguyen * if shared fifo, we cannot write anything until the 42447a1685fSDinh Nguyen * previous data has been completely sent. 42547a1685fSDinh Nguyen */ 42647a1685fSDinh Nguyen if (hs_ep->fifo_load != 0) { 4271f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 42847a1685fSDinh Nguyen return -ENOSPC; 42947a1685fSDinh Nguyen } 43047a1685fSDinh Nguyen 43147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", 43247a1685fSDinh Nguyen __func__, size_left, 43347a1685fSDinh Nguyen hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); 43447a1685fSDinh Nguyen 43547a1685fSDinh Nguyen /* how much of the data has moved */ 43647a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 43747a1685fSDinh Nguyen 43847a1685fSDinh Nguyen /* how much data is left in the fifo */ 43947a1685fSDinh Nguyen can_write = hs_ep->fifo_load - size_done; 44047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", 44147a1685fSDinh Nguyen __func__, can_write); 44247a1685fSDinh Nguyen 44347a1685fSDinh Nguyen can_write = hs_ep->fifo_size - can_write; 44447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", 44547a1685fSDinh Nguyen __func__, can_write); 44647a1685fSDinh Nguyen 44747a1685fSDinh Nguyen if (can_write <= 0) { 4481f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 44947a1685fSDinh Nguyen return -ENOSPC; 45047a1685fSDinh Nguyen } 45147a1685fSDinh Nguyen } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { 452ad674a15SRobert Baldyga can_write = dwc2_readl(hsotg->regs + 453ad674a15SRobert Baldyga DTXFSTS(hs_ep->fifo_index)); 45447a1685fSDinh Nguyen 45547a1685fSDinh Nguyen can_write &= 0xffff; 45647a1685fSDinh Nguyen can_write *= 4; 45747a1685fSDinh Nguyen } else { 45847a1685fSDinh Nguyen if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) { 45947a1685fSDinh Nguyen dev_dbg(hsotg->dev, 46047a1685fSDinh Nguyen "%s: no queue slots available (0x%08x)\n", 46147a1685fSDinh Nguyen __func__, gnptxsts); 46247a1685fSDinh Nguyen 4631f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP); 46447a1685fSDinh Nguyen return -ENOSPC; 46547a1685fSDinh Nguyen } 46647a1685fSDinh Nguyen 46747a1685fSDinh Nguyen can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts); 46847a1685fSDinh Nguyen can_write *= 4; /* fifo size is in 32bit quantities. */ 46947a1685fSDinh Nguyen } 47047a1685fSDinh Nguyen 47147a1685fSDinh Nguyen max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; 47247a1685fSDinh Nguyen 47347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", 47447a1685fSDinh Nguyen __func__, gnptxsts, can_write, to_write, max_transfer); 47547a1685fSDinh Nguyen 47647a1685fSDinh Nguyen /* 47747a1685fSDinh Nguyen * limit to 512 bytes of data, it seems at least on the non-periodic 47847a1685fSDinh Nguyen * FIFO, requests of >512 cause the endpoint to get stuck with a 47947a1685fSDinh Nguyen * fragment of the end of the transfer in it. 48047a1685fSDinh Nguyen */ 48147a1685fSDinh Nguyen if (can_write > 512 && !periodic) 48247a1685fSDinh Nguyen can_write = 512; 48347a1685fSDinh Nguyen 48447a1685fSDinh Nguyen /* 48547a1685fSDinh Nguyen * limit the write to one max-packet size worth of data, but allow 48647a1685fSDinh Nguyen * the transfer to return that it did not run out of fifo space 48747a1685fSDinh Nguyen * doing it. 48847a1685fSDinh Nguyen */ 48947a1685fSDinh Nguyen if (to_write > max_transfer) { 49047a1685fSDinh Nguyen to_write = max_transfer; 49147a1685fSDinh Nguyen 49247a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 49347a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 4941f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, 49547a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 49647a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 49747a1685fSDinh Nguyen } 49847a1685fSDinh Nguyen 49947a1685fSDinh Nguyen /* see if we can write data */ 50047a1685fSDinh Nguyen 50147a1685fSDinh Nguyen if (to_write > can_write) { 50247a1685fSDinh Nguyen to_write = can_write; 50347a1685fSDinh Nguyen pkt_round = to_write % max_transfer; 50447a1685fSDinh Nguyen 50547a1685fSDinh Nguyen /* 50647a1685fSDinh Nguyen * Round the write down to an 50747a1685fSDinh Nguyen * exact number of packets. 50847a1685fSDinh Nguyen * 50947a1685fSDinh Nguyen * Note, we do not currently check to see if we can ever 51047a1685fSDinh Nguyen * write a full packet or not to the FIFO. 51147a1685fSDinh Nguyen */ 51247a1685fSDinh Nguyen 51347a1685fSDinh Nguyen if (pkt_round) 51447a1685fSDinh Nguyen to_write -= pkt_round; 51547a1685fSDinh Nguyen 51647a1685fSDinh Nguyen /* 51747a1685fSDinh Nguyen * enable correct FIFO interrupt to alert us when there 51847a1685fSDinh Nguyen * is more room left. 51947a1685fSDinh Nguyen */ 52047a1685fSDinh Nguyen 52147a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 52247a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 5231f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, 52447a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 52547a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 52647a1685fSDinh Nguyen } 52747a1685fSDinh Nguyen 52847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", 52947a1685fSDinh Nguyen to_write, hs_req->req.length, can_write, buf_pos); 53047a1685fSDinh Nguyen 53147a1685fSDinh Nguyen if (to_write <= 0) 53247a1685fSDinh Nguyen return -ENOSPC; 53347a1685fSDinh Nguyen 53447a1685fSDinh Nguyen hs_req->req.actual = buf_pos + to_write; 53547a1685fSDinh Nguyen hs_ep->total_data += to_write; 53647a1685fSDinh Nguyen 53747a1685fSDinh Nguyen if (periodic) 53847a1685fSDinh Nguyen hs_ep->fifo_load += to_write; 53947a1685fSDinh Nguyen 54047a1685fSDinh Nguyen to_write = DIV_ROUND_UP(to_write, 4); 54147a1685fSDinh Nguyen data = hs_req->req.buf + buf_pos; 54247a1685fSDinh Nguyen 54347a1685fSDinh Nguyen iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); 54447a1685fSDinh Nguyen 54547a1685fSDinh Nguyen return (to_write >= can_write) ? -ENOSPC : 0; 54647a1685fSDinh Nguyen } 54747a1685fSDinh Nguyen 54847a1685fSDinh Nguyen /** 54947a1685fSDinh Nguyen * get_ep_limit - get the maximum data legnth for this endpoint 55047a1685fSDinh Nguyen * @hs_ep: The endpoint 55147a1685fSDinh Nguyen * 55247a1685fSDinh Nguyen * Return the maximum data that can be queued in one go on a given endpoint 55347a1685fSDinh Nguyen * so that transfers that are too long can be split. 55447a1685fSDinh Nguyen */ 5551f91b4ccSFelipe Balbi static unsigned get_ep_limit(struct dwc2_hsotg_ep *hs_ep) 55647a1685fSDinh Nguyen { 55747a1685fSDinh Nguyen int index = hs_ep->index; 55847a1685fSDinh Nguyen unsigned maxsize; 55947a1685fSDinh Nguyen unsigned maxpkt; 56047a1685fSDinh Nguyen 56147a1685fSDinh Nguyen if (index != 0) { 56247a1685fSDinh Nguyen maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; 56347a1685fSDinh Nguyen maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; 56447a1685fSDinh Nguyen } else { 56547a1685fSDinh Nguyen maxsize = 64+64; 56647a1685fSDinh Nguyen if (hs_ep->dir_in) 56747a1685fSDinh Nguyen maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; 56847a1685fSDinh Nguyen else 56947a1685fSDinh Nguyen maxpkt = 2; 57047a1685fSDinh Nguyen } 57147a1685fSDinh Nguyen 57247a1685fSDinh Nguyen /* we made the constant loading easier above by using +1 */ 57347a1685fSDinh Nguyen maxpkt--; 57447a1685fSDinh Nguyen maxsize--; 57547a1685fSDinh Nguyen 57647a1685fSDinh Nguyen /* 57747a1685fSDinh Nguyen * constrain by packet count if maxpkts*pktsize is greater 57847a1685fSDinh Nguyen * than the length register size. 57947a1685fSDinh Nguyen */ 58047a1685fSDinh Nguyen 58147a1685fSDinh Nguyen if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) 58247a1685fSDinh Nguyen maxsize = maxpkt * hs_ep->ep.maxpacket; 58347a1685fSDinh Nguyen 58447a1685fSDinh Nguyen return maxsize; 58547a1685fSDinh Nguyen } 58647a1685fSDinh Nguyen 58747a1685fSDinh Nguyen /** 588381fc8f8SVardan Mikayelyan * dwc2_hsotg_read_frameno - read current frame number 589381fc8f8SVardan Mikayelyan * @hsotg: The device instance 590381fc8f8SVardan Mikayelyan * 591381fc8f8SVardan Mikayelyan * Return the current frame number 592381fc8f8SVardan Mikayelyan */ 593381fc8f8SVardan Mikayelyan static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg) 594381fc8f8SVardan Mikayelyan { 595381fc8f8SVardan Mikayelyan u32 dsts; 596381fc8f8SVardan Mikayelyan 597381fc8f8SVardan Mikayelyan dsts = dwc2_readl(hsotg->regs + DSTS); 598381fc8f8SVardan Mikayelyan dsts &= DSTS_SOFFN_MASK; 599381fc8f8SVardan Mikayelyan dsts >>= DSTS_SOFFN_SHIFT; 600381fc8f8SVardan Mikayelyan 601381fc8f8SVardan Mikayelyan return dsts; 602381fc8f8SVardan Mikayelyan } 603381fc8f8SVardan Mikayelyan 604381fc8f8SVardan Mikayelyan /** 6051f91b4ccSFelipe Balbi * dwc2_hsotg_start_req - start a USB request from an endpoint's queue 60647a1685fSDinh Nguyen * @hsotg: The controller state. 60747a1685fSDinh Nguyen * @hs_ep: The endpoint to process a request for 60847a1685fSDinh Nguyen * @hs_req: The request to start. 60947a1685fSDinh Nguyen * @continuing: True if we are doing more for the current request. 61047a1685fSDinh Nguyen * 61147a1685fSDinh Nguyen * Start the given request running by setting the endpoint registers 61247a1685fSDinh Nguyen * appropriately, and writing any data to the FIFOs. 61347a1685fSDinh Nguyen */ 6141f91b4ccSFelipe Balbi static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, 6151f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 6161f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req, 61747a1685fSDinh Nguyen bool continuing) 61847a1685fSDinh Nguyen { 61947a1685fSDinh Nguyen struct usb_request *ureq = &hs_req->req; 62047a1685fSDinh Nguyen int index = hs_ep->index; 62147a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 62247a1685fSDinh Nguyen u32 epctrl_reg; 62347a1685fSDinh Nguyen u32 epsize_reg; 62447a1685fSDinh Nguyen u32 epsize; 62547a1685fSDinh Nguyen u32 ctrl; 62647a1685fSDinh Nguyen unsigned length; 62747a1685fSDinh Nguyen unsigned packets; 62847a1685fSDinh Nguyen unsigned maxreq; 62947a1685fSDinh Nguyen 63047a1685fSDinh Nguyen if (index != 0) { 63147a1685fSDinh Nguyen if (hs_ep->req && !continuing) { 63247a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: active request\n", __func__); 63347a1685fSDinh Nguyen WARN_ON(1); 63447a1685fSDinh Nguyen return; 63547a1685fSDinh Nguyen } else if (hs_ep->req != hs_req && continuing) { 63647a1685fSDinh Nguyen dev_err(hsotg->dev, 63747a1685fSDinh Nguyen "%s: continue different req\n", __func__); 63847a1685fSDinh Nguyen WARN_ON(1); 63947a1685fSDinh Nguyen return; 64047a1685fSDinh Nguyen } 64147a1685fSDinh Nguyen } 64247a1685fSDinh Nguyen 64347a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 64447a1685fSDinh Nguyen epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 64547a1685fSDinh Nguyen 64647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", 64795c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctrl_reg), index, 64847a1685fSDinh Nguyen hs_ep->dir_in ? "in" : "out"); 64947a1685fSDinh Nguyen 65047a1685fSDinh Nguyen /* If endpoint is stalled, we will restart request later */ 65195c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctrl_reg); 65247a1685fSDinh Nguyen 653b2d4c54eSMian Yousaf Kaukab if (index && ctrl & DXEPCTL_STALL) { 65447a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); 65547a1685fSDinh Nguyen return; 65647a1685fSDinh Nguyen } 65747a1685fSDinh Nguyen 65847a1685fSDinh Nguyen length = ureq->length - ureq->actual; 65947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", 66047a1685fSDinh Nguyen ureq->length, ureq->actual); 66147a1685fSDinh Nguyen 66247a1685fSDinh Nguyen maxreq = get_ep_limit(hs_ep); 66347a1685fSDinh Nguyen if (length > maxreq) { 66447a1685fSDinh Nguyen int round = maxreq % hs_ep->ep.maxpacket; 66547a1685fSDinh Nguyen 66647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", 66747a1685fSDinh Nguyen __func__, length, maxreq, round); 66847a1685fSDinh Nguyen 66947a1685fSDinh Nguyen /* round down to multiple of packets */ 67047a1685fSDinh Nguyen if (round) 67147a1685fSDinh Nguyen maxreq -= round; 67247a1685fSDinh Nguyen 67347a1685fSDinh Nguyen length = maxreq; 67447a1685fSDinh Nguyen } 67547a1685fSDinh Nguyen 67647a1685fSDinh Nguyen if (length) 67747a1685fSDinh Nguyen packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); 67847a1685fSDinh Nguyen else 67947a1685fSDinh Nguyen packets = 1; /* send one packet if length is zero. */ 68047a1685fSDinh Nguyen 68147a1685fSDinh Nguyen if (hs_ep->isochronous && length > (hs_ep->mc * hs_ep->ep.maxpacket)) { 68247a1685fSDinh Nguyen dev_err(hsotg->dev, "req length > maxpacket*mc\n"); 68347a1685fSDinh Nguyen return; 68447a1685fSDinh Nguyen } 68547a1685fSDinh Nguyen 68647a1685fSDinh Nguyen if (dir_in && index != 0) 68747a1685fSDinh Nguyen if (hs_ep->isochronous) 68847a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(packets); 68947a1685fSDinh Nguyen else 69047a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(1); 69147a1685fSDinh Nguyen else 69247a1685fSDinh Nguyen epsize = 0; 69347a1685fSDinh Nguyen 69447a1685fSDinh Nguyen /* 695f71b5e25SMian Yousaf Kaukab * zero length packet should be programmed on its own and should not 696f71b5e25SMian Yousaf Kaukab * be counted in DIEPTSIZ.PktCnt with other packets. 69747a1685fSDinh Nguyen */ 698f71b5e25SMian Yousaf Kaukab if (dir_in && ureq->zero && !continuing) { 699f71b5e25SMian Yousaf Kaukab /* Test if zlp is actually required. */ 700f71b5e25SMian Yousaf Kaukab if ((ureq->length >= hs_ep->ep.maxpacket) && 701f71b5e25SMian Yousaf Kaukab !(ureq->length % hs_ep->ep.maxpacket)) 7028a20fa45SMian Yousaf Kaukab hs_ep->send_zlp = 1; 70347a1685fSDinh Nguyen } 70447a1685fSDinh Nguyen 70547a1685fSDinh Nguyen epsize |= DXEPTSIZ_PKTCNT(packets); 70647a1685fSDinh Nguyen epsize |= DXEPTSIZ_XFERSIZE(length); 70747a1685fSDinh Nguyen 70847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", 70947a1685fSDinh Nguyen __func__, packets, length, ureq->length, epsize, epsize_reg); 71047a1685fSDinh Nguyen 71147a1685fSDinh Nguyen /* store the request as the current one we're doing */ 71247a1685fSDinh Nguyen hs_ep->req = hs_req; 71347a1685fSDinh Nguyen 71447a1685fSDinh Nguyen /* write size / packets */ 71595c8bc36SAntti Seppälä dwc2_writel(epsize, hsotg->regs + epsize_reg); 71647a1685fSDinh Nguyen 71747a1685fSDinh Nguyen if (using_dma(hsotg) && !continuing) { 71847a1685fSDinh Nguyen unsigned int dma_reg; 71947a1685fSDinh Nguyen 72047a1685fSDinh Nguyen /* 72147a1685fSDinh Nguyen * write DMA address to control register, buffer already 7221f91b4ccSFelipe Balbi * synced by dwc2_hsotg_ep_queue(). 72347a1685fSDinh Nguyen */ 72447a1685fSDinh Nguyen 72547a1685fSDinh Nguyen dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); 72695c8bc36SAntti Seppälä dwc2_writel(ureq->dma, hsotg->regs + dma_reg); 72747a1685fSDinh Nguyen 7280cc4cf6fSFabio Estevam dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n", 72947a1685fSDinh Nguyen __func__, &ureq->dma, dma_reg); 73047a1685fSDinh Nguyen } 73147a1685fSDinh Nguyen 732837e9f00SVardan Mikayelyan if (hs_ep->isochronous && hs_ep->interval == 1) { 733837e9f00SVardan Mikayelyan hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg); 734837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 735837e9f00SVardan Mikayelyan 736837e9f00SVardan Mikayelyan if (hs_ep->target_frame & 0x1) 737837e9f00SVardan Mikayelyan ctrl |= DXEPCTL_SETODDFR; 738837e9f00SVardan Mikayelyan else 739837e9f00SVardan Mikayelyan ctrl |= DXEPCTL_SETEVENFR; 740837e9f00SVardan Mikayelyan } 741837e9f00SVardan Mikayelyan 74247a1685fSDinh Nguyen ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 74347a1685fSDinh Nguyen 744fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state); 74547a1685fSDinh Nguyen 74647a1685fSDinh Nguyen /* For Setup request do not clear NAK */ 747fe0b94abSMian Yousaf Kaukab if (!(index == 0 && hsotg->ep0_state == DWC2_EP0_SETUP)) 74847a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 74947a1685fSDinh Nguyen 75047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 75195c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + epctrl_reg); 75247a1685fSDinh Nguyen 75347a1685fSDinh Nguyen /* 75447a1685fSDinh Nguyen * set these, it seems that DMA support increments past the end 75547a1685fSDinh Nguyen * of the packet buffer so we need to calculate the length from 75647a1685fSDinh Nguyen * this information. 75747a1685fSDinh Nguyen */ 75847a1685fSDinh Nguyen hs_ep->size_loaded = length; 75947a1685fSDinh Nguyen hs_ep->last_load = ureq->actual; 76047a1685fSDinh Nguyen 76147a1685fSDinh Nguyen if (dir_in && !using_dma(hsotg)) { 76247a1685fSDinh Nguyen /* set these anyway, we may need them for non-periodic in */ 76347a1685fSDinh Nguyen hs_ep->fifo_load = 0; 76447a1685fSDinh Nguyen 7651f91b4ccSFelipe Balbi dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 76647a1685fSDinh Nguyen } 76747a1685fSDinh Nguyen 76847a1685fSDinh Nguyen /* 76947a1685fSDinh Nguyen * Note, trying to clear the NAK here causes problems with transmit 77047a1685fSDinh Nguyen * on the S3C6400 ending up with the TXFIFO becoming full. 77147a1685fSDinh Nguyen */ 77247a1685fSDinh Nguyen 77347a1685fSDinh Nguyen /* check ep is enabled */ 77495c8bc36SAntti Seppälä if (!(dwc2_readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA)) 7751a0ed863SMian Yousaf Kaukab dev_dbg(hsotg->dev, 77647a1685fSDinh Nguyen "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", 77795c8bc36SAntti Seppälä index, dwc2_readl(hsotg->regs + epctrl_reg)); 77847a1685fSDinh Nguyen 77947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", 78095c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctrl_reg)); 78147a1685fSDinh Nguyen 78247a1685fSDinh Nguyen /* enable ep interrupts */ 7831f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1); 78447a1685fSDinh Nguyen } 78547a1685fSDinh Nguyen 78647a1685fSDinh Nguyen /** 7871f91b4ccSFelipe Balbi * dwc2_hsotg_map_dma - map the DMA memory being used for the request 78847a1685fSDinh Nguyen * @hsotg: The device state. 78947a1685fSDinh Nguyen * @hs_ep: The endpoint the request is on. 79047a1685fSDinh Nguyen * @req: The request being processed. 79147a1685fSDinh Nguyen * 79247a1685fSDinh Nguyen * We've been asked to queue a request, so ensure that the memory buffer 79347a1685fSDinh Nguyen * is correctly setup for DMA. If we've been passed an extant DMA address 79447a1685fSDinh Nguyen * then ensure the buffer has been synced to memory. If our buffer has no 79547a1685fSDinh Nguyen * DMA memory, then we map the memory and mark our request to allow us to 79647a1685fSDinh Nguyen * cleanup on completion. 79747a1685fSDinh Nguyen */ 7981f91b4ccSFelipe Balbi static int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg, 7991f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 80047a1685fSDinh Nguyen struct usb_request *req) 80147a1685fSDinh Nguyen { 8021f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 80347a1685fSDinh Nguyen int ret; 80447a1685fSDinh Nguyen 80547a1685fSDinh Nguyen /* if the length is zero, ignore the DMA data */ 80647a1685fSDinh Nguyen if (hs_req->req.length == 0) 80747a1685fSDinh Nguyen return 0; 80847a1685fSDinh Nguyen 80947a1685fSDinh Nguyen ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); 81047a1685fSDinh Nguyen if (ret) 81147a1685fSDinh Nguyen goto dma_error; 81247a1685fSDinh Nguyen 81347a1685fSDinh Nguyen return 0; 81447a1685fSDinh Nguyen 81547a1685fSDinh Nguyen dma_error: 81647a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", 81747a1685fSDinh Nguyen __func__, req->buf, req->length); 81847a1685fSDinh Nguyen 81947a1685fSDinh Nguyen return -EIO; 82047a1685fSDinh Nguyen } 82147a1685fSDinh Nguyen 8221f91b4ccSFelipe Balbi static int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, 8231f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) 8247d24c1b5SMian Yousaf Kaukab { 8257d24c1b5SMian Yousaf Kaukab void *req_buf = hs_req->req.buf; 8267d24c1b5SMian Yousaf Kaukab 8277d24c1b5SMian Yousaf Kaukab /* If dma is not being used or buffer is aligned */ 8287d24c1b5SMian Yousaf Kaukab if (!using_dma(hsotg) || !((long)req_buf & 3)) 8297d24c1b5SMian Yousaf Kaukab return 0; 8307d24c1b5SMian Yousaf Kaukab 8317d24c1b5SMian Yousaf Kaukab WARN_ON(hs_req->saved_req_buf); 8327d24c1b5SMian Yousaf Kaukab 8337d24c1b5SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__, 8347d24c1b5SMian Yousaf Kaukab hs_ep->ep.name, req_buf, hs_req->req.length); 8357d24c1b5SMian Yousaf Kaukab 8367d24c1b5SMian Yousaf Kaukab hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC); 8377d24c1b5SMian Yousaf Kaukab if (!hs_req->req.buf) { 8387d24c1b5SMian Yousaf Kaukab hs_req->req.buf = req_buf; 8397d24c1b5SMian Yousaf Kaukab dev_err(hsotg->dev, 8407d24c1b5SMian Yousaf Kaukab "%s: unable to allocate memory for bounce buffer\n", 8417d24c1b5SMian Yousaf Kaukab __func__); 8427d24c1b5SMian Yousaf Kaukab return -ENOMEM; 8437d24c1b5SMian Yousaf Kaukab } 8447d24c1b5SMian Yousaf Kaukab 8457d24c1b5SMian Yousaf Kaukab /* Save actual buffer */ 8467d24c1b5SMian Yousaf Kaukab hs_req->saved_req_buf = req_buf; 8477d24c1b5SMian Yousaf Kaukab 8487d24c1b5SMian Yousaf Kaukab if (hs_ep->dir_in) 8497d24c1b5SMian Yousaf Kaukab memcpy(hs_req->req.buf, req_buf, hs_req->req.length); 8507d24c1b5SMian Yousaf Kaukab return 0; 8517d24c1b5SMian Yousaf Kaukab } 8527d24c1b5SMian Yousaf Kaukab 8531f91b4ccSFelipe Balbi static void dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, 8541f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) 8557d24c1b5SMian Yousaf Kaukab { 8567d24c1b5SMian Yousaf Kaukab /* If dma is not being used or buffer was aligned */ 8577d24c1b5SMian Yousaf Kaukab if (!using_dma(hsotg) || !hs_req->saved_req_buf) 8587d24c1b5SMian Yousaf Kaukab return; 8597d24c1b5SMian Yousaf Kaukab 8607d24c1b5SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: %s: status=%d actual-length=%d\n", __func__, 8617d24c1b5SMian Yousaf Kaukab hs_ep->ep.name, hs_req->req.status, hs_req->req.actual); 8627d24c1b5SMian Yousaf Kaukab 8637d24c1b5SMian Yousaf Kaukab /* Copy data from bounce buffer on successful out transfer */ 8647d24c1b5SMian Yousaf Kaukab if (!hs_ep->dir_in && !hs_req->req.status) 8657d24c1b5SMian Yousaf Kaukab memcpy(hs_req->saved_req_buf, hs_req->req.buf, 8667d24c1b5SMian Yousaf Kaukab hs_req->req.actual); 8677d24c1b5SMian Yousaf Kaukab 8687d24c1b5SMian Yousaf Kaukab /* Free bounce buffer */ 8697d24c1b5SMian Yousaf Kaukab kfree(hs_req->req.buf); 8707d24c1b5SMian Yousaf Kaukab 8717d24c1b5SMian Yousaf Kaukab hs_req->req.buf = hs_req->saved_req_buf; 8727d24c1b5SMian Yousaf Kaukab hs_req->saved_req_buf = NULL; 8737d24c1b5SMian Yousaf Kaukab } 8747d24c1b5SMian Yousaf Kaukab 875381fc8f8SVardan Mikayelyan /** 876381fc8f8SVardan Mikayelyan * dwc2_gadget_target_frame_elapsed - Checks target frame 877381fc8f8SVardan Mikayelyan * @hs_ep: The driver endpoint to check 878381fc8f8SVardan Mikayelyan * 879381fc8f8SVardan Mikayelyan * Returns 1 if targeted frame elapsed. If returned 1 then we need to drop 880381fc8f8SVardan Mikayelyan * corresponding transfer. 881381fc8f8SVardan Mikayelyan */ 882381fc8f8SVardan Mikayelyan static bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep) 883381fc8f8SVardan Mikayelyan { 884381fc8f8SVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 885381fc8f8SVardan Mikayelyan u32 target_frame = hs_ep->target_frame; 886381fc8f8SVardan Mikayelyan u32 current_frame = dwc2_hsotg_read_frameno(hsotg); 887381fc8f8SVardan Mikayelyan bool frame_overrun = hs_ep->frame_overrun; 888381fc8f8SVardan Mikayelyan 889381fc8f8SVardan Mikayelyan if (!frame_overrun && current_frame >= target_frame) 890381fc8f8SVardan Mikayelyan return true; 891381fc8f8SVardan Mikayelyan 892381fc8f8SVardan Mikayelyan if (frame_overrun && current_frame >= target_frame && 893381fc8f8SVardan Mikayelyan ((current_frame - target_frame) < DSTS_SOFFN_LIMIT / 2)) 894381fc8f8SVardan Mikayelyan return true; 895381fc8f8SVardan Mikayelyan 896381fc8f8SVardan Mikayelyan return false; 897381fc8f8SVardan Mikayelyan } 898381fc8f8SVardan Mikayelyan 8991f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, 90047a1685fSDinh Nguyen gfp_t gfp_flags) 90147a1685fSDinh Nguyen { 9021f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 9031f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 904941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 90547a1685fSDinh Nguyen bool first; 9067d24c1b5SMian Yousaf Kaukab int ret; 90747a1685fSDinh Nguyen 90847a1685fSDinh Nguyen dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", 90947a1685fSDinh Nguyen ep->name, req, req->length, req->buf, req->no_interrupt, 91047a1685fSDinh Nguyen req->zero, req->short_not_ok); 91147a1685fSDinh Nguyen 9127ababa92SGregory Herrero /* Prevent new request submission when controller is suspended */ 9137ababa92SGregory Herrero if (hs->lx_state == DWC2_L2) { 9147ababa92SGregory Herrero dev_dbg(hs->dev, "%s: don't submit request while suspended\n", 9157ababa92SGregory Herrero __func__); 9167ababa92SGregory Herrero return -EAGAIN; 9177ababa92SGregory Herrero } 9187ababa92SGregory Herrero 91947a1685fSDinh Nguyen /* initialise status of the request */ 92047a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_req->queue); 92147a1685fSDinh Nguyen req->actual = 0; 92247a1685fSDinh Nguyen req->status = -EINPROGRESS; 92347a1685fSDinh Nguyen 9241f91b4ccSFelipe Balbi ret = dwc2_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req); 9257d24c1b5SMian Yousaf Kaukab if (ret) 9267d24c1b5SMian Yousaf Kaukab return ret; 9277d24c1b5SMian Yousaf Kaukab 92847a1685fSDinh Nguyen /* if we're using DMA, sync the buffers as necessary */ 92947a1685fSDinh Nguyen if (using_dma(hs)) { 9301f91b4ccSFelipe Balbi ret = dwc2_hsotg_map_dma(hs, hs_ep, req); 93147a1685fSDinh Nguyen if (ret) 93247a1685fSDinh Nguyen return ret; 93347a1685fSDinh Nguyen } 93447a1685fSDinh Nguyen 93547a1685fSDinh Nguyen first = list_empty(&hs_ep->queue); 93647a1685fSDinh Nguyen list_add_tail(&hs_req->queue, &hs_ep->queue); 93747a1685fSDinh Nguyen 938837e9f00SVardan Mikayelyan if (first) { 939837e9f00SVardan Mikayelyan if (!hs_ep->isochronous) { 9401f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 941837e9f00SVardan Mikayelyan return 0; 942837e9f00SVardan Mikayelyan } 94347a1685fSDinh Nguyen 944837e9f00SVardan Mikayelyan while (dwc2_gadget_target_frame_elapsed(hs_ep)) 945837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 946837e9f00SVardan Mikayelyan 947837e9f00SVardan Mikayelyan if (hs_ep->target_frame != TARGET_FRAME_INITIAL) 948837e9f00SVardan Mikayelyan dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 949837e9f00SVardan Mikayelyan } 95047a1685fSDinh Nguyen return 0; 95147a1685fSDinh Nguyen } 95247a1685fSDinh Nguyen 9531f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, 95447a1685fSDinh Nguyen gfp_t gfp_flags) 95547a1685fSDinh Nguyen { 9561f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 957941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 95847a1685fSDinh Nguyen unsigned long flags = 0; 95947a1685fSDinh Nguyen int ret = 0; 96047a1685fSDinh Nguyen 96147a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 9621f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(ep, req, gfp_flags); 96347a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 96447a1685fSDinh Nguyen 96547a1685fSDinh Nguyen return ret; 96647a1685fSDinh Nguyen } 96747a1685fSDinh Nguyen 9681f91b4ccSFelipe Balbi static void dwc2_hsotg_ep_free_request(struct usb_ep *ep, 96947a1685fSDinh Nguyen struct usb_request *req) 97047a1685fSDinh Nguyen { 9711f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 97247a1685fSDinh Nguyen 97347a1685fSDinh Nguyen kfree(hs_req); 97447a1685fSDinh Nguyen } 97547a1685fSDinh Nguyen 97647a1685fSDinh Nguyen /** 9771f91b4ccSFelipe Balbi * dwc2_hsotg_complete_oursetup - setup completion callback 97847a1685fSDinh Nguyen * @ep: The endpoint the request was on. 97947a1685fSDinh Nguyen * @req: The request completed. 98047a1685fSDinh Nguyen * 98147a1685fSDinh Nguyen * Called on completion of any requests the driver itself 98247a1685fSDinh Nguyen * submitted that need cleaning up. 98347a1685fSDinh Nguyen */ 9841f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_oursetup(struct usb_ep *ep, 98547a1685fSDinh Nguyen struct usb_request *req) 98647a1685fSDinh Nguyen { 9871f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 988941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 98947a1685fSDinh Nguyen 99047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); 99147a1685fSDinh Nguyen 9921f91b4ccSFelipe Balbi dwc2_hsotg_ep_free_request(ep, req); 99347a1685fSDinh Nguyen } 99447a1685fSDinh Nguyen 99547a1685fSDinh Nguyen /** 99647a1685fSDinh Nguyen * ep_from_windex - convert control wIndex value to endpoint 99747a1685fSDinh Nguyen * @hsotg: The driver state. 99847a1685fSDinh Nguyen * @windex: The control request wIndex field (in host order). 99947a1685fSDinh Nguyen * 100047a1685fSDinh Nguyen * Convert the given wIndex into a pointer to an driver endpoint 100147a1685fSDinh Nguyen * structure, or return NULL if it is not a valid endpoint. 100247a1685fSDinh Nguyen */ 10031f91b4ccSFelipe Balbi static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, 100447a1685fSDinh Nguyen u32 windex) 100547a1685fSDinh Nguyen { 10061f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 100747a1685fSDinh Nguyen int dir = (windex & USB_DIR_IN) ? 1 : 0; 100847a1685fSDinh Nguyen int idx = windex & 0x7F; 100947a1685fSDinh Nguyen 101047a1685fSDinh Nguyen if (windex >= 0x100) 101147a1685fSDinh Nguyen return NULL; 101247a1685fSDinh Nguyen 101347a1685fSDinh Nguyen if (idx > hsotg->num_of_eps) 101447a1685fSDinh Nguyen return NULL; 101547a1685fSDinh Nguyen 1016c6f5c050SMian Yousaf Kaukab ep = index_to_ep(hsotg, idx, dir); 1017c6f5c050SMian Yousaf Kaukab 101847a1685fSDinh Nguyen if (idx && ep->dir_in != dir) 101947a1685fSDinh Nguyen return NULL; 102047a1685fSDinh Nguyen 102147a1685fSDinh Nguyen return ep; 102247a1685fSDinh Nguyen } 102347a1685fSDinh Nguyen 102447a1685fSDinh Nguyen /** 10251f91b4ccSFelipe Balbi * dwc2_hsotg_set_test_mode - Enable usb Test Modes 10269e14d0a5SGregory Herrero * @hsotg: The driver state. 10279e14d0a5SGregory Herrero * @testmode: requested usb test mode 10289e14d0a5SGregory Herrero * Enable usb Test Mode requested by the Host. 10299e14d0a5SGregory Herrero */ 10301f91b4ccSFelipe Balbi int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode) 10319e14d0a5SGregory Herrero { 103295c8bc36SAntti Seppälä int dctl = dwc2_readl(hsotg->regs + DCTL); 10339e14d0a5SGregory Herrero 10349e14d0a5SGregory Herrero dctl &= ~DCTL_TSTCTL_MASK; 10359e14d0a5SGregory Herrero switch (testmode) { 10369e14d0a5SGregory Herrero case TEST_J: 10379e14d0a5SGregory Herrero case TEST_K: 10389e14d0a5SGregory Herrero case TEST_SE0_NAK: 10399e14d0a5SGregory Herrero case TEST_PACKET: 10409e14d0a5SGregory Herrero case TEST_FORCE_EN: 10419e14d0a5SGregory Herrero dctl |= testmode << DCTL_TSTCTL_SHIFT; 10429e14d0a5SGregory Herrero break; 10439e14d0a5SGregory Herrero default: 10449e14d0a5SGregory Herrero return -EINVAL; 10459e14d0a5SGregory Herrero } 104695c8bc36SAntti Seppälä dwc2_writel(dctl, hsotg->regs + DCTL); 10479e14d0a5SGregory Herrero return 0; 10489e14d0a5SGregory Herrero } 10499e14d0a5SGregory Herrero 10509e14d0a5SGregory Herrero /** 10511f91b4ccSFelipe Balbi * dwc2_hsotg_send_reply - send reply to control request 105247a1685fSDinh Nguyen * @hsotg: The device state 105347a1685fSDinh Nguyen * @ep: Endpoint 0 105447a1685fSDinh Nguyen * @buff: Buffer for request 105547a1685fSDinh Nguyen * @length: Length of reply. 105647a1685fSDinh Nguyen * 105747a1685fSDinh Nguyen * Create a request and queue it on the given endpoint. This is useful as 105847a1685fSDinh Nguyen * an internal method of sending replies to certain control requests, etc. 105947a1685fSDinh Nguyen */ 10601f91b4ccSFelipe Balbi static int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg, 10611f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep, 106247a1685fSDinh Nguyen void *buff, 106347a1685fSDinh Nguyen int length) 106447a1685fSDinh Nguyen { 106547a1685fSDinh Nguyen struct usb_request *req; 106647a1685fSDinh Nguyen int ret; 106747a1685fSDinh Nguyen 106847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); 106947a1685fSDinh Nguyen 10701f91b4ccSFelipe Balbi req = dwc2_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); 107147a1685fSDinh Nguyen hsotg->ep0_reply = req; 107247a1685fSDinh Nguyen if (!req) { 107347a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); 107447a1685fSDinh Nguyen return -ENOMEM; 107547a1685fSDinh Nguyen } 107647a1685fSDinh Nguyen 107747a1685fSDinh Nguyen req->buf = hsotg->ep0_buff; 107847a1685fSDinh Nguyen req->length = length; 1079f71b5e25SMian Yousaf Kaukab /* 1080f71b5e25SMian Yousaf Kaukab * zero flag is for sending zlp in DATA IN stage. It has no impact on 1081f71b5e25SMian Yousaf Kaukab * STATUS stage. 1082f71b5e25SMian Yousaf Kaukab */ 1083f71b5e25SMian Yousaf Kaukab req->zero = 0; 10841f91b4ccSFelipe Balbi req->complete = dwc2_hsotg_complete_oursetup; 108547a1685fSDinh Nguyen 108647a1685fSDinh Nguyen if (length) 108747a1685fSDinh Nguyen memcpy(req->buf, buff, length); 108847a1685fSDinh Nguyen 10891f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); 109047a1685fSDinh Nguyen if (ret) { 109147a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); 109247a1685fSDinh Nguyen return ret; 109347a1685fSDinh Nguyen } 109447a1685fSDinh Nguyen 109547a1685fSDinh Nguyen return 0; 109647a1685fSDinh Nguyen } 109747a1685fSDinh Nguyen 109847a1685fSDinh Nguyen /** 10991f91b4ccSFelipe Balbi * dwc2_hsotg_process_req_status - process request GET_STATUS 110047a1685fSDinh Nguyen * @hsotg: The device state 110147a1685fSDinh Nguyen * @ctrl: USB control request 110247a1685fSDinh Nguyen */ 11031f91b4ccSFelipe Balbi static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, 110447a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 110547a1685fSDinh Nguyen { 11061f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 11071f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 110847a1685fSDinh Nguyen __le16 reply; 110947a1685fSDinh Nguyen int ret; 111047a1685fSDinh Nguyen 111147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); 111247a1685fSDinh Nguyen 111347a1685fSDinh Nguyen if (!ep0->dir_in) { 111447a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: direction out?\n", __func__); 111547a1685fSDinh Nguyen return -EINVAL; 111647a1685fSDinh Nguyen } 111747a1685fSDinh Nguyen 111847a1685fSDinh Nguyen switch (ctrl->bRequestType & USB_RECIP_MASK) { 111947a1685fSDinh Nguyen case USB_RECIP_DEVICE: 112047a1685fSDinh Nguyen reply = cpu_to_le16(0); /* bit 0 => self powered, 112147a1685fSDinh Nguyen * bit 1 => remote wakeup */ 112247a1685fSDinh Nguyen break; 112347a1685fSDinh Nguyen 112447a1685fSDinh Nguyen case USB_RECIP_INTERFACE: 112547a1685fSDinh Nguyen /* currently, the data result should be zero */ 112647a1685fSDinh Nguyen reply = cpu_to_le16(0); 112747a1685fSDinh Nguyen break; 112847a1685fSDinh Nguyen 112947a1685fSDinh Nguyen case USB_RECIP_ENDPOINT: 113047a1685fSDinh Nguyen ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); 113147a1685fSDinh Nguyen if (!ep) 113247a1685fSDinh Nguyen return -ENOENT; 113347a1685fSDinh Nguyen 113447a1685fSDinh Nguyen reply = cpu_to_le16(ep->halted ? 1 : 0); 113547a1685fSDinh Nguyen break; 113647a1685fSDinh Nguyen 113747a1685fSDinh Nguyen default: 113847a1685fSDinh Nguyen return 0; 113947a1685fSDinh Nguyen } 114047a1685fSDinh Nguyen 114147a1685fSDinh Nguyen if (le16_to_cpu(ctrl->wLength) != 2) 114247a1685fSDinh Nguyen return -EINVAL; 114347a1685fSDinh Nguyen 11441f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, &reply, 2); 114547a1685fSDinh Nguyen if (ret) { 114647a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); 114747a1685fSDinh Nguyen return ret; 114847a1685fSDinh Nguyen } 114947a1685fSDinh Nguyen 115047a1685fSDinh Nguyen return 1; 115147a1685fSDinh Nguyen } 115247a1685fSDinh Nguyen 115351da43b5SVahram Aharonyan static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now); 115447a1685fSDinh Nguyen 115547a1685fSDinh Nguyen /** 115647a1685fSDinh Nguyen * get_ep_head - return the first request on the endpoint 115747a1685fSDinh Nguyen * @hs_ep: The controller endpoint to get 115847a1685fSDinh Nguyen * 115947a1685fSDinh Nguyen * Get the first request on the endpoint. 116047a1685fSDinh Nguyen */ 11611f91b4ccSFelipe Balbi static struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep) 116247a1685fSDinh Nguyen { 1163ffc4b406SMasahiro Yamada return list_first_entry_or_null(&hs_ep->queue, struct dwc2_hsotg_req, 1164ffc4b406SMasahiro Yamada queue); 116547a1685fSDinh Nguyen } 116647a1685fSDinh Nguyen 116747a1685fSDinh Nguyen /** 116841cc4cd2SVardan Mikayelyan * dwc2_gadget_start_next_request - Starts next request from ep queue 116941cc4cd2SVardan Mikayelyan * @hs_ep: Endpoint structure 117041cc4cd2SVardan Mikayelyan * 117141cc4cd2SVardan Mikayelyan * If queue is empty and EP is ISOC-OUT - unmasks OUTTKNEPDIS which is masked 117241cc4cd2SVardan Mikayelyan * in its handler. Hence we need to unmask it here to be able to do 117341cc4cd2SVardan Mikayelyan * resynchronization. 117441cc4cd2SVardan Mikayelyan */ 117541cc4cd2SVardan Mikayelyan static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep) 117641cc4cd2SVardan Mikayelyan { 117741cc4cd2SVardan Mikayelyan u32 mask; 117841cc4cd2SVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 117941cc4cd2SVardan Mikayelyan int dir_in = hs_ep->dir_in; 118041cc4cd2SVardan Mikayelyan struct dwc2_hsotg_req *hs_req; 118141cc4cd2SVardan Mikayelyan u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; 118241cc4cd2SVardan Mikayelyan 118341cc4cd2SVardan Mikayelyan if (!list_empty(&hs_ep->queue)) { 118441cc4cd2SVardan Mikayelyan hs_req = get_ep_head(hs_ep); 118541cc4cd2SVardan Mikayelyan dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false); 118641cc4cd2SVardan Mikayelyan return; 118741cc4cd2SVardan Mikayelyan } 118841cc4cd2SVardan Mikayelyan if (!hs_ep->isochronous) 118941cc4cd2SVardan Mikayelyan return; 119041cc4cd2SVardan Mikayelyan 119141cc4cd2SVardan Mikayelyan if (dir_in) { 119241cc4cd2SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: No more ISOC-IN requests\n", 119341cc4cd2SVardan Mikayelyan __func__); 119441cc4cd2SVardan Mikayelyan } else { 119541cc4cd2SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: No more ISOC-OUT requests\n", 119641cc4cd2SVardan Mikayelyan __func__); 119741cc4cd2SVardan Mikayelyan mask = dwc2_readl(hsotg->regs + epmsk_reg); 119841cc4cd2SVardan Mikayelyan mask |= DOEPMSK_OUTTKNEPDISMSK; 119941cc4cd2SVardan Mikayelyan dwc2_writel(mask, hsotg->regs + epmsk_reg); 120041cc4cd2SVardan Mikayelyan } 120141cc4cd2SVardan Mikayelyan } 120241cc4cd2SVardan Mikayelyan 120341cc4cd2SVardan Mikayelyan /** 12041f91b4ccSFelipe Balbi * dwc2_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE 120547a1685fSDinh Nguyen * @hsotg: The device state 120647a1685fSDinh Nguyen * @ctrl: USB control request 120747a1685fSDinh Nguyen */ 12081f91b4ccSFelipe Balbi static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, 120947a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 121047a1685fSDinh Nguyen { 12111f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 12121f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req; 121347a1685fSDinh Nguyen bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); 12141f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 121547a1685fSDinh Nguyen int ret; 121647a1685fSDinh Nguyen bool halted; 12179e14d0a5SGregory Herrero u32 recip; 12189e14d0a5SGregory Herrero u32 wValue; 12199e14d0a5SGregory Herrero u32 wIndex; 122047a1685fSDinh Nguyen 122147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", 122247a1685fSDinh Nguyen __func__, set ? "SET" : "CLEAR"); 122347a1685fSDinh Nguyen 12249e14d0a5SGregory Herrero wValue = le16_to_cpu(ctrl->wValue); 12259e14d0a5SGregory Herrero wIndex = le16_to_cpu(ctrl->wIndex); 12269e14d0a5SGregory Herrero recip = ctrl->bRequestType & USB_RECIP_MASK; 12279e14d0a5SGregory Herrero 12289e14d0a5SGregory Herrero switch (recip) { 12299e14d0a5SGregory Herrero case USB_RECIP_DEVICE: 12309e14d0a5SGregory Herrero switch (wValue) { 12319e14d0a5SGregory Herrero case USB_DEVICE_TEST_MODE: 12329e14d0a5SGregory Herrero if ((wIndex & 0xff) != 0) 12339e14d0a5SGregory Herrero return -EINVAL; 12349e14d0a5SGregory Herrero if (!set) 12359e14d0a5SGregory Herrero return -EINVAL; 12369e14d0a5SGregory Herrero 12379e14d0a5SGregory Herrero hsotg->test_mode = wIndex >> 8; 12381f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 12399e14d0a5SGregory Herrero if (ret) { 12409e14d0a5SGregory Herrero dev_err(hsotg->dev, 12419e14d0a5SGregory Herrero "%s: failed to send reply\n", __func__); 12429e14d0a5SGregory Herrero return ret; 12439e14d0a5SGregory Herrero } 12449e14d0a5SGregory Herrero break; 12459e14d0a5SGregory Herrero default: 12469e14d0a5SGregory Herrero return -ENOENT; 12479e14d0a5SGregory Herrero } 12489e14d0a5SGregory Herrero break; 12499e14d0a5SGregory Herrero 12509e14d0a5SGregory Herrero case USB_RECIP_ENDPOINT: 12519e14d0a5SGregory Herrero ep = ep_from_windex(hsotg, wIndex); 125247a1685fSDinh Nguyen if (!ep) { 125347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", 12549e14d0a5SGregory Herrero __func__, wIndex); 125547a1685fSDinh Nguyen return -ENOENT; 125647a1685fSDinh Nguyen } 125747a1685fSDinh Nguyen 12589e14d0a5SGregory Herrero switch (wValue) { 125947a1685fSDinh Nguyen case USB_ENDPOINT_HALT: 126047a1685fSDinh Nguyen halted = ep->halted; 126147a1685fSDinh Nguyen 126251da43b5SVahram Aharonyan dwc2_hsotg_ep_sethalt(&ep->ep, set, true); 126347a1685fSDinh Nguyen 12641f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 126547a1685fSDinh Nguyen if (ret) { 126647a1685fSDinh Nguyen dev_err(hsotg->dev, 126747a1685fSDinh Nguyen "%s: failed to send reply\n", __func__); 126847a1685fSDinh Nguyen return ret; 126947a1685fSDinh Nguyen } 127047a1685fSDinh Nguyen 127147a1685fSDinh Nguyen /* 127247a1685fSDinh Nguyen * we have to complete all requests for ep if it was 127347a1685fSDinh Nguyen * halted, and the halt was cleared by CLEAR_FEATURE 127447a1685fSDinh Nguyen */ 127547a1685fSDinh Nguyen 127647a1685fSDinh Nguyen if (!set && halted) { 127747a1685fSDinh Nguyen /* 127847a1685fSDinh Nguyen * If we have request in progress, 127947a1685fSDinh Nguyen * then complete it 128047a1685fSDinh Nguyen */ 128147a1685fSDinh Nguyen if (ep->req) { 128247a1685fSDinh Nguyen hs_req = ep->req; 128347a1685fSDinh Nguyen ep->req = NULL; 128447a1685fSDinh Nguyen list_del_init(&hs_req->queue); 1285c00dd4a6SGregory Herrero if (hs_req->req.complete) { 1286c00dd4a6SGregory Herrero spin_unlock(&hsotg->lock); 1287c00dd4a6SGregory Herrero usb_gadget_giveback_request( 1288c00dd4a6SGregory Herrero &ep->ep, &hs_req->req); 1289c00dd4a6SGregory Herrero spin_lock(&hsotg->lock); 1290c00dd4a6SGregory Herrero } 129147a1685fSDinh Nguyen } 129247a1685fSDinh Nguyen 129347a1685fSDinh Nguyen /* If we have pending request, then start it */ 1294c00dd4a6SGregory Herrero if (!ep->req) { 129541cc4cd2SVardan Mikayelyan dwc2_gadget_start_next_request(ep); 129647a1685fSDinh Nguyen } 1297c00dd4a6SGregory Herrero } 129847a1685fSDinh Nguyen 129947a1685fSDinh Nguyen break; 130047a1685fSDinh Nguyen 130147a1685fSDinh Nguyen default: 130247a1685fSDinh Nguyen return -ENOENT; 130347a1685fSDinh Nguyen } 13049e14d0a5SGregory Herrero break; 13059e14d0a5SGregory Herrero default: 13069e14d0a5SGregory Herrero return -ENOENT; 13079e14d0a5SGregory Herrero } 130847a1685fSDinh Nguyen return 1; 130947a1685fSDinh Nguyen } 131047a1685fSDinh Nguyen 13111f91b4ccSFelipe Balbi static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg); 131247a1685fSDinh Nguyen 131347a1685fSDinh Nguyen /** 13141f91b4ccSFelipe Balbi * dwc2_hsotg_stall_ep0 - stall ep0 131547a1685fSDinh Nguyen * @hsotg: The device state 131647a1685fSDinh Nguyen * 131747a1685fSDinh Nguyen * Set stall for ep0 as response for setup request. 131847a1685fSDinh Nguyen */ 13191f91b4ccSFelipe Balbi static void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg) 1320e9ebe7c3SJingoo Han { 13211f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 132247a1685fSDinh Nguyen u32 reg; 132347a1685fSDinh Nguyen u32 ctrl; 132447a1685fSDinh Nguyen 132547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); 132647a1685fSDinh Nguyen reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; 132747a1685fSDinh Nguyen 132847a1685fSDinh Nguyen /* 132947a1685fSDinh Nguyen * DxEPCTL_Stall will be cleared by EP once it has 133047a1685fSDinh Nguyen * taken effect, so no need to clear later. 133147a1685fSDinh Nguyen */ 133247a1685fSDinh Nguyen 133395c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + reg); 133447a1685fSDinh Nguyen ctrl |= DXEPCTL_STALL; 133547a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; 133695c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + reg); 133747a1685fSDinh Nguyen 133847a1685fSDinh Nguyen dev_dbg(hsotg->dev, 133947a1685fSDinh Nguyen "written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n", 134095c8bc36SAntti Seppälä ctrl, reg, dwc2_readl(hsotg->regs + reg)); 134147a1685fSDinh Nguyen 134247a1685fSDinh Nguyen /* 134347a1685fSDinh Nguyen * complete won't be called, so we enqueue 134447a1685fSDinh Nguyen * setup request here 134547a1685fSDinh Nguyen */ 13461f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 134747a1685fSDinh Nguyen } 134847a1685fSDinh Nguyen 134947a1685fSDinh Nguyen /** 13501f91b4ccSFelipe Balbi * dwc2_hsotg_process_control - process a control request 135147a1685fSDinh Nguyen * @hsotg: The device state 135247a1685fSDinh Nguyen * @ctrl: The control request received 135347a1685fSDinh Nguyen * 135447a1685fSDinh Nguyen * The controller has received the SETUP phase of a control request, and 135547a1685fSDinh Nguyen * needs to work out what to do next (and whether to pass it on to the 135647a1685fSDinh Nguyen * gadget driver). 135747a1685fSDinh Nguyen */ 13581f91b4ccSFelipe Balbi static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, 135947a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 136047a1685fSDinh Nguyen { 13611f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 136247a1685fSDinh Nguyen int ret = 0; 136347a1685fSDinh Nguyen u32 dcfg; 136447a1685fSDinh Nguyen 1365e525e743SMian Yousaf Kaukab dev_dbg(hsotg->dev, 1366e525e743SMian Yousaf Kaukab "ctrl Type=%02x, Req=%02x, V=%04x, I=%04x, L=%04x\n", 1367e525e743SMian Yousaf Kaukab ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, 1368e525e743SMian Yousaf Kaukab ctrl->wIndex, ctrl->wLength); 136947a1685fSDinh Nguyen 1370fe0b94abSMian Yousaf Kaukab if (ctrl->wLength == 0) { 137147a1685fSDinh Nguyen ep0->dir_in = 1; 1372fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_STATUS_IN; 1373fe0b94abSMian Yousaf Kaukab } else if (ctrl->bRequestType & USB_DIR_IN) { 1374fe0b94abSMian Yousaf Kaukab ep0->dir_in = 1; 1375fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_DATA_IN; 1376fe0b94abSMian Yousaf Kaukab } else { 1377fe0b94abSMian Yousaf Kaukab ep0->dir_in = 0; 1378fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_DATA_OUT; 1379fe0b94abSMian Yousaf Kaukab } 138047a1685fSDinh Nguyen 138147a1685fSDinh Nguyen if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 138247a1685fSDinh Nguyen switch (ctrl->bRequest) { 138347a1685fSDinh Nguyen case USB_REQ_SET_ADDRESS: 13846d713c15SMian Yousaf Kaukab hsotg->connected = 1; 138595c8bc36SAntti Seppälä dcfg = dwc2_readl(hsotg->regs + DCFG); 138647a1685fSDinh Nguyen dcfg &= ~DCFG_DEVADDR_MASK; 1387d5dbd3f7SPaul Zimmerman dcfg |= (le16_to_cpu(ctrl->wValue) << 1388d5dbd3f7SPaul Zimmerman DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK; 138995c8bc36SAntti Seppälä dwc2_writel(dcfg, hsotg->regs + DCFG); 139047a1685fSDinh Nguyen 139147a1685fSDinh Nguyen dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); 139247a1685fSDinh Nguyen 13931f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 139447a1685fSDinh Nguyen return; 139547a1685fSDinh Nguyen 139647a1685fSDinh Nguyen case USB_REQ_GET_STATUS: 13971f91b4ccSFelipe Balbi ret = dwc2_hsotg_process_req_status(hsotg, ctrl); 139847a1685fSDinh Nguyen break; 139947a1685fSDinh Nguyen 140047a1685fSDinh Nguyen case USB_REQ_CLEAR_FEATURE: 140147a1685fSDinh Nguyen case USB_REQ_SET_FEATURE: 14021f91b4ccSFelipe Balbi ret = dwc2_hsotg_process_req_feature(hsotg, ctrl); 140347a1685fSDinh Nguyen break; 140447a1685fSDinh Nguyen } 140547a1685fSDinh Nguyen } 140647a1685fSDinh Nguyen 140747a1685fSDinh Nguyen /* as a fallback, try delivering it to the driver to deal with */ 140847a1685fSDinh Nguyen 140947a1685fSDinh Nguyen if (ret == 0 && hsotg->driver) { 141047a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 141147a1685fSDinh Nguyen ret = hsotg->driver->setup(&hsotg->gadget, ctrl); 141247a1685fSDinh Nguyen spin_lock(&hsotg->lock); 141347a1685fSDinh Nguyen if (ret < 0) 141447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); 141547a1685fSDinh Nguyen } 141647a1685fSDinh Nguyen 141747a1685fSDinh Nguyen /* 141847a1685fSDinh Nguyen * the request is either unhandlable, or is not formatted correctly 141947a1685fSDinh Nguyen * so respond with a STALL for the status stage to indicate failure. 142047a1685fSDinh Nguyen */ 142147a1685fSDinh Nguyen 142247a1685fSDinh Nguyen if (ret < 0) 14231f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hsotg); 142447a1685fSDinh Nguyen } 142547a1685fSDinh Nguyen 142647a1685fSDinh Nguyen /** 14271f91b4ccSFelipe Balbi * dwc2_hsotg_complete_setup - completion of a setup transfer 142847a1685fSDinh Nguyen * @ep: The endpoint the request was on. 142947a1685fSDinh Nguyen * @req: The request completed. 143047a1685fSDinh Nguyen * 143147a1685fSDinh Nguyen * Called on completion of any requests the driver itself submitted for 143247a1685fSDinh Nguyen * EP0 setup packets 143347a1685fSDinh Nguyen */ 14341f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_setup(struct usb_ep *ep, 143547a1685fSDinh Nguyen struct usb_request *req) 143647a1685fSDinh Nguyen { 14371f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1438941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 143947a1685fSDinh Nguyen 144047a1685fSDinh Nguyen if (req->status < 0) { 144147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); 144247a1685fSDinh Nguyen return; 144347a1685fSDinh Nguyen } 144447a1685fSDinh Nguyen 144547a1685fSDinh Nguyen spin_lock(&hsotg->lock); 144647a1685fSDinh Nguyen if (req->actual == 0) 14471f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 144847a1685fSDinh Nguyen else 14491f91b4ccSFelipe Balbi dwc2_hsotg_process_control(hsotg, req->buf); 145047a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 145147a1685fSDinh Nguyen } 145247a1685fSDinh Nguyen 145347a1685fSDinh Nguyen /** 14541f91b4ccSFelipe Balbi * dwc2_hsotg_enqueue_setup - start a request for EP0 packets 145547a1685fSDinh Nguyen * @hsotg: The device state. 145647a1685fSDinh Nguyen * 145747a1685fSDinh Nguyen * Enqueue a request on EP0 if necessary to received any SETUP packets 145847a1685fSDinh Nguyen * received from the host. 145947a1685fSDinh Nguyen */ 14601f91b4ccSFelipe Balbi static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg) 146147a1685fSDinh Nguyen { 146247a1685fSDinh Nguyen struct usb_request *req = hsotg->ctrl_req; 14631f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 146447a1685fSDinh Nguyen int ret; 146547a1685fSDinh Nguyen 146647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); 146747a1685fSDinh Nguyen 146847a1685fSDinh Nguyen req->zero = 0; 146947a1685fSDinh Nguyen req->length = 8; 147047a1685fSDinh Nguyen req->buf = hsotg->ctrl_buff; 14711f91b4ccSFelipe Balbi req->complete = dwc2_hsotg_complete_setup; 147247a1685fSDinh Nguyen 147347a1685fSDinh Nguyen if (!list_empty(&hs_req->queue)) { 147447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s already queued???\n", __func__); 147547a1685fSDinh Nguyen return; 147647a1685fSDinh Nguyen } 147747a1685fSDinh Nguyen 1478c6f5c050SMian Yousaf Kaukab hsotg->eps_out[0]->dir_in = 0; 14798a20fa45SMian Yousaf Kaukab hsotg->eps_out[0]->send_zlp = 0; 1480fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_SETUP; 148147a1685fSDinh Nguyen 14821f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(&hsotg->eps_out[0]->ep, req, GFP_ATOMIC); 148347a1685fSDinh Nguyen if (ret < 0) { 148447a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); 148547a1685fSDinh Nguyen /* 148647a1685fSDinh Nguyen * Don't think there's much we can do other than watch the 148747a1685fSDinh Nguyen * driver fail. 148847a1685fSDinh Nguyen */ 148947a1685fSDinh Nguyen } 149047a1685fSDinh Nguyen } 149147a1685fSDinh Nguyen 14921f91b4ccSFelipe Balbi static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, 14931f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 1494fe0b94abSMian Yousaf Kaukab { 1495fe0b94abSMian Yousaf Kaukab u32 ctrl; 1496fe0b94abSMian Yousaf Kaukab u8 index = hs_ep->index; 1497fe0b94abSMian Yousaf Kaukab u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 1498fe0b94abSMian Yousaf Kaukab u32 epsiz_reg = hs_ep->dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 1499fe0b94abSMian Yousaf Kaukab 1500ccb34a91SMian Yousaf Kaukab if (hs_ep->dir_in) 1501ccb34a91SMian Yousaf Kaukab dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n", 1502ccb34a91SMian Yousaf Kaukab index); 1503ccb34a91SMian Yousaf Kaukab else 1504ccb34a91SMian Yousaf Kaukab dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n", 1505ccb34a91SMian Yousaf Kaukab index); 1506fe0b94abSMian Yousaf Kaukab 150795c8bc36SAntti Seppälä dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 1508fe0b94abSMian Yousaf Kaukab DXEPTSIZ_XFERSIZE(0), hsotg->regs + 1509fe0b94abSMian Yousaf Kaukab epsiz_reg); 1510fe0b94abSMian Yousaf Kaukab 151195c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctl_reg); 1512fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 1513fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 1514fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_USBACTEP; 151595c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + epctl_reg); 1516fe0b94abSMian Yousaf Kaukab } 1517fe0b94abSMian Yousaf Kaukab 151847a1685fSDinh Nguyen /** 15191f91b4ccSFelipe Balbi * dwc2_hsotg_complete_request - complete a request given to us 152047a1685fSDinh Nguyen * @hsotg: The device state. 152147a1685fSDinh Nguyen * @hs_ep: The endpoint the request was on. 152247a1685fSDinh Nguyen * @hs_req: The request to complete. 152347a1685fSDinh Nguyen * @result: The result code (0 => Ok, otherwise errno) 152447a1685fSDinh Nguyen * 152547a1685fSDinh Nguyen * The given request has finished, so call the necessary completion 152647a1685fSDinh Nguyen * if it has one and then look to see if we can start a new request 152747a1685fSDinh Nguyen * on the endpoint. 152847a1685fSDinh Nguyen * 152947a1685fSDinh Nguyen * Note, expects the ep to already be locked as appropriate. 153047a1685fSDinh Nguyen */ 15311f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, 15321f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 15331f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req, 153447a1685fSDinh Nguyen int result) 153547a1685fSDinh Nguyen { 153647a1685fSDinh Nguyen 153747a1685fSDinh Nguyen if (!hs_req) { 153847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); 153947a1685fSDinh Nguyen return; 154047a1685fSDinh Nguyen } 154147a1685fSDinh Nguyen 154247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", 154347a1685fSDinh Nguyen hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); 154447a1685fSDinh Nguyen 154547a1685fSDinh Nguyen /* 154647a1685fSDinh Nguyen * only replace the status if we've not already set an error 154747a1685fSDinh Nguyen * from a previous transaction 154847a1685fSDinh Nguyen */ 154947a1685fSDinh Nguyen 155047a1685fSDinh Nguyen if (hs_req->req.status == -EINPROGRESS) 155147a1685fSDinh Nguyen hs_req->req.status = result; 155247a1685fSDinh Nguyen 155344583fecSYunzhi Li if (using_dma(hsotg)) 155444583fecSYunzhi Li dwc2_hsotg_unmap_dma(hsotg, hs_ep, hs_req); 155544583fecSYunzhi Li 15561f91b4ccSFelipe Balbi dwc2_hsotg_handle_unaligned_buf_complete(hsotg, hs_ep, hs_req); 15577d24c1b5SMian Yousaf Kaukab 155847a1685fSDinh Nguyen hs_ep->req = NULL; 155947a1685fSDinh Nguyen list_del_init(&hs_req->queue); 156047a1685fSDinh Nguyen 156147a1685fSDinh Nguyen /* 156247a1685fSDinh Nguyen * call the complete request with the locks off, just in case the 156347a1685fSDinh Nguyen * request tries to queue more work for this endpoint. 156447a1685fSDinh Nguyen */ 156547a1685fSDinh Nguyen 156647a1685fSDinh Nguyen if (hs_req->req.complete) { 156747a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 1568304f7e5eSMichal Sojka usb_gadget_giveback_request(&hs_ep->ep, &hs_req->req); 156947a1685fSDinh Nguyen spin_lock(&hsotg->lock); 157047a1685fSDinh Nguyen } 157147a1685fSDinh Nguyen 157247a1685fSDinh Nguyen /* 157347a1685fSDinh Nguyen * Look to see if there is anything else to do. Note, the completion 157447a1685fSDinh Nguyen * of the previous request may have caused a new request to be started 157547a1685fSDinh Nguyen * so be careful when doing this. 157647a1685fSDinh Nguyen */ 157747a1685fSDinh Nguyen 157847a1685fSDinh Nguyen if (!hs_ep->req && result >= 0) { 157941cc4cd2SVardan Mikayelyan dwc2_gadget_start_next_request(hs_ep); 158047a1685fSDinh Nguyen } 158147a1685fSDinh Nguyen } 158247a1685fSDinh Nguyen 158347a1685fSDinh Nguyen /** 15841f91b4ccSFelipe Balbi * dwc2_hsotg_rx_data - receive data from the FIFO for an endpoint 158547a1685fSDinh Nguyen * @hsotg: The device state. 158647a1685fSDinh Nguyen * @ep_idx: The endpoint index for the data 158747a1685fSDinh Nguyen * @size: The size of data in the fifo, in bytes 158847a1685fSDinh Nguyen * 158947a1685fSDinh Nguyen * The FIFO status shows there is data to read from the FIFO for a given 159047a1685fSDinh Nguyen * endpoint, so sort out whether we need to read the data into a request 159147a1685fSDinh Nguyen * that has been made for that endpoint. 159247a1685fSDinh Nguyen */ 15931f91b4ccSFelipe Balbi static void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size) 159447a1685fSDinh Nguyen { 15951f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[ep_idx]; 15961f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 159747a1685fSDinh Nguyen void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx); 159847a1685fSDinh Nguyen int to_read; 159947a1685fSDinh Nguyen int max_req; 160047a1685fSDinh Nguyen int read_ptr; 160147a1685fSDinh Nguyen 160247a1685fSDinh Nguyen 160347a1685fSDinh Nguyen if (!hs_req) { 160495c8bc36SAntti Seppälä u32 epctl = dwc2_readl(hsotg->regs + DOEPCTL(ep_idx)); 160547a1685fSDinh Nguyen int ptr; 160647a1685fSDinh Nguyen 16076b448af4SRobert Baldyga dev_dbg(hsotg->dev, 160847a1685fSDinh Nguyen "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", 160947a1685fSDinh Nguyen __func__, size, ep_idx, epctl); 161047a1685fSDinh Nguyen 161147a1685fSDinh Nguyen /* dump the data from the FIFO, we've nothing we can do */ 161247a1685fSDinh Nguyen for (ptr = 0; ptr < size; ptr += 4) 161395c8bc36SAntti Seppälä (void)dwc2_readl(fifo); 161447a1685fSDinh Nguyen 161547a1685fSDinh Nguyen return; 161647a1685fSDinh Nguyen } 161747a1685fSDinh Nguyen 161847a1685fSDinh Nguyen to_read = size; 161947a1685fSDinh Nguyen read_ptr = hs_req->req.actual; 162047a1685fSDinh Nguyen max_req = hs_req->req.length - read_ptr; 162147a1685fSDinh Nguyen 162247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", 162347a1685fSDinh Nguyen __func__, to_read, max_req, read_ptr, hs_req->req.length); 162447a1685fSDinh Nguyen 162547a1685fSDinh Nguyen if (to_read > max_req) { 162647a1685fSDinh Nguyen /* 162747a1685fSDinh Nguyen * more data appeared than we where willing 162847a1685fSDinh Nguyen * to deal with in this request. 162947a1685fSDinh Nguyen */ 163047a1685fSDinh Nguyen 163147a1685fSDinh Nguyen /* currently we don't deal this */ 163247a1685fSDinh Nguyen WARN_ON_ONCE(1); 163347a1685fSDinh Nguyen } 163447a1685fSDinh Nguyen 163547a1685fSDinh Nguyen hs_ep->total_data += to_read; 163647a1685fSDinh Nguyen hs_req->req.actual += to_read; 163747a1685fSDinh Nguyen to_read = DIV_ROUND_UP(to_read, 4); 163847a1685fSDinh Nguyen 163947a1685fSDinh Nguyen /* 164047a1685fSDinh Nguyen * note, we might over-write the buffer end by 3 bytes depending on 164147a1685fSDinh Nguyen * alignment of the data. 164247a1685fSDinh Nguyen */ 164347a1685fSDinh Nguyen ioread32_rep(fifo, hs_req->req.buf + read_ptr, to_read); 164447a1685fSDinh Nguyen } 164547a1685fSDinh Nguyen 164647a1685fSDinh Nguyen /** 16471f91b4ccSFelipe Balbi * dwc2_hsotg_ep0_zlp - send/receive zero-length packet on control endpoint 164847a1685fSDinh Nguyen * @hsotg: The device instance 1649fe0b94abSMian Yousaf Kaukab * @dir_in: If IN zlp 165047a1685fSDinh Nguyen * 165147a1685fSDinh Nguyen * Generate a zero-length IN packet request for terminating a SETUP 165247a1685fSDinh Nguyen * transaction. 165347a1685fSDinh Nguyen * 165447a1685fSDinh Nguyen * Note, since we don't write any data to the TxFIFO, then it is 165547a1685fSDinh Nguyen * currently believed that we do not need to wait for any space in 165647a1685fSDinh Nguyen * the TxFIFO. 165747a1685fSDinh Nguyen */ 16581f91b4ccSFelipe Balbi static void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in) 165947a1685fSDinh Nguyen { 1660c6f5c050SMian Yousaf Kaukab /* eps_out[0] is used in both directions */ 1661fe0b94abSMian Yousaf Kaukab hsotg->eps_out[0]->dir_in = dir_in; 1662fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = dir_in ? DWC2_EP0_STATUS_IN : DWC2_EP0_STATUS_OUT; 166347a1685fSDinh Nguyen 16641f91b4ccSFelipe Balbi dwc2_hsotg_program_zlp(hsotg, hsotg->eps_out[0]); 166547a1685fSDinh Nguyen } 166647a1685fSDinh Nguyen 1667ec1f9d9fSRoman Bacik static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg, 1668ec1f9d9fSRoman Bacik u32 epctl_reg) 1669ec1f9d9fSRoman Bacik { 1670ec1f9d9fSRoman Bacik u32 ctrl; 1671ec1f9d9fSRoman Bacik 1672ec1f9d9fSRoman Bacik ctrl = dwc2_readl(hsotg->regs + epctl_reg); 1673ec1f9d9fSRoman Bacik if (ctrl & DXEPCTL_EOFRNUM) 1674ec1f9d9fSRoman Bacik ctrl |= DXEPCTL_SETEVENFR; 1675ec1f9d9fSRoman Bacik else 1676ec1f9d9fSRoman Bacik ctrl |= DXEPCTL_SETODDFR; 1677ec1f9d9fSRoman Bacik dwc2_writel(ctrl, hsotg->regs + epctl_reg); 1678ec1f9d9fSRoman Bacik } 1679ec1f9d9fSRoman Bacik 168047a1685fSDinh Nguyen /** 16811f91b4ccSFelipe Balbi * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO 168247a1685fSDinh Nguyen * @hsotg: The device instance 168347a1685fSDinh Nguyen * @epnum: The endpoint received from 168447a1685fSDinh Nguyen * 168547a1685fSDinh Nguyen * The RXFIFO has delivered an OutDone event, which means that the data 168647a1685fSDinh Nguyen * transfer for an OUT endpoint has been completed, either by a short 168747a1685fSDinh Nguyen * packet or by the finish of a transfer. 168847a1685fSDinh Nguyen */ 16891f91b4ccSFelipe Balbi static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) 169047a1685fSDinh Nguyen { 169195c8bc36SAntti Seppälä u32 epsize = dwc2_readl(hsotg->regs + DOEPTSIZ(epnum)); 16921f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[epnum]; 16931f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 169447a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 169547a1685fSDinh Nguyen unsigned size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 169647a1685fSDinh Nguyen int result = 0; 169747a1685fSDinh Nguyen 169847a1685fSDinh Nguyen if (!hs_req) { 169947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no request active\n", __func__); 170047a1685fSDinh Nguyen return; 170147a1685fSDinh Nguyen } 170247a1685fSDinh Nguyen 1703fe0b94abSMian Yousaf Kaukab if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_OUT) { 1704fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "zlp packet received\n"); 17051f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 17061f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 1707fe0b94abSMian Yousaf Kaukab return; 1708fe0b94abSMian Yousaf Kaukab } 1709fe0b94abSMian Yousaf Kaukab 171047a1685fSDinh Nguyen if (using_dma(hsotg)) { 171147a1685fSDinh Nguyen unsigned size_done; 171247a1685fSDinh Nguyen 171347a1685fSDinh Nguyen /* 171447a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much 171547a1685fSDinh Nguyen * is left in the endpoint size register and then working it 171647a1685fSDinh Nguyen * out from the amount we loaded for the transfer. 171747a1685fSDinh Nguyen * 171847a1685fSDinh Nguyen * We need to do this as DMA pointers are always 32bit aligned 171947a1685fSDinh Nguyen * so may overshoot/undershoot the transfer. 172047a1685fSDinh Nguyen */ 172147a1685fSDinh Nguyen 172247a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 172347a1685fSDinh Nguyen size_done += hs_ep->last_load; 172447a1685fSDinh Nguyen 172547a1685fSDinh Nguyen req->actual = size_done; 172647a1685fSDinh Nguyen } 172747a1685fSDinh Nguyen 172847a1685fSDinh Nguyen /* if there is more request to do, schedule new transfer */ 172947a1685fSDinh Nguyen if (req->actual < req->length && size_left == 0) { 17301f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 173147a1685fSDinh Nguyen return; 173247a1685fSDinh Nguyen } 173347a1685fSDinh Nguyen 173447a1685fSDinh Nguyen if (req->actual < req->length && req->short_not_ok) { 173547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", 173647a1685fSDinh Nguyen __func__, req->actual, req->length); 173747a1685fSDinh Nguyen 173847a1685fSDinh Nguyen /* 173947a1685fSDinh Nguyen * todo - what should we return here? there's no one else 174047a1685fSDinh Nguyen * even bothering to check the status. 174147a1685fSDinh Nguyen */ 174247a1685fSDinh Nguyen } 174347a1685fSDinh Nguyen 1744fe0b94abSMian Yousaf Kaukab if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_DATA_OUT) { 1745fe0b94abSMian Yousaf Kaukab /* Move to STATUS IN */ 17461f91b4ccSFelipe Balbi dwc2_hsotg_ep0_zlp(hsotg, true); 1747fe0b94abSMian Yousaf Kaukab return; 174847a1685fSDinh Nguyen } 174947a1685fSDinh Nguyen 1750ec1f9d9fSRoman Bacik /* 1751ec1f9d9fSRoman Bacik * Slave mode OUT transfers do not go through XferComplete so 1752ec1f9d9fSRoman Bacik * adjust the ISOC parity here. 1753ec1f9d9fSRoman Bacik */ 1754ec1f9d9fSRoman Bacik if (!using_dma(hsotg)) { 1755ec1f9d9fSRoman Bacik if (hs_ep->isochronous && hs_ep->interval == 1) 1756ec1f9d9fSRoman Bacik dwc2_hsotg_change_ep_iso_parity(hsotg, DOEPCTL(epnum)); 1757837e9f00SVardan Mikayelyan else if (hs_ep->isochronous && hs_ep->interval > 1) 1758837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 1759ec1f9d9fSRoman Bacik } 1760ec1f9d9fSRoman Bacik 17611f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result); 176247a1685fSDinh Nguyen } 176347a1685fSDinh Nguyen 176447a1685fSDinh Nguyen /** 17651f91b4ccSFelipe Balbi * dwc2_hsotg_handle_rx - RX FIFO has data 176647a1685fSDinh Nguyen * @hsotg: The device instance 176747a1685fSDinh Nguyen * 176847a1685fSDinh Nguyen * The IRQ handler has detected that the RX FIFO has some data in it 176947a1685fSDinh Nguyen * that requires processing, so find out what is in there and do the 177047a1685fSDinh Nguyen * appropriate read. 177147a1685fSDinh Nguyen * 177247a1685fSDinh Nguyen * The RXFIFO is a true FIFO, the packets coming out are still in packet 177347a1685fSDinh Nguyen * chunks, so if you have x packets received on an endpoint you'll get x 177447a1685fSDinh Nguyen * FIFO events delivered, each with a packet's worth of data in it. 177547a1685fSDinh Nguyen * 177647a1685fSDinh Nguyen * When using DMA, we should not be processing events from the RXFIFO 177747a1685fSDinh Nguyen * as the actual data should be sent to the memory directly and we turn 177847a1685fSDinh Nguyen * on the completion interrupts to get notifications of transfer completion. 177947a1685fSDinh Nguyen */ 17801f91b4ccSFelipe Balbi static void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg) 178147a1685fSDinh Nguyen { 178295c8bc36SAntti Seppälä u32 grxstsr = dwc2_readl(hsotg->regs + GRXSTSP); 178347a1685fSDinh Nguyen u32 epnum, status, size; 178447a1685fSDinh Nguyen 178547a1685fSDinh Nguyen WARN_ON(using_dma(hsotg)); 178647a1685fSDinh Nguyen 178747a1685fSDinh Nguyen epnum = grxstsr & GRXSTS_EPNUM_MASK; 178847a1685fSDinh Nguyen status = grxstsr & GRXSTS_PKTSTS_MASK; 178947a1685fSDinh Nguyen 179047a1685fSDinh Nguyen size = grxstsr & GRXSTS_BYTECNT_MASK; 179147a1685fSDinh Nguyen size >>= GRXSTS_BYTECNT_SHIFT; 179247a1685fSDinh Nguyen 179347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", 179447a1685fSDinh Nguyen __func__, grxstsr, size, epnum); 179547a1685fSDinh Nguyen 179647a1685fSDinh Nguyen switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { 179747a1685fSDinh Nguyen case GRXSTS_PKTSTS_GLOBALOUTNAK: 179847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GLOBALOUTNAK\n"); 179947a1685fSDinh Nguyen break; 180047a1685fSDinh Nguyen 180147a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTDONE: 180247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", 18031f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg)); 180447a1685fSDinh Nguyen 180547a1685fSDinh Nguyen if (!using_dma(hsotg)) 18061f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, epnum); 180747a1685fSDinh Nguyen break; 180847a1685fSDinh Nguyen 180947a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPDONE: 181047a1685fSDinh Nguyen dev_dbg(hsotg->dev, 181147a1685fSDinh Nguyen "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 18121f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg), 181395c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL(0))); 1814fe0b94abSMian Yousaf Kaukab /* 18151f91b4ccSFelipe Balbi * Call dwc2_hsotg_handle_outdone here if it was not called from 1816fe0b94abSMian Yousaf Kaukab * GRXSTS_PKTSTS_OUTDONE. That is, if the core didn't 1817fe0b94abSMian Yousaf Kaukab * generate GRXSTS_PKTSTS_OUTDONE for setup packet. 1818fe0b94abSMian Yousaf Kaukab */ 1819fe0b94abSMian Yousaf Kaukab if (hsotg->ep0_state == DWC2_EP0_SETUP) 18201f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, epnum); 182147a1685fSDinh Nguyen break; 182247a1685fSDinh Nguyen 182347a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTRX: 18241f91b4ccSFelipe Balbi dwc2_hsotg_rx_data(hsotg, epnum, size); 182547a1685fSDinh Nguyen break; 182647a1685fSDinh Nguyen 182747a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPRX: 182847a1685fSDinh Nguyen dev_dbg(hsotg->dev, 182947a1685fSDinh Nguyen "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 18301f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg), 183195c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL(0))); 183247a1685fSDinh Nguyen 1833fe0b94abSMian Yousaf Kaukab WARN_ON(hsotg->ep0_state != DWC2_EP0_SETUP); 1834fe0b94abSMian Yousaf Kaukab 18351f91b4ccSFelipe Balbi dwc2_hsotg_rx_data(hsotg, epnum, size); 183647a1685fSDinh Nguyen break; 183747a1685fSDinh Nguyen 183847a1685fSDinh Nguyen default: 183947a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: unknown status %08x\n", 184047a1685fSDinh Nguyen __func__, grxstsr); 184147a1685fSDinh Nguyen 18421f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 184347a1685fSDinh Nguyen break; 184447a1685fSDinh Nguyen } 184547a1685fSDinh Nguyen } 184647a1685fSDinh Nguyen 184747a1685fSDinh Nguyen /** 18481f91b4ccSFelipe Balbi * dwc2_hsotg_ep0_mps - turn max packet size into register setting 184947a1685fSDinh Nguyen * @mps: The maximum packet size in bytes. 185047a1685fSDinh Nguyen */ 18511f91b4ccSFelipe Balbi static u32 dwc2_hsotg_ep0_mps(unsigned int mps) 185247a1685fSDinh Nguyen { 185347a1685fSDinh Nguyen switch (mps) { 185447a1685fSDinh Nguyen case 64: 185547a1685fSDinh Nguyen return D0EPCTL_MPS_64; 185647a1685fSDinh Nguyen case 32: 185747a1685fSDinh Nguyen return D0EPCTL_MPS_32; 185847a1685fSDinh Nguyen case 16: 185947a1685fSDinh Nguyen return D0EPCTL_MPS_16; 186047a1685fSDinh Nguyen case 8: 186147a1685fSDinh Nguyen return D0EPCTL_MPS_8; 186247a1685fSDinh Nguyen } 186347a1685fSDinh Nguyen 186447a1685fSDinh Nguyen /* bad max packet size, warn and return invalid result */ 186547a1685fSDinh Nguyen WARN_ON(1); 186647a1685fSDinh Nguyen return (u32)-1; 186747a1685fSDinh Nguyen } 186847a1685fSDinh Nguyen 186947a1685fSDinh Nguyen /** 18701f91b4ccSFelipe Balbi * dwc2_hsotg_set_ep_maxpacket - set endpoint's max-packet field 187147a1685fSDinh Nguyen * @hsotg: The driver state. 187247a1685fSDinh Nguyen * @ep: The index number of the endpoint 187347a1685fSDinh Nguyen * @mps: The maximum packet size in bytes 1874ee2c40deSVardan Mikayelyan * @mc: The multicount value 187547a1685fSDinh Nguyen * 187647a1685fSDinh Nguyen * Configure the maximum packet size for the given endpoint, updating 187747a1685fSDinh Nguyen * the hardware control registers to reflect this. 187847a1685fSDinh Nguyen */ 18791f91b4ccSFelipe Balbi static void dwc2_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg, 1880ee2c40deSVardan Mikayelyan unsigned int ep, unsigned int mps, 1881ee2c40deSVardan Mikayelyan unsigned int mc, unsigned int dir_in) 188247a1685fSDinh Nguyen { 18831f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep; 188447a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 188547a1685fSDinh Nguyen u32 reg; 188647a1685fSDinh Nguyen 1887c6f5c050SMian Yousaf Kaukab hs_ep = index_to_ep(hsotg, ep, dir_in); 1888c6f5c050SMian Yousaf Kaukab if (!hs_ep) 1889c6f5c050SMian Yousaf Kaukab return; 1890c6f5c050SMian Yousaf Kaukab 189147a1685fSDinh Nguyen if (ep == 0) { 1892ee2c40deSVardan Mikayelyan u32 mps_bytes = mps; 1893ee2c40deSVardan Mikayelyan 189447a1685fSDinh Nguyen /* EP0 is a special case */ 1895ee2c40deSVardan Mikayelyan mps = dwc2_hsotg_ep0_mps(mps_bytes); 1896ee2c40deSVardan Mikayelyan if (mps > 3) 189747a1685fSDinh Nguyen goto bad_mps; 1898ee2c40deSVardan Mikayelyan hs_ep->ep.maxpacket = mps_bytes; 189947a1685fSDinh Nguyen hs_ep->mc = 1; 190047a1685fSDinh Nguyen } else { 1901ee2c40deSVardan Mikayelyan if (mps > 1024) 190247a1685fSDinh Nguyen goto bad_mps; 1903ee2c40deSVardan Mikayelyan hs_ep->mc = mc; 1904ee2c40deSVardan Mikayelyan if (mc > 3) 190547a1685fSDinh Nguyen goto bad_mps; 1906ee2c40deSVardan Mikayelyan hs_ep->ep.maxpacket = mps; 190747a1685fSDinh Nguyen } 190847a1685fSDinh Nguyen 1909c6f5c050SMian Yousaf Kaukab if (dir_in) { 191095c8bc36SAntti Seppälä reg = dwc2_readl(regs + DIEPCTL(ep)); 191147a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 1912ee2c40deSVardan Mikayelyan reg |= mps; 191395c8bc36SAntti Seppälä dwc2_writel(reg, regs + DIEPCTL(ep)); 1914c6f5c050SMian Yousaf Kaukab } else { 191595c8bc36SAntti Seppälä reg = dwc2_readl(regs + DOEPCTL(ep)); 191647a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 1917ee2c40deSVardan Mikayelyan reg |= mps; 191895c8bc36SAntti Seppälä dwc2_writel(reg, regs + DOEPCTL(ep)); 191947a1685fSDinh Nguyen } 192047a1685fSDinh Nguyen 192147a1685fSDinh Nguyen return; 192247a1685fSDinh Nguyen 192347a1685fSDinh Nguyen bad_mps: 192447a1685fSDinh Nguyen dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); 192547a1685fSDinh Nguyen } 192647a1685fSDinh Nguyen 192747a1685fSDinh Nguyen /** 19281f91b4ccSFelipe Balbi * dwc2_hsotg_txfifo_flush - flush Tx FIFO 192947a1685fSDinh Nguyen * @hsotg: The driver state 193047a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 193147a1685fSDinh Nguyen */ 19321f91b4ccSFelipe Balbi static void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx) 193347a1685fSDinh Nguyen { 193447a1685fSDinh Nguyen int timeout; 193547a1685fSDinh Nguyen int val; 193647a1685fSDinh Nguyen 193795c8bc36SAntti Seppälä dwc2_writel(GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH, 193847a1685fSDinh Nguyen hsotg->regs + GRSTCTL); 193947a1685fSDinh Nguyen 194047a1685fSDinh Nguyen /* wait until the fifo is flushed */ 194147a1685fSDinh Nguyen timeout = 100; 194247a1685fSDinh Nguyen 194347a1685fSDinh Nguyen while (1) { 194495c8bc36SAntti Seppälä val = dwc2_readl(hsotg->regs + GRSTCTL); 194547a1685fSDinh Nguyen 194647a1685fSDinh Nguyen if ((val & (GRSTCTL_TXFFLSH)) == 0) 194747a1685fSDinh Nguyen break; 194847a1685fSDinh Nguyen 194947a1685fSDinh Nguyen if (--timeout == 0) { 195047a1685fSDinh Nguyen dev_err(hsotg->dev, 195147a1685fSDinh Nguyen "%s: timeout flushing fifo (GRSTCTL=%08x)\n", 195247a1685fSDinh Nguyen __func__, val); 1953e0cbe595SMarek Szyprowski break; 195447a1685fSDinh Nguyen } 195547a1685fSDinh Nguyen 195647a1685fSDinh Nguyen udelay(1); 195747a1685fSDinh Nguyen } 195847a1685fSDinh Nguyen } 195947a1685fSDinh Nguyen 196047a1685fSDinh Nguyen /** 19611f91b4ccSFelipe Balbi * dwc2_hsotg_trytx - check to see if anything needs transmitting 196247a1685fSDinh Nguyen * @hsotg: The driver state 196347a1685fSDinh Nguyen * @hs_ep: The driver endpoint to check. 196447a1685fSDinh Nguyen * 196547a1685fSDinh Nguyen * Check to see if there is a request that has data to send, and if so 196647a1685fSDinh Nguyen * make an attempt to write data into the FIFO. 196747a1685fSDinh Nguyen */ 19681f91b4ccSFelipe Balbi static int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, 19691f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 197047a1685fSDinh Nguyen { 19711f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 197247a1685fSDinh Nguyen 197347a1685fSDinh Nguyen if (!hs_ep->dir_in || !hs_req) { 197447a1685fSDinh Nguyen /** 197547a1685fSDinh Nguyen * if request is not enqueued, we disable interrupts 197647a1685fSDinh Nguyen * for endpoints, excepting ep0 197747a1685fSDinh Nguyen */ 197847a1685fSDinh Nguyen if (hs_ep->index != 0) 19791f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, 198047a1685fSDinh Nguyen hs_ep->dir_in, 0); 198147a1685fSDinh Nguyen return 0; 198247a1685fSDinh Nguyen } 198347a1685fSDinh Nguyen 198447a1685fSDinh Nguyen if (hs_req->req.actual < hs_req->req.length) { 198547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "trying to write more for ep%d\n", 198647a1685fSDinh Nguyen hs_ep->index); 19871f91b4ccSFelipe Balbi return dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 198847a1685fSDinh Nguyen } 198947a1685fSDinh Nguyen 199047a1685fSDinh Nguyen return 0; 199147a1685fSDinh Nguyen } 199247a1685fSDinh Nguyen 199347a1685fSDinh Nguyen /** 19941f91b4ccSFelipe Balbi * dwc2_hsotg_complete_in - complete IN transfer 199547a1685fSDinh Nguyen * @hsotg: The device state. 199647a1685fSDinh Nguyen * @hs_ep: The endpoint that has just completed. 199747a1685fSDinh Nguyen * 199847a1685fSDinh Nguyen * An IN transfer has been completed, update the transfer's state and then 199947a1685fSDinh Nguyen * call the relevant completion routines. 200047a1685fSDinh Nguyen */ 20011f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, 20021f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 200347a1685fSDinh Nguyen { 20041f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 200595c8bc36SAntti Seppälä u32 epsize = dwc2_readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); 200647a1685fSDinh Nguyen int size_left, size_done; 200747a1685fSDinh Nguyen 200847a1685fSDinh Nguyen if (!hs_req) { 200947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "XferCompl but no req\n"); 201047a1685fSDinh Nguyen return; 201147a1685fSDinh Nguyen } 201247a1685fSDinh Nguyen 201347a1685fSDinh Nguyen /* Finish ZLP handling for IN EP0 transactions */ 2014fe0b94abSMian Yousaf Kaukab if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) { 2015fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "zlp packet sent\n"); 20161f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 20179e14d0a5SGregory Herrero if (hsotg->test_mode) { 20189e14d0a5SGregory Herrero int ret; 20199e14d0a5SGregory Herrero 20201f91b4ccSFelipe Balbi ret = dwc2_hsotg_set_test_mode(hsotg, hsotg->test_mode); 20219e14d0a5SGregory Herrero if (ret < 0) { 20229e14d0a5SGregory Herrero dev_dbg(hsotg->dev, "Invalid Test #%d\n", 20239e14d0a5SGregory Herrero hsotg->test_mode); 20241f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hsotg); 20259e14d0a5SGregory Herrero return; 20269e14d0a5SGregory Herrero } 20279e14d0a5SGregory Herrero } 20281f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 202947a1685fSDinh Nguyen return; 203047a1685fSDinh Nguyen } 203147a1685fSDinh Nguyen 203247a1685fSDinh Nguyen /* 203347a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much is left 203447a1685fSDinh Nguyen * in the endpoint size register and then working it out from 203547a1685fSDinh Nguyen * the amount we loaded for the transfer. 203647a1685fSDinh Nguyen * 203747a1685fSDinh Nguyen * We do this even for DMA, as the transfer may have incremented 203847a1685fSDinh Nguyen * past the end of the buffer (DMA transfers are always 32bit 203947a1685fSDinh Nguyen * aligned). 204047a1685fSDinh Nguyen */ 204147a1685fSDinh Nguyen 204247a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 204347a1685fSDinh Nguyen 204447a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 204547a1685fSDinh Nguyen size_done += hs_ep->last_load; 204647a1685fSDinh Nguyen 204747a1685fSDinh Nguyen if (hs_req->req.actual != size_done) 204847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", 204947a1685fSDinh Nguyen __func__, hs_req->req.actual, size_done); 205047a1685fSDinh Nguyen 205147a1685fSDinh Nguyen hs_req->req.actual = size_done; 205247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", 205347a1685fSDinh Nguyen hs_req->req.length, hs_req->req.actual, hs_req->req.zero); 205447a1685fSDinh Nguyen 205547a1685fSDinh Nguyen if (!size_left && hs_req->req.actual < hs_req->req.length) { 205647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); 20571f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 2058fe0b94abSMian Yousaf Kaukab return; 2059fe0b94abSMian Yousaf Kaukab } 2060fe0b94abSMian Yousaf Kaukab 2061f71b5e25SMian Yousaf Kaukab /* Zlp for all endpoints, for ep0 only in DATA IN stage */ 20628a20fa45SMian Yousaf Kaukab if (hs_ep->send_zlp) { 20631f91b4ccSFelipe Balbi dwc2_hsotg_program_zlp(hsotg, hs_ep); 20648a20fa45SMian Yousaf Kaukab hs_ep->send_zlp = 0; 2065f71b5e25SMian Yousaf Kaukab /* transfer will be completed on next complete interrupt */ 2066f71b5e25SMian Yousaf Kaukab return; 2067f71b5e25SMian Yousaf Kaukab } 2068f71b5e25SMian Yousaf Kaukab 2069fe0b94abSMian Yousaf Kaukab if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_DATA_IN) { 2070fe0b94abSMian Yousaf Kaukab /* Move to STATUS OUT */ 20711f91b4ccSFelipe Balbi dwc2_hsotg_ep0_zlp(hsotg, false); 2072fe0b94abSMian Yousaf Kaukab return; 2073fe0b94abSMian Yousaf Kaukab } 2074fe0b94abSMian Yousaf Kaukab 20751f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 207647a1685fSDinh Nguyen } 207747a1685fSDinh Nguyen 207847a1685fSDinh Nguyen /** 207932601588SVardan Mikayelyan * dwc2_gadget_read_ep_interrupts - reads interrupts for given ep 208032601588SVardan Mikayelyan * @hsotg: The device state. 208132601588SVardan Mikayelyan * @idx: Index of ep. 208232601588SVardan Mikayelyan * @dir_in: Endpoint direction 1-in 0-out. 208332601588SVardan Mikayelyan * 208432601588SVardan Mikayelyan * Reads for endpoint with given index and direction, by masking 208532601588SVardan Mikayelyan * epint_reg with coresponding mask. 208632601588SVardan Mikayelyan */ 208732601588SVardan Mikayelyan static u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg, 208832601588SVardan Mikayelyan unsigned int idx, int dir_in) 208932601588SVardan Mikayelyan { 209032601588SVardan Mikayelyan u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; 209132601588SVardan Mikayelyan u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 209232601588SVardan Mikayelyan u32 ints; 209332601588SVardan Mikayelyan u32 mask; 209432601588SVardan Mikayelyan u32 diepempmsk; 209532601588SVardan Mikayelyan 209632601588SVardan Mikayelyan mask = dwc2_readl(hsotg->regs + epmsk_reg); 209732601588SVardan Mikayelyan diepempmsk = dwc2_readl(hsotg->regs + DIEPEMPMSK); 209832601588SVardan Mikayelyan mask |= ((diepempmsk >> idx) & 0x1) ? DIEPMSK_TXFIFOEMPTY : 0; 209932601588SVardan Mikayelyan mask |= DXEPINT_SETUP_RCVD; 210032601588SVardan Mikayelyan 210132601588SVardan Mikayelyan ints = dwc2_readl(hsotg->regs + epint_reg); 210232601588SVardan Mikayelyan ints &= mask; 210332601588SVardan Mikayelyan return ints; 210432601588SVardan Mikayelyan } 210532601588SVardan Mikayelyan 210632601588SVardan Mikayelyan /** 2107bd9971f0SVardan Mikayelyan * dwc2_gadget_handle_ep_disabled - handle DXEPINT_EPDISBLD 2108bd9971f0SVardan Mikayelyan * @hs_ep: The endpoint on which interrupt is asserted. 2109bd9971f0SVardan Mikayelyan * 2110bd9971f0SVardan Mikayelyan * This interrupt indicates that the endpoint has been disabled per the 2111bd9971f0SVardan Mikayelyan * application's request. 2112bd9971f0SVardan Mikayelyan * 2113bd9971f0SVardan Mikayelyan * For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK, 2114bd9971f0SVardan Mikayelyan * in case of ISOC completes current request. 2115bd9971f0SVardan Mikayelyan * 2116bd9971f0SVardan Mikayelyan * For ISOC-OUT endpoints completes expired requests. If there is remaining 2117bd9971f0SVardan Mikayelyan * request starts it. 2118bd9971f0SVardan Mikayelyan */ 2119bd9971f0SVardan Mikayelyan static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) 2120bd9971f0SVardan Mikayelyan { 2121bd9971f0SVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 2122bd9971f0SVardan Mikayelyan struct dwc2_hsotg_req *hs_req; 2123bd9971f0SVardan Mikayelyan unsigned char idx = hs_ep->index; 2124bd9971f0SVardan Mikayelyan int dir_in = hs_ep->dir_in; 2125bd9971f0SVardan Mikayelyan u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 2126bd9971f0SVardan Mikayelyan int dctl = dwc2_readl(hsotg->regs + DCTL); 2127bd9971f0SVardan Mikayelyan 2128bd9971f0SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); 2129bd9971f0SVardan Mikayelyan 2130bd9971f0SVardan Mikayelyan if (dir_in) { 2131bd9971f0SVardan Mikayelyan int epctl = dwc2_readl(hsotg->regs + epctl_reg); 2132bd9971f0SVardan Mikayelyan 2133bd9971f0SVardan Mikayelyan dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); 2134bd9971f0SVardan Mikayelyan 2135bd9971f0SVardan Mikayelyan if (hs_ep->isochronous) { 2136bd9971f0SVardan Mikayelyan dwc2_hsotg_complete_in(hsotg, hs_ep); 2137bd9971f0SVardan Mikayelyan return; 2138bd9971f0SVardan Mikayelyan } 2139bd9971f0SVardan Mikayelyan 2140bd9971f0SVardan Mikayelyan if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) { 2141bd9971f0SVardan Mikayelyan int dctl = dwc2_readl(hsotg->regs + DCTL); 2142bd9971f0SVardan Mikayelyan 2143bd9971f0SVardan Mikayelyan dctl |= DCTL_CGNPINNAK; 2144bd9971f0SVardan Mikayelyan dwc2_writel(dctl, hsotg->regs + DCTL); 2145bd9971f0SVardan Mikayelyan } 2146bd9971f0SVardan Mikayelyan return; 2147bd9971f0SVardan Mikayelyan } 2148bd9971f0SVardan Mikayelyan 2149bd9971f0SVardan Mikayelyan if (dctl & DCTL_GOUTNAKSTS) { 2150bd9971f0SVardan Mikayelyan dctl |= DCTL_CGOUTNAK; 2151bd9971f0SVardan Mikayelyan dwc2_writel(dctl, hsotg->regs + DCTL); 2152bd9971f0SVardan Mikayelyan } 2153bd9971f0SVardan Mikayelyan 2154bd9971f0SVardan Mikayelyan if (!hs_ep->isochronous) 2155bd9971f0SVardan Mikayelyan return; 2156bd9971f0SVardan Mikayelyan 2157bd9971f0SVardan Mikayelyan if (list_empty(&hs_ep->queue)) { 2158bd9971f0SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: complete_ep 0x%p, ep->queue empty!\n", 2159bd9971f0SVardan Mikayelyan __func__, hs_ep); 2160bd9971f0SVardan Mikayelyan return; 2161bd9971f0SVardan Mikayelyan } 2162bd9971f0SVardan Mikayelyan 2163bd9971f0SVardan Mikayelyan do { 2164bd9971f0SVardan Mikayelyan hs_req = get_ep_head(hs_ep); 2165bd9971f0SVardan Mikayelyan if (hs_req) 2166bd9971f0SVardan Mikayelyan dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 2167bd9971f0SVardan Mikayelyan -ENODATA); 2168bd9971f0SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 2169bd9971f0SVardan Mikayelyan } while (dwc2_gadget_target_frame_elapsed(hs_ep)); 2170bd9971f0SVardan Mikayelyan 2171bd9971f0SVardan Mikayelyan dwc2_gadget_start_next_request(hs_ep); 2172bd9971f0SVardan Mikayelyan } 2173bd9971f0SVardan Mikayelyan 2174bd9971f0SVardan Mikayelyan /** 21755321922cSVardan Mikayelyan * dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS 21765321922cSVardan Mikayelyan * @hs_ep: The endpoint on which interrupt is asserted. 21775321922cSVardan Mikayelyan * 21785321922cSVardan Mikayelyan * This is starting point for ISOC-OUT transfer, synchronization done with 21795321922cSVardan Mikayelyan * first out token received from host while corresponding EP is disabled. 21805321922cSVardan Mikayelyan * 21815321922cSVardan Mikayelyan * Device does not know initial frame in which out token will come. For this 21825321922cSVardan Mikayelyan * HW generates OUTTKNEPDIS - out token is received while EP is disabled. Upon 21835321922cSVardan Mikayelyan * getting this interrupt SW starts calculation for next transfer frame. 21845321922cSVardan Mikayelyan */ 21855321922cSVardan Mikayelyan static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) 21865321922cSVardan Mikayelyan { 21875321922cSVardan Mikayelyan struct dwc2_hsotg *hsotg = ep->parent; 21885321922cSVardan Mikayelyan int dir_in = ep->dir_in; 21895321922cSVardan Mikayelyan u32 doepmsk; 21905321922cSVardan Mikayelyan 21915321922cSVardan Mikayelyan if (dir_in || !ep->isochronous) 21925321922cSVardan Mikayelyan return; 21935321922cSVardan Mikayelyan 21945321922cSVardan Mikayelyan dwc2_hsotg_complete_request(hsotg, ep, get_ep_head(ep), -ENODATA); 21955321922cSVardan Mikayelyan 21965321922cSVardan Mikayelyan if (ep->interval > 1 && 21975321922cSVardan Mikayelyan ep->target_frame == TARGET_FRAME_INITIAL) { 21985321922cSVardan Mikayelyan u32 dsts; 21995321922cSVardan Mikayelyan u32 ctrl; 22005321922cSVardan Mikayelyan 22015321922cSVardan Mikayelyan dsts = dwc2_readl(hsotg->regs + DSTS); 22025321922cSVardan Mikayelyan ep->target_frame = dwc2_hsotg_read_frameno(hsotg); 22035321922cSVardan Mikayelyan dwc2_gadget_incr_frame_num(ep); 22045321922cSVardan Mikayelyan 22055321922cSVardan Mikayelyan ctrl = dwc2_readl(hsotg->regs + DOEPCTL(ep->index)); 22065321922cSVardan Mikayelyan if (ep->target_frame & 0x1) 22075321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETODDFR; 22085321922cSVardan Mikayelyan else 22095321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETEVENFR; 22105321922cSVardan Mikayelyan 22115321922cSVardan Mikayelyan dwc2_writel(ctrl, hsotg->regs + DOEPCTL(ep->index)); 22125321922cSVardan Mikayelyan } 22135321922cSVardan Mikayelyan 22145321922cSVardan Mikayelyan dwc2_gadget_start_next_request(ep); 22155321922cSVardan Mikayelyan doepmsk = dwc2_readl(hsotg->regs + DOEPMSK); 22165321922cSVardan Mikayelyan doepmsk &= ~DOEPMSK_OUTTKNEPDISMSK; 22175321922cSVardan Mikayelyan dwc2_writel(doepmsk, hsotg->regs + DOEPMSK); 22185321922cSVardan Mikayelyan } 22195321922cSVardan Mikayelyan 22205321922cSVardan Mikayelyan /** 22215321922cSVardan Mikayelyan * dwc2_gadget_handle_nak - handle NAK interrupt 22225321922cSVardan Mikayelyan * @hs_ep: The endpoint on which interrupt is asserted. 22235321922cSVardan Mikayelyan * 22245321922cSVardan Mikayelyan * This is starting point for ISOC-IN transfer, synchronization done with 22255321922cSVardan Mikayelyan * first IN token received from host while corresponding EP is disabled. 22265321922cSVardan Mikayelyan * 22275321922cSVardan Mikayelyan * Device does not know when first one token will arrive from host. On first 22285321922cSVardan Mikayelyan * token arrival HW generates 2 interrupts: 'in token received while FIFO empty' 22295321922cSVardan Mikayelyan * and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was 22305321922cSVardan Mikayelyan * sent in response to that as there was no data in FIFO. SW is basing on this 22315321922cSVardan Mikayelyan * interrupt to obtain frame in which token has come and then based on the 22325321922cSVardan Mikayelyan * interval calculates next frame for transfer. 22335321922cSVardan Mikayelyan */ 22345321922cSVardan Mikayelyan static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) 22355321922cSVardan Mikayelyan { 22365321922cSVardan Mikayelyan struct dwc2_hsotg *hsotg = hs_ep->parent; 22375321922cSVardan Mikayelyan int dir_in = hs_ep->dir_in; 22385321922cSVardan Mikayelyan 22395321922cSVardan Mikayelyan if (!dir_in || !hs_ep->isochronous) 22405321922cSVardan Mikayelyan return; 22415321922cSVardan Mikayelyan 22425321922cSVardan Mikayelyan if (hs_ep->target_frame == TARGET_FRAME_INITIAL) { 22435321922cSVardan Mikayelyan hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg); 22445321922cSVardan Mikayelyan if (hs_ep->interval > 1) { 22455321922cSVardan Mikayelyan u32 ctrl = dwc2_readl(hsotg->regs + 22465321922cSVardan Mikayelyan DIEPCTL(hs_ep->index)); 22475321922cSVardan Mikayelyan if (hs_ep->target_frame & 0x1) 22485321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETODDFR; 22495321922cSVardan Mikayelyan else 22505321922cSVardan Mikayelyan ctrl |= DXEPCTL_SETEVENFR; 22515321922cSVardan Mikayelyan 22525321922cSVardan Mikayelyan dwc2_writel(ctrl, hsotg->regs + DIEPCTL(hs_ep->index)); 22535321922cSVardan Mikayelyan } 22545321922cSVardan Mikayelyan 22555321922cSVardan Mikayelyan dwc2_hsotg_complete_request(hsotg, hs_ep, 22565321922cSVardan Mikayelyan get_ep_head(hs_ep), 0); 22575321922cSVardan Mikayelyan } 22585321922cSVardan Mikayelyan 22595321922cSVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 22605321922cSVardan Mikayelyan } 22615321922cSVardan Mikayelyan 22625321922cSVardan Mikayelyan /** 22631f91b4ccSFelipe Balbi * dwc2_hsotg_epint - handle an in/out endpoint interrupt 226447a1685fSDinh Nguyen * @hsotg: The driver state 226547a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 226647a1685fSDinh Nguyen * @dir_in: Set if this is an IN endpoint 226747a1685fSDinh Nguyen * 226847a1685fSDinh Nguyen * Process and clear any interrupt pending for an individual endpoint 226947a1685fSDinh Nguyen */ 22701f91b4ccSFelipe Balbi static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, 227147a1685fSDinh Nguyen int dir_in) 227247a1685fSDinh Nguyen { 22731f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in); 227447a1685fSDinh Nguyen u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 227547a1685fSDinh Nguyen u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 227647a1685fSDinh Nguyen u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); 227747a1685fSDinh Nguyen u32 ints; 227847a1685fSDinh Nguyen u32 ctrl; 227947a1685fSDinh Nguyen 228032601588SVardan Mikayelyan ints = dwc2_gadget_read_ep_interrupts(hsotg, idx, dir_in); 228195c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctl_reg); 228247a1685fSDinh Nguyen 228347a1685fSDinh Nguyen /* Clear endpoint interrupts */ 228495c8bc36SAntti Seppälä dwc2_writel(ints, hsotg->regs + epint_reg); 228547a1685fSDinh Nguyen 2286c6f5c050SMian Yousaf Kaukab if (!hs_ep) { 2287c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n", 2288c6f5c050SMian Yousaf Kaukab __func__, idx, dir_in ? "in" : "out"); 2289c6f5c050SMian Yousaf Kaukab return; 2290c6f5c050SMian Yousaf Kaukab } 2291c6f5c050SMian Yousaf Kaukab 229247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", 229347a1685fSDinh Nguyen __func__, idx, dir_in ? "in" : "out", ints); 229447a1685fSDinh Nguyen 2295b787d755SMian Yousaf Kaukab /* Don't process XferCompl interrupt if it is a setup packet */ 2296b787d755SMian Yousaf Kaukab if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD))) 2297b787d755SMian Yousaf Kaukab ints &= ~DXEPINT_XFERCOMPL; 2298b787d755SMian Yousaf Kaukab 2299837e9f00SVardan Mikayelyan if (ints & DXEPINT_STSPHSERCVD) 2300837e9f00SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: StsPhseRcvd asserted\n", __func__); 230147a1685fSDinh Nguyen 2302837e9f00SVardan Mikayelyan if (ints & DXEPINT_XFERCOMPL) { 230347a1685fSDinh Nguyen dev_dbg(hsotg->dev, 230447a1685fSDinh Nguyen "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", 230595c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctl_reg), 230695c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + epsiz_reg)); 230747a1685fSDinh Nguyen 230847a1685fSDinh Nguyen /* 230947a1685fSDinh Nguyen * we get OutDone from the FIFO, so we only need to look 231047a1685fSDinh Nguyen * at completing IN requests here 231147a1685fSDinh Nguyen */ 231247a1685fSDinh Nguyen if (dir_in) { 2313837e9f00SVardan Mikayelyan if (hs_ep->isochronous && hs_ep->interval > 1) 2314837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 2315837e9f00SVardan Mikayelyan 23161f91b4ccSFelipe Balbi dwc2_hsotg_complete_in(hsotg, hs_ep); 2317837e9f00SVardan Mikayelyan if (ints & DXEPINT_NAKINTRPT) 2318837e9f00SVardan Mikayelyan ints &= ~DXEPINT_NAKINTRPT; 231947a1685fSDinh Nguyen 232047a1685fSDinh Nguyen if (idx == 0 && !hs_ep->req) 23211f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 232247a1685fSDinh Nguyen } else if (using_dma(hsotg)) { 232347a1685fSDinh Nguyen /* 232447a1685fSDinh Nguyen * We're using DMA, we need to fire an OutDone here 232547a1685fSDinh Nguyen * as we ignore the RXFIFO. 232647a1685fSDinh Nguyen */ 2327837e9f00SVardan Mikayelyan if (hs_ep->isochronous && hs_ep->interval > 1) 2328837e9f00SVardan Mikayelyan dwc2_gadget_incr_frame_num(hs_ep); 232947a1685fSDinh Nguyen 23301f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, idx); 233147a1685fSDinh Nguyen } 233247a1685fSDinh Nguyen } 233347a1685fSDinh Nguyen 2334bd9971f0SVardan Mikayelyan if (ints & DXEPINT_EPDISBLD) 2335bd9971f0SVardan Mikayelyan dwc2_gadget_handle_ep_disabled(hs_ep); 233647a1685fSDinh Nguyen 23375321922cSVardan Mikayelyan if (ints & DXEPINT_OUTTKNEPDIS) 23385321922cSVardan Mikayelyan dwc2_gadget_handle_out_token_ep_disabled(hs_ep); 23395321922cSVardan Mikayelyan 23405321922cSVardan Mikayelyan if (ints & DXEPINT_NAKINTRPT) 23415321922cSVardan Mikayelyan dwc2_gadget_handle_nak(hs_ep); 23425321922cSVardan Mikayelyan 234347a1685fSDinh Nguyen if (ints & DXEPINT_AHBERR) 234447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); 234547a1685fSDinh Nguyen 234647a1685fSDinh Nguyen if (ints & DXEPINT_SETUP) { /* Setup or Timeout */ 234747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); 234847a1685fSDinh Nguyen 234947a1685fSDinh Nguyen if (using_dma(hsotg) && idx == 0) { 235047a1685fSDinh Nguyen /* 235147a1685fSDinh Nguyen * this is the notification we've received a 235247a1685fSDinh Nguyen * setup packet. In non-DMA mode we'd get this 235347a1685fSDinh Nguyen * from the RXFIFO, instead we need to process 235447a1685fSDinh Nguyen * the setup here. 235547a1685fSDinh Nguyen */ 235647a1685fSDinh Nguyen 235747a1685fSDinh Nguyen if (dir_in) 235847a1685fSDinh Nguyen WARN_ON_ONCE(1); 235947a1685fSDinh Nguyen else 23601f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, 0); 236147a1685fSDinh Nguyen } 236247a1685fSDinh Nguyen } 236347a1685fSDinh Nguyen 236447a1685fSDinh Nguyen if (ints & DXEPINT_BACK2BACKSETUP) 236547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); 236647a1685fSDinh Nguyen 236747a1685fSDinh Nguyen if (dir_in && !hs_ep->isochronous) { 236847a1685fSDinh Nguyen /* not sure if this is important, but we'll clear it anyway */ 236926ddef5dSVardan Mikayelyan if (ints & DXEPINT_INTKNTXFEMP) { 237047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", 237147a1685fSDinh Nguyen __func__, idx); 237247a1685fSDinh Nguyen } 237347a1685fSDinh Nguyen 237447a1685fSDinh Nguyen /* this probably means something bad is happening */ 237526ddef5dSVardan Mikayelyan if (ints & DXEPINT_INTKNEPMIS) { 237647a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", 237747a1685fSDinh Nguyen __func__, idx); 237847a1685fSDinh Nguyen } 237947a1685fSDinh Nguyen 238047a1685fSDinh Nguyen /* FIFO has space or is empty (see GAHBCFG) */ 238147a1685fSDinh Nguyen if (hsotg->dedicated_fifos && 238226ddef5dSVardan Mikayelyan ints & DXEPINT_TXFEMP) { 238347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", 238447a1685fSDinh Nguyen __func__, idx); 238547a1685fSDinh Nguyen if (!using_dma(hsotg)) 23861f91b4ccSFelipe Balbi dwc2_hsotg_trytx(hsotg, hs_ep); 238747a1685fSDinh Nguyen } 238847a1685fSDinh Nguyen } 238947a1685fSDinh Nguyen } 239047a1685fSDinh Nguyen 239147a1685fSDinh Nguyen /** 23921f91b4ccSFelipe Balbi * dwc2_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) 239347a1685fSDinh Nguyen * @hsotg: The device state. 239447a1685fSDinh Nguyen * 239547a1685fSDinh Nguyen * Handle updating the device settings after the enumeration phase has 239647a1685fSDinh Nguyen * been completed. 239747a1685fSDinh Nguyen */ 23981f91b4ccSFelipe Balbi static void dwc2_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg) 239947a1685fSDinh Nguyen { 240095c8bc36SAntti Seppälä u32 dsts = dwc2_readl(hsotg->regs + DSTS); 24019b2667f1SJingoo Han int ep0_mps = 0, ep_mps = 8; 240247a1685fSDinh Nguyen 240347a1685fSDinh Nguyen /* 240447a1685fSDinh Nguyen * This should signal the finish of the enumeration phase 240547a1685fSDinh Nguyen * of the USB handshaking, so we should now know what rate 240647a1685fSDinh Nguyen * we connected at. 240747a1685fSDinh Nguyen */ 240847a1685fSDinh Nguyen 240947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); 241047a1685fSDinh Nguyen 241147a1685fSDinh Nguyen /* 241247a1685fSDinh Nguyen * note, since we're limited by the size of transfer on EP0, and 241347a1685fSDinh Nguyen * it seems IN transfers must be a even number of packets we do 241447a1685fSDinh Nguyen * not advertise a 64byte MPS on EP0. 241547a1685fSDinh Nguyen */ 241647a1685fSDinh Nguyen 241747a1685fSDinh Nguyen /* catch both EnumSpd_FS and EnumSpd_FS48 */ 24186d76c92cSMarek Vasut switch ((dsts & DSTS_ENUMSPD_MASK) >> DSTS_ENUMSPD_SHIFT) { 241947a1685fSDinh Nguyen case DSTS_ENUMSPD_FS: 242047a1685fSDinh Nguyen case DSTS_ENUMSPD_FS48: 242147a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_FULL; 242247a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 242347a1685fSDinh Nguyen ep_mps = 1023; 242447a1685fSDinh Nguyen break; 242547a1685fSDinh Nguyen 242647a1685fSDinh Nguyen case DSTS_ENUMSPD_HS: 242747a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_HIGH; 242847a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 242947a1685fSDinh Nguyen ep_mps = 1024; 243047a1685fSDinh Nguyen break; 243147a1685fSDinh Nguyen 243247a1685fSDinh Nguyen case DSTS_ENUMSPD_LS: 243347a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_LOW; 243447a1685fSDinh Nguyen /* 243547a1685fSDinh Nguyen * note, we don't actually support LS in this driver at the 243647a1685fSDinh Nguyen * moment, and the documentation seems to imply that it isn't 243747a1685fSDinh Nguyen * supported by the PHYs on some of the devices. 243847a1685fSDinh Nguyen */ 243947a1685fSDinh Nguyen break; 244047a1685fSDinh Nguyen } 244147a1685fSDinh Nguyen dev_info(hsotg->dev, "new device is %s\n", 244247a1685fSDinh Nguyen usb_speed_string(hsotg->gadget.speed)); 244347a1685fSDinh Nguyen 244447a1685fSDinh Nguyen /* 244547a1685fSDinh Nguyen * we should now know the maximum packet size for an 244647a1685fSDinh Nguyen * endpoint, so set the endpoints to a default value. 244747a1685fSDinh Nguyen */ 244847a1685fSDinh Nguyen 244947a1685fSDinh Nguyen if (ep0_mps) { 245047a1685fSDinh Nguyen int i; 2451c6f5c050SMian Yousaf Kaukab /* Initialize ep0 for both in and out directions */ 2452ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 1); 2453ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 0); 2454c6f5c050SMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; i++) { 2455c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[i]) 2456ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 2457ee2c40deSVardan Mikayelyan 0, 1); 2458c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[i]) 2459ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 2460ee2c40deSVardan Mikayelyan 0, 0); 2461c6f5c050SMian Yousaf Kaukab } 246247a1685fSDinh Nguyen } 246347a1685fSDinh Nguyen 246447a1685fSDinh Nguyen /* ensure after enumeration our EP0 is active */ 246547a1685fSDinh Nguyen 24661f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 246747a1685fSDinh Nguyen 246847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 246995c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DIEPCTL0), 247095c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL0)); 247147a1685fSDinh Nguyen } 247247a1685fSDinh Nguyen 247347a1685fSDinh Nguyen /** 247447a1685fSDinh Nguyen * kill_all_requests - remove all requests from the endpoint's queue 247547a1685fSDinh Nguyen * @hsotg: The device state. 247647a1685fSDinh Nguyen * @ep: The endpoint the requests may be on. 247747a1685fSDinh Nguyen * @result: The result code to use. 247847a1685fSDinh Nguyen * 247947a1685fSDinh Nguyen * Go through the requests on the given endpoint and mark them 248047a1685fSDinh Nguyen * completed with the given result code. 248147a1685fSDinh Nguyen */ 2482941fcce4SDinh Nguyen static void kill_all_requests(struct dwc2_hsotg *hsotg, 24831f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep, 24846b448af4SRobert Baldyga int result) 248547a1685fSDinh Nguyen { 24861f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req, *treq; 2487b203d0a2SRobert Baldyga unsigned size; 248847a1685fSDinh Nguyen 24896b448af4SRobert Baldyga ep->req = NULL; 249047a1685fSDinh Nguyen 24916b448af4SRobert Baldyga list_for_each_entry_safe(req, treq, &ep->queue, queue) 24921f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, ep, req, 249347a1685fSDinh Nguyen result); 24946b448af4SRobert Baldyga 2495b203d0a2SRobert Baldyga if (!hsotg->dedicated_fifos) 2496b203d0a2SRobert Baldyga return; 2497ad674a15SRobert Baldyga size = (dwc2_readl(hsotg->regs + DTXFSTS(ep->fifo_index)) & 0xffff) * 4; 2498b203d0a2SRobert Baldyga if (size < ep->fifo_size) 24991f91b4ccSFelipe Balbi dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); 250047a1685fSDinh Nguyen } 250147a1685fSDinh Nguyen 250247a1685fSDinh Nguyen /** 25031f91b4ccSFelipe Balbi * dwc2_hsotg_disconnect - disconnect service 250447a1685fSDinh Nguyen * @hsotg: The device state. 250547a1685fSDinh Nguyen * 250647a1685fSDinh Nguyen * The device has been disconnected. Remove all current 250747a1685fSDinh Nguyen * transactions and signal the gadget driver that this 250847a1685fSDinh Nguyen * has happened. 250947a1685fSDinh Nguyen */ 25101f91b4ccSFelipe Balbi void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) 251147a1685fSDinh Nguyen { 251247a1685fSDinh Nguyen unsigned ep; 251347a1685fSDinh Nguyen 25144ace06e8SMarek Szyprowski if (!hsotg->connected) 25154ace06e8SMarek Szyprowski return; 25164ace06e8SMarek Szyprowski 25174ace06e8SMarek Szyprowski hsotg->connected = 0; 25189e14d0a5SGregory Herrero hsotg->test_mode = 0; 2519c6f5c050SMian Yousaf Kaukab 2520c6f5c050SMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps; ep++) { 2521c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 2522c6f5c050SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_in[ep], 2523c6f5c050SMian Yousaf Kaukab -ESHUTDOWN); 2524c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 2525c6f5c050SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_out[ep], 2526c6f5c050SMian Yousaf Kaukab -ESHUTDOWN); 2527c6f5c050SMian Yousaf Kaukab } 252847a1685fSDinh Nguyen 252947a1685fSDinh Nguyen call_gadget(hsotg, disconnect); 2530065d3931SGregory Herrero hsotg->lx_state = DWC2_L3; 253147a1685fSDinh Nguyen } 253247a1685fSDinh Nguyen 253347a1685fSDinh Nguyen /** 25341f91b4ccSFelipe Balbi * dwc2_hsotg_irq_fifoempty - TX FIFO empty interrupt handler 253547a1685fSDinh Nguyen * @hsotg: The device state: 253647a1685fSDinh Nguyen * @periodic: True if this is a periodic FIFO interrupt 253747a1685fSDinh Nguyen */ 25381f91b4ccSFelipe Balbi static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) 253947a1685fSDinh Nguyen { 25401f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 254147a1685fSDinh Nguyen int epno, ret; 254247a1685fSDinh Nguyen 254347a1685fSDinh Nguyen /* look through for any more data to transmit */ 254447a1685fSDinh Nguyen for (epno = 0; epno < hsotg->num_of_eps; epno++) { 2545c6f5c050SMian Yousaf Kaukab ep = index_to_ep(hsotg, epno, 1); 2546c6f5c050SMian Yousaf Kaukab 2547c6f5c050SMian Yousaf Kaukab if (!ep) 2548c6f5c050SMian Yousaf Kaukab continue; 254947a1685fSDinh Nguyen 255047a1685fSDinh Nguyen if (!ep->dir_in) 255147a1685fSDinh Nguyen continue; 255247a1685fSDinh Nguyen 255347a1685fSDinh Nguyen if ((periodic && !ep->periodic) || 255447a1685fSDinh Nguyen (!periodic && ep->periodic)) 255547a1685fSDinh Nguyen continue; 255647a1685fSDinh Nguyen 25571f91b4ccSFelipe Balbi ret = dwc2_hsotg_trytx(hsotg, ep); 255847a1685fSDinh Nguyen if (ret < 0) 255947a1685fSDinh Nguyen break; 256047a1685fSDinh Nguyen } 256147a1685fSDinh Nguyen } 256247a1685fSDinh Nguyen 256347a1685fSDinh Nguyen /* IRQ flags which will trigger a retry around the IRQ loop */ 256447a1685fSDinh Nguyen #define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ 256547a1685fSDinh Nguyen GINTSTS_PTXFEMP | \ 256647a1685fSDinh Nguyen GINTSTS_RXFLVL) 256747a1685fSDinh Nguyen 256847a1685fSDinh Nguyen /** 25691f91b4ccSFelipe Balbi * dwc2_hsotg_core_init - issue softreset to the core 257047a1685fSDinh Nguyen * @hsotg: The device state 257147a1685fSDinh Nguyen * 257247a1685fSDinh Nguyen * Issue a soft reset to the core, and await the core finishing it. 257347a1685fSDinh Nguyen */ 25741f91b4ccSFelipe Balbi void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, 2575643cc4deSGregory Herrero bool is_usb_reset) 257647a1685fSDinh Nguyen { 25771ee6903bSGregory Herrero u32 intmsk; 2578643cc4deSGregory Herrero u32 val; 2579ecd9a7adSPrzemek Rudy u32 usbcfg; 2580643cc4deSGregory Herrero 25815390d438SMian Yousaf Kaukab /* Kill any ep0 requests as controller will be reinitialized */ 25825390d438SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); 25835390d438SMian Yousaf Kaukab 2584643cc4deSGregory Herrero if (!is_usb_reset) 2585241729baSJohn Youn if (dwc2_core_reset(hsotg)) 258686de4895SGregory Herrero return; 258747a1685fSDinh Nguyen 258847a1685fSDinh Nguyen /* 258947a1685fSDinh Nguyen * we must now enable ep0 ready for host detection and then 259047a1685fSDinh Nguyen * set configuration. 259147a1685fSDinh Nguyen */ 259247a1685fSDinh Nguyen 2593ecd9a7adSPrzemek Rudy /* keep other bits untouched (so e.g. forced modes are not lost) */ 2594ecd9a7adSPrzemek Rudy usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); 2595ecd9a7adSPrzemek Rudy usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP | 2596ecd9a7adSPrzemek Rudy GUSBCFG_HNPCAP); 2597ecd9a7adSPrzemek Rudy 259847a1685fSDinh Nguyen /* set the PLL on, remove the HNP/SRP and set the PHY */ 2599fa4a8d72SMian Yousaf Kaukab val = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5; 2600ecd9a7adSPrzemek Rudy usbcfg |= hsotg->phyif | GUSBCFG_TOUTCAL(7) | 2601ecd9a7adSPrzemek Rudy (val << GUSBCFG_USBTRDTIM_SHIFT); 2602ecd9a7adSPrzemek Rudy dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); 260347a1685fSDinh Nguyen 26041f91b4ccSFelipe Balbi dwc2_hsotg_init_fifo(hsotg); 260547a1685fSDinh Nguyen 2606643cc4deSGregory Herrero if (!is_usb_reset) 260747a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 260847a1685fSDinh Nguyen 260995c8bc36SAntti Seppälä dwc2_writel(DCFG_EPMISCNT(1) | DCFG_DEVSPD_HS, hsotg->regs + DCFG); 261047a1685fSDinh Nguyen 261147a1685fSDinh Nguyen /* Clear any pending OTG interrupts */ 261295c8bc36SAntti Seppälä dwc2_writel(0xffffffff, hsotg->regs + GOTGINT); 261347a1685fSDinh Nguyen 261447a1685fSDinh Nguyen /* Clear any pending interrupts */ 261595c8bc36SAntti Seppälä dwc2_writel(0xffffffff, hsotg->regs + GINTSTS); 26161ee6903bSGregory Herrero intmsk = GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT | 261747a1685fSDinh Nguyen GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | 26181ee6903bSGregory Herrero GINTSTS_USBRST | GINTSTS_RESETDET | 26191ee6903bSGregory Herrero GINTSTS_ENUMDONE | GINTSTS_OTGINT | 2620ec1f9d9fSRoman Bacik GINTSTS_USBSUSP | GINTSTS_WKUPINT | 2621ec1f9d9fSRoman Bacik GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT; 26221ee6903bSGregory Herrero 2623bea8e86cSJohn Youn if (hsotg->params.external_id_pin_ctl <= 0) 26241ee6903bSGregory Herrero intmsk |= GINTSTS_CONIDSTSCHNG; 26251ee6903bSGregory Herrero 26261ee6903bSGregory Herrero dwc2_writel(intmsk, hsotg->regs + GINTMSK); 262747a1685fSDinh Nguyen 262847a1685fSDinh Nguyen if (using_dma(hsotg)) 262995c8bc36SAntti Seppälä dwc2_writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN | 26305f05048eSGregory Herrero (GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT), 263147a1685fSDinh Nguyen hsotg->regs + GAHBCFG); 263247a1685fSDinh Nguyen else 263395c8bc36SAntti Seppälä dwc2_writel(((hsotg->dedicated_fifos) ? 263495c8bc36SAntti Seppälä (GAHBCFG_NP_TXF_EMP_LVL | 263547a1685fSDinh Nguyen GAHBCFG_P_TXF_EMP_LVL) : 0) | 263695c8bc36SAntti Seppälä GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG); 263747a1685fSDinh Nguyen 263847a1685fSDinh Nguyen /* 263947a1685fSDinh Nguyen * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts 264047a1685fSDinh Nguyen * when we have no data to transfer. Otherwise we get being flooded by 264147a1685fSDinh Nguyen * interrupts. 264247a1685fSDinh Nguyen */ 264347a1685fSDinh Nguyen 264495c8bc36SAntti Seppälä dwc2_writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ? 26456ff2e832SMian Yousaf Kaukab DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) | 264647a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | 2647837e9f00SVardan Mikayelyan DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK, 264847a1685fSDinh Nguyen hsotg->regs + DIEPMSK); 264947a1685fSDinh Nguyen 265047a1685fSDinh Nguyen /* 265147a1685fSDinh Nguyen * don't need XferCompl, we get that from RXFIFO in slave mode. In 265247a1685fSDinh Nguyen * DMA mode we may need this. 265347a1685fSDinh Nguyen */ 2654837e9f00SVardan Mikayelyan dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK) : 0) | 265547a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | 2656837e9f00SVardan Mikayelyan DOEPMSK_SETUPMSK | DOEPMSK_STSPHSERCVDMSK, 265747a1685fSDinh Nguyen hsotg->regs + DOEPMSK); 265847a1685fSDinh Nguyen 265995c8bc36SAntti Seppälä dwc2_writel(0, hsotg->regs + DAINTMSK); 266047a1685fSDinh Nguyen 266147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 266295c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DIEPCTL0), 266395c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL0)); 266447a1685fSDinh Nguyen 266547a1685fSDinh Nguyen /* enable in and out endpoint interrupts */ 26661f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT); 266747a1685fSDinh Nguyen 266847a1685fSDinh Nguyen /* 266947a1685fSDinh Nguyen * Enable the RXFIFO when in slave mode, as this is how we collect 267047a1685fSDinh Nguyen * the data. In DMA mode, we get events from the FIFO but also 267147a1685fSDinh Nguyen * things we cannot process, so do not use it. 267247a1685fSDinh Nguyen */ 267347a1685fSDinh Nguyen if (!using_dma(hsotg)) 26741f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL); 267547a1685fSDinh Nguyen 267647a1685fSDinh Nguyen /* Enable interrupts for EP0 in and out */ 26771f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, 0, 0, 1); 26781f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, 0, 1, 1); 267947a1685fSDinh Nguyen 2680643cc4deSGregory Herrero if (!is_usb_reset) { 268147a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); 268247a1685fSDinh Nguyen udelay(10); /* see openiboot */ 268347a1685fSDinh Nguyen __bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); 2684643cc4deSGregory Herrero } 268547a1685fSDinh Nguyen 268695c8bc36SAntti Seppälä dev_dbg(hsotg->dev, "DCTL=0x%08x\n", dwc2_readl(hsotg->regs + DCTL)); 268747a1685fSDinh Nguyen 268847a1685fSDinh Nguyen /* 268947a1685fSDinh Nguyen * DxEPCTL_USBActEp says RO in manual, but seems to be set by 269047a1685fSDinh Nguyen * writing to the EPCTL register.. 269147a1685fSDinh Nguyen */ 269247a1685fSDinh Nguyen 269347a1685fSDinh Nguyen /* set to read 1 8byte packet */ 269495c8bc36SAntti Seppälä dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 269547a1685fSDinh Nguyen DXEPTSIZ_XFERSIZE(8), hsotg->regs + DOEPTSIZ0); 269647a1685fSDinh Nguyen 269795c8bc36SAntti Seppälä dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 269847a1685fSDinh Nguyen DXEPCTL_CNAK | DXEPCTL_EPENA | 269947a1685fSDinh Nguyen DXEPCTL_USBACTEP, 270047a1685fSDinh Nguyen hsotg->regs + DOEPCTL0); 270147a1685fSDinh Nguyen 270247a1685fSDinh Nguyen /* enable, but don't activate EP0in */ 270395c8bc36SAntti Seppälä dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 270447a1685fSDinh Nguyen DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0); 270547a1685fSDinh Nguyen 27061f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 270747a1685fSDinh Nguyen 270847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 270995c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DIEPCTL0), 271095c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL0)); 271147a1685fSDinh Nguyen 271247a1685fSDinh Nguyen /* clear global NAKs */ 2713643cc4deSGregory Herrero val = DCTL_CGOUTNAK | DCTL_CGNPINNAK; 2714643cc4deSGregory Herrero if (!is_usb_reset) 2715643cc4deSGregory Herrero val |= DCTL_SFTDISCON; 2716643cc4deSGregory Herrero __orr32(hsotg->regs + DCTL, val); 271747a1685fSDinh Nguyen 271847a1685fSDinh Nguyen /* must be at-least 3ms to allow bus to see disconnect */ 271947a1685fSDinh Nguyen mdelay(3); 272047a1685fSDinh Nguyen 2721065d3931SGregory Herrero hsotg->lx_state = DWC2_L0; 2722ad38dc5dSMarek Szyprowski } 2723ac3c81f3SMarek Szyprowski 27241f91b4ccSFelipe Balbi static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) 2725ad38dc5dSMarek Szyprowski { 2726ad38dc5dSMarek Szyprowski /* set the soft-disconnect bit */ 2727ad38dc5dSMarek Szyprowski __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 2728ad38dc5dSMarek Szyprowski } 2729ad38dc5dSMarek Szyprowski 27301f91b4ccSFelipe Balbi void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) 2731ad38dc5dSMarek Szyprowski { 273247a1685fSDinh Nguyen /* remove the soft-disconnect and let's go */ 273347a1685fSDinh Nguyen __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON); 273447a1685fSDinh Nguyen } 273547a1685fSDinh Nguyen 273647a1685fSDinh Nguyen /** 2737381fc8f8SVardan Mikayelyan * dwc2_gadget_handle_incomplete_isoc_in - handle incomplete ISO IN Interrupt. 2738381fc8f8SVardan Mikayelyan * @hsotg: The device state: 2739381fc8f8SVardan Mikayelyan * 2740381fc8f8SVardan Mikayelyan * This interrupt indicates one of the following conditions occurred while 2741381fc8f8SVardan Mikayelyan * transmitting an ISOC transaction. 2742381fc8f8SVardan Mikayelyan * - Corrupted IN Token for ISOC EP. 2743381fc8f8SVardan Mikayelyan * - Packet not complete in FIFO. 2744381fc8f8SVardan Mikayelyan * 2745381fc8f8SVardan Mikayelyan * The following actions will be taken: 2746381fc8f8SVardan Mikayelyan * - Determine the EP 2747381fc8f8SVardan Mikayelyan * - Disable EP; when 'Endpoint Disabled' interrupt is received Flush FIFO 2748381fc8f8SVardan Mikayelyan */ 2749381fc8f8SVardan Mikayelyan static void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg) 2750381fc8f8SVardan Mikayelyan { 2751381fc8f8SVardan Mikayelyan struct dwc2_hsotg_ep *hs_ep; 2752381fc8f8SVardan Mikayelyan u32 epctrl; 2753381fc8f8SVardan Mikayelyan u32 idx; 2754381fc8f8SVardan Mikayelyan 2755381fc8f8SVardan Mikayelyan dev_dbg(hsotg->dev, "Incomplete isoc in interrupt received:\n"); 2756381fc8f8SVardan Mikayelyan 2757381fc8f8SVardan Mikayelyan for (idx = 1; idx <= hsotg->num_of_eps; idx++) { 2758381fc8f8SVardan Mikayelyan hs_ep = hsotg->eps_in[idx]; 2759381fc8f8SVardan Mikayelyan epctrl = dwc2_readl(hsotg->regs + DIEPCTL(idx)); 2760381fc8f8SVardan Mikayelyan if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous && 2761381fc8f8SVardan Mikayelyan dwc2_gadget_target_frame_elapsed(hs_ep)) { 2762381fc8f8SVardan Mikayelyan epctrl |= DXEPCTL_SNAK; 2763381fc8f8SVardan Mikayelyan epctrl |= DXEPCTL_EPDIS; 2764381fc8f8SVardan Mikayelyan dwc2_writel(epctrl, hsotg->regs + DIEPCTL(idx)); 2765381fc8f8SVardan Mikayelyan } 2766381fc8f8SVardan Mikayelyan } 2767381fc8f8SVardan Mikayelyan 2768381fc8f8SVardan Mikayelyan /* Clear interrupt */ 2769381fc8f8SVardan Mikayelyan dwc2_writel(GINTSTS_INCOMPL_SOIN, hsotg->regs + GINTSTS); 2770381fc8f8SVardan Mikayelyan } 2771381fc8f8SVardan Mikayelyan 2772381fc8f8SVardan Mikayelyan /** 2773381fc8f8SVardan Mikayelyan * dwc2_gadget_handle_incomplete_isoc_out - handle incomplete ISO OUT Interrupt 2774381fc8f8SVardan Mikayelyan * @hsotg: The device state: 2775381fc8f8SVardan Mikayelyan * 2776381fc8f8SVardan Mikayelyan * This interrupt indicates one of the following conditions occurred while 2777381fc8f8SVardan Mikayelyan * transmitting an ISOC transaction. 2778381fc8f8SVardan Mikayelyan * - Corrupted OUT Token for ISOC EP. 2779381fc8f8SVardan Mikayelyan * - Packet not complete in FIFO. 2780381fc8f8SVardan Mikayelyan * 2781381fc8f8SVardan Mikayelyan * The following actions will be taken: 2782381fc8f8SVardan Mikayelyan * - Determine the EP 2783381fc8f8SVardan Mikayelyan * - Set DCTL_SGOUTNAK and unmask GOUTNAKEFF if target frame elapsed. 2784381fc8f8SVardan Mikayelyan */ 2785381fc8f8SVardan Mikayelyan static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg) 2786381fc8f8SVardan Mikayelyan { 2787381fc8f8SVardan Mikayelyan u32 gintsts; 2788381fc8f8SVardan Mikayelyan u32 gintmsk; 2789381fc8f8SVardan Mikayelyan u32 epctrl; 2790381fc8f8SVardan Mikayelyan struct dwc2_hsotg_ep *hs_ep; 2791381fc8f8SVardan Mikayelyan int idx; 2792381fc8f8SVardan Mikayelyan 2793381fc8f8SVardan Mikayelyan dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__); 2794381fc8f8SVardan Mikayelyan 2795381fc8f8SVardan Mikayelyan for (idx = 1; idx <= hsotg->num_of_eps; idx++) { 2796381fc8f8SVardan Mikayelyan hs_ep = hsotg->eps_out[idx]; 2797381fc8f8SVardan Mikayelyan epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx)); 2798381fc8f8SVardan Mikayelyan if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous && 2799381fc8f8SVardan Mikayelyan dwc2_gadget_target_frame_elapsed(hs_ep)) { 2800381fc8f8SVardan Mikayelyan /* Unmask GOUTNAKEFF interrupt */ 2801381fc8f8SVardan Mikayelyan gintmsk = dwc2_readl(hsotg->regs + GINTMSK); 2802381fc8f8SVardan Mikayelyan gintmsk |= GINTSTS_GOUTNAKEFF; 2803381fc8f8SVardan Mikayelyan dwc2_writel(gintmsk, hsotg->regs + GINTMSK); 2804381fc8f8SVardan Mikayelyan 2805381fc8f8SVardan Mikayelyan gintsts = dwc2_readl(hsotg->regs + GINTSTS); 2806381fc8f8SVardan Mikayelyan if (!(gintsts & GINTSTS_GOUTNAKEFF)) 2807381fc8f8SVardan Mikayelyan __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK); 2808381fc8f8SVardan Mikayelyan } 2809381fc8f8SVardan Mikayelyan } 2810381fc8f8SVardan Mikayelyan 2811381fc8f8SVardan Mikayelyan /* Clear interrupt */ 2812381fc8f8SVardan Mikayelyan dwc2_writel(GINTSTS_INCOMPL_SOOUT, hsotg->regs + GINTSTS); 2813381fc8f8SVardan Mikayelyan } 2814381fc8f8SVardan Mikayelyan 2815381fc8f8SVardan Mikayelyan /** 28161f91b4ccSFelipe Balbi * dwc2_hsotg_irq - handle device interrupt 281747a1685fSDinh Nguyen * @irq: The IRQ number triggered 281847a1685fSDinh Nguyen * @pw: The pw value when registered the handler. 281947a1685fSDinh Nguyen */ 28201f91b4ccSFelipe Balbi static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) 282147a1685fSDinh Nguyen { 2822941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = pw; 282347a1685fSDinh Nguyen int retry_count = 8; 282447a1685fSDinh Nguyen u32 gintsts; 282547a1685fSDinh Nguyen u32 gintmsk; 282647a1685fSDinh Nguyen 2827ee3de8d7SVardan Mikayelyan if (!dwc2_is_device_mode(hsotg)) 2828ee3de8d7SVardan Mikayelyan return IRQ_NONE; 2829ee3de8d7SVardan Mikayelyan 283047a1685fSDinh Nguyen spin_lock(&hsotg->lock); 283147a1685fSDinh Nguyen irq_retry: 283295c8bc36SAntti Seppälä gintsts = dwc2_readl(hsotg->regs + GINTSTS); 283395c8bc36SAntti Seppälä gintmsk = dwc2_readl(hsotg->regs + GINTMSK); 283447a1685fSDinh Nguyen 283547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", 283647a1685fSDinh Nguyen __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); 283747a1685fSDinh Nguyen 283847a1685fSDinh Nguyen gintsts &= gintmsk; 283947a1685fSDinh Nguyen 28408fc37b82SMian Yousaf Kaukab if (gintsts & GINTSTS_RESETDET) { 28418fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: USBRstDet\n", __func__); 28428fc37b82SMian Yousaf Kaukab 28438fc37b82SMian Yousaf Kaukab dwc2_writel(GINTSTS_RESETDET, hsotg->regs + GINTSTS); 28448fc37b82SMian Yousaf Kaukab 28458fc37b82SMian Yousaf Kaukab /* This event must be used only if controller is suspended */ 28468fc37b82SMian Yousaf Kaukab if (hsotg->lx_state == DWC2_L2) { 28478fc37b82SMian Yousaf Kaukab dwc2_exit_hibernation(hsotg, true); 28488fc37b82SMian Yousaf Kaukab hsotg->lx_state = DWC2_L0; 28498fc37b82SMian Yousaf Kaukab } 28508fc37b82SMian Yousaf Kaukab } 28518fc37b82SMian Yousaf Kaukab 28528fc37b82SMian Yousaf Kaukab if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) { 28538fc37b82SMian Yousaf Kaukab 28548fc37b82SMian Yousaf Kaukab u32 usb_status = dwc2_readl(hsotg->regs + GOTGCTL); 28558fc37b82SMian Yousaf Kaukab u32 connected = hsotg->connected; 28568fc37b82SMian Yousaf Kaukab 28578fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: USBRst\n", __func__); 28588fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", 28598fc37b82SMian Yousaf Kaukab dwc2_readl(hsotg->regs + GNPTXSTS)); 28608fc37b82SMian Yousaf Kaukab 28618fc37b82SMian Yousaf Kaukab dwc2_writel(GINTSTS_USBRST, hsotg->regs + GINTSTS); 28628fc37b82SMian Yousaf Kaukab 28638fc37b82SMian Yousaf Kaukab /* Report disconnection if it is not already done. */ 28648fc37b82SMian Yousaf Kaukab dwc2_hsotg_disconnect(hsotg); 28658fc37b82SMian Yousaf Kaukab 28668fc37b82SMian Yousaf Kaukab if (usb_status & GOTGCTL_BSESVLD && connected) 28678fc37b82SMian Yousaf Kaukab dwc2_hsotg_core_init_disconnected(hsotg, true); 28688fc37b82SMian Yousaf Kaukab } 28698fc37b82SMian Yousaf Kaukab 287047a1685fSDinh Nguyen if (gintsts & GINTSTS_ENUMDONE) { 287195c8bc36SAntti Seppälä dwc2_writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); 287247a1685fSDinh Nguyen 28731f91b4ccSFelipe Balbi dwc2_hsotg_irq_enumdone(hsotg); 287447a1685fSDinh Nguyen } 287547a1685fSDinh Nguyen 287647a1685fSDinh Nguyen if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { 287795c8bc36SAntti Seppälä u32 daint = dwc2_readl(hsotg->regs + DAINT); 287895c8bc36SAntti Seppälä u32 daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); 287947a1685fSDinh Nguyen u32 daint_out, daint_in; 288047a1685fSDinh Nguyen int ep; 288147a1685fSDinh Nguyen 288247a1685fSDinh Nguyen daint &= daintmsk; 288347a1685fSDinh Nguyen daint_out = daint >> DAINT_OUTEP_SHIFT; 288447a1685fSDinh Nguyen daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); 288547a1685fSDinh Nguyen 288647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); 288747a1685fSDinh Nguyen 2888cec87f1dSMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps && daint_out; 2889cec87f1dSMian Yousaf Kaukab ep++, daint_out >>= 1) { 289047a1685fSDinh Nguyen if (daint_out & 1) 28911f91b4ccSFelipe Balbi dwc2_hsotg_epint(hsotg, ep, 0); 289247a1685fSDinh Nguyen } 289347a1685fSDinh Nguyen 2894cec87f1dSMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps && daint_in; 2895cec87f1dSMian Yousaf Kaukab ep++, daint_in >>= 1) { 289647a1685fSDinh Nguyen if (daint_in & 1) 28971f91b4ccSFelipe Balbi dwc2_hsotg_epint(hsotg, ep, 1); 289847a1685fSDinh Nguyen } 289947a1685fSDinh Nguyen } 290047a1685fSDinh Nguyen 290147a1685fSDinh Nguyen /* check both FIFOs */ 290247a1685fSDinh Nguyen 290347a1685fSDinh Nguyen if (gintsts & GINTSTS_NPTXFEMP) { 290447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "NPTxFEmp\n"); 290547a1685fSDinh Nguyen 290647a1685fSDinh Nguyen /* 290747a1685fSDinh Nguyen * Disable the interrupt to stop it happening again 290847a1685fSDinh Nguyen * unless one of these endpoint routines decides that 290947a1685fSDinh Nguyen * it needs re-enabling 291047a1685fSDinh Nguyen */ 291147a1685fSDinh Nguyen 29121f91b4ccSFelipe Balbi dwc2_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); 29131f91b4ccSFelipe Balbi dwc2_hsotg_irq_fifoempty(hsotg, false); 291447a1685fSDinh Nguyen } 291547a1685fSDinh Nguyen 291647a1685fSDinh Nguyen if (gintsts & GINTSTS_PTXFEMP) { 291747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "PTxFEmp\n"); 291847a1685fSDinh Nguyen 291947a1685fSDinh Nguyen /* See note in GINTSTS_NPTxFEmp */ 292047a1685fSDinh Nguyen 29211f91b4ccSFelipe Balbi dwc2_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); 29221f91b4ccSFelipe Balbi dwc2_hsotg_irq_fifoempty(hsotg, true); 292347a1685fSDinh Nguyen } 292447a1685fSDinh Nguyen 292547a1685fSDinh Nguyen if (gintsts & GINTSTS_RXFLVL) { 292647a1685fSDinh Nguyen /* 292747a1685fSDinh Nguyen * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, 29281f91b4ccSFelipe Balbi * we need to retry dwc2_hsotg_handle_rx if this is still 292947a1685fSDinh Nguyen * set. 293047a1685fSDinh Nguyen */ 293147a1685fSDinh Nguyen 29321f91b4ccSFelipe Balbi dwc2_hsotg_handle_rx(hsotg); 293347a1685fSDinh Nguyen } 293447a1685fSDinh Nguyen 293547a1685fSDinh Nguyen if (gintsts & GINTSTS_ERLYSUSP) { 293647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); 293795c8bc36SAntti Seppälä dwc2_writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS); 293847a1685fSDinh Nguyen } 293947a1685fSDinh Nguyen 294047a1685fSDinh Nguyen /* 294147a1685fSDinh Nguyen * these next two seem to crop-up occasionally causing the core 294247a1685fSDinh Nguyen * to shutdown the USB transfer, so try clearing them and logging 294347a1685fSDinh Nguyen * the occurrence. 294447a1685fSDinh Nguyen */ 294547a1685fSDinh Nguyen 294647a1685fSDinh Nguyen if (gintsts & GINTSTS_GOUTNAKEFF) { 2947837e9f00SVardan Mikayelyan u8 idx; 2948837e9f00SVardan Mikayelyan u32 epctrl; 2949837e9f00SVardan Mikayelyan u32 gintmsk; 2950837e9f00SVardan Mikayelyan struct dwc2_hsotg_ep *hs_ep; 295147a1685fSDinh Nguyen 2952837e9f00SVardan Mikayelyan /* Mask this interrupt */ 2953837e9f00SVardan Mikayelyan gintmsk = dwc2_readl(hsotg->regs + GINTMSK); 2954837e9f00SVardan Mikayelyan gintmsk &= ~GINTSTS_GOUTNAKEFF; 2955837e9f00SVardan Mikayelyan dwc2_writel(gintmsk, hsotg->regs + GINTMSK); 295647a1685fSDinh Nguyen 2957837e9f00SVardan Mikayelyan dev_dbg(hsotg->dev, "GOUTNakEff triggered\n"); 2958837e9f00SVardan Mikayelyan for (idx = 1; idx <= hsotg->num_of_eps; idx++) { 2959837e9f00SVardan Mikayelyan hs_ep = hsotg->eps_out[idx]; 2960837e9f00SVardan Mikayelyan epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx)); 2961837e9f00SVardan Mikayelyan 2962837e9f00SVardan Mikayelyan if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous) { 2963837e9f00SVardan Mikayelyan epctrl |= DXEPCTL_SNAK; 2964837e9f00SVardan Mikayelyan epctrl |= DXEPCTL_EPDIS; 2965837e9f00SVardan Mikayelyan dwc2_writel(epctrl, hsotg->regs + DOEPCTL(idx)); 2966837e9f00SVardan Mikayelyan } 2967837e9f00SVardan Mikayelyan } 2968837e9f00SVardan Mikayelyan 2969837e9f00SVardan Mikayelyan /* This interrupt bit is cleared in DXEPINT_EPDISBLD handler */ 297047a1685fSDinh Nguyen } 297147a1685fSDinh Nguyen 297247a1685fSDinh Nguyen if (gintsts & GINTSTS_GINNAKEFF) { 297347a1685fSDinh Nguyen dev_info(hsotg->dev, "GINNakEff triggered\n"); 297447a1685fSDinh Nguyen 29753be99cd0SGregory Herrero __orr32(hsotg->regs + DCTL, DCTL_CGNPINNAK); 297647a1685fSDinh Nguyen 29771f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 297847a1685fSDinh Nguyen } 297947a1685fSDinh Nguyen 2980381fc8f8SVardan Mikayelyan if (gintsts & GINTSTS_INCOMPL_SOIN) 2981381fc8f8SVardan Mikayelyan dwc2_gadget_handle_incomplete_isoc_in(hsotg); 2982ec1f9d9fSRoman Bacik 2983381fc8f8SVardan Mikayelyan if (gintsts & GINTSTS_INCOMPL_SOOUT) 2984381fc8f8SVardan Mikayelyan dwc2_gadget_handle_incomplete_isoc_out(hsotg); 2985ec1f9d9fSRoman Bacik 298647a1685fSDinh Nguyen /* 298747a1685fSDinh Nguyen * if we've had fifo events, we should try and go around the 298847a1685fSDinh Nguyen * loop again to see if there's any point in returning yet. 298947a1685fSDinh Nguyen */ 299047a1685fSDinh Nguyen 299147a1685fSDinh Nguyen if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) 299247a1685fSDinh Nguyen goto irq_retry; 299347a1685fSDinh Nguyen 299447a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 299547a1685fSDinh Nguyen 299647a1685fSDinh Nguyen return IRQ_HANDLED; 299747a1685fSDinh Nguyen } 299847a1685fSDinh Nguyen 299947a1685fSDinh Nguyen /** 30001f91b4ccSFelipe Balbi * dwc2_hsotg_ep_enable - enable the given endpoint 300147a1685fSDinh Nguyen * @ep: The USB endpint to configure 300247a1685fSDinh Nguyen * @desc: The USB endpoint descriptor to configure with. 300347a1685fSDinh Nguyen * 300447a1685fSDinh Nguyen * This is called from the USB gadget code's usb_ep_enable(). 300547a1685fSDinh Nguyen */ 30061f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_enable(struct usb_ep *ep, 300747a1685fSDinh Nguyen const struct usb_endpoint_descriptor *desc) 300847a1685fSDinh Nguyen { 30091f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 3010941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 301147a1685fSDinh Nguyen unsigned long flags; 3012ca4c55adSMian Yousaf Kaukab unsigned int index = hs_ep->index; 301347a1685fSDinh Nguyen u32 epctrl_reg; 301447a1685fSDinh Nguyen u32 epctrl; 301547a1685fSDinh Nguyen u32 mps; 3016ee2c40deSVardan Mikayelyan u32 mc; 3017837e9f00SVardan Mikayelyan u32 mask; 3018ca4c55adSMian Yousaf Kaukab unsigned int dir_in; 3019ca4c55adSMian Yousaf Kaukab unsigned int i, val, size; 302047a1685fSDinh Nguyen int ret = 0; 302147a1685fSDinh Nguyen 302247a1685fSDinh Nguyen dev_dbg(hsotg->dev, 302347a1685fSDinh Nguyen "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", 302447a1685fSDinh Nguyen __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, 302547a1685fSDinh Nguyen desc->wMaxPacketSize, desc->bInterval); 302647a1685fSDinh Nguyen 302747a1685fSDinh Nguyen /* not to be called for EP0 */ 30288c3d6092SVahram Aharonyan if (index == 0) { 30298c3d6092SVahram Aharonyan dev_err(hsotg->dev, "%s: called for EP 0\n", __func__); 30308c3d6092SVahram Aharonyan return -EINVAL; 30318c3d6092SVahram Aharonyan } 303247a1685fSDinh Nguyen 303347a1685fSDinh Nguyen dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; 303447a1685fSDinh Nguyen if (dir_in != hs_ep->dir_in) { 303547a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); 303647a1685fSDinh Nguyen return -EINVAL; 303747a1685fSDinh Nguyen } 303847a1685fSDinh Nguyen 303947a1685fSDinh Nguyen mps = usb_endpoint_maxp(desc); 3040ee2c40deSVardan Mikayelyan mc = usb_endpoint_maxp_mult(desc); 304147a1685fSDinh Nguyen 30421f91b4ccSFelipe Balbi /* note, we handle this here instead of dwc2_hsotg_set_ep_maxpacket */ 304347a1685fSDinh Nguyen 304447a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 304595c8bc36SAntti Seppälä epctrl = dwc2_readl(hsotg->regs + epctrl_reg); 304647a1685fSDinh Nguyen 304747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", 304847a1685fSDinh Nguyen __func__, epctrl, epctrl_reg); 304947a1685fSDinh Nguyen 305047a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 305147a1685fSDinh Nguyen 305247a1685fSDinh Nguyen epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK); 305347a1685fSDinh Nguyen epctrl |= DXEPCTL_MPS(mps); 305447a1685fSDinh Nguyen 305547a1685fSDinh Nguyen /* 305647a1685fSDinh Nguyen * mark the endpoint as active, otherwise the core may ignore 305747a1685fSDinh Nguyen * transactions entirely for this endpoint 305847a1685fSDinh Nguyen */ 305947a1685fSDinh Nguyen epctrl |= DXEPCTL_USBACTEP; 306047a1685fSDinh Nguyen 306147a1685fSDinh Nguyen /* update the endpoint state */ 3062ee2c40deSVardan Mikayelyan dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, mc, dir_in); 306347a1685fSDinh Nguyen 306447a1685fSDinh Nguyen /* default, set to non-periodic */ 306547a1685fSDinh Nguyen hs_ep->isochronous = 0; 306647a1685fSDinh Nguyen hs_ep->periodic = 0; 306747a1685fSDinh Nguyen hs_ep->halted = 0; 306847a1685fSDinh Nguyen hs_ep->interval = desc->bInterval; 306947a1685fSDinh Nguyen 307047a1685fSDinh Nguyen switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { 307147a1685fSDinh Nguyen case USB_ENDPOINT_XFER_ISOC: 307247a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_ISO; 307347a1685fSDinh Nguyen epctrl |= DXEPCTL_SETEVENFR; 307447a1685fSDinh Nguyen hs_ep->isochronous = 1; 3075142bd33fSVardan Mikayelyan hs_ep->interval = 1 << (desc->bInterval - 1); 3076837e9f00SVardan Mikayelyan hs_ep->target_frame = TARGET_FRAME_INITIAL; 3077837e9f00SVardan Mikayelyan if (dir_in) { 307847a1685fSDinh Nguyen hs_ep->periodic = 1; 3079837e9f00SVardan Mikayelyan mask = dwc2_readl(hsotg->regs + DIEPMSK); 3080837e9f00SVardan Mikayelyan mask |= DIEPMSK_NAKMSK; 3081837e9f00SVardan Mikayelyan dwc2_writel(mask, hsotg->regs + DIEPMSK); 3082837e9f00SVardan Mikayelyan } else { 3083837e9f00SVardan Mikayelyan mask = dwc2_readl(hsotg->regs + DOEPMSK); 3084837e9f00SVardan Mikayelyan mask |= DOEPMSK_OUTTKNEPDISMSK; 3085837e9f00SVardan Mikayelyan dwc2_writel(mask, hsotg->regs + DOEPMSK); 3086837e9f00SVardan Mikayelyan } 308747a1685fSDinh Nguyen break; 308847a1685fSDinh Nguyen 308947a1685fSDinh Nguyen case USB_ENDPOINT_XFER_BULK: 309047a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_BULK; 309147a1685fSDinh Nguyen break; 309247a1685fSDinh Nguyen 309347a1685fSDinh Nguyen case USB_ENDPOINT_XFER_INT: 3094b203d0a2SRobert Baldyga if (dir_in) 309547a1685fSDinh Nguyen hs_ep->periodic = 1; 309647a1685fSDinh Nguyen 3097142bd33fSVardan Mikayelyan if (hsotg->gadget.speed == USB_SPEED_HIGH) 3098142bd33fSVardan Mikayelyan hs_ep->interval = 1 << (desc->bInterval - 1); 3099142bd33fSVardan Mikayelyan 310047a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_INTERRUPT; 310147a1685fSDinh Nguyen break; 310247a1685fSDinh Nguyen 310347a1685fSDinh Nguyen case USB_ENDPOINT_XFER_CONTROL: 310447a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_CONTROL; 310547a1685fSDinh Nguyen break; 310647a1685fSDinh Nguyen } 310747a1685fSDinh Nguyen 310847a1685fSDinh Nguyen /* 310947a1685fSDinh Nguyen * if the hardware has dedicated fifos, we must give each IN EP 311047a1685fSDinh Nguyen * a unique tx-fifo even if it is non-periodic. 311147a1685fSDinh Nguyen */ 311221f3bb52SRobert Baldyga if (dir_in && hsotg->dedicated_fifos) { 3113ca4c55adSMian Yousaf Kaukab u32 fifo_index = 0; 3114ca4c55adSMian Yousaf Kaukab u32 fifo_size = UINT_MAX; 3115b203d0a2SRobert Baldyga size = hs_ep->ep.maxpacket*hs_ep->mc; 31165f2196bdSMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; ++i) { 3117b203d0a2SRobert Baldyga if (hsotg->fifo_map & (1<<i)) 3118b203d0a2SRobert Baldyga continue; 311995c8bc36SAntti Seppälä val = dwc2_readl(hsotg->regs + DPTXFSIZN(i)); 3120b203d0a2SRobert Baldyga val = (val >> FIFOSIZE_DEPTH_SHIFT)*4; 3121b203d0a2SRobert Baldyga if (val < size) 3122b203d0a2SRobert Baldyga continue; 3123ca4c55adSMian Yousaf Kaukab /* Search for smallest acceptable fifo */ 3124ca4c55adSMian Yousaf Kaukab if (val < fifo_size) { 3125ca4c55adSMian Yousaf Kaukab fifo_size = val; 3126ca4c55adSMian Yousaf Kaukab fifo_index = i; 3127b203d0a2SRobert Baldyga } 3128ca4c55adSMian Yousaf Kaukab } 3129ca4c55adSMian Yousaf Kaukab if (!fifo_index) { 31305f2196bdSMian Yousaf Kaukab dev_err(hsotg->dev, 31315f2196bdSMian Yousaf Kaukab "%s: No suitable fifo found\n", __func__); 3132b585a48bSSudip Mukherjee ret = -ENOMEM; 3133b585a48bSSudip Mukherjee goto error; 3134b585a48bSSudip Mukherjee } 3135ca4c55adSMian Yousaf Kaukab hsotg->fifo_map |= 1 << fifo_index; 3136ca4c55adSMian Yousaf Kaukab epctrl |= DXEPCTL_TXFNUM(fifo_index); 3137ca4c55adSMian Yousaf Kaukab hs_ep->fifo_index = fifo_index; 3138ca4c55adSMian Yousaf Kaukab hs_ep->fifo_size = fifo_size; 3139b203d0a2SRobert Baldyga } 314047a1685fSDinh Nguyen 314147a1685fSDinh Nguyen /* for non control endpoints, set PID to D0 */ 3142837e9f00SVardan Mikayelyan if (index && !hs_ep->isochronous) 314347a1685fSDinh Nguyen epctrl |= DXEPCTL_SETD0PID; 314447a1685fSDinh Nguyen 314547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", 314647a1685fSDinh Nguyen __func__, epctrl); 314747a1685fSDinh Nguyen 314895c8bc36SAntti Seppälä dwc2_writel(epctrl, hsotg->regs + epctrl_reg); 314947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", 315095c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctrl_reg)); 315147a1685fSDinh Nguyen 315247a1685fSDinh Nguyen /* enable the endpoint interrupt */ 31531f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, index, dir_in, 1); 315447a1685fSDinh Nguyen 3155b585a48bSSudip Mukherjee error: 315647a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 315747a1685fSDinh Nguyen return ret; 315847a1685fSDinh Nguyen } 315947a1685fSDinh Nguyen 316047a1685fSDinh Nguyen /** 31611f91b4ccSFelipe Balbi * dwc2_hsotg_ep_disable - disable given endpoint 316247a1685fSDinh Nguyen * @ep: The endpoint to disable. 316347a1685fSDinh Nguyen */ 31641f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_disable(struct usb_ep *ep) 316547a1685fSDinh Nguyen { 31661f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 3167941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 316847a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 316947a1685fSDinh Nguyen int index = hs_ep->index; 317047a1685fSDinh Nguyen unsigned long flags; 317147a1685fSDinh Nguyen u32 epctrl_reg; 317247a1685fSDinh Nguyen u32 ctrl; 317347a1685fSDinh Nguyen 31741e011293SMarek Szyprowski dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); 317547a1685fSDinh Nguyen 3176c6f5c050SMian Yousaf Kaukab if (ep == &hsotg->eps_out[0]->ep) { 317747a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: called for ep0\n", __func__); 317847a1685fSDinh Nguyen return -EINVAL; 317947a1685fSDinh Nguyen } 318047a1685fSDinh Nguyen 318147a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 318247a1685fSDinh Nguyen 318347a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 318447a1685fSDinh Nguyen 318595c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctrl_reg); 318647a1685fSDinh Nguyen ctrl &= ~DXEPCTL_EPENA; 318747a1685fSDinh Nguyen ctrl &= ~DXEPCTL_USBACTEP; 318847a1685fSDinh Nguyen ctrl |= DXEPCTL_SNAK; 318947a1685fSDinh Nguyen 319047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 319195c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + epctrl_reg); 319247a1685fSDinh Nguyen 319347a1685fSDinh Nguyen /* disable endpoint interrupts */ 31941f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); 319547a1685fSDinh Nguyen 31961141ea01SMian Yousaf Kaukab /* terminate all requests with shutdown */ 31971141ea01SMian Yousaf Kaukab kill_all_requests(hsotg, hs_ep, -ESHUTDOWN); 31981141ea01SMian Yousaf Kaukab 31991c07b20eSRobert Baldyga hsotg->fifo_map &= ~(1 << hs_ep->fifo_index); 32001c07b20eSRobert Baldyga hs_ep->fifo_index = 0; 32011c07b20eSRobert Baldyga hs_ep->fifo_size = 0; 32021c07b20eSRobert Baldyga 320347a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 320447a1685fSDinh Nguyen return 0; 320547a1685fSDinh Nguyen } 320647a1685fSDinh Nguyen 320747a1685fSDinh Nguyen /** 320847a1685fSDinh Nguyen * on_list - check request is on the given endpoint 320947a1685fSDinh Nguyen * @ep: The endpoint to check. 321047a1685fSDinh Nguyen * @test: The request to test if it is on the endpoint. 321147a1685fSDinh Nguyen */ 32121f91b4ccSFelipe Balbi static bool on_list(struct dwc2_hsotg_ep *ep, struct dwc2_hsotg_req *test) 321347a1685fSDinh Nguyen { 32141f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req, *treq; 321547a1685fSDinh Nguyen 321647a1685fSDinh Nguyen list_for_each_entry_safe(req, treq, &ep->queue, queue) { 321747a1685fSDinh Nguyen if (req == test) 321847a1685fSDinh Nguyen return true; 321947a1685fSDinh Nguyen } 322047a1685fSDinh Nguyen 322147a1685fSDinh Nguyen return false; 322247a1685fSDinh Nguyen } 322347a1685fSDinh Nguyen 3224c524dd5fSMian Yousaf Kaukab static int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hs_otg, u32 reg, 3225c524dd5fSMian Yousaf Kaukab u32 bit, u32 timeout) 3226c524dd5fSMian Yousaf Kaukab { 3227c524dd5fSMian Yousaf Kaukab u32 i; 3228c524dd5fSMian Yousaf Kaukab 3229c524dd5fSMian Yousaf Kaukab for (i = 0; i < timeout; i++) { 3230c524dd5fSMian Yousaf Kaukab if (dwc2_readl(hs_otg->regs + reg) & bit) 3231c524dd5fSMian Yousaf Kaukab return 0; 3232c524dd5fSMian Yousaf Kaukab udelay(1); 3233c524dd5fSMian Yousaf Kaukab } 3234c524dd5fSMian Yousaf Kaukab 3235c524dd5fSMian Yousaf Kaukab return -ETIMEDOUT; 3236c524dd5fSMian Yousaf Kaukab } 3237c524dd5fSMian Yousaf Kaukab 3238c524dd5fSMian Yousaf Kaukab static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, 3239c524dd5fSMian Yousaf Kaukab struct dwc2_hsotg_ep *hs_ep) 3240c524dd5fSMian Yousaf Kaukab { 3241c524dd5fSMian Yousaf Kaukab u32 epctrl_reg; 3242c524dd5fSMian Yousaf Kaukab u32 epint_reg; 3243c524dd5fSMian Yousaf Kaukab 3244c524dd5fSMian Yousaf Kaukab epctrl_reg = hs_ep->dir_in ? DIEPCTL(hs_ep->index) : 3245c524dd5fSMian Yousaf Kaukab DOEPCTL(hs_ep->index); 3246c524dd5fSMian Yousaf Kaukab epint_reg = hs_ep->dir_in ? DIEPINT(hs_ep->index) : 3247c524dd5fSMian Yousaf Kaukab DOEPINT(hs_ep->index); 3248c524dd5fSMian Yousaf Kaukab 3249c524dd5fSMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: stopping transfer on %s\n", __func__, 3250c524dd5fSMian Yousaf Kaukab hs_ep->name); 3251c524dd5fSMian Yousaf Kaukab if (hs_ep->dir_in) { 3252c524dd5fSMian Yousaf Kaukab __orr32(hsotg->regs + epctrl_reg, DXEPCTL_SNAK); 3253c524dd5fSMian Yousaf Kaukab /* Wait for Nak effect */ 3254c524dd5fSMian Yousaf Kaukab if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, 3255c524dd5fSMian Yousaf Kaukab DXEPINT_INEPNAKEFF, 100)) 3256c524dd5fSMian Yousaf Kaukab dev_warn(hsotg->dev, 3257c524dd5fSMian Yousaf Kaukab "%s: timeout DIEPINT.NAKEFF\n", __func__); 3258c524dd5fSMian Yousaf Kaukab } else { 32596b58cb07SVardan Mikayelyan if (!(dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_GOUTNAKEFF)) 32600676c7e7SDu, Changbin __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK); 3261c524dd5fSMian Yousaf Kaukab 3262c524dd5fSMian Yousaf Kaukab /* Wait for global nak to take effect */ 3263c524dd5fSMian Yousaf Kaukab if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 32640676c7e7SDu, Changbin GINTSTS_GOUTNAKEFF, 100)) 3265c524dd5fSMian Yousaf Kaukab dev_warn(hsotg->dev, 32660676c7e7SDu, Changbin "%s: timeout GINTSTS.GOUTNAKEFF\n", __func__); 3267c524dd5fSMian Yousaf Kaukab } 3268c524dd5fSMian Yousaf Kaukab 3269c524dd5fSMian Yousaf Kaukab /* Disable ep */ 3270c524dd5fSMian Yousaf Kaukab __orr32(hsotg->regs + epctrl_reg, DXEPCTL_EPDIS | DXEPCTL_SNAK); 3271c524dd5fSMian Yousaf Kaukab 3272c524dd5fSMian Yousaf Kaukab /* Wait for ep to be disabled */ 3273c524dd5fSMian Yousaf Kaukab if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, DXEPINT_EPDISBLD, 100)) 3274c524dd5fSMian Yousaf Kaukab dev_warn(hsotg->dev, 3275c524dd5fSMian Yousaf Kaukab "%s: timeout DOEPCTL.EPDisable\n", __func__); 3276c524dd5fSMian Yousaf Kaukab 3277c524dd5fSMian Yousaf Kaukab if (hs_ep->dir_in) { 3278c524dd5fSMian Yousaf Kaukab if (hsotg->dedicated_fifos) { 3279c524dd5fSMian Yousaf Kaukab dwc2_writel(GRSTCTL_TXFNUM(hs_ep->fifo_index) | 3280c524dd5fSMian Yousaf Kaukab GRSTCTL_TXFFLSH, hsotg->regs + GRSTCTL); 3281c524dd5fSMian Yousaf Kaukab /* Wait for fifo flush */ 3282c524dd5fSMian Yousaf Kaukab if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, 3283c524dd5fSMian Yousaf Kaukab GRSTCTL_TXFFLSH, 100)) 3284c524dd5fSMian Yousaf Kaukab dev_warn(hsotg->dev, 3285c524dd5fSMian Yousaf Kaukab "%s: timeout flushing fifos\n", 3286c524dd5fSMian Yousaf Kaukab __func__); 3287c524dd5fSMian Yousaf Kaukab } 3288c524dd5fSMian Yousaf Kaukab /* TODO: Flush shared tx fifo */ 3289c524dd5fSMian Yousaf Kaukab } else { 3290c524dd5fSMian Yousaf Kaukab /* Remove global NAKs */ 32910676c7e7SDu, Changbin __bic32(hsotg->regs + DCTL, DCTL_SGOUTNAK); 3292c524dd5fSMian Yousaf Kaukab } 3293c524dd5fSMian Yousaf Kaukab } 3294c524dd5fSMian Yousaf Kaukab 329547a1685fSDinh Nguyen /** 32961f91b4ccSFelipe Balbi * dwc2_hsotg_ep_dequeue - dequeue given endpoint 329747a1685fSDinh Nguyen * @ep: The endpoint to dequeue. 329847a1685fSDinh Nguyen * @req: The request to be removed from a queue. 329947a1685fSDinh Nguyen */ 33001f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) 330147a1685fSDinh Nguyen { 33021f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 33031f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 3304941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 330547a1685fSDinh Nguyen unsigned long flags; 330647a1685fSDinh Nguyen 33071e011293SMarek Szyprowski dev_dbg(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); 330847a1685fSDinh Nguyen 330947a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 331047a1685fSDinh Nguyen 331147a1685fSDinh Nguyen if (!on_list(hs_ep, hs_req)) { 331247a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 331347a1685fSDinh Nguyen return -EINVAL; 331447a1685fSDinh Nguyen } 331547a1685fSDinh Nguyen 3316c524dd5fSMian Yousaf Kaukab /* Dequeue already started request */ 3317c524dd5fSMian Yousaf Kaukab if (req == &hs_ep->req->req) 3318c524dd5fSMian Yousaf Kaukab dwc2_hsotg_ep_stop_xfr(hs, hs_ep); 3319c524dd5fSMian Yousaf Kaukab 33201f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); 332147a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 332247a1685fSDinh Nguyen 332347a1685fSDinh Nguyen return 0; 332447a1685fSDinh Nguyen } 332547a1685fSDinh Nguyen 332647a1685fSDinh Nguyen /** 33271f91b4ccSFelipe Balbi * dwc2_hsotg_ep_sethalt - set halt on a given endpoint 332847a1685fSDinh Nguyen * @ep: The endpoint to set halt. 332947a1685fSDinh Nguyen * @value: Set or unset the halt. 333051da43b5SVahram Aharonyan * @now: If true, stall the endpoint now. Otherwise return -EAGAIN if 333151da43b5SVahram Aharonyan * the endpoint is busy processing requests. 333251da43b5SVahram Aharonyan * 333351da43b5SVahram Aharonyan * We need to stall the endpoint immediately if request comes from set_feature 333451da43b5SVahram Aharonyan * protocol command handler. 333547a1685fSDinh Nguyen */ 333651da43b5SVahram Aharonyan static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now) 333747a1685fSDinh Nguyen { 33381f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 3339941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 334047a1685fSDinh Nguyen int index = hs_ep->index; 334147a1685fSDinh Nguyen u32 epreg; 334247a1685fSDinh Nguyen u32 epctl; 334347a1685fSDinh Nguyen u32 xfertype; 334447a1685fSDinh Nguyen 334547a1685fSDinh Nguyen dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); 334647a1685fSDinh Nguyen 334747a1685fSDinh Nguyen if (index == 0) { 334847a1685fSDinh Nguyen if (value) 33491f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hs); 335047a1685fSDinh Nguyen else 335147a1685fSDinh Nguyen dev_warn(hs->dev, 335247a1685fSDinh Nguyen "%s: can't clear halt on ep0\n", __func__); 335347a1685fSDinh Nguyen return 0; 335447a1685fSDinh Nguyen } 335547a1685fSDinh Nguyen 335615186f10SVahram Aharonyan if (hs_ep->isochronous) { 335715186f10SVahram Aharonyan dev_err(hs->dev, "%s is Isochronous Endpoint\n", ep->name); 335815186f10SVahram Aharonyan return -EINVAL; 335915186f10SVahram Aharonyan } 336015186f10SVahram Aharonyan 336151da43b5SVahram Aharonyan if (!now && value && !list_empty(&hs_ep->queue)) { 336251da43b5SVahram Aharonyan dev_dbg(hs->dev, "%s request is pending, cannot halt\n", 336351da43b5SVahram Aharonyan ep->name); 336451da43b5SVahram Aharonyan return -EAGAIN; 336551da43b5SVahram Aharonyan } 336651da43b5SVahram Aharonyan 3367c6f5c050SMian Yousaf Kaukab if (hs_ep->dir_in) { 336847a1685fSDinh Nguyen epreg = DIEPCTL(index); 336995c8bc36SAntti Seppälä epctl = dwc2_readl(hs->regs + epreg); 337047a1685fSDinh Nguyen 337147a1685fSDinh Nguyen if (value) { 33725a350d53SFelipe Balbi epctl |= DXEPCTL_STALL | DXEPCTL_SNAK; 337347a1685fSDinh Nguyen if (epctl & DXEPCTL_EPENA) 337447a1685fSDinh Nguyen epctl |= DXEPCTL_EPDIS; 337547a1685fSDinh Nguyen } else { 337647a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 337747a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 337847a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 337947a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 338047a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 338147a1685fSDinh Nguyen } 338295c8bc36SAntti Seppälä dwc2_writel(epctl, hs->regs + epreg); 3383c6f5c050SMian Yousaf Kaukab } else { 338447a1685fSDinh Nguyen 338547a1685fSDinh Nguyen epreg = DOEPCTL(index); 338695c8bc36SAntti Seppälä epctl = dwc2_readl(hs->regs + epreg); 338747a1685fSDinh Nguyen 338847a1685fSDinh Nguyen if (value) 338947a1685fSDinh Nguyen epctl |= DXEPCTL_STALL; 339047a1685fSDinh Nguyen else { 339147a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 339247a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 339347a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 339447a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 339547a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 339647a1685fSDinh Nguyen } 339795c8bc36SAntti Seppälä dwc2_writel(epctl, hs->regs + epreg); 3398c6f5c050SMian Yousaf Kaukab } 339947a1685fSDinh Nguyen 340047a1685fSDinh Nguyen hs_ep->halted = value; 340147a1685fSDinh Nguyen 340247a1685fSDinh Nguyen return 0; 340347a1685fSDinh Nguyen } 340447a1685fSDinh Nguyen 340547a1685fSDinh Nguyen /** 34061f91b4ccSFelipe Balbi * dwc2_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held 340747a1685fSDinh Nguyen * @ep: The endpoint to set halt. 340847a1685fSDinh Nguyen * @value: Set or unset the halt. 340947a1685fSDinh Nguyen */ 34101f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) 341147a1685fSDinh Nguyen { 34121f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 3413941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 341447a1685fSDinh Nguyen unsigned long flags = 0; 341547a1685fSDinh Nguyen int ret = 0; 341647a1685fSDinh Nguyen 341747a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 341851da43b5SVahram Aharonyan ret = dwc2_hsotg_ep_sethalt(ep, value, false); 341947a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 342047a1685fSDinh Nguyen 342147a1685fSDinh Nguyen return ret; 342247a1685fSDinh Nguyen } 342347a1685fSDinh Nguyen 34241f91b4ccSFelipe Balbi static struct usb_ep_ops dwc2_hsotg_ep_ops = { 34251f91b4ccSFelipe Balbi .enable = dwc2_hsotg_ep_enable, 34261f91b4ccSFelipe Balbi .disable = dwc2_hsotg_ep_disable, 34271f91b4ccSFelipe Balbi .alloc_request = dwc2_hsotg_ep_alloc_request, 34281f91b4ccSFelipe Balbi .free_request = dwc2_hsotg_ep_free_request, 34291f91b4ccSFelipe Balbi .queue = dwc2_hsotg_ep_queue_lock, 34301f91b4ccSFelipe Balbi .dequeue = dwc2_hsotg_ep_dequeue, 34311f91b4ccSFelipe Balbi .set_halt = dwc2_hsotg_ep_sethalt_lock, 343247a1685fSDinh Nguyen /* note, don't believe we have any call for the fifo routines */ 343347a1685fSDinh Nguyen }; 343447a1685fSDinh Nguyen 343547a1685fSDinh Nguyen /** 34361f91b4ccSFelipe Balbi * dwc2_hsotg_init - initalize the usb core 343747a1685fSDinh Nguyen * @hsotg: The driver state 343847a1685fSDinh Nguyen */ 34391f91b4ccSFelipe Balbi static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) 344047a1685fSDinh Nguyen { 3441fa4a8d72SMian Yousaf Kaukab u32 trdtim; 3442ecd9a7adSPrzemek Rudy u32 usbcfg; 344347a1685fSDinh Nguyen /* unmask subset of endpoint interrupts */ 344447a1685fSDinh Nguyen 344595c8bc36SAntti Seppälä dwc2_writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | 344647a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK, 344747a1685fSDinh Nguyen hsotg->regs + DIEPMSK); 344847a1685fSDinh Nguyen 344995c8bc36SAntti Seppälä dwc2_writel(DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | 345047a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK, 345147a1685fSDinh Nguyen hsotg->regs + DOEPMSK); 345247a1685fSDinh Nguyen 345395c8bc36SAntti Seppälä dwc2_writel(0, hsotg->regs + DAINTMSK); 345447a1685fSDinh Nguyen 345547a1685fSDinh Nguyen /* Be in disconnected state until gadget is registered */ 345647a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 345747a1685fSDinh Nguyen 345847a1685fSDinh Nguyen /* setup fifos */ 345947a1685fSDinh Nguyen 346047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 346195c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + GRXFSIZ), 346295c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + GNPTXFSIZ)); 346347a1685fSDinh Nguyen 34641f91b4ccSFelipe Balbi dwc2_hsotg_init_fifo(hsotg); 346547a1685fSDinh Nguyen 3466ecd9a7adSPrzemek Rudy /* keep other bits untouched (so e.g. forced modes are not lost) */ 3467ecd9a7adSPrzemek Rudy usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); 3468ecd9a7adSPrzemek Rudy usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP | 3469ecd9a7adSPrzemek Rudy GUSBCFG_HNPCAP); 3470ecd9a7adSPrzemek Rudy 347147a1685fSDinh Nguyen /* set the PLL on, remove the HNP/SRP and set the PHY */ 3472fa4a8d72SMian Yousaf Kaukab trdtim = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5; 3473ecd9a7adSPrzemek Rudy usbcfg |= hsotg->phyif | GUSBCFG_TOUTCAL(7) | 3474ecd9a7adSPrzemek Rudy (trdtim << GUSBCFG_USBTRDTIM_SHIFT); 3475ecd9a7adSPrzemek Rudy dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); 347647a1685fSDinh Nguyen 3477f5090044SGregory Herrero if (using_dma(hsotg)) 3478f5090044SGregory Herrero __orr32(hsotg->regs + GAHBCFG, GAHBCFG_DMA_EN); 347947a1685fSDinh Nguyen } 348047a1685fSDinh Nguyen 348147a1685fSDinh Nguyen /** 34821f91b4ccSFelipe Balbi * dwc2_hsotg_udc_start - prepare the udc for work 348347a1685fSDinh Nguyen * @gadget: The usb gadget state 348447a1685fSDinh Nguyen * @driver: The usb gadget driver 348547a1685fSDinh Nguyen * 348647a1685fSDinh Nguyen * Perform initialization to prepare udc device and driver 348747a1685fSDinh Nguyen * to work. 348847a1685fSDinh Nguyen */ 34891f91b4ccSFelipe Balbi static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, 349047a1685fSDinh Nguyen struct usb_gadget_driver *driver) 349147a1685fSDinh Nguyen { 3492941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 34935b9451f8SMarek Szyprowski unsigned long flags; 349447a1685fSDinh Nguyen int ret; 349547a1685fSDinh Nguyen 349647a1685fSDinh Nguyen if (!hsotg) { 349747a1685fSDinh Nguyen pr_err("%s: called with no device\n", __func__); 349847a1685fSDinh Nguyen return -ENODEV; 349947a1685fSDinh Nguyen } 350047a1685fSDinh Nguyen 350147a1685fSDinh Nguyen if (!driver) { 350247a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: no driver\n", __func__); 350347a1685fSDinh Nguyen return -EINVAL; 350447a1685fSDinh Nguyen } 350547a1685fSDinh Nguyen 350647a1685fSDinh Nguyen if (driver->max_speed < USB_SPEED_FULL) 350747a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: bad speed\n", __func__); 350847a1685fSDinh Nguyen 350947a1685fSDinh Nguyen if (!driver->setup) { 351047a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: missing entry points\n", __func__); 351147a1685fSDinh Nguyen return -EINVAL; 351247a1685fSDinh Nguyen } 351347a1685fSDinh Nguyen 351447a1685fSDinh Nguyen WARN_ON(hsotg->driver); 351547a1685fSDinh Nguyen 351647a1685fSDinh Nguyen driver->driver.bus = NULL; 351747a1685fSDinh Nguyen hsotg->driver = driver; 351847a1685fSDinh Nguyen hsotg->gadget.dev.of_node = hsotg->dev->of_node; 351947a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 352047a1685fSDinh Nguyen 352109a75e85SMarek Szyprowski if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) { 352209a75e85SMarek Szyprowski ret = dwc2_lowlevel_hw_enable(hsotg); 352309a75e85SMarek Szyprowski if (ret) 352447a1685fSDinh Nguyen goto err; 352547a1685fSDinh Nguyen } 352647a1685fSDinh Nguyen 3527f6c01592SGregory Herrero if (!IS_ERR_OR_NULL(hsotg->uphy)) 3528f6c01592SGregory Herrero otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget); 3529c816c47fSMarek Szyprowski 35305b9451f8SMarek Szyprowski spin_lock_irqsave(&hsotg->lock, flags); 3531d0f0ac56SJohn Youn if (dwc2_hw_is_device(hsotg)) { 35321f91b4ccSFelipe Balbi dwc2_hsotg_init(hsotg); 35331f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 3534d0f0ac56SJohn Youn } 3535d0f0ac56SJohn Youn 3536dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 35375b9451f8SMarek Szyprowski spin_unlock_irqrestore(&hsotg->lock, flags); 35385b9451f8SMarek Szyprowski 353947a1685fSDinh Nguyen dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); 35405b9451f8SMarek Szyprowski 354147a1685fSDinh Nguyen return 0; 354247a1685fSDinh Nguyen 354347a1685fSDinh Nguyen err: 354447a1685fSDinh Nguyen hsotg->driver = NULL; 354547a1685fSDinh Nguyen return ret; 354647a1685fSDinh Nguyen } 354747a1685fSDinh Nguyen 354847a1685fSDinh Nguyen /** 35491f91b4ccSFelipe Balbi * dwc2_hsotg_udc_stop - stop the udc 355047a1685fSDinh Nguyen * @gadget: The usb gadget state 355147a1685fSDinh Nguyen * @driver: The usb gadget driver 355247a1685fSDinh Nguyen * 355347a1685fSDinh Nguyen * Stop udc hw block and stay tunned for future transmissions 355447a1685fSDinh Nguyen */ 35551f91b4ccSFelipe Balbi static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) 355647a1685fSDinh Nguyen { 3557941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 355847a1685fSDinh Nguyen unsigned long flags = 0; 355947a1685fSDinh Nguyen int ep; 356047a1685fSDinh Nguyen 356147a1685fSDinh Nguyen if (!hsotg) 356247a1685fSDinh Nguyen return -ENODEV; 356347a1685fSDinh Nguyen 356447a1685fSDinh Nguyen /* all endpoints should be shutdown */ 3565c6f5c050SMian Yousaf Kaukab for (ep = 1; ep < hsotg->num_of_eps; ep++) { 3566c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 35671f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 3568c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 35691f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 3570c6f5c050SMian Yousaf Kaukab } 357147a1685fSDinh Nguyen 357247a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 357347a1685fSDinh Nguyen 357447a1685fSDinh Nguyen hsotg->driver = NULL; 357547a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 3576dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 357747a1685fSDinh Nguyen 357847a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 357947a1685fSDinh Nguyen 3580f6c01592SGregory Herrero if (!IS_ERR_OR_NULL(hsotg->uphy)) 3581f6c01592SGregory Herrero otg_set_peripheral(hsotg->uphy->otg, NULL); 3582c816c47fSMarek Szyprowski 358309a75e85SMarek Szyprowski if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 358409a75e85SMarek Szyprowski dwc2_lowlevel_hw_disable(hsotg); 358547a1685fSDinh Nguyen 358647a1685fSDinh Nguyen return 0; 358747a1685fSDinh Nguyen } 358847a1685fSDinh Nguyen 358947a1685fSDinh Nguyen /** 35901f91b4ccSFelipe Balbi * dwc2_hsotg_gadget_getframe - read the frame number 359147a1685fSDinh Nguyen * @gadget: The usb gadget state 359247a1685fSDinh Nguyen * 359347a1685fSDinh Nguyen * Read the {micro} frame number 359447a1685fSDinh Nguyen */ 35951f91b4ccSFelipe Balbi static int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget) 359647a1685fSDinh Nguyen { 35971f91b4ccSFelipe Balbi return dwc2_hsotg_read_frameno(to_hsotg(gadget)); 359847a1685fSDinh Nguyen } 359947a1685fSDinh Nguyen 360047a1685fSDinh Nguyen /** 36011f91b4ccSFelipe Balbi * dwc2_hsotg_pullup - connect/disconnect the USB PHY 360247a1685fSDinh Nguyen * @gadget: The usb gadget state 360347a1685fSDinh Nguyen * @is_on: Current state of the USB PHY 360447a1685fSDinh Nguyen * 360547a1685fSDinh Nguyen * Connect/Disconnect the USB PHY pullup 360647a1685fSDinh Nguyen */ 36071f91b4ccSFelipe Balbi static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) 360847a1685fSDinh Nguyen { 3609941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 361047a1685fSDinh Nguyen unsigned long flags = 0; 361147a1685fSDinh Nguyen 361277ba9119SGregory Herrero dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on, 361377ba9119SGregory Herrero hsotg->op_state); 361477ba9119SGregory Herrero 361577ba9119SGregory Herrero /* Don't modify pullup state while in host mode */ 361677ba9119SGregory Herrero if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { 361777ba9119SGregory Herrero hsotg->enabled = is_on; 361877ba9119SGregory Herrero return 0; 361977ba9119SGregory Herrero } 362047a1685fSDinh Nguyen 362147a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 362247a1685fSDinh Nguyen if (is_on) { 3623dc6e69e6SMarek Szyprowski hsotg->enabled = 1; 36241f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 36251f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 362647a1685fSDinh Nguyen } else { 36271f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 36281f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 3629dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 363047a1685fSDinh Nguyen } 363147a1685fSDinh Nguyen 363247a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 363347a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 363447a1685fSDinh Nguyen 363547a1685fSDinh Nguyen return 0; 363647a1685fSDinh Nguyen } 363747a1685fSDinh Nguyen 36381f91b4ccSFelipe Balbi static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) 363983d98223SGregory Herrero { 364083d98223SGregory Herrero struct dwc2_hsotg *hsotg = to_hsotg(gadget); 364183d98223SGregory Herrero unsigned long flags; 364283d98223SGregory Herrero 364383d98223SGregory Herrero dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active); 364483d98223SGregory Herrero spin_lock_irqsave(&hsotg->lock, flags); 364583d98223SGregory Herrero 364618b2b37cSGregory Herrero /* 364718b2b37cSGregory Herrero * If controller is hibernated, it must exit from hibernation 364861f7223bSGregory Herrero * before being initialized / de-initialized 364918b2b37cSGregory Herrero */ 3650065d3931SGregory Herrero if (hsotg->lx_state == DWC2_L2) 365118b2b37cSGregory Herrero dwc2_exit_hibernation(hsotg, false); 3652065d3931SGregory Herrero 365361f7223bSGregory Herrero if (is_active) { 365461f7223bSGregory Herrero hsotg->op_state = OTG_STATE_B_PERIPHERAL; 365561f7223bSGregory Herrero 36561f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 365783d98223SGregory Herrero if (hsotg->enabled) 36581f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 365983d98223SGregory Herrero } else { 36601f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 36611f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 366283d98223SGregory Herrero } 366383d98223SGregory Herrero 366483d98223SGregory Herrero spin_unlock_irqrestore(&hsotg->lock, flags); 366583d98223SGregory Herrero return 0; 366683d98223SGregory Herrero } 366783d98223SGregory Herrero 3668596d696aSGregory Herrero /** 36691f91b4ccSFelipe Balbi * dwc2_hsotg_vbus_draw - report bMaxPower field 3670596d696aSGregory Herrero * @gadget: The usb gadget state 3671596d696aSGregory Herrero * @mA: Amount of current 3672596d696aSGregory Herrero * 3673596d696aSGregory Herrero * Report how much power the device may consume to the phy. 3674596d696aSGregory Herrero */ 36751f91b4ccSFelipe Balbi static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned mA) 3676596d696aSGregory Herrero { 3677596d696aSGregory Herrero struct dwc2_hsotg *hsotg = to_hsotg(gadget); 3678596d696aSGregory Herrero 3679596d696aSGregory Herrero if (IS_ERR_OR_NULL(hsotg->uphy)) 3680596d696aSGregory Herrero return -ENOTSUPP; 3681596d696aSGregory Herrero return usb_phy_set_power(hsotg->uphy, mA); 3682596d696aSGregory Herrero } 3683596d696aSGregory Herrero 36841f91b4ccSFelipe Balbi static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { 36851f91b4ccSFelipe Balbi .get_frame = dwc2_hsotg_gadget_getframe, 36861f91b4ccSFelipe Balbi .udc_start = dwc2_hsotg_udc_start, 36871f91b4ccSFelipe Balbi .udc_stop = dwc2_hsotg_udc_stop, 36881f91b4ccSFelipe Balbi .pullup = dwc2_hsotg_pullup, 36891f91b4ccSFelipe Balbi .vbus_session = dwc2_hsotg_vbus_session, 36901f91b4ccSFelipe Balbi .vbus_draw = dwc2_hsotg_vbus_draw, 369147a1685fSDinh Nguyen }; 369247a1685fSDinh Nguyen 369347a1685fSDinh Nguyen /** 36941f91b4ccSFelipe Balbi * dwc2_hsotg_initep - initialise a single endpoint 369547a1685fSDinh Nguyen * @hsotg: The device state. 369647a1685fSDinh Nguyen * @hs_ep: The endpoint to be initialised. 369747a1685fSDinh Nguyen * @epnum: The endpoint number 369847a1685fSDinh Nguyen * 369947a1685fSDinh Nguyen * Initialise the given endpoint (as part of the probe and device state 370047a1685fSDinh Nguyen * creation) to give to the gadget driver. Setup the endpoint name, any 370147a1685fSDinh Nguyen * direction information and other state that may be required. 370247a1685fSDinh Nguyen */ 37031f91b4ccSFelipe Balbi static void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, 37041f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 3705c6f5c050SMian Yousaf Kaukab int epnum, 3706c6f5c050SMian Yousaf Kaukab bool dir_in) 370747a1685fSDinh Nguyen { 370847a1685fSDinh Nguyen char *dir; 370947a1685fSDinh Nguyen 371047a1685fSDinh Nguyen if (epnum == 0) 371147a1685fSDinh Nguyen dir = ""; 3712c6f5c050SMian Yousaf Kaukab else if (dir_in) 371347a1685fSDinh Nguyen dir = "in"; 3714c6f5c050SMian Yousaf Kaukab else 3715c6f5c050SMian Yousaf Kaukab dir = "out"; 371647a1685fSDinh Nguyen 3717c6f5c050SMian Yousaf Kaukab hs_ep->dir_in = dir_in; 371847a1685fSDinh Nguyen hs_ep->index = epnum; 371947a1685fSDinh Nguyen 372047a1685fSDinh Nguyen snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); 372147a1685fSDinh Nguyen 372247a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->queue); 372347a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->ep.ep_list); 372447a1685fSDinh Nguyen 372547a1685fSDinh Nguyen /* add to the list of endpoints known by the gadget driver */ 372647a1685fSDinh Nguyen if (epnum) 372747a1685fSDinh Nguyen list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); 372847a1685fSDinh Nguyen 372947a1685fSDinh Nguyen hs_ep->parent = hsotg; 373047a1685fSDinh Nguyen hs_ep->ep.name = hs_ep->name; 373147a1685fSDinh Nguyen usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT); 37321f91b4ccSFelipe Balbi hs_ep->ep.ops = &dwc2_hsotg_ep_ops; 373347a1685fSDinh Nguyen 37342954522fSRobert Baldyga if (epnum == 0) { 37352954522fSRobert Baldyga hs_ep->ep.caps.type_control = true; 37362954522fSRobert Baldyga } else { 37372954522fSRobert Baldyga hs_ep->ep.caps.type_iso = true; 37382954522fSRobert Baldyga hs_ep->ep.caps.type_bulk = true; 37392954522fSRobert Baldyga hs_ep->ep.caps.type_int = true; 37402954522fSRobert Baldyga } 37412954522fSRobert Baldyga 37422954522fSRobert Baldyga if (dir_in) 37432954522fSRobert Baldyga hs_ep->ep.caps.dir_in = true; 37442954522fSRobert Baldyga else 37452954522fSRobert Baldyga hs_ep->ep.caps.dir_out = true; 37462954522fSRobert Baldyga 374747a1685fSDinh Nguyen /* 374847a1685fSDinh Nguyen * if we're using dma, we need to set the next-endpoint pointer 374947a1685fSDinh Nguyen * to be something valid. 375047a1685fSDinh Nguyen */ 375147a1685fSDinh Nguyen 375247a1685fSDinh Nguyen if (using_dma(hsotg)) { 375347a1685fSDinh Nguyen u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); 3754c6f5c050SMian Yousaf Kaukab if (dir_in) 375595c8bc36SAntti Seppälä dwc2_writel(next, hsotg->regs + DIEPCTL(epnum)); 3756c6f5c050SMian Yousaf Kaukab else 375795c8bc36SAntti Seppälä dwc2_writel(next, hsotg->regs + DOEPCTL(epnum)); 375847a1685fSDinh Nguyen } 375947a1685fSDinh Nguyen } 376047a1685fSDinh Nguyen 376147a1685fSDinh Nguyen /** 37621f91b4ccSFelipe Balbi * dwc2_hsotg_hw_cfg - read HW configuration registers 376347a1685fSDinh Nguyen * @param: The device state 376447a1685fSDinh Nguyen * 376547a1685fSDinh Nguyen * Read the USB core HW configuration registers 376647a1685fSDinh Nguyen */ 37671f91b4ccSFelipe Balbi static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) 376847a1685fSDinh Nguyen { 3769c6f5c050SMian Yousaf Kaukab u32 cfg; 3770c6f5c050SMian Yousaf Kaukab u32 ep_type; 3771c6f5c050SMian Yousaf Kaukab u32 i; 3772c6f5c050SMian Yousaf Kaukab 377347a1685fSDinh Nguyen /* check hardware configuration */ 377447a1685fSDinh Nguyen 377543e90349SJohn Youn hsotg->num_of_eps = hsotg->hw_params.num_dev_ep; 377643e90349SJohn Youn 3777c6f5c050SMian Yousaf Kaukab /* Add ep0 */ 3778c6f5c050SMian Yousaf Kaukab hsotg->num_of_eps++; 377947a1685fSDinh Nguyen 37801f91b4ccSFelipe Balbi hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, sizeof(struct dwc2_hsotg_ep), 3781c6f5c050SMian Yousaf Kaukab GFP_KERNEL); 3782c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_in[0]) 3783c6f5c050SMian Yousaf Kaukab return -ENOMEM; 37841f91b4ccSFelipe Balbi /* Same dwc2_hsotg_ep is used in both directions for ep0 */ 3785c6f5c050SMian Yousaf Kaukab hsotg->eps_out[0] = hsotg->eps_in[0]; 378647a1685fSDinh Nguyen 378743e90349SJohn Youn cfg = hsotg->hw_params.dev_ep_dirs; 3788251a17f5SRoshan Pius for (i = 1, cfg >>= 2; i < hsotg->num_of_eps; i++, cfg >>= 2) { 3789c6f5c050SMian Yousaf Kaukab ep_type = cfg & 3; 3790c6f5c050SMian Yousaf Kaukab /* Direction in or both */ 3791c6f5c050SMian Yousaf Kaukab if (!(ep_type & 2)) { 3792c6f5c050SMian Yousaf Kaukab hsotg->eps_in[i] = devm_kzalloc(hsotg->dev, 37931f91b4ccSFelipe Balbi sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 3794c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_in[i]) 3795c6f5c050SMian Yousaf Kaukab return -ENOMEM; 3796c6f5c050SMian Yousaf Kaukab } 3797c6f5c050SMian Yousaf Kaukab /* Direction out or both */ 3798c6f5c050SMian Yousaf Kaukab if (!(ep_type & 1)) { 3799c6f5c050SMian Yousaf Kaukab hsotg->eps_out[i] = devm_kzalloc(hsotg->dev, 38001f91b4ccSFelipe Balbi sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 3801c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_out[i]) 3802c6f5c050SMian Yousaf Kaukab return -ENOMEM; 3803c6f5c050SMian Yousaf Kaukab } 3804c6f5c050SMian Yousaf Kaukab } 3805c6f5c050SMian Yousaf Kaukab 380643e90349SJohn Youn hsotg->fifo_mem = hsotg->hw_params.total_fifo_size; 380743e90349SJohn Youn hsotg->dedicated_fifos = hsotg->hw_params.en_multiple_tx_fifo; 380847a1685fSDinh Nguyen 3809cff9eb75SMarek Szyprowski dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n", 3810cff9eb75SMarek Szyprowski hsotg->num_of_eps, 3811cff9eb75SMarek Szyprowski hsotg->dedicated_fifos ? "dedicated" : "shared", 3812cff9eb75SMarek Szyprowski hsotg->fifo_mem); 3813c6f5c050SMian Yousaf Kaukab return 0; 381447a1685fSDinh Nguyen } 381547a1685fSDinh Nguyen 381647a1685fSDinh Nguyen /** 38171f91b4ccSFelipe Balbi * dwc2_hsotg_dump - dump state of the udc 381847a1685fSDinh Nguyen * @param: The device state 381947a1685fSDinh Nguyen */ 38201f91b4ccSFelipe Balbi static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) 382147a1685fSDinh Nguyen { 382247a1685fSDinh Nguyen #ifdef DEBUG 382347a1685fSDinh Nguyen struct device *dev = hsotg->dev; 382447a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 382547a1685fSDinh Nguyen u32 val; 382647a1685fSDinh Nguyen int idx; 382747a1685fSDinh Nguyen 382847a1685fSDinh Nguyen dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", 382995c8bc36SAntti Seppälä dwc2_readl(regs + DCFG), dwc2_readl(regs + DCTL), 383095c8bc36SAntti Seppälä dwc2_readl(regs + DIEPMSK)); 383147a1685fSDinh Nguyen 3832f889f23dSMian Yousaf Kaukab dev_info(dev, "GAHBCFG=0x%08x, GHWCFG1=0x%08x\n", 383395c8bc36SAntti Seppälä dwc2_readl(regs + GAHBCFG), dwc2_readl(regs + GHWCFG1)); 383447a1685fSDinh Nguyen 383547a1685fSDinh Nguyen dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 383695c8bc36SAntti Seppälä dwc2_readl(regs + GRXFSIZ), dwc2_readl(regs + GNPTXFSIZ)); 383747a1685fSDinh Nguyen 383847a1685fSDinh Nguyen /* show periodic fifo settings */ 383947a1685fSDinh Nguyen 3840364f8e93SMian Yousaf Kaukab for (idx = 1; idx < hsotg->num_of_eps; idx++) { 384195c8bc36SAntti Seppälä val = dwc2_readl(regs + DPTXFSIZN(idx)); 384247a1685fSDinh Nguyen dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, 384347a1685fSDinh Nguyen val >> FIFOSIZE_DEPTH_SHIFT, 384447a1685fSDinh Nguyen val & FIFOSIZE_STARTADDR_MASK); 384547a1685fSDinh Nguyen } 384647a1685fSDinh Nguyen 3847364f8e93SMian Yousaf Kaukab for (idx = 0; idx < hsotg->num_of_eps; idx++) { 384847a1685fSDinh Nguyen dev_info(dev, 384947a1685fSDinh Nguyen "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, 385095c8bc36SAntti Seppälä dwc2_readl(regs + DIEPCTL(idx)), 385195c8bc36SAntti Seppälä dwc2_readl(regs + DIEPTSIZ(idx)), 385295c8bc36SAntti Seppälä dwc2_readl(regs + DIEPDMA(idx))); 385347a1685fSDinh Nguyen 385495c8bc36SAntti Seppälä val = dwc2_readl(regs + DOEPCTL(idx)); 385547a1685fSDinh Nguyen dev_info(dev, 385647a1685fSDinh Nguyen "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", 385795c8bc36SAntti Seppälä idx, dwc2_readl(regs + DOEPCTL(idx)), 385895c8bc36SAntti Seppälä dwc2_readl(regs + DOEPTSIZ(idx)), 385995c8bc36SAntti Seppälä dwc2_readl(regs + DOEPDMA(idx))); 386047a1685fSDinh Nguyen 386147a1685fSDinh Nguyen } 386247a1685fSDinh Nguyen 386347a1685fSDinh Nguyen dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", 386495c8bc36SAntti Seppälä dwc2_readl(regs + DVBUSDIS), dwc2_readl(regs + DVBUSPULSE)); 386547a1685fSDinh Nguyen #endif 386647a1685fSDinh Nguyen } 386747a1685fSDinh Nguyen 386847a1685fSDinh Nguyen /** 3869117777b2SDinh Nguyen * dwc2_gadget_init - init function for gadget 3870117777b2SDinh Nguyen * @dwc2: The data structure for the DWC2 driver. 3871117777b2SDinh Nguyen * @irq: The IRQ number for the controller. 387247a1685fSDinh Nguyen */ 3873117777b2SDinh Nguyen int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) 387447a1685fSDinh Nguyen { 3875117777b2SDinh Nguyen struct device *dev = hsotg->dev; 387647a1685fSDinh Nguyen int epnum; 387747a1685fSDinh Nguyen int ret; 387843e90349SJohn Youn 38790a176279SGregory Herrero /* Dump fifo information */ 38800a176279SGregory Herrero dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n", 388105ee799fSJohn Youn hsotg->params.g_np_tx_fifo_size); 388205ee799fSJohn Youn dev_dbg(dev, "RXFIFO size: %d\n", hsotg->params.g_rx_fifo_size); 388347a1685fSDinh Nguyen 388447a1685fSDinh Nguyen hsotg->gadget.max_speed = USB_SPEED_HIGH; 38851f91b4ccSFelipe Balbi hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; 388647a1685fSDinh Nguyen hsotg->gadget.name = dev_name(dev); 3887097ee662SGregory Herrero if (hsotg->dr_mode == USB_DR_MODE_OTG) 3888097ee662SGregory Herrero hsotg->gadget.is_otg = 1; 3889ec4cc657SMian Yousaf Kaukab else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 3890ec4cc657SMian Yousaf Kaukab hsotg->op_state = OTG_STATE_B_PERIPHERAL; 389147a1685fSDinh Nguyen 38921f91b4ccSFelipe Balbi ret = dwc2_hsotg_hw_cfg(hsotg); 3893c6f5c050SMian Yousaf Kaukab if (ret) { 3894c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret); 389509a75e85SMarek Szyprowski return ret; 3896c6f5c050SMian Yousaf Kaukab } 3897c6f5c050SMian Yousaf Kaukab 38983f95001dSMian Yousaf Kaukab hsotg->ctrl_buff = devm_kzalloc(hsotg->dev, 38993f95001dSMian Yousaf Kaukab DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 39008bae0f8cSWolfram Sang if (!hsotg->ctrl_buff) 390109a75e85SMarek Szyprowski return -ENOMEM; 39023f95001dSMian Yousaf Kaukab 39033f95001dSMian Yousaf Kaukab hsotg->ep0_buff = devm_kzalloc(hsotg->dev, 39043f95001dSMian Yousaf Kaukab DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 39058bae0f8cSWolfram Sang if (!hsotg->ep0_buff) 390609a75e85SMarek Szyprowski return -ENOMEM; 39073f95001dSMian Yousaf Kaukab 3908*0f6b80c0SVahram Aharonyan if (using_desc_dma(hsotg)) { 3909*0f6b80c0SVahram Aharonyan ret = dwc2_gadget_alloc_ctrl_desc_chains(hsotg); 3910*0f6b80c0SVahram Aharonyan if (ret < 0) 3911*0f6b80c0SVahram Aharonyan return ret; 3912*0f6b80c0SVahram Aharonyan } 3913*0f6b80c0SVahram Aharonyan 39141f91b4ccSFelipe Balbi ret = devm_request_irq(hsotg->dev, irq, dwc2_hsotg_irq, IRQF_SHARED, 3915db8178c3SDinh Nguyen dev_name(hsotg->dev), hsotg); 3916eb3c56c5SMarek Szyprowski if (ret < 0) { 3917db8178c3SDinh Nguyen dev_err(dev, "cannot claim IRQ for gadget\n"); 391809a75e85SMarek Szyprowski return ret; 3919eb3c56c5SMarek Szyprowski } 3920eb3c56c5SMarek Szyprowski 392147a1685fSDinh Nguyen /* hsotg->num_of_eps holds number of EPs other than ep0 */ 392247a1685fSDinh Nguyen 392347a1685fSDinh Nguyen if (hsotg->num_of_eps == 0) { 392447a1685fSDinh Nguyen dev_err(dev, "wrong number of EPs (zero)\n"); 392509a75e85SMarek Szyprowski return -EINVAL; 392647a1685fSDinh Nguyen } 392747a1685fSDinh Nguyen 392847a1685fSDinh Nguyen /* setup endpoint information */ 392947a1685fSDinh Nguyen 393047a1685fSDinh Nguyen INIT_LIST_HEAD(&hsotg->gadget.ep_list); 3931c6f5c050SMian Yousaf Kaukab hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep; 393247a1685fSDinh Nguyen 393347a1685fSDinh Nguyen /* allocate EP0 request */ 393447a1685fSDinh Nguyen 39351f91b4ccSFelipe Balbi hsotg->ctrl_req = dwc2_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep, 393647a1685fSDinh Nguyen GFP_KERNEL); 393747a1685fSDinh Nguyen if (!hsotg->ctrl_req) { 393847a1685fSDinh Nguyen dev_err(dev, "failed to allocate ctrl req\n"); 393909a75e85SMarek Szyprowski return -ENOMEM; 394047a1685fSDinh Nguyen } 394147a1685fSDinh Nguyen 394247a1685fSDinh Nguyen /* initialise the endpoints now the core has been initialised */ 3943c6f5c050SMian Yousaf Kaukab for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) { 3944c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[epnum]) 39451f91b4ccSFelipe Balbi dwc2_hsotg_initep(hsotg, hsotg->eps_in[epnum], 3946c6f5c050SMian Yousaf Kaukab epnum, 1); 3947c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[epnum]) 39481f91b4ccSFelipe Balbi dwc2_hsotg_initep(hsotg, hsotg->eps_out[epnum], 3949c6f5c050SMian Yousaf Kaukab epnum, 0); 3950c6f5c050SMian Yousaf Kaukab } 395147a1685fSDinh Nguyen 3952117777b2SDinh Nguyen ret = usb_add_gadget_udc(dev, &hsotg->gadget); 395347a1685fSDinh Nguyen if (ret) 395409a75e85SMarek Szyprowski return ret; 395547a1685fSDinh Nguyen 39561f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 395747a1685fSDinh Nguyen 395847a1685fSDinh Nguyen return 0; 395947a1685fSDinh Nguyen } 396047a1685fSDinh Nguyen 396147a1685fSDinh Nguyen /** 39621f91b4ccSFelipe Balbi * dwc2_hsotg_remove - remove function for hsotg driver 396347a1685fSDinh Nguyen * @pdev: The platform information for the driver 396447a1685fSDinh Nguyen */ 39651f91b4ccSFelipe Balbi int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg) 396647a1685fSDinh Nguyen { 396747a1685fSDinh Nguyen usb_del_gadget_udc(&hsotg->gadget); 396847a1685fSDinh Nguyen 396947a1685fSDinh Nguyen return 0; 397047a1685fSDinh Nguyen } 397147a1685fSDinh Nguyen 39721f91b4ccSFelipe Balbi int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) 397347a1685fSDinh Nguyen { 397447a1685fSDinh Nguyen unsigned long flags; 397547a1685fSDinh Nguyen 39769e779778SGregory Herrero if (hsotg->lx_state != DWC2_L0) 397709a75e85SMarek Szyprowski return 0; 39789e779778SGregory Herrero 3979dc6e69e6SMarek Szyprowski if (hsotg->driver) { 3980dc6e69e6SMarek Szyprowski int ep; 3981dc6e69e6SMarek Szyprowski 398247a1685fSDinh Nguyen dev_info(hsotg->dev, "suspending usb gadget %s\n", 398347a1685fSDinh Nguyen hsotg->driver->driver.name); 398447a1685fSDinh Nguyen 398547a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 3986dc6e69e6SMarek Szyprowski if (hsotg->enabled) 39871f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 39881f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 398947a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 399047a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 399147a1685fSDinh Nguyen 3992c6f5c050SMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps; ep++) { 3993c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 39941f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 3995c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 39961f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 3997c6f5c050SMian Yousaf Kaukab } 399847a1685fSDinh Nguyen } 399947a1685fSDinh Nguyen 400009a75e85SMarek Szyprowski return 0; 400147a1685fSDinh Nguyen } 400247a1685fSDinh Nguyen 40031f91b4ccSFelipe Balbi int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg) 400447a1685fSDinh Nguyen { 400547a1685fSDinh Nguyen unsigned long flags; 400647a1685fSDinh Nguyen 40079e779778SGregory Herrero if (hsotg->lx_state == DWC2_L2) 400809a75e85SMarek Szyprowski return 0; 40099e779778SGregory Herrero 401047a1685fSDinh Nguyen if (hsotg->driver) { 401147a1685fSDinh Nguyen dev_info(hsotg->dev, "resuming usb gadget %s\n", 401247a1685fSDinh Nguyen hsotg->driver->driver.name); 4013d00b4142SRobert Baldyga 401447a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 40151f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 4016dc6e69e6SMarek Szyprowski if (hsotg->enabled) 40171f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 401847a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 4019dc6e69e6SMarek Szyprowski } 402047a1685fSDinh Nguyen 402109a75e85SMarek Szyprowski return 0; 402247a1685fSDinh Nguyen } 402358e52ff6SJohn Youn 402458e52ff6SJohn Youn /** 402558e52ff6SJohn Youn * dwc2_backup_device_registers() - Backup controller device registers. 402658e52ff6SJohn Youn * When suspending usb bus, registers needs to be backuped 402758e52ff6SJohn Youn * if controller power is disabled once suspended. 402858e52ff6SJohn Youn * 402958e52ff6SJohn Youn * @hsotg: Programming view of the DWC_otg controller 403058e52ff6SJohn Youn */ 403158e52ff6SJohn Youn int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg) 403258e52ff6SJohn Youn { 403358e52ff6SJohn Youn struct dwc2_dregs_backup *dr; 403458e52ff6SJohn Youn int i; 403558e52ff6SJohn Youn 403658e52ff6SJohn Youn dev_dbg(hsotg->dev, "%s\n", __func__); 403758e52ff6SJohn Youn 403858e52ff6SJohn Youn /* Backup dev regs */ 403958e52ff6SJohn Youn dr = &hsotg->dr_backup; 404058e52ff6SJohn Youn 404158e52ff6SJohn Youn dr->dcfg = dwc2_readl(hsotg->regs + DCFG); 404258e52ff6SJohn Youn dr->dctl = dwc2_readl(hsotg->regs + DCTL); 404358e52ff6SJohn Youn dr->daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); 404458e52ff6SJohn Youn dr->diepmsk = dwc2_readl(hsotg->regs + DIEPMSK); 404558e52ff6SJohn Youn dr->doepmsk = dwc2_readl(hsotg->regs + DOEPMSK); 404658e52ff6SJohn Youn 404758e52ff6SJohn Youn for (i = 0; i < hsotg->num_of_eps; i++) { 404858e52ff6SJohn Youn /* Backup IN EPs */ 404958e52ff6SJohn Youn dr->diepctl[i] = dwc2_readl(hsotg->regs + DIEPCTL(i)); 405058e52ff6SJohn Youn 405158e52ff6SJohn Youn /* Ensure DATA PID is correctly configured */ 405258e52ff6SJohn Youn if (dr->diepctl[i] & DXEPCTL_DPID) 405358e52ff6SJohn Youn dr->diepctl[i] |= DXEPCTL_SETD1PID; 405458e52ff6SJohn Youn else 405558e52ff6SJohn Youn dr->diepctl[i] |= DXEPCTL_SETD0PID; 405658e52ff6SJohn Youn 405758e52ff6SJohn Youn dr->dieptsiz[i] = dwc2_readl(hsotg->regs + DIEPTSIZ(i)); 405858e52ff6SJohn Youn dr->diepdma[i] = dwc2_readl(hsotg->regs + DIEPDMA(i)); 405958e52ff6SJohn Youn 406058e52ff6SJohn Youn /* Backup OUT EPs */ 406158e52ff6SJohn Youn dr->doepctl[i] = dwc2_readl(hsotg->regs + DOEPCTL(i)); 406258e52ff6SJohn Youn 406358e52ff6SJohn Youn /* Ensure DATA PID is correctly configured */ 406458e52ff6SJohn Youn if (dr->doepctl[i] & DXEPCTL_DPID) 406558e52ff6SJohn Youn dr->doepctl[i] |= DXEPCTL_SETD1PID; 406658e52ff6SJohn Youn else 406758e52ff6SJohn Youn dr->doepctl[i] |= DXEPCTL_SETD0PID; 406858e52ff6SJohn Youn 406958e52ff6SJohn Youn dr->doeptsiz[i] = dwc2_readl(hsotg->regs + DOEPTSIZ(i)); 407058e52ff6SJohn Youn dr->doepdma[i] = dwc2_readl(hsotg->regs + DOEPDMA(i)); 407158e52ff6SJohn Youn } 407258e52ff6SJohn Youn dr->valid = true; 407358e52ff6SJohn Youn return 0; 407458e52ff6SJohn Youn } 407558e52ff6SJohn Youn 407658e52ff6SJohn Youn /** 407758e52ff6SJohn Youn * dwc2_restore_device_registers() - Restore controller device registers. 407858e52ff6SJohn Youn * When resuming usb bus, device registers needs to be restored 407958e52ff6SJohn Youn * if controller power were disabled. 408058e52ff6SJohn Youn * 408158e52ff6SJohn Youn * @hsotg: Programming view of the DWC_otg controller 408258e52ff6SJohn Youn */ 408358e52ff6SJohn Youn int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg) 408458e52ff6SJohn Youn { 408558e52ff6SJohn Youn struct dwc2_dregs_backup *dr; 408658e52ff6SJohn Youn u32 dctl; 408758e52ff6SJohn Youn int i; 408858e52ff6SJohn Youn 408958e52ff6SJohn Youn dev_dbg(hsotg->dev, "%s\n", __func__); 409058e52ff6SJohn Youn 409158e52ff6SJohn Youn /* Restore dev regs */ 409258e52ff6SJohn Youn dr = &hsotg->dr_backup; 409358e52ff6SJohn Youn if (!dr->valid) { 409458e52ff6SJohn Youn dev_err(hsotg->dev, "%s: no device registers to restore\n", 409558e52ff6SJohn Youn __func__); 409658e52ff6SJohn Youn return -EINVAL; 409758e52ff6SJohn Youn } 409858e52ff6SJohn Youn dr->valid = false; 409958e52ff6SJohn Youn 410058e52ff6SJohn Youn dwc2_writel(dr->dcfg, hsotg->regs + DCFG); 410158e52ff6SJohn Youn dwc2_writel(dr->dctl, hsotg->regs + DCTL); 410258e52ff6SJohn Youn dwc2_writel(dr->daintmsk, hsotg->regs + DAINTMSK); 410358e52ff6SJohn Youn dwc2_writel(dr->diepmsk, hsotg->regs + DIEPMSK); 410458e52ff6SJohn Youn dwc2_writel(dr->doepmsk, hsotg->regs + DOEPMSK); 410558e52ff6SJohn Youn 410658e52ff6SJohn Youn for (i = 0; i < hsotg->num_of_eps; i++) { 410758e52ff6SJohn Youn /* Restore IN EPs */ 410858e52ff6SJohn Youn dwc2_writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i)); 410958e52ff6SJohn Youn dwc2_writel(dr->dieptsiz[i], hsotg->regs + DIEPTSIZ(i)); 411058e52ff6SJohn Youn dwc2_writel(dr->diepdma[i], hsotg->regs + DIEPDMA(i)); 411158e52ff6SJohn Youn 411258e52ff6SJohn Youn /* Restore OUT EPs */ 411358e52ff6SJohn Youn dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i)); 411458e52ff6SJohn Youn dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i)); 411558e52ff6SJohn Youn dwc2_writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i)); 411658e52ff6SJohn Youn } 411758e52ff6SJohn Youn 411858e52ff6SJohn Youn /* Set the Power-On Programming done bit */ 411958e52ff6SJohn Youn dctl = dwc2_readl(hsotg->regs + DCTL); 412058e52ff6SJohn Youn dctl |= DCTL_PWRONPRGDONE; 412158e52ff6SJohn Youn dwc2_writel(dctl, hsotg->regs + DCTL); 412258e52ff6SJohn Youn 412358e52ff6SJohn Youn return 0; 412458e52ff6SJohn Youn } 4125