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 { 96edd74be8SGregory Herrero return hsotg->g_using_dma; 9747a1685fSDinh Nguyen } 9847a1685fSDinh Nguyen 9947a1685fSDinh Nguyen /** 1001f91b4ccSFelipe Balbi * dwc2_hsotg_en_gsint - enable one or more of the general interrupt 10147a1685fSDinh Nguyen * @hsotg: The device state 10247a1685fSDinh Nguyen * @ints: A bitmask of the interrupts to enable 10347a1685fSDinh Nguyen */ 1041f91b4ccSFelipe Balbi static void dwc2_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints) 10547a1685fSDinh Nguyen { 10695c8bc36SAntti Seppälä u32 gsintmsk = dwc2_readl(hsotg->regs + GINTMSK); 10747a1685fSDinh Nguyen u32 new_gsintmsk; 10847a1685fSDinh Nguyen 10947a1685fSDinh Nguyen new_gsintmsk = gsintmsk | ints; 11047a1685fSDinh Nguyen 11147a1685fSDinh Nguyen if (new_gsintmsk != gsintmsk) { 11247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); 11395c8bc36SAntti Seppälä dwc2_writel(new_gsintmsk, hsotg->regs + GINTMSK); 11447a1685fSDinh Nguyen } 11547a1685fSDinh Nguyen } 11647a1685fSDinh Nguyen 11747a1685fSDinh Nguyen /** 1181f91b4ccSFelipe Balbi * dwc2_hsotg_disable_gsint - disable one or more of the general interrupt 11947a1685fSDinh Nguyen * @hsotg: The device state 12047a1685fSDinh Nguyen * @ints: A bitmask of the interrupts to enable 12147a1685fSDinh Nguyen */ 1221f91b4ccSFelipe Balbi static void dwc2_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints) 12347a1685fSDinh Nguyen { 12495c8bc36SAntti Seppälä u32 gsintmsk = dwc2_readl(hsotg->regs + GINTMSK); 12547a1685fSDinh Nguyen u32 new_gsintmsk; 12647a1685fSDinh Nguyen 12747a1685fSDinh Nguyen new_gsintmsk = gsintmsk & ~ints; 12847a1685fSDinh Nguyen 12947a1685fSDinh Nguyen if (new_gsintmsk != gsintmsk) 13095c8bc36SAntti Seppälä dwc2_writel(new_gsintmsk, hsotg->regs + GINTMSK); 13147a1685fSDinh Nguyen } 13247a1685fSDinh Nguyen 13347a1685fSDinh Nguyen /** 1341f91b4ccSFelipe Balbi * dwc2_hsotg_ctrl_epint - enable/disable an endpoint irq 13547a1685fSDinh Nguyen * @hsotg: The device state 13647a1685fSDinh Nguyen * @ep: The endpoint index 13747a1685fSDinh Nguyen * @dir_in: True if direction is in. 13847a1685fSDinh Nguyen * @en: The enable value, true to enable 13947a1685fSDinh Nguyen * 14047a1685fSDinh Nguyen * Set or clear the mask for an individual endpoint's interrupt 14147a1685fSDinh Nguyen * request. 14247a1685fSDinh Nguyen */ 1431f91b4ccSFelipe Balbi static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, 14447a1685fSDinh Nguyen unsigned int ep, unsigned int dir_in, 14547a1685fSDinh Nguyen unsigned int en) 14647a1685fSDinh Nguyen { 14747a1685fSDinh Nguyen unsigned long flags; 14847a1685fSDinh Nguyen u32 bit = 1 << ep; 14947a1685fSDinh Nguyen u32 daint; 15047a1685fSDinh Nguyen 15147a1685fSDinh Nguyen if (!dir_in) 15247a1685fSDinh Nguyen bit <<= 16; 15347a1685fSDinh Nguyen 15447a1685fSDinh Nguyen local_irq_save(flags); 15595c8bc36SAntti Seppälä daint = dwc2_readl(hsotg->regs + DAINTMSK); 15647a1685fSDinh Nguyen if (en) 15747a1685fSDinh Nguyen daint |= bit; 15847a1685fSDinh Nguyen else 15947a1685fSDinh Nguyen daint &= ~bit; 16095c8bc36SAntti Seppälä dwc2_writel(daint, hsotg->regs + DAINTMSK); 16147a1685fSDinh Nguyen local_irq_restore(flags); 16247a1685fSDinh Nguyen } 16347a1685fSDinh Nguyen 16447a1685fSDinh Nguyen /** 1651f91b4ccSFelipe Balbi * dwc2_hsotg_init_fifo - initialise non-periodic FIFOs 16647a1685fSDinh Nguyen * @hsotg: The device instance. 16747a1685fSDinh Nguyen */ 1681f91b4ccSFelipe Balbi static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) 16947a1685fSDinh Nguyen { 17047a1685fSDinh Nguyen unsigned int ep; 17147a1685fSDinh Nguyen unsigned int addr; 17247a1685fSDinh Nguyen int timeout; 17347a1685fSDinh Nguyen u32 val; 17447a1685fSDinh Nguyen 1757fcbc95cSGregory Herrero /* Reset fifo map if not correctly cleared during previous session */ 1767fcbc95cSGregory Herrero WARN_ON(hsotg->fifo_map); 1777fcbc95cSGregory Herrero hsotg->fifo_map = 0; 1787fcbc95cSGregory Herrero 1790a176279SGregory Herrero /* set RX/NPTX FIFO sizes */ 18095c8bc36SAntti Seppälä dwc2_writel(hsotg->g_rx_fifo_sz, hsotg->regs + GRXFSIZ); 18195c8bc36SAntti Seppälä dwc2_writel((hsotg->g_rx_fifo_sz << FIFOSIZE_STARTADDR_SHIFT) | 1820a176279SGregory Herrero (hsotg->g_np_g_tx_fifo_sz << FIFOSIZE_DEPTH_SHIFT), 1830a176279SGregory Herrero hsotg->regs + GNPTXFSIZ); 18447a1685fSDinh Nguyen 18547a1685fSDinh Nguyen /* 18647a1685fSDinh Nguyen * arange all the rest of the TX FIFOs, as some versions of this 18747a1685fSDinh Nguyen * block have overlapping default addresses. This also ensures 18847a1685fSDinh Nguyen * that if the settings have been changed, then they are set to 18947a1685fSDinh Nguyen * known values. 19047a1685fSDinh Nguyen */ 19147a1685fSDinh Nguyen 19247a1685fSDinh Nguyen /* start at the end of the GNPTXFSIZ, rounded up */ 1930a176279SGregory Herrero addr = hsotg->g_rx_fifo_sz + hsotg->g_np_g_tx_fifo_sz; 19447a1685fSDinh Nguyen 19547a1685fSDinh Nguyen /* 1960a176279SGregory Herrero * Configure fifos sizes from provided configuration and assign 197b203d0a2SRobert Baldyga * them to endpoints dynamically according to maxpacket size value of 198b203d0a2SRobert Baldyga * given endpoint. 19947a1685fSDinh Nguyen */ 2000a176279SGregory Herrero for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) { 2010a176279SGregory Herrero if (!hsotg->g_tx_fifo_sz[ep]) 2020a176279SGregory Herrero continue; 203b203d0a2SRobert Baldyga val = addr; 2040a176279SGregory Herrero val |= hsotg->g_tx_fifo_sz[ep] << FIFOSIZE_DEPTH_SHIFT; 2050a176279SGregory Herrero WARN_ONCE(addr + hsotg->g_tx_fifo_sz[ep] > hsotg->fifo_mem, 206b203d0a2SRobert Baldyga "insufficient fifo memory"); 2070a176279SGregory Herrero addr += hsotg->g_tx_fifo_sz[ep]; 20847a1685fSDinh Nguyen 20995c8bc36SAntti Seppälä dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep)); 21047a1685fSDinh Nguyen } 21147a1685fSDinh Nguyen 21247a1685fSDinh Nguyen /* 21347a1685fSDinh Nguyen * according to p428 of the design guide, we need to ensure that 21447a1685fSDinh Nguyen * all fifos are flushed before continuing 21547a1685fSDinh Nguyen */ 21647a1685fSDinh Nguyen 21795c8bc36SAntti Seppälä dwc2_writel(GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | 21847a1685fSDinh Nguyen GRSTCTL_RXFFLSH, hsotg->regs + GRSTCTL); 21947a1685fSDinh Nguyen 22047a1685fSDinh Nguyen /* wait until the fifos are both flushed */ 22147a1685fSDinh Nguyen timeout = 100; 22247a1685fSDinh Nguyen while (1) { 22395c8bc36SAntti Seppälä val = dwc2_readl(hsotg->regs + GRSTCTL); 22447a1685fSDinh Nguyen 22547a1685fSDinh Nguyen if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0) 22647a1685fSDinh Nguyen break; 22747a1685fSDinh Nguyen 22847a1685fSDinh Nguyen if (--timeout == 0) { 22947a1685fSDinh Nguyen dev_err(hsotg->dev, 23047a1685fSDinh Nguyen "%s: timeout flushing fifos (GRSTCTL=%08x)\n", 23147a1685fSDinh Nguyen __func__, val); 23248b20bcbSGregory Herrero break; 23347a1685fSDinh Nguyen } 23447a1685fSDinh Nguyen 23547a1685fSDinh Nguyen udelay(1); 23647a1685fSDinh Nguyen } 23747a1685fSDinh Nguyen 23847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); 23947a1685fSDinh Nguyen } 24047a1685fSDinh Nguyen 24147a1685fSDinh Nguyen /** 24247a1685fSDinh Nguyen * @ep: USB endpoint to allocate request for. 24347a1685fSDinh Nguyen * @flags: Allocation flags 24447a1685fSDinh Nguyen * 24547a1685fSDinh Nguyen * Allocate a new USB request structure appropriate for the specified endpoint 24647a1685fSDinh Nguyen */ 2471f91b4ccSFelipe Balbi static struct usb_request *dwc2_hsotg_ep_alloc_request(struct usb_ep *ep, 24847a1685fSDinh Nguyen gfp_t flags) 24947a1685fSDinh Nguyen { 2501f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req; 25147a1685fSDinh Nguyen 2521f91b4ccSFelipe Balbi req = kzalloc(sizeof(struct dwc2_hsotg_req), flags); 25347a1685fSDinh Nguyen if (!req) 25447a1685fSDinh Nguyen return NULL; 25547a1685fSDinh Nguyen 25647a1685fSDinh Nguyen INIT_LIST_HEAD(&req->queue); 25747a1685fSDinh Nguyen 25847a1685fSDinh Nguyen return &req->req; 25947a1685fSDinh Nguyen } 26047a1685fSDinh Nguyen 26147a1685fSDinh Nguyen /** 26247a1685fSDinh Nguyen * is_ep_periodic - return true if the endpoint is in periodic mode. 26347a1685fSDinh Nguyen * @hs_ep: The endpoint to query. 26447a1685fSDinh Nguyen * 26547a1685fSDinh Nguyen * Returns true if the endpoint is in periodic mode, meaning it is being 26647a1685fSDinh Nguyen * used for an Interrupt or ISO transfer. 26747a1685fSDinh Nguyen */ 2681f91b4ccSFelipe Balbi static inline int is_ep_periodic(struct dwc2_hsotg_ep *hs_ep) 26947a1685fSDinh Nguyen { 27047a1685fSDinh Nguyen return hs_ep->periodic; 27147a1685fSDinh Nguyen } 27247a1685fSDinh Nguyen 27347a1685fSDinh Nguyen /** 2741f91b4ccSFelipe Balbi * dwc2_hsotg_unmap_dma - unmap the DMA memory being used for the request 27547a1685fSDinh Nguyen * @hsotg: The device state. 27647a1685fSDinh Nguyen * @hs_ep: The endpoint for the request 27747a1685fSDinh Nguyen * @hs_req: The request being processed. 27847a1685fSDinh Nguyen * 2791f91b4ccSFelipe Balbi * This is the reverse of dwc2_hsotg_map_dma(), called for the completion 28047a1685fSDinh Nguyen * of a request to ensure the buffer is ready for access by the caller. 28147a1685fSDinh Nguyen */ 2821f91b4ccSFelipe Balbi static void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg, 2831f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 2841f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req) 28547a1685fSDinh Nguyen { 28647a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 28747a1685fSDinh Nguyen 28847a1685fSDinh Nguyen /* ignore this if we're not moving any data */ 28947a1685fSDinh Nguyen if (hs_req->req.length == 0) 29047a1685fSDinh Nguyen return; 29147a1685fSDinh Nguyen 29247a1685fSDinh Nguyen usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); 29347a1685fSDinh Nguyen } 29447a1685fSDinh Nguyen 29547a1685fSDinh Nguyen /** 2961f91b4ccSFelipe Balbi * dwc2_hsotg_write_fifo - write packet Data to the TxFIFO 29747a1685fSDinh Nguyen * @hsotg: The controller state. 29847a1685fSDinh Nguyen * @hs_ep: The endpoint we're going to write for. 29947a1685fSDinh Nguyen * @hs_req: The request to write data for. 30047a1685fSDinh Nguyen * 30147a1685fSDinh Nguyen * This is called when the TxFIFO has some space in it to hold a new 30247a1685fSDinh Nguyen * transmission and we have something to give it. The actual setup of 30347a1685fSDinh Nguyen * the data size is done elsewhere, so all we have to do is to actually 30447a1685fSDinh Nguyen * write the data. 30547a1685fSDinh Nguyen * 30647a1685fSDinh Nguyen * The return value is zero if there is more space (or nothing was done) 30747a1685fSDinh Nguyen * otherwise -ENOSPC is returned if the FIFO space was used up. 30847a1685fSDinh Nguyen * 30947a1685fSDinh Nguyen * This routine is only needed for PIO 31047a1685fSDinh Nguyen */ 3111f91b4ccSFelipe Balbi static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, 3121f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 3131f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req) 31447a1685fSDinh Nguyen { 31547a1685fSDinh Nguyen bool periodic = is_ep_periodic(hs_ep); 31695c8bc36SAntti Seppälä u32 gnptxsts = dwc2_readl(hsotg->regs + GNPTXSTS); 31747a1685fSDinh Nguyen int buf_pos = hs_req->req.actual; 31847a1685fSDinh Nguyen int to_write = hs_ep->size_loaded; 31947a1685fSDinh Nguyen void *data; 32047a1685fSDinh Nguyen int can_write; 32147a1685fSDinh Nguyen int pkt_round; 32247a1685fSDinh Nguyen int max_transfer; 32347a1685fSDinh Nguyen 32447a1685fSDinh Nguyen to_write -= (buf_pos - hs_ep->last_load); 32547a1685fSDinh Nguyen 32647a1685fSDinh Nguyen /* if there's nothing to write, get out early */ 32747a1685fSDinh Nguyen if (to_write == 0) 32847a1685fSDinh Nguyen return 0; 32947a1685fSDinh Nguyen 33047a1685fSDinh Nguyen if (periodic && !hsotg->dedicated_fifos) { 33195c8bc36SAntti Seppälä u32 epsize = dwc2_readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); 33247a1685fSDinh Nguyen int size_left; 33347a1685fSDinh Nguyen int size_done; 33447a1685fSDinh Nguyen 33547a1685fSDinh Nguyen /* 33647a1685fSDinh Nguyen * work out how much data was loaded so we can calculate 33747a1685fSDinh Nguyen * how much data is left in the fifo. 33847a1685fSDinh Nguyen */ 33947a1685fSDinh Nguyen 34047a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 34147a1685fSDinh Nguyen 34247a1685fSDinh Nguyen /* 34347a1685fSDinh Nguyen * if shared fifo, we cannot write anything until the 34447a1685fSDinh Nguyen * previous data has been completely sent. 34547a1685fSDinh Nguyen */ 34647a1685fSDinh Nguyen if (hs_ep->fifo_load != 0) { 3471f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 34847a1685fSDinh Nguyen return -ENOSPC; 34947a1685fSDinh Nguyen } 35047a1685fSDinh Nguyen 35147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", 35247a1685fSDinh Nguyen __func__, size_left, 35347a1685fSDinh Nguyen hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); 35447a1685fSDinh Nguyen 35547a1685fSDinh Nguyen /* how much of the data has moved */ 35647a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 35747a1685fSDinh Nguyen 35847a1685fSDinh Nguyen /* how much data is left in the fifo */ 35947a1685fSDinh Nguyen can_write = hs_ep->fifo_load - size_done; 36047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", 36147a1685fSDinh Nguyen __func__, can_write); 36247a1685fSDinh Nguyen 36347a1685fSDinh Nguyen can_write = hs_ep->fifo_size - can_write; 36447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", 36547a1685fSDinh Nguyen __func__, can_write); 36647a1685fSDinh Nguyen 36747a1685fSDinh Nguyen if (can_write <= 0) { 3681f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 36947a1685fSDinh Nguyen return -ENOSPC; 37047a1685fSDinh Nguyen } 37147a1685fSDinh Nguyen } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { 37295c8bc36SAntti Seppälä can_write = dwc2_readl(hsotg->regs + DTXFSTS(hs_ep->index)); 37347a1685fSDinh Nguyen 37447a1685fSDinh Nguyen can_write &= 0xffff; 37547a1685fSDinh Nguyen can_write *= 4; 37647a1685fSDinh Nguyen } else { 37747a1685fSDinh Nguyen if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) { 37847a1685fSDinh Nguyen dev_dbg(hsotg->dev, 37947a1685fSDinh Nguyen "%s: no queue slots available (0x%08x)\n", 38047a1685fSDinh Nguyen __func__, gnptxsts); 38147a1685fSDinh Nguyen 3821f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP); 38347a1685fSDinh Nguyen return -ENOSPC; 38447a1685fSDinh Nguyen } 38547a1685fSDinh Nguyen 38647a1685fSDinh Nguyen can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts); 38747a1685fSDinh Nguyen can_write *= 4; /* fifo size is in 32bit quantities. */ 38847a1685fSDinh Nguyen } 38947a1685fSDinh Nguyen 39047a1685fSDinh Nguyen max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; 39147a1685fSDinh Nguyen 39247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", 39347a1685fSDinh Nguyen __func__, gnptxsts, can_write, to_write, max_transfer); 39447a1685fSDinh Nguyen 39547a1685fSDinh Nguyen /* 39647a1685fSDinh Nguyen * limit to 512 bytes of data, it seems at least on the non-periodic 39747a1685fSDinh Nguyen * FIFO, requests of >512 cause the endpoint to get stuck with a 39847a1685fSDinh Nguyen * fragment of the end of the transfer in it. 39947a1685fSDinh Nguyen */ 40047a1685fSDinh Nguyen if (can_write > 512 && !periodic) 40147a1685fSDinh Nguyen can_write = 512; 40247a1685fSDinh Nguyen 40347a1685fSDinh Nguyen /* 40447a1685fSDinh Nguyen * limit the write to one max-packet size worth of data, but allow 40547a1685fSDinh Nguyen * the transfer to return that it did not run out of fifo space 40647a1685fSDinh Nguyen * doing it. 40747a1685fSDinh Nguyen */ 40847a1685fSDinh Nguyen if (to_write > max_transfer) { 40947a1685fSDinh Nguyen to_write = max_transfer; 41047a1685fSDinh Nguyen 41147a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 41247a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 4131f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, 41447a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 41547a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 41647a1685fSDinh Nguyen } 41747a1685fSDinh Nguyen 41847a1685fSDinh Nguyen /* see if we can write data */ 41947a1685fSDinh Nguyen 42047a1685fSDinh Nguyen if (to_write > can_write) { 42147a1685fSDinh Nguyen to_write = can_write; 42247a1685fSDinh Nguyen pkt_round = to_write % max_transfer; 42347a1685fSDinh Nguyen 42447a1685fSDinh Nguyen /* 42547a1685fSDinh Nguyen * Round the write down to an 42647a1685fSDinh Nguyen * exact number of packets. 42747a1685fSDinh Nguyen * 42847a1685fSDinh Nguyen * Note, we do not currently check to see if we can ever 42947a1685fSDinh Nguyen * write a full packet or not to the FIFO. 43047a1685fSDinh Nguyen */ 43147a1685fSDinh Nguyen 43247a1685fSDinh Nguyen if (pkt_round) 43347a1685fSDinh Nguyen to_write -= pkt_round; 43447a1685fSDinh Nguyen 43547a1685fSDinh Nguyen /* 43647a1685fSDinh Nguyen * enable correct FIFO interrupt to alert us when there 43747a1685fSDinh Nguyen * is more room left. 43847a1685fSDinh Nguyen */ 43947a1685fSDinh Nguyen 44047a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 44147a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 4421f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, 44347a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 44447a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 44547a1685fSDinh Nguyen } 44647a1685fSDinh Nguyen 44747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", 44847a1685fSDinh Nguyen to_write, hs_req->req.length, can_write, buf_pos); 44947a1685fSDinh Nguyen 45047a1685fSDinh Nguyen if (to_write <= 0) 45147a1685fSDinh Nguyen return -ENOSPC; 45247a1685fSDinh Nguyen 45347a1685fSDinh Nguyen hs_req->req.actual = buf_pos + to_write; 45447a1685fSDinh Nguyen hs_ep->total_data += to_write; 45547a1685fSDinh Nguyen 45647a1685fSDinh Nguyen if (periodic) 45747a1685fSDinh Nguyen hs_ep->fifo_load += to_write; 45847a1685fSDinh Nguyen 45947a1685fSDinh Nguyen to_write = DIV_ROUND_UP(to_write, 4); 46047a1685fSDinh Nguyen data = hs_req->req.buf + buf_pos; 46147a1685fSDinh Nguyen 46247a1685fSDinh Nguyen iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); 46347a1685fSDinh Nguyen 46447a1685fSDinh Nguyen return (to_write >= can_write) ? -ENOSPC : 0; 46547a1685fSDinh Nguyen } 46647a1685fSDinh Nguyen 46747a1685fSDinh Nguyen /** 46847a1685fSDinh Nguyen * get_ep_limit - get the maximum data legnth for this endpoint 46947a1685fSDinh Nguyen * @hs_ep: The endpoint 47047a1685fSDinh Nguyen * 47147a1685fSDinh Nguyen * Return the maximum data that can be queued in one go on a given endpoint 47247a1685fSDinh Nguyen * so that transfers that are too long can be split. 47347a1685fSDinh Nguyen */ 4741f91b4ccSFelipe Balbi static unsigned get_ep_limit(struct dwc2_hsotg_ep *hs_ep) 47547a1685fSDinh Nguyen { 47647a1685fSDinh Nguyen int index = hs_ep->index; 47747a1685fSDinh Nguyen unsigned maxsize; 47847a1685fSDinh Nguyen unsigned maxpkt; 47947a1685fSDinh Nguyen 48047a1685fSDinh Nguyen if (index != 0) { 48147a1685fSDinh Nguyen maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; 48247a1685fSDinh Nguyen maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; 48347a1685fSDinh Nguyen } else { 48447a1685fSDinh Nguyen maxsize = 64+64; 48547a1685fSDinh Nguyen if (hs_ep->dir_in) 48647a1685fSDinh Nguyen maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; 48747a1685fSDinh Nguyen else 48847a1685fSDinh Nguyen maxpkt = 2; 48947a1685fSDinh Nguyen } 49047a1685fSDinh Nguyen 49147a1685fSDinh Nguyen /* we made the constant loading easier above by using +1 */ 49247a1685fSDinh Nguyen maxpkt--; 49347a1685fSDinh Nguyen maxsize--; 49447a1685fSDinh Nguyen 49547a1685fSDinh Nguyen /* 49647a1685fSDinh Nguyen * constrain by packet count if maxpkts*pktsize is greater 49747a1685fSDinh Nguyen * than the length register size. 49847a1685fSDinh Nguyen */ 49947a1685fSDinh Nguyen 50047a1685fSDinh Nguyen if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) 50147a1685fSDinh Nguyen maxsize = maxpkt * hs_ep->ep.maxpacket; 50247a1685fSDinh Nguyen 50347a1685fSDinh Nguyen return maxsize; 50447a1685fSDinh Nguyen } 50547a1685fSDinh Nguyen 50647a1685fSDinh Nguyen /** 5071f91b4ccSFelipe Balbi * dwc2_hsotg_start_req - start a USB request from an endpoint's queue 50847a1685fSDinh Nguyen * @hsotg: The controller state. 50947a1685fSDinh Nguyen * @hs_ep: The endpoint to process a request for 51047a1685fSDinh Nguyen * @hs_req: The request to start. 51147a1685fSDinh Nguyen * @continuing: True if we are doing more for the current request. 51247a1685fSDinh Nguyen * 51347a1685fSDinh Nguyen * Start the given request running by setting the endpoint registers 51447a1685fSDinh Nguyen * appropriately, and writing any data to the FIFOs. 51547a1685fSDinh Nguyen */ 5161f91b4ccSFelipe Balbi static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, 5171f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 5181f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req, 51947a1685fSDinh Nguyen bool continuing) 52047a1685fSDinh Nguyen { 52147a1685fSDinh Nguyen struct usb_request *ureq = &hs_req->req; 52247a1685fSDinh Nguyen int index = hs_ep->index; 52347a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 52447a1685fSDinh Nguyen u32 epctrl_reg; 52547a1685fSDinh Nguyen u32 epsize_reg; 52647a1685fSDinh Nguyen u32 epsize; 52747a1685fSDinh Nguyen u32 ctrl; 52847a1685fSDinh Nguyen unsigned length; 52947a1685fSDinh Nguyen unsigned packets; 53047a1685fSDinh Nguyen unsigned maxreq; 53147a1685fSDinh Nguyen 53247a1685fSDinh Nguyen if (index != 0) { 53347a1685fSDinh Nguyen if (hs_ep->req && !continuing) { 53447a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: active request\n", __func__); 53547a1685fSDinh Nguyen WARN_ON(1); 53647a1685fSDinh Nguyen return; 53747a1685fSDinh Nguyen } else if (hs_ep->req != hs_req && continuing) { 53847a1685fSDinh Nguyen dev_err(hsotg->dev, 53947a1685fSDinh Nguyen "%s: continue different req\n", __func__); 54047a1685fSDinh Nguyen WARN_ON(1); 54147a1685fSDinh Nguyen return; 54247a1685fSDinh Nguyen } 54347a1685fSDinh Nguyen } 54447a1685fSDinh Nguyen 54547a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 54647a1685fSDinh Nguyen epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 54747a1685fSDinh Nguyen 54847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", 54995c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctrl_reg), index, 55047a1685fSDinh Nguyen hs_ep->dir_in ? "in" : "out"); 55147a1685fSDinh Nguyen 55247a1685fSDinh Nguyen /* If endpoint is stalled, we will restart request later */ 55395c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctrl_reg); 55447a1685fSDinh Nguyen 555b2d4c54eSMian Yousaf Kaukab if (index && ctrl & DXEPCTL_STALL) { 55647a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); 55747a1685fSDinh Nguyen return; 55847a1685fSDinh Nguyen } 55947a1685fSDinh Nguyen 56047a1685fSDinh Nguyen length = ureq->length - ureq->actual; 56147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", 56247a1685fSDinh Nguyen ureq->length, ureq->actual); 56347a1685fSDinh Nguyen 56447a1685fSDinh Nguyen maxreq = get_ep_limit(hs_ep); 56547a1685fSDinh Nguyen if (length > maxreq) { 56647a1685fSDinh Nguyen int round = maxreq % hs_ep->ep.maxpacket; 56747a1685fSDinh Nguyen 56847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", 56947a1685fSDinh Nguyen __func__, length, maxreq, round); 57047a1685fSDinh Nguyen 57147a1685fSDinh Nguyen /* round down to multiple of packets */ 57247a1685fSDinh Nguyen if (round) 57347a1685fSDinh Nguyen maxreq -= round; 57447a1685fSDinh Nguyen 57547a1685fSDinh Nguyen length = maxreq; 57647a1685fSDinh Nguyen } 57747a1685fSDinh Nguyen 57847a1685fSDinh Nguyen if (length) 57947a1685fSDinh Nguyen packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); 58047a1685fSDinh Nguyen else 58147a1685fSDinh Nguyen packets = 1; /* send one packet if length is zero. */ 58247a1685fSDinh Nguyen 58347a1685fSDinh Nguyen if (hs_ep->isochronous && length > (hs_ep->mc * hs_ep->ep.maxpacket)) { 58447a1685fSDinh Nguyen dev_err(hsotg->dev, "req length > maxpacket*mc\n"); 58547a1685fSDinh Nguyen return; 58647a1685fSDinh Nguyen } 58747a1685fSDinh Nguyen 58847a1685fSDinh Nguyen if (dir_in && index != 0) 58947a1685fSDinh Nguyen if (hs_ep->isochronous) 59047a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(packets); 59147a1685fSDinh Nguyen else 59247a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(1); 59347a1685fSDinh Nguyen else 59447a1685fSDinh Nguyen epsize = 0; 59547a1685fSDinh Nguyen 59647a1685fSDinh Nguyen /* 597f71b5e25SMian Yousaf Kaukab * zero length packet should be programmed on its own and should not 598f71b5e25SMian Yousaf Kaukab * be counted in DIEPTSIZ.PktCnt with other packets. 59947a1685fSDinh Nguyen */ 600f71b5e25SMian Yousaf Kaukab if (dir_in && ureq->zero && !continuing) { 601f71b5e25SMian Yousaf Kaukab /* Test if zlp is actually required. */ 602f71b5e25SMian Yousaf Kaukab if ((ureq->length >= hs_ep->ep.maxpacket) && 603f71b5e25SMian Yousaf Kaukab !(ureq->length % hs_ep->ep.maxpacket)) 6048a20fa45SMian Yousaf Kaukab hs_ep->send_zlp = 1; 60547a1685fSDinh Nguyen } 60647a1685fSDinh Nguyen 60747a1685fSDinh Nguyen epsize |= DXEPTSIZ_PKTCNT(packets); 60847a1685fSDinh Nguyen epsize |= DXEPTSIZ_XFERSIZE(length); 60947a1685fSDinh Nguyen 61047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", 61147a1685fSDinh Nguyen __func__, packets, length, ureq->length, epsize, epsize_reg); 61247a1685fSDinh Nguyen 61347a1685fSDinh Nguyen /* store the request as the current one we're doing */ 61447a1685fSDinh Nguyen hs_ep->req = hs_req; 61547a1685fSDinh Nguyen 61647a1685fSDinh Nguyen /* write size / packets */ 61795c8bc36SAntti Seppälä dwc2_writel(epsize, hsotg->regs + epsize_reg); 61847a1685fSDinh Nguyen 61947a1685fSDinh Nguyen if (using_dma(hsotg) && !continuing) { 62047a1685fSDinh Nguyen unsigned int dma_reg; 62147a1685fSDinh Nguyen 62247a1685fSDinh Nguyen /* 62347a1685fSDinh Nguyen * write DMA address to control register, buffer already 6241f91b4ccSFelipe Balbi * synced by dwc2_hsotg_ep_queue(). 62547a1685fSDinh Nguyen */ 62647a1685fSDinh Nguyen 62747a1685fSDinh Nguyen dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); 62895c8bc36SAntti Seppälä dwc2_writel(ureq->dma, hsotg->regs + dma_reg); 62947a1685fSDinh Nguyen 6300cc4cf6fSFabio Estevam dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n", 63147a1685fSDinh Nguyen __func__, &ureq->dma, dma_reg); 63247a1685fSDinh Nguyen } 63347a1685fSDinh Nguyen 63447a1685fSDinh Nguyen ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 63547a1685fSDinh Nguyen ctrl |= DXEPCTL_USBACTEP; 63647a1685fSDinh Nguyen 637fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state); 63847a1685fSDinh Nguyen 63947a1685fSDinh Nguyen /* For Setup request do not clear NAK */ 640fe0b94abSMian Yousaf Kaukab if (!(index == 0 && hsotg->ep0_state == DWC2_EP0_SETUP)) 64147a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 64247a1685fSDinh Nguyen 64347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 64495c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + epctrl_reg); 64547a1685fSDinh Nguyen 64647a1685fSDinh Nguyen /* 64747a1685fSDinh Nguyen * set these, it seems that DMA support increments past the end 64847a1685fSDinh Nguyen * of the packet buffer so we need to calculate the length from 64947a1685fSDinh Nguyen * this information. 65047a1685fSDinh Nguyen */ 65147a1685fSDinh Nguyen hs_ep->size_loaded = length; 65247a1685fSDinh Nguyen hs_ep->last_load = ureq->actual; 65347a1685fSDinh Nguyen 65447a1685fSDinh Nguyen if (dir_in && !using_dma(hsotg)) { 65547a1685fSDinh Nguyen /* set these anyway, we may need them for non-periodic in */ 65647a1685fSDinh Nguyen hs_ep->fifo_load = 0; 65747a1685fSDinh Nguyen 6581f91b4ccSFelipe Balbi dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 65947a1685fSDinh Nguyen } 66047a1685fSDinh Nguyen 66147a1685fSDinh Nguyen /* 66247a1685fSDinh Nguyen * clear the INTknTXFEmpMsk when we start request, more as a aide 66347a1685fSDinh Nguyen * to debugging to see what is going on. 66447a1685fSDinh Nguyen */ 66547a1685fSDinh Nguyen if (dir_in) 66695c8bc36SAntti Seppälä dwc2_writel(DIEPMSK_INTKNTXFEMPMSK, 66747a1685fSDinh Nguyen hsotg->regs + DIEPINT(index)); 66847a1685fSDinh Nguyen 66947a1685fSDinh Nguyen /* 67047a1685fSDinh Nguyen * Note, trying to clear the NAK here causes problems with transmit 67147a1685fSDinh Nguyen * on the S3C6400 ending up with the TXFIFO becoming full. 67247a1685fSDinh Nguyen */ 67347a1685fSDinh Nguyen 67447a1685fSDinh Nguyen /* check ep is enabled */ 67595c8bc36SAntti Seppälä if (!(dwc2_readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA)) 6761a0ed863SMian Yousaf Kaukab dev_dbg(hsotg->dev, 67747a1685fSDinh Nguyen "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", 67895c8bc36SAntti Seppälä index, dwc2_readl(hsotg->regs + epctrl_reg)); 67947a1685fSDinh Nguyen 68047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", 68195c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctrl_reg)); 68247a1685fSDinh Nguyen 68347a1685fSDinh Nguyen /* enable ep interrupts */ 6841f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1); 68547a1685fSDinh Nguyen } 68647a1685fSDinh Nguyen 68747a1685fSDinh Nguyen /** 6881f91b4ccSFelipe Balbi * dwc2_hsotg_map_dma - map the DMA memory being used for the request 68947a1685fSDinh Nguyen * @hsotg: The device state. 69047a1685fSDinh Nguyen * @hs_ep: The endpoint the request is on. 69147a1685fSDinh Nguyen * @req: The request being processed. 69247a1685fSDinh Nguyen * 69347a1685fSDinh Nguyen * We've been asked to queue a request, so ensure that the memory buffer 69447a1685fSDinh Nguyen * is correctly setup for DMA. If we've been passed an extant DMA address 69547a1685fSDinh Nguyen * then ensure the buffer has been synced to memory. If our buffer has no 69647a1685fSDinh Nguyen * DMA memory, then we map the memory and mark our request to allow us to 69747a1685fSDinh Nguyen * cleanup on completion. 69847a1685fSDinh Nguyen */ 6991f91b4ccSFelipe Balbi static int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg, 7001f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 70147a1685fSDinh Nguyen struct usb_request *req) 70247a1685fSDinh Nguyen { 7031f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 70447a1685fSDinh Nguyen int ret; 70547a1685fSDinh Nguyen 70647a1685fSDinh Nguyen /* if the length is zero, ignore the DMA data */ 70747a1685fSDinh Nguyen if (hs_req->req.length == 0) 70847a1685fSDinh Nguyen return 0; 70947a1685fSDinh Nguyen 71047a1685fSDinh Nguyen ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); 71147a1685fSDinh Nguyen if (ret) 71247a1685fSDinh Nguyen goto dma_error; 71347a1685fSDinh Nguyen 71447a1685fSDinh Nguyen return 0; 71547a1685fSDinh Nguyen 71647a1685fSDinh Nguyen dma_error: 71747a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", 71847a1685fSDinh Nguyen __func__, req->buf, req->length); 71947a1685fSDinh Nguyen 72047a1685fSDinh Nguyen return -EIO; 72147a1685fSDinh Nguyen } 72247a1685fSDinh Nguyen 7231f91b4ccSFelipe Balbi static int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, 7241f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) 7257d24c1b5SMian Yousaf Kaukab { 7267d24c1b5SMian Yousaf Kaukab void *req_buf = hs_req->req.buf; 7277d24c1b5SMian Yousaf Kaukab 7287d24c1b5SMian Yousaf Kaukab /* If dma is not being used or buffer is aligned */ 7297d24c1b5SMian Yousaf Kaukab if (!using_dma(hsotg) || !((long)req_buf & 3)) 7307d24c1b5SMian Yousaf Kaukab return 0; 7317d24c1b5SMian Yousaf Kaukab 7327d24c1b5SMian Yousaf Kaukab WARN_ON(hs_req->saved_req_buf); 7337d24c1b5SMian Yousaf Kaukab 7347d24c1b5SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__, 7357d24c1b5SMian Yousaf Kaukab hs_ep->ep.name, req_buf, hs_req->req.length); 7367d24c1b5SMian Yousaf Kaukab 7377d24c1b5SMian Yousaf Kaukab hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC); 7387d24c1b5SMian Yousaf Kaukab if (!hs_req->req.buf) { 7397d24c1b5SMian Yousaf Kaukab hs_req->req.buf = req_buf; 7407d24c1b5SMian Yousaf Kaukab dev_err(hsotg->dev, 7417d24c1b5SMian Yousaf Kaukab "%s: unable to allocate memory for bounce buffer\n", 7427d24c1b5SMian Yousaf Kaukab __func__); 7437d24c1b5SMian Yousaf Kaukab return -ENOMEM; 7447d24c1b5SMian Yousaf Kaukab } 7457d24c1b5SMian Yousaf Kaukab 7467d24c1b5SMian Yousaf Kaukab /* Save actual buffer */ 7477d24c1b5SMian Yousaf Kaukab hs_req->saved_req_buf = req_buf; 7487d24c1b5SMian Yousaf Kaukab 7497d24c1b5SMian Yousaf Kaukab if (hs_ep->dir_in) 7507d24c1b5SMian Yousaf Kaukab memcpy(hs_req->req.buf, req_buf, hs_req->req.length); 7517d24c1b5SMian Yousaf Kaukab return 0; 7527d24c1b5SMian Yousaf Kaukab } 7537d24c1b5SMian Yousaf Kaukab 7541f91b4ccSFelipe Balbi static void dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, 7551f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) 7567d24c1b5SMian Yousaf Kaukab { 7577d24c1b5SMian Yousaf Kaukab /* If dma is not being used or buffer was aligned */ 7587d24c1b5SMian Yousaf Kaukab if (!using_dma(hsotg) || !hs_req->saved_req_buf) 7597d24c1b5SMian Yousaf Kaukab return; 7607d24c1b5SMian Yousaf Kaukab 7617d24c1b5SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: %s: status=%d actual-length=%d\n", __func__, 7627d24c1b5SMian Yousaf Kaukab hs_ep->ep.name, hs_req->req.status, hs_req->req.actual); 7637d24c1b5SMian Yousaf Kaukab 7647d24c1b5SMian Yousaf Kaukab /* Copy data from bounce buffer on successful out transfer */ 7657d24c1b5SMian Yousaf Kaukab if (!hs_ep->dir_in && !hs_req->req.status) 7667d24c1b5SMian Yousaf Kaukab memcpy(hs_req->saved_req_buf, hs_req->req.buf, 7677d24c1b5SMian Yousaf Kaukab hs_req->req.actual); 7687d24c1b5SMian Yousaf Kaukab 7697d24c1b5SMian Yousaf Kaukab /* Free bounce buffer */ 7707d24c1b5SMian Yousaf Kaukab kfree(hs_req->req.buf); 7717d24c1b5SMian Yousaf Kaukab 7727d24c1b5SMian Yousaf Kaukab hs_req->req.buf = hs_req->saved_req_buf; 7737d24c1b5SMian Yousaf Kaukab hs_req->saved_req_buf = NULL; 7747d24c1b5SMian Yousaf Kaukab } 7757d24c1b5SMian Yousaf Kaukab 7761f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, 77747a1685fSDinh Nguyen gfp_t gfp_flags) 77847a1685fSDinh Nguyen { 7791f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 7801f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 781941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 78247a1685fSDinh Nguyen bool first; 7837d24c1b5SMian Yousaf Kaukab int ret; 78447a1685fSDinh Nguyen 78547a1685fSDinh Nguyen dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", 78647a1685fSDinh Nguyen ep->name, req, req->length, req->buf, req->no_interrupt, 78747a1685fSDinh Nguyen req->zero, req->short_not_ok); 78847a1685fSDinh Nguyen 7897ababa92SGregory Herrero /* Prevent new request submission when controller is suspended */ 7907ababa92SGregory Herrero if (hs->lx_state == DWC2_L2) { 7917ababa92SGregory Herrero dev_dbg(hs->dev, "%s: don't submit request while suspended\n", 7927ababa92SGregory Herrero __func__); 7937ababa92SGregory Herrero return -EAGAIN; 7947ababa92SGregory Herrero } 7957ababa92SGregory Herrero 79647a1685fSDinh Nguyen /* initialise status of the request */ 79747a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_req->queue); 79847a1685fSDinh Nguyen req->actual = 0; 79947a1685fSDinh Nguyen req->status = -EINPROGRESS; 80047a1685fSDinh Nguyen 8011f91b4ccSFelipe Balbi ret = dwc2_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req); 8027d24c1b5SMian Yousaf Kaukab if (ret) 8037d24c1b5SMian Yousaf Kaukab return ret; 8047d24c1b5SMian Yousaf Kaukab 80547a1685fSDinh Nguyen /* if we're using DMA, sync the buffers as necessary */ 80647a1685fSDinh Nguyen if (using_dma(hs)) { 8071f91b4ccSFelipe Balbi ret = dwc2_hsotg_map_dma(hs, hs_ep, req); 80847a1685fSDinh Nguyen if (ret) 80947a1685fSDinh Nguyen return ret; 81047a1685fSDinh Nguyen } 81147a1685fSDinh Nguyen 81247a1685fSDinh Nguyen first = list_empty(&hs_ep->queue); 81347a1685fSDinh Nguyen list_add_tail(&hs_req->queue, &hs_ep->queue); 81447a1685fSDinh Nguyen 81547a1685fSDinh Nguyen if (first) 8161f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 81747a1685fSDinh Nguyen 81847a1685fSDinh Nguyen return 0; 81947a1685fSDinh Nguyen } 82047a1685fSDinh Nguyen 8211f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, 82247a1685fSDinh Nguyen gfp_t gfp_flags) 82347a1685fSDinh Nguyen { 8241f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 825941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 82647a1685fSDinh Nguyen unsigned long flags = 0; 82747a1685fSDinh Nguyen int ret = 0; 82847a1685fSDinh Nguyen 82947a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 8301f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(ep, req, gfp_flags); 83147a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 83247a1685fSDinh Nguyen 83347a1685fSDinh Nguyen return ret; 83447a1685fSDinh Nguyen } 83547a1685fSDinh Nguyen 8361f91b4ccSFelipe Balbi static void dwc2_hsotg_ep_free_request(struct usb_ep *ep, 83747a1685fSDinh Nguyen struct usb_request *req) 83847a1685fSDinh Nguyen { 8391f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 84047a1685fSDinh Nguyen 84147a1685fSDinh Nguyen kfree(hs_req); 84247a1685fSDinh Nguyen } 84347a1685fSDinh Nguyen 84447a1685fSDinh Nguyen /** 8451f91b4ccSFelipe Balbi * dwc2_hsotg_complete_oursetup - setup completion callback 84647a1685fSDinh Nguyen * @ep: The endpoint the request was on. 84747a1685fSDinh Nguyen * @req: The request completed. 84847a1685fSDinh Nguyen * 84947a1685fSDinh Nguyen * Called on completion of any requests the driver itself 85047a1685fSDinh Nguyen * submitted that need cleaning up. 85147a1685fSDinh Nguyen */ 8521f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_oursetup(struct usb_ep *ep, 85347a1685fSDinh Nguyen struct usb_request *req) 85447a1685fSDinh Nguyen { 8551f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 856941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 85747a1685fSDinh Nguyen 85847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); 85947a1685fSDinh Nguyen 8601f91b4ccSFelipe Balbi dwc2_hsotg_ep_free_request(ep, req); 86147a1685fSDinh Nguyen } 86247a1685fSDinh Nguyen 86347a1685fSDinh Nguyen /** 86447a1685fSDinh Nguyen * ep_from_windex - convert control wIndex value to endpoint 86547a1685fSDinh Nguyen * @hsotg: The driver state. 86647a1685fSDinh Nguyen * @windex: The control request wIndex field (in host order). 86747a1685fSDinh Nguyen * 86847a1685fSDinh Nguyen * Convert the given wIndex into a pointer to an driver endpoint 86947a1685fSDinh Nguyen * structure, or return NULL if it is not a valid endpoint. 87047a1685fSDinh Nguyen */ 8711f91b4ccSFelipe Balbi static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, 87247a1685fSDinh Nguyen u32 windex) 87347a1685fSDinh Nguyen { 8741f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 87547a1685fSDinh Nguyen int dir = (windex & USB_DIR_IN) ? 1 : 0; 87647a1685fSDinh Nguyen int idx = windex & 0x7F; 87747a1685fSDinh Nguyen 87847a1685fSDinh Nguyen if (windex >= 0x100) 87947a1685fSDinh Nguyen return NULL; 88047a1685fSDinh Nguyen 88147a1685fSDinh Nguyen if (idx > hsotg->num_of_eps) 88247a1685fSDinh Nguyen return NULL; 88347a1685fSDinh Nguyen 884c6f5c050SMian Yousaf Kaukab ep = index_to_ep(hsotg, idx, dir); 885c6f5c050SMian Yousaf Kaukab 88647a1685fSDinh Nguyen if (idx && ep->dir_in != dir) 88747a1685fSDinh Nguyen return NULL; 88847a1685fSDinh Nguyen 88947a1685fSDinh Nguyen return ep; 89047a1685fSDinh Nguyen } 89147a1685fSDinh Nguyen 89247a1685fSDinh Nguyen /** 8931f91b4ccSFelipe Balbi * dwc2_hsotg_set_test_mode - Enable usb Test Modes 8949e14d0a5SGregory Herrero * @hsotg: The driver state. 8959e14d0a5SGregory Herrero * @testmode: requested usb test mode 8969e14d0a5SGregory Herrero * Enable usb Test Mode requested by the Host. 8979e14d0a5SGregory Herrero */ 8981f91b4ccSFelipe Balbi int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode) 8999e14d0a5SGregory Herrero { 90095c8bc36SAntti Seppälä int dctl = dwc2_readl(hsotg->regs + DCTL); 9019e14d0a5SGregory Herrero 9029e14d0a5SGregory Herrero dctl &= ~DCTL_TSTCTL_MASK; 9039e14d0a5SGregory Herrero switch (testmode) { 9049e14d0a5SGregory Herrero case TEST_J: 9059e14d0a5SGregory Herrero case TEST_K: 9069e14d0a5SGregory Herrero case TEST_SE0_NAK: 9079e14d0a5SGregory Herrero case TEST_PACKET: 9089e14d0a5SGregory Herrero case TEST_FORCE_EN: 9099e14d0a5SGregory Herrero dctl |= testmode << DCTL_TSTCTL_SHIFT; 9109e14d0a5SGregory Herrero break; 9119e14d0a5SGregory Herrero default: 9129e14d0a5SGregory Herrero return -EINVAL; 9139e14d0a5SGregory Herrero } 91495c8bc36SAntti Seppälä dwc2_writel(dctl, hsotg->regs + DCTL); 9159e14d0a5SGregory Herrero return 0; 9169e14d0a5SGregory Herrero } 9179e14d0a5SGregory Herrero 9189e14d0a5SGregory Herrero /** 9191f91b4ccSFelipe Balbi * dwc2_hsotg_send_reply - send reply to control request 92047a1685fSDinh Nguyen * @hsotg: The device state 92147a1685fSDinh Nguyen * @ep: Endpoint 0 92247a1685fSDinh Nguyen * @buff: Buffer for request 92347a1685fSDinh Nguyen * @length: Length of reply. 92447a1685fSDinh Nguyen * 92547a1685fSDinh Nguyen * Create a request and queue it on the given endpoint. This is useful as 92647a1685fSDinh Nguyen * an internal method of sending replies to certain control requests, etc. 92747a1685fSDinh Nguyen */ 9281f91b4ccSFelipe Balbi static int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg, 9291f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep, 93047a1685fSDinh Nguyen void *buff, 93147a1685fSDinh Nguyen int length) 93247a1685fSDinh Nguyen { 93347a1685fSDinh Nguyen struct usb_request *req; 93447a1685fSDinh Nguyen int ret; 93547a1685fSDinh Nguyen 93647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); 93747a1685fSDinh Nguyen 9381f91b4ccSFelipe Balbi req = dwc2_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); 93947a1685fSDinh Nguyen hsotg->ep0_reply = req; 94047a1685fSDinh Nguyen if (!req) { 94147a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); 94247a1685fSDinh Nguyen return -ENOMEM; 94347a1685fSDinh Nguyen } 94447a1685fSDinh Nguyen 94547a1685fSDinh Nguyen req->buf = hsotg->ep0_buff; 94647a1685fSDinh Nguyen req->length = length; 947f71b5e25SMian Yousaf Kaukab /* 948f71b5e25SMian Yousaf Kaukab * zero flag is for sending zlp in DATA IN stage. It has no impact on 949f71b5e25SMian Yousaf Kaukab * STATUS stage. 950f71b5e25SMian Yousaf Kaukab */ 951f71b5e25SMian Yousaf Kaukab req->zero = 0; 9521f91b4ccSFelipe Balbi req->complete = dwc2_hsotg_complete_oursetup; 95347a1685fSDinh Nguyen 95447a1685fSDinh Nguyen if (length) 95547a1685fSDinh Nguyen memcpy(req->buf, buff, length); 95647a1685fSDinh Nguyen 9571f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); 95847a1685fSDinh Nguyen if (ret) { 95947a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); 96047a1685fSDinh Nguyen return ret; 96147a1685fSDinh Nguyen } 96247a1685fSDinh Nguyen 96347a1685fSDinh Nguyen return 0; 96447a1685fSDinh Nguyen } 96547a1685fSDinh Nguyen 96647a1685fSDinh Nguyen /** 9671f91b4ccSFelipe Balbi * dwc2_hsotg_process_req_status - process request GET_STATUS 96847a1685fSDinh Nguyen * @hsotg: The device state 96947a1685fSDinh Nguyen * @ctrl: USB control request 97047a1685fSDinh Nguyen */ 9711f91b4ccSFelipe Balbi static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, 97247a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 97347a1685fSDinh Nguyen { 9741f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 9751f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 97647a1685fSDinh Nguyen __le16 reply; 97747a1685fSDinh Nguyen int ret; 97847a1685fSDinh Nguyen 97947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); 98047a1685fSDinh Nguyen 98147a1685fSDinh Nguyen if (!ep0->dir_in) { 98247a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: direction out?\n", __func__); 98347a1685fSDinh Nguyen return -EINVAL; 98447a1685fSDinh Nguyen } 98547a1685fSDinh Nguyen 98647a1685fSDinh Nguyen switch (ctrl->bRequestType & USB_RECIP_MASK) { 98747a1685fSDinh Nguyen case USB_RECIP_DEVICE: 98847a1685fSDinh Nguyen reply = cpu_to_le16(0); /* bit 0 => self powered, 98947a1685fSDinh Nguyen * bit 1 => remote wakeup */ 99047a1685fSDinh Nguyen break; 99147a1685fSDinh Nguyen 99247a1685fSDinh Nguyen case USB_RECIP_INTERFACE: 99347a1685fSDinh Nguyen /* currently, the data result should be zero */ 99447a1685fSDinh Nguyen reply = cpu_to_le16(0); 99547a1685fSDinh Nguyen break; 99647a1685fSDinh Nguyen 99747a1685fSDinh Nguyen case USB_RECIP_ENDPOINT: 99847a1685fSDinh Nguyen ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); 99947a1685fSDinh Nguyen if (!ep) 100047a1685fSDinh Nguyen return -ENOENT; 100147a1685fSDinh Nguyen 100247a1685fSDinh Nguyen reply = cpu_to_le16(ep->halted ? 1 : 0); 100347a1685fSDinh Nguyen break; 100447a1685fSDinh Nguyen 100547a1685fSDinh Nguyen default: 100647a1685fSDinh Nguyen return 0; 100747a1685fSDinh Nguyen } 100847a1685fSDinh Nguyen 100947a1685fSDinh Nguyen if (le16_to_cpu(ctrl->wLength) != 2) 101047a1685fSDinh Nguyen return -EINVAL; 101147a1685fSDinh Nguyen 10121f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, &reply, 2); 101347a1685fSDinh Nguyen if (ret) { 101447a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); 101547a1685fSDinh Nguyen return ret; 101647a1685fSDinh Nguyen } 101747a1685fSDinh Nguyen 101847a1685fSDinh Nguyen return 1; 101947a1685fSDinh Nguyen } 102047a1685fSDinh Nguyen 10211f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value); 102247a1685fSDinh Nguyen 102347a1685fSDinh Nguyen /** 102447a1685fSDinh Nguyen * get_ep_head - return the first request on the endpoint 102547a1685fSDinh Nguyen * @hs_ep: The controller endpoint to get 102647a1685fSDinh Nguyen * 102747a1685fSDinh Nguyen * Get the first request on the endpoint. 102847a1685fSDinh Nguyen */ 10291f91b4ccSFelipe Balbi static struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep) 103047a1685fSDinh Nguyen { 103147a1685fSDinh Nguyen if (list_empty(&hs_ep->queue)) 103247a1685fSDinh Nguyen return NULL; 103347a1685fSDinh Nguyen 10341f91b4ccSFelipe Balbi return list_first_entry(&hs_ep->queue, struct dwc2_hsotg_req, queue); 103547a1685fSDinh Nguyen } 103647a1685fSDinh Nguyen 103747a1685fSDinh Nguyen /** 10381f91b4ccSFelipe Balbi * dwc2_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE 103947a1685fSDinh Nguyen * @hsotg: The device state 104047a1685fSDinh Nguyen * @ctrl: USB control request 104147a1685fSDinh Nguyen */ 10421f91b4ccSFelipe Balbi static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, 104347a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 104447a1685fSDinh Nguyen { 10451f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 10461f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req; 104747a1685fSDinh Nguyen bool restart; 104847a1685fSDinh Nguyen bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); 10491f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 105047a1685fSDinh Nguyen int ret; 105147a1685fSDinh Nguyen bool halted; 10529e14d0a5SGregory Herrero u32 recip; 10539e14d0a5SGregory Herrero u32 wValue; 10549e14d0a5SGregory Herrero u32 wIndex; 105547a1685fSDinh Nguyen 105647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", 105747a1685fSDinh Nguyen __func__, set ? "SET" : "CLEAR"); 105847a1685fSDinh Nguyen 10599e14d0a5SGregory Herrero wValue = le16_to_cpu(ctrl->wValue); 10609e14d0a5SGregory Herrero wIndex = le16_to_cpu(ctrl->wIndex); 10619e14d0a5SGregory Herrero recip = ctrl->bRequestType & USB_RECIP_MASK; 10629e14d0a5SGregory Herrero 10639e14d0a5SGregory Herrero switch (recip) { 10649e14d0a5SGregory Herrero case USB_RECIP_DEVICE: 10659e14d0a5SGregory Herrero switch (wValue) { 10669e14d0a5SGregory Herrero case USB_DEVICE_TEST_MODE: 10679e14d0a5SGregory Herrero if ((wIndex & 0xff) != 0) 10689e14d0a5SGregory Herrero return -EINVAL; 10699e14d0a5SGregory Herrero if (!set) 10709e14d0a5SGregory Herrero return -EINVAL; 10719e14d0a5SGregory Herrero 10729e14d0a5SGregory Herrero hsotg->test_mode = wIndex >> 8; 10731f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 10749e14d0a5SGregory Herrero if (ret) { 10759e14d0a5SGregory Herrero dev_err(hsotg->dev, 10769e14d0a5SGregory Herrero "%s: failed to send reply\n", __func__); 10779e14d0a5SGregory Herrero return ret; 10789e14d0a5SGregory Herrero } 10799e14d0a5SGregory Herrero break; 10809e14d0a5SGregory Herrero default: 10819e14d0a5SGregory Herrero return -ENOENT; 10829e14d0a5SGregory Herrero } 10839e14d0a5SGregory Herrero break; 10849e14d0a5SGregory Herrero 10859e14d0a5SGregory Herrero case USB_RECIP_ENDPOINT: 10869e14d0a5SGregory Herrero ep = ep_from_windex(hsotg, wIndex); 108747a1685fSDinh Nguyen if (!ep) { 108847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", 10899e14d0a5SGregory Herrero __func__, wIndex); 109047a1685fSDinh Nguyen return -ENOENT; 109147a1685fSDinh Nguyen } 109247a1685fSDinh Nguyen 10939e14d0a5SGregory Herrero switch (wValue) { 109447a1685fSDinh Nguyen case USB_ENDPOINT_HALT: 109547a1685fSDinh Nguyen halted = ep->halted; 109647a1685fSDinh Nguyen 10971f91b4ccSFelipe Balbi dwc2_hsotg_ep_sethalt(&ep->ep, set); 109847a1685fSDinh Nguyen 10991f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 110047a1685fSDinh Nguyen if (ret) { 110147a1685fSDinh Nguyen dev_err(hsotg->dev, 110247a1685fSDinh Nguyen "%s: failed to send reply\n", __func__); 110347a1685fSDinh Nguyen return ret; 110447a1685fSDinh Nguyen } 110547a1685fSDinh Nguyen 110647a1685fSDinh Nguyen /* 110747a1685fSDinh Nguyen * we have to complete all requests for ep if it was 110847a1685fSDinh Nguyen * halted, and the halt was cleared by CLEAR_FEATURE 110947a1685fSDinh Nguyen */ 111047a1685fSDinh Nguyen 111147a1685fSDinh Nguyen if (!set && halted) { 111247a1685fSDinh Nguyen /* 111347a1685fSDinh Nguyen * If we have request in progress, 111447a1685fSDinh Nguyen * then complete it 111547a1685fSDinh Nguyen */ 111647a1685fSDinh Nguyen if (ep->req) { 111747a1685fSDinh Nguyen hs_req = ep->req; 111847a1685fSDinh Nguyen ep->req = NULL; 111947a1685fSDinh Nguyen list_del_init(&hs_req->queue); 1120c00dd4a6SGregory Herrero if (hs_req->req.complete) { 1121c00dd4a6SGregory Herrero spin_unlock(&hsotg->lock); 1122c00dd4a6SGregory Herrero usb_gadget_giveback_request( 1123c00dd4a6SGregory Herrero &ep->ep, &hs_req->req); 1124c00dd4a6SGregory Herrero spin_lock(&hsotg->lock); 1125c00dd4a6SGregory Herrero } 112647a1685fSDinh Nguyen } 112747a1685fSDinh Nguyen 112847a1685fSDinh Nguyen /* If we have pending request, then start it */ 1129c00dd4a6SGregory Herrero if (!ep->req) { 113047a1685fSDinh Nguyen restart = !list_empty(&ep->queue); 113147a1685fSDinh Nguyen if (restart) { 113247a1685fSDinh Nguyen hs_req = get_ep_head(ep); 11331f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hsotg, ep, 113447a1685fSDinh Nguyen hs_req, false); 113547a1685fSDinh Nguyen } 113647a1685fSDinh Nguyen } 1137c00dd4a6SGregory Herrero } 113847a1685fSDinh Nguyen 113947a1685fSDinh Nguyen break; 114047a1685fSDinh Nguyen 114147a1685fSDinh Nguyen default: 114247a1685fSDinh Nguyen return -ENOENT; 114347a1685fSDinh Nguyen } 11449e14d0a5SGregory Herrero break; 11459e14d0a5SGregory Herrero default: 11469e14d0a5SGregory Herrero return -ENOENT; 11479e14d0a5SGregory Herrero } 114847a1685fSDinh Nguyen return 1; 114947a1685fSDinh Nguyen } 115047a1685fSDinh Nguyen 11511f91b4ccSFelipe Balbi static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg); 115247a1685fSDinh Nguyen 115347a1685fSDinh Nguyen /** 11541f91b4ccSFelipe Balbi * dwc2_hsotg_stall_ep0 - stall ep0 115547a1685fSDinh Nguyen * @hsotg: The device state 115647a1685fSDinh Nguyen * 115747a1685fSDinh Nguyen * Set stall for ep0 as response for setup request. 115847a1685fSDinh Nguyen */ 11591f91b4ccSFelipe Balbi static void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg) 1160e9ebe7c3SJingoo Han { 11611f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 116247a1685fSDinh Nguyen u32 reg; 116347a1685fSDinh Nguyen u32 ctrl; 116447a1685fSDinh Nguyen 116547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); 116647a1685fSDinh Nguyen reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; 116747a1685fSDinh Nguyen 116847a1685fSDinh Nguyen /* 116947a1685fSDinh Nguyen * DxEPCTL_Stall will be cleared by EP once it has 117047a1685fSDinh Nguyen * taken effect, so no need to clear later. 117147a1685fSDinh Nguyen */ 117247a1685fSDinh Nguyen 117395c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + reg); 117447a1685fSDinh Nguyen ctrl |= DXEPCTL_STALL; 117547a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; 117695c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + reg); 117747a1685fSDinh Nguyen 117847a1685fSDinh Nguyen dev_dbg(hsotg->dev, 117947a1685fSDinh Nguyen "written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n", 118095c8bc36SAntti Seppälä ctrl, reg, dwc2_readl(hsotg->regs + reg)); 118147a1685fSDinh Nguyen 118247a1685fSDinh Nguyen /* 118347a1685fSDinh Nguyen * complete won't be called, so we enqueue 118447a1685fSDinh Nguyen * setup request here 118547a1685fSDinh Nguyen */ 11861f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 118747a1685fSDinh Nguyen } 118847a1685fSDinh Nguyen 118947a1685fSDinh Nguyen /** 11901f91b4ccSFelipe Balbi * dwc2_hsotg_process_control - process a control request 119147a1685fSDinh Nguyen * @hsotg: The device state 119247a1685fSDinh Nguyen * @ctrl: The control request received 119347a1685fSDinh Nguyen * 119447a1685fSDinh Nguyen * The controller has received the SETUP phase of a control request, and 119547a1685fSDinh Nguyen * needs to work out what to do next (and whether to pass it on to the 119647a1685fSDinh Nguyen * gadget driver). 119747a1685fSDinh Nguyen */ 11981f91b4ccSFelipe Balbi static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, 119947a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 120047a1685fSDinh Nguyen { 12011f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 120247a1685fSDinh Nguyen int ret = 0; 120347a1685fSDinh Nguyen u32 dcfg; 120447a1685fSDinh Nguyen 1205e525e743SMian Yousaf Kaukab dev_dbg(hsotg->dev, 1206e525e743SMian Yousaf Kaukab "ctrl Type=%02x, Req=%02x, V=%04x, I=%04x, L=%04x\n", 1207e525e743SMian Yousaf Kaukab ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, 1208e525e743SMian Yousaf Kaukab ctrl->wIndex, ctrl->wLength); 120947a1685fSDinh Nguyen 1210fe0b94abSMian Yousaf Kaukab if (ctrl->wLength == 0) { 121147a1685fSDinh Nguyen ep0->dir_in = 1; 1212fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_STATUS_IN; 1213fe0b94abSMian Yousaf Kaukab } else if (ctrl->bRequestType & USB_DIR_IN) { 1214fe0b94abSMian Yousaf Kaukab ep0->dir_in = 1; 1215fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_DATA_IN; 1216fe0b94abSMian Yousaf Kaukab } else { 1217fe0b94abSMian Yousaf Kaukab ep0->dir_in = 0; 1218fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_DATA_OUT; 1219fe0b94abSMian Yousaf Kaukab } 122047a1685fSDinh Nguyen 122147a1685fSDinh Nguyen if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 122247a1685fSDinh Nguyen switch (ctrl->bRequest) { 122347a1685fSDinh Nguyen case USB_REQ_SET_ADDRESS: 12246d713c15SMian Yousaf Kaukab hsotg->connected = 1; 122595c8bc36SAntti Seppälä dcfg = dwc2_readl(hsotg->regs + DCFG); 122647a1685fSDinh Nguyen dcfg &= ~DCFG_DEVADDR_MASK; 1227d5dbd3f7SPaul Zimmerman dcfg |= (le16_to_cpu(ctrl->wValue) << 1228d5dbd3f7SPaul Zimmerman DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK; 122995c8bc36SAntti Seppälä dwc2_writel(dcfg, hsotg->regs + DCFG); 123047a1685fSDinh Nguyen 123147a1685fSDinh Nguyen dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); 123247a1685fSDinh Nguyen 12331f91b4ccSFelipe Balbi ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 123447a1685fSDinh Nguyen return; 123547a1685fSDinh Nguyen 123647a1685fSDinh Nguyen case USB_REQ_GET_STATUS: 12371f91b4ccSFelipe Balbi ret = dwc2_hsotg_process_req_status(hsotg, ctrl); 123847a1685fSDinh Nguyen break; 123947a1685fSDinh Nguyen 124047a1685fSDinh Nguyen case USB_REQ_CLEAR_FEATURE: 124147a1685fSDinh Nguyen case USB_REQ_SET_FEATURE: 12421f91b4ccSFelipe Balbi ret = dwc2_hsotg_process_req_feature(hsotg, ctrl); 124347a1685fSDinh Nguyen break; 124447a1685fSDinh Nguyen } 124547a1685fSDinh Nguyen } 124647a1685fSDinh Nguyen 124747a1685fSDinh Nguyen /* as a fallback, try delivering it to the driver to deal with */ 124847a1685fSDinh Nguyen 124947a1685fSDinh Nguyen if (ret == 0 && hsotg->driver) { 125047a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 125147a1685fSDinh Nguyen ret = hsotg->driver->setup(&hsotg->gadget, ctrl); 125247a1685fSDinh Nguyen spin_lock(&hsotg->lock); 125347a1685fSDinh Nguyen if (ret < 0) 125447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); 125547a1685fSDinh Nguyen } 125647a1685fSDinh Nguyen 125747a1685fSDinh Nguyen /* 125847a1685fSDinh Nguyen * the request is either unhandlable, or is not formatted correctly 125947a1685fSDinh Nguyen * so respond with a STALL for the status stage to indicate failure. 126047a1685fSDinh Nguyen */ 126147a1685fSDinh Nguyen 126247a1685fSDinh Nguyen if (ret < 0) 12631f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hsotg); 126447a1685fSDinh Nguyen } 126547a1685fSDinh Nguyen 126647a1685fSDinh Nguyen /** 12671f91b4ccSFelipe Balbi * dwc2_hsotg_complete_setup - completion of a setup transfer 126847a1685fSDinh Nguyen * @ep: The endpoint the request was on. 126947a1685fSDinh Nguyen * @req: The request completed. 127047a1685fSDinh Nguyen * 127147a1685fSDinh Nguyen * Called on completion of any requests the driver itself submitted for 127247a1685fSDinh Nguyen * EP0 setup packets 127347a1685fSDinh Nguyen */ 12741f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_setup(struct usb_ep *ep, 127547a1685fSDinh Nguyen struct usb_request *req) 127647a1685fSDinh Nguyen { 12771f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 1278941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 127947a1685fSDinh Nguyen 128047a1685fSDinh Nguyen if (req->status < 0) { 128147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); 128247a1685fSDinh Nguyen return; 128347a1685fSDinh Nguyen } 128447a1685fSDinh Nguyen 128547a1685fSDinh Nguyen spin_lock(&hsotg->lock); 128647a1685fSDinh Nguyen if (req->actual == 0) 12871f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 128847a1685fSDinh Nguyen else 12891f91b4ccSFelipe Balbi dwc2_hsotg_process_control(hsotg, req->buf); 129047a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 129147a1685fSDinh Nguyen } 129247a1685fSDinh Nguyen 129347a1685fSDinh Nguyen /** 12941f91b4ccSFelipe Balbi * dwc2_hsotg_enqueue_setup - start a request for EP0 packets 129547a1685fSDinh Nguyen * @hsotg: The device state. 129647a1685fSDinh Nguyen * 129747a1685fSDinh Nguyen * Enqueue a request on EP0 if necessary to received any SETUP packets 129847a1685fSDinh Nguyen * received from the host. 129947a1685fSDinh Nguyen */ 13001f91b4ccSFelipe Balbi static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg) 130147a1685fSDinh Nguyen { 130247a1685fSDinh Nguyen struct usb_request *req = hsotg->ctrl_req; 13031f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 130447a1685fSDinh Nguyen int ret; 130547a1685fSDinh Nguyen 130647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); 130747a1685fSDinh Nguyen 130847a1685fSDinh Nguyen req->zero = 0; 130947a1685fSDinh Nguyen req->length = 8; 131047a1685fSDinh Nguyen req->buf = hsotg->ctrl_buff; 13111f91b4ccSFelipe Balbi req->complete = dwc2_hsotg_complete_setup; 131247a1685fSDinh Nguyen 131347a1685fSDinh Nguyen if (!list_empty(&hs_req->queue)) { 131447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s already queued???\n", __func__); 131547a1685fSDinh Nguyen return; 131647a1685fSDinh Nguyen } 131747a1685fSDinh Nguyen 1318c6f5c050SMian Yousaf Kaukab hsotg->eps_out[0]->dir_in = 0; 13198a20fa45SMian Yousaf Kaukab hsotg->eps_out[0]->send_zlp = 0; 1320fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_SETUP; 132147a1685fSDinh Nguyen 13221f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_queue(&hsotg->eps_out[0]->ep, req, GFP_ATOMIC); 132347a1685fSDinh Nguyen if (ret < 0) { 132447a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); 132547a1685fSDinh Nguyen /* 132647a1685fSDinh Nguyen * Don't think there's much we can do other than watch the 132747a1685fSDinh Nguyen * driver fail. 132847a1685fSDinh Nguyen */ 132947a1685fSDinh Nguyen } 133047a1685fSDinh Nguyen } 133147a1685fSDinh Nguyen 13321f91b4ccSFelipe Balbi static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, 13331f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 1334fe0b94abSMian Yousaf Kaukab { 1335fe0b94abSMian Yousaf Kaukab u32 ctrl; 1336fe0b94abSMian Yousaf Kaukab u8 index = hs_ep->index; 1337fe0b94abSMian Yousaf Kaukab u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 1338fe0b94abSMian Yousaf Kaukab u32 epsiz_reg = hs_ep->dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 1339fe0b94abSMian Yousaf Kaukab 1340ccb34a91SMian Yousaf Kaukab if (hs_ep->dir_in) 1341ccb34a91SMian Yousaf Kaukab dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n", 1342ccb34a91SMian Yousaf Kaukab index); 1343ccb34a91SMian Yousaf Kaukab else 1344ccb34a91SMian Yousaf Kaukab dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n", 1345ccb34a91SMian Yousaf Kaukab index); 1346fe0b94abSMian Yousaf Kaukab 134795c8bc36SAntti Seppälä dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 1348fe0b94abSMian Yousaf Kaukab DXEPTSIZ_XFERSIZE(0), hsotg->regs + 1349fe0b94abSMian Yousaf Kaukab epsiz_reg); 1350fe0b94abSMian Yousaf Kaukab 135195c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctl_reg); 1352fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 1353fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 1354fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_USBACTEP; 135595c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + epctl_reg); 1356fe0b94abSMian Yousaf Kaukab } 1357fe0b94abSMian Yousaf Kaukab 135847a1685fSDinh Nguyen /** 13591f91b4ccSFelipe Balbi * dwc2_hsotg_complete_request - complete a request given to us 136047a1685fSDinh Nguyen * @hsotg: The device state. 136147a1685fSDinh Nguyen * @hs_ep: The endpoint the request was on. 136247a1685fSDinh Nguyen * @hs_req: The request to complete. 136347a1685fSDinh Nguyen * @result: The result code (0 => Ok, otherwise errno) 136447a1685fSDinh Nguyen * 136547a1685fSDinh Nguyen * The given request has finished, so call the necessary completion 136647a1685fSDinh Nguyen * if it has one and then look to see if we can start a new request 136747a1685fSDinh Nguyen * on the endpoint. 136847a1685fSDinh Nguyen * 136947a1685fSDinh Nguyen * Note, expects the ep to already be locked as appropriate. 137047a1685fSDinh Nguyen */ 13711f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, 13721f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 13731f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req, 137447a1685fSDinh Nguyen int result) 137547a1685fSDinh Nguyen { 137647a1685fSDinh Nguyen bool restart; 137747a1685fSDinh Nguyen 137847a1685fSDinh Nguyen if (!hs_req) { 137947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); 138047a1685fSDinh Nguyen return; 138147a1685fSDinh Nguyen } 138247a1685fSDinh Nguyen 138347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", 138447a1685fSDinh Nguyen hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); 138547a1685fSDinh Nguyen 138647a1685fSDinh Nguyen /* 138747a1685fSDinh Nguyen * only replace the status if we've not already set an error 138847a1685fSDinh Nguyen * from a previous transaction 138947a1685fSDinh Nguyen */ 139047a1685fSDinh Nguyen 139147a1685fSDinh Nguyen if (hs_req->req.status == -EINPROGRESS) 139247a1685fSDinh Nguyen hs_req->req.status = result; 139347a1685fSDinh Nguyen 139444583fecSYunzhi Li if (using_dma(hsotg)) 139544583fecSYunzhi Li dwc2_hsotg_unmap_dma(hsotg, hs_ep, hs_req); 139644583fecSYunzhi Li 13971f91b4ccSFelipe Balbi dwc2_hsotg_handle_unaligned_buf_complete(hsotg, hs_ep, hs_req); 13987d24c1b5SMian Yousaf Kaukab 139947a1685fSDinh Nguyen hs_ep->req = NULL; 140047a1685fSDinh Nguyen list_del_init(&hs_req->queue); 140147a1685fSDinh Nguyen 140247a1685fSDinh Nguyen /* 140347a1685fSDinh Nguyen * call the complete request with the locks off, just in case the 140447a1685fSDinh Nguyen * request tries to queue more work for this endpoint. 140547a1685fSDinh Nguyen */ 140647a1685fSDinh Nguyen 140747a1685fSDinh Nguyen if (hs_req->req.complete) { 140847a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 1409304f7e5eSMichal Sojka usb_gadget_giveback_request(&hs_ep->ep, &hs_req->req); 141047a1685fSDinh Nguyen spin_lock(&hsotg->lock); 141147a1685fSDinh Nguyen } 141247a1685fSDinh Nguyen 141347a1685fSDinh Nguyen /* 141447a1685fSDinh Nguyen * Look to see if there is anything else to do. Note, the completion 141547a1685fSDinh Nguyen * of the previous request may have caused a new request to be started 141647a1685fSDinh Nguyen * so be careful when doing this. 141747a1685fSDinh Nguyen */ 141847a1685fSDinh Nguyen 141947a1685fSDinh Nguyen if (!hs_ep->req && result >= 0) { 142047a1685fSDinh Nguyen restart = !list_empty(&hs_ep->queue); 142147a1685fSDinh Nguyen if (restart) { 142247a1685fSDinh Nguyen hs_req = get_ep_head(hs_ep); 14231f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false); 142447a1685fSDinh Nguyen } 142547a1685fSDinh Nguyen } 142647a1685fSDinh Nguyen } 142747a1685fSDinh Nguyen 142847a1685fSDinh Nguyen /** 14291f91b4ccSFelipe Balbi * dwc2_hsotg_rx_data - receive data from the FIFO for an endpoint 143047a1685fSDinh Nguyen * @hsotg: The device state. 143147a1685fSDinh Nguyen * @ep_idx: The endpoint index for the data 143247a1685fSDinh Nguyen * @size: The size of data in the fifo, in bytes 143347a1685fSDinh Nguyen * 143447a1685fSDinh Nguyen * The FIFO status shows there is data to read from the FIFO for a given 143547a1685fSDinh Nguyen * endpoint, so sort out whether we need to read the data into a request 143647a1685fSDinh Nguyen * that has been made for that endpoint. 143747a1685fSDinh Nguyen */ 14381f91b4ccSFelipe Balbi static void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size) 143947a1685fSDinh Nguyen { 14401f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[ep_idx]; 14411f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 144247a1685fSDinh Nguyen void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx); 144347a1685fSDinh Nguyen int to_read; 144447a1685fSDinh Nguyen int max_req; 144547a1685fSDinh Nguyen int read_ptr; 144647a1685fSDinh Nguyen 144747a1685fSDinh Nguyen 144847a1685fSDinh Nguyen if (!hs_req) { 144995c8bc36SAntti Seppälä u32 epctl = dwc2_readl(hsotg->regs + DOEPCTL(ep_idx)); 145047a1685fSDinh Nguyen int ptr; 145147a1685fSDinh Nguyen 14526b448af4SRobert Baldyga dev_dbg(hsotg->dev, 145347a1685fSDinh Nguyen "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", 145447a1685fSDinh Nguyen __func__, size, ep_idx, epctl); 145547a1685fSDinh Nguyen 145647a1685fSDinh Nguyen /* dump the data from the FIFO, we've nothing we can do */ 145747a1685fSDinh Nguyen for (ptr = 0; ptr < size; ptr += 4) 145895c8bc36SAntti Seppälä (void)dwc2_readl(fifo); 145947a1685fSDinh Nguyen 146047a1685fSDinh Nguyen return; 146147a1685fSDinh Nguyen } 146247a1685fSDinh Nguyen 146347a1685fSDinh Nguyen to_read = size; 146447a1685fSDinh Nguyen read_ptr = hs_req->req.actual; 146547a1685fSDinh Nguyen max_req = hs_req->req.length - read_ptr; 146647a1685fSDinh Nguyen 146747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", 146847a1685fSDinh Nguyen __func__, to_read, max_req, read_ptr, hs_req->req.length); 146947a1685fSDinh Nguyen 147047a1685fSDinh Nguyen if (to_read > max_req) { 147147a1685fSDinh Nguyen /* 147247a1685fSDinh Nguyen * more data appeared than we where willing 147347a1685fSDinh Nguyen * to deal with in this request. 147447a1685fSDinh Nguyen */ 147547a1685fSDinh Nguyen 147647a1685fSDinh Nguyen /* currently we don't deal this */ 147747a1685fSDinh Nguyen WARN_ON_ONCE(1); 147847a1685fSDinh Nguyen } 147947a1685fSDinh Nguyen 148047a1685fSDinh Nguyen hs_ep->total_data += to_read; 148147a1685fSDinh Nguyen hs_req->req.actual += to_read; 148247a1685fSDinh Nguyen to_read = DIV_ROUND_UP(to_read, 4); 148347a1685fSDinh Nguyen 148447a1685fSDinh Nguyen /* 148547a1685fSDinh Nguyen * note, we might over-write the buffer end by 3 bytes depending on 148647a1685fSDinh Nguyen * alignment of the data. 148747a1685fSDinh Nguyen */ 148847a1685fSDinh Nguyen ioread32_rep(fifo, hs_req->req.buf + read_ptr, to_read); 148947a1685fSDinh Nguyen } 149047a1685fSDinh Nguyen 149147a1685fSDinh Nguyen /** 14921f91b4ccSFelipe Balbi * dwc2_hsotg_ep0_zlp - send/receive zero-length packet on control endpoint 149347a1685fSDinh Nguyen * @hsotg: The device instance 1494fe0b94abSMian Yousaf Kaukab * @dir_in: If IN zlp 149547a1685fSDinh Nguyen * 149647a1685fSDinh Nguyen * Generate a zero-length IN packet request for terminating a SETUP 149747a1685fSDinh Nguyen * transaction. 149847a1685fSDinh Nguyen * 149947a1685fSDinh Nguyen * Note, since we don't write any data to the TxFIFO, then it is 150047a1685fSDinh Nguyen * currently believed that we do not need to wait for any space in 150147a1685fSDinh Nguyen * the TxFIFO. 150247a1685fSDinh Nguyen */ 15031f91b4ccSFelipe Balbi static void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in) 150447a1685fSDinh Nguyen { 1505c6f5c050SMian Yousaf Kaukab /* eps_out[0] is used in both directions */ 1506fe0b94abSMian Yousaf Kaukab hsotg->eps_out[0]->dir_in = dir_in; 1507fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = dir_in ? DWC2_EP0_STATUS_IN : DWC2_EP0_STATUS_OUT; 150847a1685fSDinh Nguyen 15091f91b4ccSFelipe Balbi dwc2_hsotg_program_zlp(hsotg, hsotg->eps_out[0]); 151047a1685fSDinh Nguyen } 151147a1685fSDinh Nguyen 1512ec1f9d9fSRoman Bacik static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg, 1513ec1f9d9fSRoman Bacik u32 epctl_reg) 1514ec1f9d9fSRoman Bacik { 1515ec1f9d9fSRoman Bacik u32 ctrl; 1516ec1f9d9fSRoman Bacik 1517ec1f9d9fSRoman Bacik ctrl = dwc2_readl(hsotg->regs + epctl_reg); 1518ec1f9d9fSRoman Bacik if (ctrl & DXEPCTL_EOFRNUM) 1519ec1f9d9fSRoman Bacik ctrl |= DXEPCTL_SETEVENFR; 1520ec1f9d9fSRoman Bacik else 1521ec1f9d9fSRoman Bacik ctrl |= DXEPCTL_SETODDFR; 1522ec1f9d9fSRoman Bacik dwc2_writel(ctrl, hsotg->regs + epctl_reg); 1523ec1f9d9fSRoman Bacik } 1524ec1f9d9fSRoman Bacik 152547a1685fSDinh Nguyen /** 15261f91b4ccSFelipe Balbi * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO 152747a1685fSDinh Nguyen * @hsotg: The device instance 152847a1685fSDinh Nguyen * @epnum: The endpoint received from 152947a1685fSDinh Nguyen * 153047a1685fSDinh Nguyen * The RXFIFO has delivered an OutDone event, which means that the data 153147a1685fSDinh Nguyen * transfer for an OUT endpoint has been completed, either by a short 153247a1685fSDinh Nguyen * packet or by the finish of a transfer. 153347a1685fSDinh Nguyen */ 15341f91b4ccSFelipe Balbi static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) 153547a1685fSDinh Nguyen { 153695c8bc36SAntti Seppälä u32 epsize = dwc2_readl(hsotg->regs + DOEPTSIZ(epnum)); 15371f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[epnum]; 15381f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 153947a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 154047a1685fSDinh Nguyen unsigned size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 154147a1685fSDinh Nguyen int result = 0; 154247a1685fSDinh Nguyen 154347a1685fSDinh Nguyen if (!hs_req) { 154447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no request active\n", __func__); 154547a1685fSDinh Nguyen return; 154647a1685fSDinh Nguyen } 154747a1685fSDinh Nguyen 1548fe0b94abSMian Yousaf Kaukab if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_OUT) { 1549fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "zlp packet received\n"); 15501f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 15511f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 1552fe0b94abSMian Yousaf Kaukab return; 1553fe0b94abSMian Yousaf Kaukab } 1554fe0b94abSMian Yousaf Kaukab 155547a1685fSDinh Nguyen if (using_dma(hsotg)) { 155647a1685fSDinh Nguyen unsigned size_done; 155747a1685fSDinh Nguyen 155847a1685fSDinh Nguyen /* 155947a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much 156047a1685fSDinh Nguyen * is left in the endpoint size register and then working it 156147a1685fSDinh Nguyen * out from the amount we loaded for the transfer. 156247a1685fSDinh Nguyen * 156347a1685fSDinh Nguyen * We need to do this as DMA pointers are always 32bit aligned 156447a1685fSDinh Nguyen * so may overshoot/undershoot the transfer. 156547a1685fSDinh Nguyen */ 156647a1685fSDinh Nguyen 156747a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 156847a1685fSDinh Nguyen size_done += hs_ep->last_load; 156947a1685fSDinh Nguyen 157047a1685fSDinh Nguyen req->actual = size_done; 157147a1685fSDinh Nguyen } 157247a1685fSDinh Nguyen 157347a1685fSDinh Nguyen /* if there is more request to do, schedule new transfer */ 157447a1685fSDinh Nguyen if (req->actual < req->length && size_left == 0) { 15751f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 157647a1685fSDinh Nguyen return; 157747a1685fSDinh Nguyen } 157847a1685fSDinh Nguyen 157947a1685fSDinh Nguyen if (req->actual < req->length && req->short_not_ok) { 158047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", 158147a1685fSDinh Nguyen __func__, req->actual, req->length); 158247a1685fSDinh Nguyen 158347a1685fSDinh Nguyen /* 158447a1685fSDinh Nguyen * todo - what should we return here? there's no one else 158547a1685fSDinh Nguyen * even bothering to check the status. 158647a1685fSDinh Nguyen */ 158747a1685fSDinh Nguyen } 158847a1685fSDinh Nguyen 1589fe0b94abSMian Yousaf Kaukab if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_DATA_OUT) { 1590fe0b94abSMian Yousaf Kaukab /* Move to STATUS IN */ 15911f91b4ccSFelipe Balbi dwc2_hsotg_ep0_zlp(hsotg, true); 1592fe0b94abSMian Yousaf Kaukab return; 159347a1685fSDinh Nguyen } 159447a1685fSDinh Nguyen 1595ec1f9d9fSRoman Bacik /* 1596ec1f9d9fSRoman Bacik * Slave mode OUT transfers do not go through XferComplete so 1597ec1f9d9fSRoman Bacik * adjust the ISOC parity here. 1598ec1f9d9fSRoman Bacik */ 1599ec1f9d9fSRoman Bacik if (!using_dma(hsotg)) { 1600ec1f9d9fSRoman Bacik hs_ep->has_correct_parity = 1; 1601ec1f9d9fSRoman Bacik if (hs_ep->isochronous && hs_ep->interval == 1) 1602ec1f9d9fSRoman Bacik dwc2_hsotg_change_ep_iso_parity(hsotg, DOEPCTL(epnum)); 1603ec1f9d9fSRoman Bacik } 1604ec1f9d9fSRoman Bacik 16051f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result); 160647a1685fSDinh Nguyen } 160747a1685fSDinh Nguyen 160847a1685fSDinh Nguyen /** 16091f91b4ccSFelipe Balbi * dwc2_hsotg_read_frameno - read current frame number 161047a1685fSDinh Nguyen * @hsotg: The device instance 161147a1685fSDinh Nguyen * 161247a1685fSDinh Nguyen * Return the current frame number 161347a1685fSDinh Nguyen */ 16141f91b4ccSFelipe Balbi static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg) 161547a1685fSDinh Nguyen { 161647a1685fSDinh Nguyen u32 dsts; 161747a1685fSDinh Nguyen 161895c8bc36SAntti Seppälä dsts = dwc2_readl(hsotg->regs + DSTS); 161947a1685fSDinh Nguyen dsts &= DSTS_SOFFN_MASK; 162047a1685fSDinh Nguyen dsts >>= DSTS_SOFFN_SHIFT; 162147a1685fSDinh Nguyen 162247a1685fSDinh Nguyen return dsts; 162347a1685fSDinh Nguyen } 162447a1685fSDinh Nguyen 162547a1685fSDinh Nguyen /** 16261f91b4ccSFelipe Balbi * dwc2_hsotg_handle_rx - RX FIFO has data 162747a1685fSDinh Nguyen * @hsotg: The device instance 162847a1685fSDinh Nguyen * 162947a1685fSDinh Nguyen * The IRQ handler has detected that the RX FIFO has some data in it 163047a1685fSDinh Nguyen * that requires processing, so find out what is in there and do the 163147a1685fSDinh Nguyen * appropriate read. 163247a1685fSDinh Nguyen * 163347a1685fSDinh Nguyen * The RXFIFO is a true FIFO, the packets coming out are still in packet 163447a1685fSDinh Nguyen * chunks, so if you have x packets received on an endpoint you'll get x 163547a1685fSDinh Nguyen * FIFO events delivered, each with a packet's worth of data in it. 163647a1685fSDinh Nguyen * 163747a1685fSDinh Nguyen * When using DMA, we should not be processing events from the RXFIFO 163847a1685fSDinh Nguyen * as the actual data should be sent to the memory directly and we turn 163947a1685fSDinh Nguyen * on the completion interrupts to get notifications of transfer completion. 164047a1685fSDinh Nguyen */ 16411f91b4ccSFelipe Balbi static void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg) 164247a1685fSDinh Nguyen { 164395c8bc36SAntti Seppälä u32 grxstsr = dwc2_readl(hsotg->regs + GRXSTSP); 164447a1685fSDinh Nguyen u32 epnum, status, size; 164547a1685fSDinh Nguyen 164647a1685fSDinh Nguyen WARN_ON(using_dma(hsotg)); 164747a1685fSDinh Nguyen 164847a1685fSDinh Nguyen epnum = grxstsr & GRXSTS_EPNUM_MASK; 164947a1685fSDinh Nguyen status = grxstsr & GRXSTS_PKTSTS_MASK; 165047a1685fSDinh Nguyen 165147a1685fSDinh Nguyen size = grxstsr & GRXSTS_BYTECNT_MASK; 165247a1685fSDinh Nguyen size >>= GRXSTS_BYTECNT_SHIFT; 165347a1685fSDinh Nguyen 165447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", 165547a1685fSDinh Nguyen __func__, grxstsr, size, epnum); 165647a1685fSDinh Nguyen 165747a1685fSDinh Nguyen switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { 165847a1685fSDinh Nguyen case GRXSTS_PKTSTS_GLOBALOUTNAK: 165947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GLOBALOUTNAK\n"); 166047a1685fSDinh Nguyen break; 166147a1685fSDinh Nguyen 166247a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTDONE: 166347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", 16641f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg)); 166547a1685fSDinh Nguyen 166647a1685fSDinh Nguyen if (!using_dma(hsotg)) 16671f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, epnum); 166847a1685fSDinh Nguyen break; 166947a1685fSDinh Nguyen 167047a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPDONE: 167147a1685fSDinh Nguyen dev_dbg(hsotg->dev, 167247a1685fSDinh Nguyen "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 16731f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg), 167495c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL(0))); 1675fe0b94abSMian Yousaf Kaukab /* 16761f91b4ccSFelipe Balbi * Call dwc2_hsotg_handle_outdone here if it was not called from 1677fe0b94abSMian Yousaf Kaukab * GRXSTS_PKTSTS_OUTDONE. That is, if the core didn't 1678fe0b94abSMian Yousaf Kaukab * generate GRXSTS_PKTSTS_OUTDONE for setup packet. 1679fe0b94abSMian Yousaf Kaukab */ 1680fe0b94abSMian Yousaf Kaukab if (hsotg->ep0_state == DWC2_EP0_SETUP) 16811f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, epnum); 168247a1685fSDinh Nguyen break; 168347a1685fSDinh Nguyen 168447a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTRX: 16851f91b4ccSFelipe Balbi dwc2_hsotg_rx_data(hsotg, epnum, size); 168647a1685fSDinh Nguyen break; 168747a1685fSDinh Nguyen 168847a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPRX: 168947a1685fSDinh Nguyen dev_dbg(hsotg->dev, 169047a1685fSDinh Nguyen "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 16911f91b4ccSFelipe Balbi dwc2_hsotg_read_frameno(hsotg), 169295c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL(0))); 169347a1685fSDinh Nguyen 1694fe0b94abSMian Yousaf Kaukab WARN_ON(hsotg->ep0_state != DWC2_EP0_SETUP); 1695fe0b94abSMian Yousaf Kaukab 16961f91b4ccSFelipe Balbi dwc2_hsotg_rx_data(hsotg, epnum, size); 169747a1685fSDinh Nguyen break; 169847a1685fSDinh Nguyen 169947a1685fSDinh Nguyen default: 170047a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: unknown status %08x\n", 170147a1685fSDinh Nguyen __func__, grxstsr); 170247a1685fSDinh Nguyen 17031f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 170447a1685fSDinh Nguyen break; 170547a1685fSDinh Nguyen } 170647a1685fSDinh Nguyen } 170747a1685fSDinh Nguyen 170847a1685fSDinh Nguyen /** 17091f91b4ccSFelipe Balbi * dwc2_hsotg_ep0_mps - turn max packet size into register setting 171047a1685fSDinh Nguyen * @mps: The maximum packet size in bytes. 171147a1685fSDinh Nguyen */ 17121f91b4ccSFelipe Balbi static u32 dwc2_hsotg_ep0_mps(unsigned int mps) 171347a1685fSDinh Nguyen { 171447a1685fSDinh Nguyen switch (mps) { 171547a1685fSDinh Nguyen case 64: 171647a1685fSDinh Nguyen return D0EPCTL_MPS_64; 171747a1685fSDinh Nguyen case 32: 171847a1685fSDinh Nguyen return D0EPCTL_MPS_32; 171947a1685fSDinh Nguyen case 16: 172047a1685fSDinh Nguyen return D0EPCTL_MPS_16; 172147a1685fSDinh Nguyen case 8: 172247a1685fSDinh Nguyen return D0EPCTL_MPS_8; 172347a1685fSDinh Nguyen } 172447a1685fSDinh Nguyen 172547a1685fSDinh Nguyen /* bad max packet size, warn and return invalid result */ 172647a1685fSDinh Nguyen WARN_ON(1); 172747a1685fSDinh Nguyen return (u32)-1; 172847a1685fSDinh Nguyen } 172947a1685fSDinh Nguyen 173047a1685fSDinh Nguyen /** 17311f91b4ccSFelipe Balbi * dwc2_hsotg_set_ep_maxpacket - set endpoint's max-packet field 173247a1685fSDinh Nguyen * @hsotg: The driver state. 173347a1685fSDinh Nguyen * @ep: The index number of the endpoint 173447a1685fSDinh Nguyen * @mps: The maximum packet size in bytes 173547a1685fSDinh Nguyen * 173647a1685fSDinh Nguyen * Configure the maximum packet size for the given endpoint, updating 173747a1685fSDinh Nguyen * the hardware control registers to reflect this. 173847a1685fSDinh Nguyen */ 17391f91b4ccSFelipe Balbi static void dwc2_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg, 1740c6f5c050SMian Yousaf Kaukab unsigned int ep, unsigned int mps, unsigned int dir_in) 174147a1685fSDinh Nguyen { 17421f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep; 174347a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 174447a1685fSDinh Nguyen u32 mpsval; 174547a1685fSDinh Nguyen u32 mcval; 174647a1685fSDinh Nguyen u32 reg; 174747a1685fSDinh Nguyen 1748c6f5c050SMian Yousaf Kaukab hs_ep = index_to_ep(hsotg, ep, dir_in); 1749c6f5c050SMian Yousaf Kaukab if (!hs_ep) 1750c6f5c050SMian Yousaf Kaukab return; 1751c6f5c050SMian Yousaf Kaukab 175247a1685fSDinh Nguyen if (ep == 0) { 175347a1685fSDinh Nguyen /* EP0 is a special case */ 17541f91b4ccSFelipe Balbi mpsval = dwc2_hsotg_ep0_mps(mps); 175547a1685fSDinh Nguyen if (mpsval > 3) 175647a1685fSDinh Nguyen goto bad_mps; 175747a1685fSDinh Nguyen hs_ep->ep.maxpacket = mps; 175847a1685fSDinh Nguyen hs_ep->mc = 1; 175947a1685fSDinh Nguyen } else { 176047a1685fSDinh Nguyen mpsval = mps & DXEPCTL_MPS_MASK; 176147a1685fSDinh Nguyen if (mpsval > 1024) 176247a1685fSDinh Nguyen goto bad_mps; 176347a1685fSDinh Nguyen mcval = ((mps >> 11) & 0x3) + 1; 176447a1685fSDinh Nguyen hs_ep->mc = mcval; 176547a1685fSDinh Nguyen if (mcval > 3) 176647a1685fSDinh Nguyen goto bad_mps; 176747a1685fSDinh Nguyen hs_ep->ep.maxpacket = mpsval; 176847a1685fSDinh Nguyen } 176947a1685fSDinh Nguyen 1770c6f5c050SMian Yousaf Kaukab if (dir_in) { 177195c8bc36SAntti Seppälä reg = dwc2_readl(regs + DIEPCTL(ep)); 177247a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 177347a1685fSDinh Nguyen reg |= mpsval; 177495c8bc36SAntti Seppälä dwc2_writel(reg, regs + DIEPCTL(ep)); 1775c6f5c050SMian Yousaf Kaukab } else { 177695c8bc36SAntti Seppälä reg = dwc2_readl(regs + DOEPCTL(ep)); 177747a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 177847a1685fSDinh Nguyen reg |= mpsval; 177995c8bc36SAntti Seppälä dwc2_writel(reg, regs + DOEPCTL(ep)); 178047a1685fSDinh Nguyen } 178147a1685fSDinh Nguyen 178247a1685fSDinh Nguyen return; 178347a1685fSDinh Nguyen 178447a1685fSDinh Nguyen bad_mps: 178547a1685fSDinh Nguyen dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); 178647a1685fSDinh Nguyen } 178747a1685fSDinh Nguyen 178847a1685fSDinh Nguyen /** 17891f91b4ccSFelipe Balbi * dwc2_hsotg_txfifo_flush - flush Tx FIFO 179047a1685fSDinh Nguyen * @hsotg: The driver state 179147a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 179247a1685fSDinh Nguyen */ 17931f91b4ccSFelipe Balbi static void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx) 179447a1685fSDinh Nguyen { 179547a1685fSDinh Nguyen int timeout; 179647a1685fSDinh Nguyen int val; 179747a1685fSDinh Nguyen 179895c8bc36SAntti Seppälä dwc2_writel(GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH, 179947a1685fSDinh Nguyen hsotg->regs + GRSTCTL); 180047a1685fSDinh Nguyen 180147a1685fSDinh Nguyen /* wait until the fifo is flushed */ 180247a1685fSDinh Nguyen timeout = 100; 180347a1685fSDinh Nguyen 180447a1685fSDinh Nguyen while (1) { 180595c8bc36SAntti Seppälä val = dwc2_readl(hsotg->regs + GRSTCTL); 180647a1685fSDinh Nguyen 180747a1685fSDinh Nguyen if ((val & (GRSTCTL_TXFFLSH)) == 0) 180847a1685fSDinh Nguyen break; 180947a1685fSDinh Nguyen 181047a1685fSDinh Nguyen if (--timeout == 0) { 181147a1685fSDinh Nguyen dev_err(hsotg->dev, 181247a1685fSDinh Nguyen "%s: timeout flushing fifo (GRSTCTL=%08x)\n", 181347a1685fSDinh Nguyen __func__, val); 1814e0cbe595SMarek Szyprowski break; 181547a1685fSDinh Nguyen } 181647a1685fSDinh Nguyen 181747a1685fSDinh Nguyen udelay(1); 181847a1685fSDinh Nguyen } 181947a1685fSDinh Nguyen } 182047a1685fSDinh Nguyen 182147a1685fSDinh Nguyen /** 18221f91b4ccSFelipe Balbi * dwc2_hsotg_trytx - check to see if anything needs transmitting 182347a1685fSDinh Nguyen * @hsotg: The driver state 182447a1685fSDinh Nguyen * @hs_ep: The driver endpoint to check. 182547a1685fSDinh Nguyen * 182647a1685fSDinh Nguyen * Check to see if there is a request that has data to send, and if so 182747a1685fSDinh Nguyen * make an attempt to write data into the FIFO. 182847a1685fSDinh Nguyen */ 18291f91b4ccSFelipe Balbi static int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, 18301f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 183147a1685fSDinh Nguyen { 18321f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 183347a1685fSDinh Nguyen 183447a1685fSDinh Nguyen if (!hs_ep->dir_in || !hs_req) { 183547a1685fSDinh Nguyen /** 183647a1685fSDinh Nguyen * if request is not enqueued, we disable interrupts 183747a1685fSDinh Nguyen * for endpoints, excepting ep0 183847a1685fSDinh Nguyen */ 183947a1685fSDinh Nguyen if (hs_ep->index != 0) 18401f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, 184147a1685fSDinh Nguyen hs_ep->dir_in, 0); 184247a1685fSDinh Nguyen return 0; 184347a1685fSDinh Nguyen } 184447a1685fSDinh Nguyen 184547a1685fSDinh Nguyen if (hs_req->req.actual < hs_req->req.length) { 184647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "trying to write more for ep%d\n", 184747a1685fSDinh Nguyen hs_ep->index); 18481f91b4ccSFelipe Balbi return dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 184947a1685fSDinh Nguyen } 185047a1685fSDinh Nguyen 185147a1685fSDinh Nguyen return 0; 185247a1685fSDinh Nguyen } 185347a1685fSDinh Nguyen 185447a1685fSDinh Nguyen /** 18551f91b4ccSFelipe Balbi * dwc2_hsotg_complete_in - complete IN transfer 185647a1685fSDinh Nguyen * @hsotg: The device state. 185747a1685fSDinh Nguyen * @hs_ep: The endpoint that has just completed. 185847a1685fSDinh Nguyen * 185947a1685fSDinh Nguyen * An IN transfer has been completed, update the transfer's state and then 186047a1685fSDinh Nguyen * call the relevant completion routines. 186147a1685fSDinh Nguyen */ 18621f91b4ccSFelipe Balbi static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, 18631f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep) 186447a1685fSDinh Nguyen { 18651f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = hs_ep->req; 186695c8bc36SAntti Seppälä u32 epsize = dwc2_readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); 186747a1685fSDinh Nguyen int size_left, size_done; 186847a1685fSDinh Nguyen 186947a1685fSDinh Nguyen if (!hs_req) { 187047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "XferCompl but no req\n"); 187147a1685fSDinh Nguyen return; 187247a1685fSDinh Nguyen } 187347a1685fSDinh Nguyen 187447a1685fSDinh Nguyen /* Finish ZLP handling for IN EP0 transactions */ 1875fe0b94abSMian Yousaf Kaukab if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) { 1876fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "zlp packet sent\n"); 18771f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 18789e14d0a5SGregory Herrero if (hsotg->test_mode) { 18799e14d0a5SGregory Herrero int ret; 18809e14d0a5SGregory Herrero 18811f91b4ccSFelipe Balbi ret = dwc2_hsotg_set_test_mode(hsotg, hsotg->test_mode); 18829e14d0a5SGregory Herrero if (ret < 0) { 18839e14d0a5SGregory Herrero dev_dbg(hsotg->dev, "Invalid Test #%d\n", 18849e14d0a5SGregory Herrero hsotg->test_mode); 18851f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hsotg); 18869e14d0a5SGregory Herrero return; 18879e14d0a5SGregory Herrero } 18889e14d0a5SGregory Herrero } 18891f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 189047a1685fSDinh Nguyen return; 189147a1685fSDinh Nguyen } 189247a1685fSDinh Nguyen 189347a1685fSDinh Nguyen /* 189447a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much is left 189547a1685fSDinh Nguyen * in the endpoint size register and then working it out from 189647a1685fSDinh Nguyen * the amount we loaded for the transfer. 189747a1685fSDinh Nguyen * 189847a1685fSDinh Nguyen * We do this even for DMA, as the transfer may have incremented 189947a1685fSDinh Nguyen * past the end of the buffer (DMA transfers are always 32bit 190047a1685fSDinh Nguyen * aligned). 190147a1685fSDinh Nguyen */ 190247a1685fSDinh Nguyen 190347a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 190447a1685fSDinh Nguyen 190547a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 190647a1685fSDinh Nguyen size_done += hs_ep->last_load; 190747a1685fSDinh Nguyen 190847a1685fSDinh Nguyen if (hs_req->req.actual != size_done) 190947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", 191047a1685fSDinh Nguyen __func__, hs_req->req.actual, size_done); 191147a1685fSDinh Nguyen 191247a1685fSDinh Nguyen hs_req->req.actual = size_done; 191347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", 191447a1685fSDinh Nguyen hs_req->req.length, hs_req->req.actual, hs_req->req.zero); 191547a1685fSDinh Nguyen 191647a1685fSDinh Nguyen if (!size_left && hs_req->req.actual < hs_req->req.length) { 191747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); 19181f91b4ccSFelipe Balbi dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 1919fe0b94abSMian Yousaf Kaukab return; 1920fe0b94abSMian Yousaf Kaukab } 1921fe0b94abSMian Yousaf Kaukab 1922f71b5e25SMian Yousaf Kaukab /* Zlp for all endpoints, for ep0 only in DATA IN stage */ 19238a20fa45SMian Yousaf Kaukab if (hs_ep->send_zlp) { 19241f91b4ccSFelipe Balbi dwc2_hsotg_program_zlp(hsotg, hs_ep); 19258a20fa45SMian Yousaf Kaukab hs_ep->send_zlp = 0; 1926f71b5e25SMian Yousaf Kaukab /* transfer will be completed on next complete interrupt */ 1927f71b5e25SMian Yousaf Kaukab return; 1928f71b5e25SMian Yousaf Kaukab } 1929f71b5e25SMian Yousaf Kaukab 1930fe0b94abSMian Yousaf Kaukab if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_DATA_IN) { 1931fe0b94abSMian Yousaf Kaukab /* Move to STATUS OUT */ 19321f91b4ccSFelipe Balbi dwc2_hsotg_ep0_zlp(hsotg, false); 1933fe0b94abSMian Yousaf Kaukab return; 1934fe0b94abSMian Yousaf Kaukab } 1935fe0b94abSMian Yousaf Kaukab 19361f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 193747a1685fSDinh Nguyen } 193847a1685fSDinh Nguyen 193947a1685fSDinh Nguyen /** 19401f91b4ccSFelipe Balbi * dwc2_hsotg_epint - handle an in/out endpoint interrupt 194147a1685fSDinh Nguyen * @hsotg: The driver state 194247a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 194347a1685fSDinh Nguyen * @dir_in: Set if this is an IN endpoint 194447a1685fSDinh Nguyen * 194547a1685fSDinh Nguyen * Process and clear any interrupt pending for an individual endpoint 194647a1685fSDinh Nguyen */ 19471f91b4ccSFelipe Balbi static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, 194847a1685fSDinh Nguyen int dir_in) 194947a1685fSDinh Nguyen { 19501f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in); 195147a1685fSDinh Nguyen u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 195247a1685fSDinh Nguyen u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 195347a1685fSDinh Nguyen u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); 195447a1685fSDinh Nguyen u32 ints; 195547a1685fSDinh Nguyen u32 ctrl; 195647a1685fSDinh Nguyen 195795c8bc36SAntti Seppälä ints = dwc2_readl(hsotg->regs + epint_reg); 195895c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctl_reg); 195947a1685fSDinh Nguyen 196047a1685fSDinh Nguyen /* Clear endpoint interrupts */ 196195c8bc36SAntti Seppälä dwc2_writel(ints, hsotg->regs + epint_reg); 196247a1685fSDinh Nguyen 1963c6f5c050SMian Yousaf Kaukab if (!hs_ep) { 1964c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n", 1965c6f5c050SMian Yousaf Kaukab __func__, idx, dir_in ? "in" : "out"); 1966c6f5c050SMian Yousaf Kaukab return; 1967c6f5c050SMian Yousaf Kaukab } 1968c6f5c050SMian Yousaf Kaukab 196947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", 197047a1685fSDinh Nguyen __func__, idx, dir_in ? "in" : "out", ints); 197147a1685fSDinh Nguyen 1972b787d755SMian Yousaf Kaukab /* Don't process XferCompl interrupt if it is a setup packet */ 1973b787d755SMian Yousaf Kaukab if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD))) 1974b787d755SMian Yousaf Kaukab ints &= ~DXEPINT_XFERCOMPL; 1975b787d755SMian Yousaf Kaukab 197647a1685fSDinh Nguyen if (ints & DXEPINT_XFERCOMPL) { 1977ec1f9d9fSRoman Bacik hs_ep->has_correct_parity = 1; 1978ec1f9d9fSRoman Bacik if (hs_ep->isochronous && hs_ep->interval == 1) 1979ec1f9d9fSRoman Bacik dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg); 198047a1685fSDinh Nguyen 198147a1685fSDinh Nguyen dev_dbg(hsotg->dev, 198247a1685fSDinh Nguyen "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", 198395c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctl_reg), 198495c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + epsiz_reg)); 198547a1685fSDinh Nguyen 198647a1685fSDinh Nguyen /* 198747a1685fSDinh Nguyen * we get OutDone from the FIFO, so we only need to look 198847a1685fSDinh Nguyen * at completing IN requests here 198947a1685fSDinh Nguyen */ 199047a1685fSDinh Nguyen if (dir_in) { 19911f91b4ccSFelipe Balbi dwc2_hsotg_complete_in(hsotg, hs_ep); 199247a1685fSDinh Nguyen 199347a1685fSDinh Nguyen if (idx == 0 && !hs_ep->req) 19941f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 199547a1685fSDinh Nguyen } else if (using_dma(hsotg)) { 199647a1685fSDinh Nguyen /* 199747a1685fSDinh Nguyen * We're using DMA, we need to fire an OutDone here 199847a1685fSDinh Nguyen * as we ignore the RXFIFO. 199947a1685fSDinh Nguyen */ 200047a1685fSDinh Nguyen 20011f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, idx); 200247a1685fSDinh Nguyen } 200347a1685fSDinh Nguyen } 200447a1685fSDinh Nguyen 200547a1685fSDinh Nguyen if (ints & DXEPINT_EPDISBLD) { 200647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); 200747a1685fSDinh Nguyen 200847a1685fSDinh Nguyen if (dir_in) { 200995c8bc36SAntti Seppälä int epctl = dwc2_readl(hsotg->regs + epctl_reg); 201047a1685fSDinh Nguyen 20111f91b4ccSFelipe Balbi dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); 201247a1685fSDinh Nguyen 201347a1685fSDinh Nguyen if ((epctl & DXEPCTL_STALL) && 201447a1685fSDinh Nguyen (epctl & DXEPCTL_EPTYPE_BULK)) { 201595c8bc36SAntti Seppälä int dctl = dwc2_readl(hsotg->regs + DCTL); 201647a1685fSDinh Nguyen 201747a1685fSDinh Nguyen dctl |= DCTL_CGNPINNAK; 201895c8bc36SAntti Seppälä dwc2_writel(dctl, hsotg->regs + DCTL); 201947a1685fSDinh Nguyen } 202047a1685fSDinh Nguyen } 202147a1685fSDinh Nguyen } 202247a1685fSDinh Nguyen 202347a1685fSDinh Nguyen if (ints & DXEPINT_AHBERR) 202447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); 202547a1685fSDinh Nguyen 202647a1685fSDinh Nguyen if (ints & DXEPINT_SETUP) { /* Setup or Timeout */ 202747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); 202847a1685fSDinh Nguyen 202947a1685fSDinh Nguyen if (using_dma(hsotg) && idx == 0) { 203047a1685fSDinh Nguyen /* 203147a1685fSDinh Nguyen * this is the notification we've received a 203247a1685fSDinh Nguyen * setup packet. In non-DMA mode we'd get this 203347a1685fSDinh Nguyen * from the RXFIFO, instead we need to process 203447a1685fSDinh Nguyen * the setup here. 203547a1685fSDinh Nguyen */ 203647a1685fSDinh Nguyen 203747a1685fSDinh Nguyen if (dir_in) 203847a1685fSDinh Nguyen WARN_ON_ONCE(1); 203947a1685fSDinh Nguyen else 20401f91b4ccSFelipe Balbi dwc2_hsotg_handle_outdone(hsotg, 0); 204147a1685fSDinh Nguyen } 204247a1685fSDinh Nguyen } 204347a1685fSDinh Nguyen 204447a1685fSDinh Nguyen if (ints & DXEPINT_BACK2BACKSETUP) 204547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); 204647a1685fSDinh Nguyen 204747a1685fSDinh Nguyen if (dir_in && !hs_ep->isochronous) { 204847a1685fSDinh Nguyen /* not sure if this is important, but we'll clear it anyway */ 204947a1685fSDinh Nguyen if (ints & DIEPMSK_INTKNTXFEMPMSK) { 205047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", 205147a1685fSDinh Nguyen __func__, idx); 205247a1685fSDinh Nguyen } 205347a1685fSDinh Nguyen 205447a1685fSDinh Nguyen /* this probably means something bad is happening */ 205547a1685fSDinh Nguyen if (ints & DIEPMSK_INTKNEPMISMSK) { 205647a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", 205747a1685fSDinh Nguyen __func__, idx); 205847a1685fSDinh Nguyen } 205947a1685fSDinh Nguyen 206047a1685fSDinh Nguyen /* FIFO has space or is empty (see GAHBCFG) */ 206147a1685fSDinh Nguyen if (hsotg->dedicated_fifos && 206247a1685fSDinh Nguyen ints & DIEPMSK_TXFIFOEMPTY) { 206347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", 206447a1685fSDinh Nguyen __func__, idx); 206547a1685fSDinh Nguyen if (!using_dma(hsotg)) 20661f91b4ccSFelipe Balbi dwc2_hsotg_trytx(hsotg, hs_ep); 206747a1685fSDinh Nguyen } 206847a1685fSDinh Nguyen } 206947a1685fSDinh Nguyen } 207047a1685fSDinh Nguyen 207147a1685fSDinh Nguyen /** 20721f91b4ccSFelipe Balbi * dwc2_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) 207347a1685fSDinh Nguyen * @hsotg: The device state. 207447a1685fSDinh Nguyen * 207547a1685fSDinh Nguyen * Handle updating the device settings after the enumeration phase has 207647a1685fSDinh Nguyen * been completed. 207747a1685fSDinh Nguyen */ 20781f91b4ccSFelipe Balbi static void dwc2_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg) 207947a1685fSDinh Nguyen { 208095c8bc36SAntti Seppälä u32 dsts = dwc2_readl(hsotg->regs + DSTS); 20819b2667f1SJingoo Han int ep0_mps = 0, ep_mps = 8; 208247a1685fSDinh Nguyen 208347a1685fSDinh Nguyen /* 208447a1685fSDinh Nguyen * This should signal the finish of the enumeration phase 208547a1685fSDinh Nguyen * of the USB handshaking, so we should now know what rate 208647a1685fSDinh Nguyen * we connected at. 208747a1685fSDinh Nguyen */ 208847a1685fSDinh Nguyen 208947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); 209047a1685fSDinh Nguyen 209147a1685fSDinh Nguyen /* 209247a1685fSDinh Nguyen * note, since we're limited by the size of transfer on EP0, and 209347a1685fSDinh Nguyen * it seems IN transfers must be a even number of packets we do 209447a1685fSDinh Nguyen * not advertise a 64byte MPS on EP0. 209547a1685fSDinh Nguyen */ 209647a1685fSDinh Nguyen 209747a1685fSDinh Nguyen /* catch both EnumSpd_FS and EnumSpd_FS48 */ 20986d76c92cSMarek Vasut switch ((dsts & DSTS_ENUMSPD_MASK) >> DSTS_ENUMSPD_SHIFT) { 209947a1685fSDinh Nguyen case DSTS_ENUMSPD_FS: 210047a1685fSDinh Nguyen case DSTS_ENUMSPD_FS48: 210147a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_FULL; 210247a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 210347a1685fSDinh Nguyen ep_mps = 1023; 210447a1685fSDinh Nguyen break; 210547a1685fSDinh Nguyen 210647a1685fSDinh Nguyen case DSTS_ENUMSPD_HS: 210747a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_HIGH; 210847a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 210947a1685fSDinh Nguyen ep_mps = 1024; 211047a1685fSDinh Nguyen break; 211147a1685fSDinh Nguyen 211247a1685fSDinh Nguyen case DSTS_ENUMSPD_LS: 211347a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_LOW; 211447a1685fSDinh Nguyen /* 211547a1685fSDinh Nguyen * note, we don't actually support LS in this driver at the 211647a1685fSDinh Nguyen * moment, and the documentation seems to imply that it isn't 211747a1685fSDinh Nguyen * supported by the PHYs on some of the devices. 211847a1685fSDinh Nguyen */ 211947a1685fSDinh Nguyen break; 212047a1685fSDinh Nguyen } 212147a1685fSDinh Nguyen dev_info(hsotg->dev, "new device is %s\n", 212247a1685fSDinh Nguyen usb_speed_string(hsotg->gadget.speed)); 212347a1685fSDinh Nguyen 212447a1685fSDinh Nguyen /* 212547a1685fSDinh Nguyen * we should now know the maximum packet size for an 212647a1685fSDinh Nguyen * endpoint, so set the endpoints to a default value. 212747a1685fSDinh Nguyen */ 212847a1685fSDinh Nguyen 212947a1685fSDinh Nguyen if (ep0_mps) { 213047a1685fSDinh Nguyen int i; 2131c6f5c050SMian Yousaf Kaukab /* Initialize ep0 for both in and out directions */ 21321f91b4ccSFelipe Balbi dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 1); 21331f91b4ccSFelipe Balbi dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0); 2134c6f5c050SMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; i++) { 2135c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[i]) 21361f91b4ccSFelipe Balbi dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 1); 2137c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[i]) 21381f91b4ccSFelipe Balbi dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 0); 2139c6f5c050SMian Yousaf Kaukab } 214047a1685fSDinh Nguyen } 214147a1685fSDinh Nguyen 214247a1685fSDinh Nguyen /* ensure after enumeration our EP0 is active */ 214347a1685fSDinh Nguyen 21441f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 214547a1685fSDinh Nguyen 214647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 214795c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DIEPCTL0), 214895c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL0)); 214947a1685fSDinh Nguyen } 215047a1685fSDinh Nguyen 215147a1685fSDinh Nguyen /** 215247a1685fSDinh Nguyen * kill_all_requests - remove all requests from the endpoint's queue 215347a1685fSDinh Nguyen * @hsotg: The device state. 215447a1685fSDinh Nguyen * @ep: The endpoint the requests may be on. 215547a1685fSDinh Nguyen * @result: The result code to use. 215647a1685fSDinh Nguyen * 215747a1685fSDinh Nguyen * Go through the requests on the given endpoint and mark them 215847a1685fSDinh Nguyen * completed with the given result code. 215947a1685fSDinh Nguyen */ 2160941fcce4SDinh Nguyen static void kill_all_requests(struct dwc2_hsotg *hsotg, 21611f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep, 21626b448af4SRobert Baldyga int result) 216347a1685fSDinh Nguyen { 21641f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req, *treq; 2165b203d0a2SRobert Baldyga unsigned size; 216647a1685fSDinh Nguyen 21676b448af4SRobert Baldyga ep->req = NULL; 216847a1685fSDinh Nguyen 21696b448af4SRobert Baldyga list_for_each_entry_safe(req, treq, &ep->queue, queue) 21701f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hsotg, ep, req, 217147a1685fSDinh Nguyen result); 21726b448af4SRobert Baldyga 2173b203d0a2SRobert Baldyga if (!hsotg->dedicated_fifos) 2174b203d0a2SRobert Baldyga return; 217595c8bc36SAntti Seppälä size = (dwc2_readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4; 2176b203d0a2SRobert Baldyga if (size < ep->fifo_size) 21771f91b4ccSFelipe Balbi dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); 217847a1685fSDinh Nguyen } 217947a1685fSDinh Nguyen 218047a1685fSDinh Nguyen /** 21811f91b4ccSFelipe Balbi * dwc2_hsotg_disconnect - disconnect service 218247a1685fSDinh Nguyen * @hsotg: The device state. 218347a1685fSDinh Nguyen * 218447a1685fSDinh Nguyen * The device has been disconnected. Remove all current 218547a1685fSDinh Nguyen * transactions and signal the gadget driver that this 218647a1685fSDinh Nguyen * has happened. 218747a1685fSDinh Nguyen */ 21881f91b4ccSFelipe Balbi void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) 218947a1685fSDinh Nguyen { 219047a1685fSDinh Nguyen unsigned ep; 219147a1685fSDinh Nguyen 21924ace06e8SMarek Szyprowski if (!hsotg->connected) 21934ace06e8SMarek Szyprowski return; 21944ace06e8SMarek Szyprowski 21954ace06e8SMarek Szyprowski hsotg->connected = 0; 21969e14d0a5SGregory Herrero hsotg->test_mode = 0; 2197c6f5c050SMian Yousaf Kaukab 2198c6f5c050SMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps; ep++) { 2199c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 2200c6f5c050SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_in[ep], 2201c6f5c050SMian Yousaf Kaukab -ESHUTDOWN); 2202c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 2203c6f5c050SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_out[ep], 2204c6f5c050SMian Yousaf Kaukab -ESHUTDOWN); 2205c6f5c050SMian Yousaf Kaukab } 220647a1685fSDinh Nguyen 220747a1685fSDinh Nguyen call_gadget(hsotg, disconnect); 2208065d3931SGregory Herrero hsotg->lx_state = DWC2_L3; 220947a1685fSDinh Nguyen } 221047a1685fSDinh Nguyen 221147a1685fSDinh Nguyen /** 22121f91b4ccSFelipe Balbi * dwc2_hsotg_irq_fifoempty - TX FIFO empty interrupt handler 221347a1685fSDinh Nguyen * @hsotg: The device state: 221447a1685fSDinh Nguyen * @periodic: True if this is a periodic FIFO interrupt 221547a1685fSDinh Nguyen */ 22161f91b4ccSFelipe Balbi static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) 221747a1685fSDinh Nguyen { 22181f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *ep; 221947a1685fSDinh Nguyen int epno, ret; 222047a1685fSDinh Nguyen 222147a1685fSDinh Nguyen /* look through for any more data to transmit */ 222247a1685fSDinh Nguyen for (epno = 0; epno < hsotg->num_of_eps; epno++) { 2223c6f5c050SMian Yousaf Kaukab ep = index_to_ep(hsotg, epno, 1); 2224c6f5c050SMian Yousaf Kaukab 2225c6f5c050SMian Yousaf Kaukab if (!ep) 2226c6f5c050SMian Yousaf Kaukab continue; 222747a1685fSDinh Nguyen 222847a1685fSDinh Nguyen if (!ep->dir_in) 222947a1685fSDinh Nguyen continue; 223047a1685fSDinh Nguyen 223147a1685fSDinh Nguyen if ((periodic && !ep->periodic) || 223247a1685fSDinh Nguyen (!periodic && ep->periodic)) 223347a1685fSDinh Nguyen continue; 223447a1685fSDinh Nguyen 22351f91b4ccSFelipe Balbi ret = dwc2_hsotg_trytx(hsotg, ep); 223647a1685fSDinh Nguyen if (ret < 0) 223747a1685fSDinh Nguyen break; 223847a1685fSDinh Nguyen } 223947a1685fSDinh Nguyen } 224047a1685fSDinh Nguyen 224147a1685fSDinh Nguyen /* IRQ flags which will trigger a retry around the IRQ loop */ 224247a1685fSDinh Nguyen #define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ 224347a1685fSDinh Nguyen GINTSTS_PTXFEMP | \ 224447a1685fSDinh Nguyen GINTSTS_RXFLVL) 224547a1685fSDinh Nguyen 224647a1685fSDinh Nguyen /** 22471f91b4ccSFelipe Balbi * dwc2_hsotg_core_init - issue softreset to the core 224847a1685fSDinh Nguyen * @hsotg: The device state 224947a1685fSDinh Nguyen * 225047a1685fSDinh Nguyen * Issue a soft reset to the core, and await the core finishing it. 225147a1685fSDinh Nguyen */ 22521f91b4ccSFelipe Balbi void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, 2253643cc4deSGregory Herrero bool is_usb_reset) 225447a1685fSDinh Nguyen { 22551ee6903bSGregory Herrero u32 intmsk; 2256643cc4deSGregory Herrero u32 val; 2257ecd9a7adSPrzemek Rudy u32 usbcfg; 2258643cc4deSGregory Herrero 22595390d438SMian Yousaf Kaukab /* Kill any ep0 requests as controller will be reinitialized */ 22605390d438SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); 22615390d438SMian Yousaf Kaukab 2262643cc4deSGregory Herrero if (!is_usb_reset) 2263241729baSJohn Youn if (dwc2_core_reset(hsotg)) 226486de4895SGregory Herrero return; 226547a1685fSDinh Nguyen 226647a1685fSDinh Nguyen /* 226747a1685fSDinh Nguyen * we must now enable ep0 ready for host detection and then 226847a1685fSDinh Nguyen * set configuration. 226947a1685fSDinh Nguyen */ 227047a1685fSDinh Nguyen 2271ecd9a7adSPrzemek Rudy /* keep other bits untouched (so e.g. forced modes are not lost) */ 2272ecd9a7adSPrzemek Rudy usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); 2273ecd9a7adSPrzemek Rudy usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP | 2274ecd9a7adSPrzemek Rudy GUSBCFG_HNPCAP); 2275ecd9a7adSPrzemek Rudy 227647a1685fSDinh Nguyen /* set the PLL on, remove the HNP/SRP and set the PHY */ 2277fa4a8d72SMian Yousaf Kaukab val = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5; 2278ecd9a7adSPrzemek Rudy usbcfg |= hsotg->phyif | GUSBCFG_TOUTCAL(7) | 2279ecd9a7adSPrzemek Rudy (val << GUSBCFG_USBTRDTIM_SHIFT); 2280ecd9a7adSPrzemek Rudy dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); 228147a1685fSDinh Nguyen 22821f91b4ccSFelipe Balbi dwc2_hsotg_init_fifo(hsotg); 228347a1685fSDinh Nguyen 2284643cc4deSGregory Herrero if (!is_usb_reset) 228547a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 228647a1685fSDinh Nguyen 228795c8bc36SAntti Seppälä dwc2_writel(DCFG_EPMISCNT(1) | DCFG_DEVSPD_HS, hsotg->regs + DCFG); 228847a1685fSDinh Nguyen 228947a1685fSDinh Nguyen /* Clear any pending OTG interrupts */ 229095c8bc36SAntti Seppälä dwc2_writel(0xffffffff, hsotg->regs + GOTGINT); 229147a1685fSDinh Nguyen 229247a1685fSDinh Nguyen /* Clear any pending interrupts */ 229395c8bc36SAntti Seppälä dwc2_writel(0xffffffff, hsotg->regs + GINTSTS); 22941ee6903bSGregory Herrero intmsk = GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT | 229547a1685fSDinh Nguyen GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | 22961ee6903bSGregory Herrero GINTSTS_USBRST | GINTSTS_RESETDET | 22971ee6903bSGregory Herrero GINTSTS_ENUMDONE | GINTSTS_OTGINT | 2298ec1f9d9fSRoman Bacik GINTSTS_USBSUSP | GINTSTS_WKUPINT | 2299ec1f9d9fSRoman Bacik GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT; 23001ee6903bSGregory Herrero 23011ee6903bSGregory Herrero if (hsotg->core_params->external_id_pin_ctl <= 0) 23021ee6903bSGregory Herrero intmsk |= GINTSTS_CONIDSTSCHNG; 23031ee6903bSGregory Herrero 23041ee6903bSGregory Herrero dwc2_writel(intmsk, hsotg->regs + GINTMSK); 230547a1685fSDinh Nguyen 230647a1685fSDinh Nguyen if (using_dma(hsotg)) 230795c8bc36SAntti Seppälä dwc2_writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN | 23085f05048eSGregory Herrero (GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT), 230947a1685fSDinh Nguyen hsotg->regs + GAHBCFG); 231047a1685fSDinh Nguyen else 231195c8bc36SAntti Seppälä dwc2_writel(((hsotg->dedicated_fifos) ? 231295c8bc36SAntti Seppälä (GAHBCFG_NP_TXF_EMP_LVL | 231347a1685fSDinh Nguyen GAHBCFG_P_TXF_EMP_LVL) : 0) | 231495c8bc36SAntti Seppälä GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG); 231547a1685fSDinh Nguyen 231647a1685fSDinh Nguyen /* 231747a1685fSDinh Nguyen * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts 231847a1685fSDinh Nguyen * when we have no data to transfer. Otherwise we get being flooded by 231947a1685fSDinh Nguyen * interrupts. 232047a1685fSDinh Nguyen */ 232147a1685fSDinh Nguyen 232295c8bc36SAntti Seppälä dwc2_writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ? 23236ff2e832SMian Yousaf Kaukab DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) | 232447a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | 232547a1685fSDinh Nguyen DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | 232647a1685fSDinh Nguyen DIEPMSK_INTKNEPMISMSK, 232747a1685fSDinh Nguyen hsotg->regs + DIEPMSK); 232847a1685fSDinh Nguyen 232947a1685fSDinh Nguyen /* 233047a1685fSDinh Nguyen * don't need XferCompl, we get that from RXFIFO in slave mode. In 233147a1685fSDinh Nguyen * DMA mode we may need this. 233247a1685fSDinh Nguyen */ 233395c8bc36SAntti Seppälä dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK | 233447a1685fSDinh Nguyen DIEPMSK_TIMEOUTMSK) : 0) | 233547a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | 233647a1685fSDinh Nguyen DOEPMSK_SETUPMSK, 233747a1685fSDinh Nguyen hsotg->regs + DOEPMSK); 233847a1685fSDinh Nguyen 233995c8bc36SAntti Seppälä dwc2_writel(0, hsotg->regs + DAINTMSK); 234047a1685fSDinh Nguyen 234147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 234295c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DIEPCTL0), 234395c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL0)); 234447a1685fSDinh Nguyen 234547a1685fSDinh Nguyen /* enable in and out endpoint interrupts */ 23461f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT); 234747a1685fSDinh Nguyen 234847a1685fSDinh Nguyen /* 234947a1685fSDinh Nguyen * Enable the RXFIFO when in slave mode, as this is how we collect 235047a1685fSDinh Nguyen * the data. In DMA mode, we get events from the FIFO but also 235147a1685fSDinh Nguyen * things we cannot process, so do not use it. 235247a1685fSDinh Nguyen */ 235347a1685fSDinh Nguyen if (!using_dma(hsotg)) 23541f91b4ccSFelipe Balbi dwc2_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL); 235547a1685fSDinh Nguyen 235647a1685fSDinh Nguyen /* Enable interrupts for EP0 in and out */ 23571f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, 0, 0, 1); 23581f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, 0, 1, 1); 235947a1685fSDinh Nguyen 2360643cc4deSGregory Herrero if (!is_usb_reset) { 236147a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); 236247a1685fSDinh Nguyen udelay(10); /* see openiboot */ 236347a1685fSDinh Nguyen __bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); 2364643cc4deSGregory Herrero } 236547a1685fSDinh Nguyen 236695c8bc36SAntti Seppälä dev_dbg(hsotg->dev, "DCTL=0x%08x\n", dwc2_readl(hsotg->regs + DCTL)); 236747a1685fSDinh Nguyen 236847a1685fSDinh Nguyen /* 236947a1685fSDinh Nguyen * DxEPCTL_USBActEp says RO in manual, but seems to be set by 237047a1685fSDinh Nguyen * writing to the EPCTL register.. 237147a1685fSDinh Nguyen */ 237247a1685fSDinh Nguyen 237347a1685fSDinh Nguyen /* set to read 1 8byte packet */ 237495c8bc36SAntti Seppälä dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 237547a1685fSDinh Nguyen DXEPTSIZ_XFERSIZE(8), hsotg->regs + DOEPTSIZ0); 237647a1685fSDinh Nguyen 237795c8bc36SAntti Seppälä dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 237847a1685fSDinh Nguyen DXEPCTL_CNAK | DXEPCTL_EPENA | 237947a1685fSDinh Nguyen DXEPCTL_USBACTEP, 238047a1685fSDinh Nguyen hsotg->regs + DOEPCTL0); 238147a1685fSDinh Nguyen 238247a1685fSDinh Nguyen /* enable, but don't activate EP0in */ 238395c8bc36SAntti Seppälä dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 238447a1685fSDinh Nguyen DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0); 238547a1685fSDinh Nguyen 23861f91b4ccSFelipe Balbi dwc2_hsotg_enqueue_setup(hsotg); 238747a1685fSDinh Nguyen 238847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 238995c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DIEPCTL0), 239095c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + DOEPCTL0)); 239147a1685fSDinh Nguyen 239247a1685fSDinh Nguyen /* clear global NAKs */ 2393643cc4deSGregory Herrero val = DCTL_CGOUTNAK | DCTL_CGNPINNAK; 2394643cc4deSGregory Herrero if (!is_usb_reset) 2395643cc4deSGregory Herrero val |= DCTL_SFTDISCON; 2396643cc4deSGregory Herrero __orr32(hsotg->regs + DCTL, val); 239747a1685fSDinh Nguyen 239847a1685fSDinh Nguyen /* must be at-least 3ms to allow bus to see disconnect */ 239947a1685fSDinh Nguyen mdelay(3); 240047a1685fSDinh Nguyen 2401065d3931SGregory Herrero hsotg->lx_state = DWC2_L0; 2402ad38dc5dSMarek Szyprowski } 2403ac3c81f3SMarek Szyprowski 24041f91b4ccSFelipe Balbi static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) 2405ad38dc5dSMarek Szyprowski { 2406ad38dc5dSMarek Szyprowski /* set the soft-disconnect bit */ 2407ad38dc5dSMarek Szyprowski __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 2408ad38dc5dSMarek Szyprowski } 2409ad38dc5dSMarek Szyprowski 24101f91b4ccSFelipe Balbi void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) 2411ad38dc5dSMarek Szyprowski { 241247a1685fSDinh Nguyen /* remove the soft-disconnect and let's go */ 241347a1685fSDinh Nguyen __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON); 241447a1685fSDinh Nguyen } 241547a1685fSDinh Nguyen 241647a1685fSDinh Nguyen /** 24171f91b4ccSFelipe Balbi * dwc2_hsotg_irq - handle device interrupt 241847a1685fSDinh Nguyen * @irq: The IRQ number triggered 241947a1685fSDinh Nguyen * @pw: The pw value when registered the handler. 242047a1685fSDinh Nguyen */ 24211f91b4ccSFelipe Balbi static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) 242247a1685fSDinh Nguyen { 2423941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = pw; 242447a1685fSDinh Nguyen int retry_count = 8; 242547a1685fSDinh Nguyen u32 gintsts; 242647a1685fSDinh Nguyen u32 gintmsk; 242747a1685fSDinh Nguyen 2428*ee3de8d7SVardan Mikayelyan if (!dwc2_is_device_mode(hsotg)) 2429*ee3de8d7SVardan Mikayelyan return IRQ_NONE; 2430*ee3de8d7SVardan Mikayelyan 243147a1685fSDinh Nguyen spin_lock(&hsotg->lock); 243247a1685fSDinh Nguyen irq_retry: 243395c8bc36SAntti Seppälä gintsts = dwc2_readl(hsotg->regs + GINTSTS); 243495c8bc36SAntti Seppälä gintmsk = dwc2_readl(hsotg->regs + GINTMSK); 243547a1685fSDinh Nguyen 243647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", 243747a1685fSDinh Nguyen __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); 243847a1685fSDinh Nguyen 243947a1685fSDinh Nguyen gintsts &= gintmsk; 244047a1685fSDinh Nguyen 24418fc37b82SMian Yousaf Kaukab if (gintsts & GINTSTS_RESETDET) { 24428fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: USBRstDet\n", __func__); 24438fc37b82SMian Yousaf Kaukab 24448fc37b82SMian Yousaf Kaukab dwc2_writel(GINTSTS_RESETDET, hsotg->regs + GINTSTS); 24458fc37b82SMian Yousaf Kaukab 24468fc37b82SMian Yousaf Kaukab /* This event must be used only if controller is suspended */ 24478fc37b82SMian Yousaf Kaukab if (hsotg->lx_state == DWC2_L2) { 24488fc37b82SMian Yousaf Kaukab dwc2_exit_hibernation(hsotg, true); 24498fc37b82SMian Yousaf Kaukab hsotg->lx_state = DWC2_L0; 24508fc37b82SMian Yousaf Kaukab } 24518fc37b82SMian Yousaf Kaukab } 24528fc37b82SMian Yousaf Kaukab 24538fc37b82SMian Yousaf Kaukab if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) { 24548fc37b82SMian Yousaf Kaukab 24558fc37b82SMian Yousaf Kaukab u32 usb_status = dwc2_readl(hsotg->regs + GOTGCTL); 24568fc37b82SMian Yousaf Kaukab u32 connected = hsotg->connected; 24578fc37b82SMian Yousaf Kaukab 24588fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: USBRst\n", __func__); 24598fc37b82SMian Yousaf Kaukab dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", 24608fc37b82SMian Yousaf Kaukab dwc2_readl(hsotg->regs + GNPTXSTS)); 24618fc37b82SMian Yousaf Kaukab 24628fc37b82SMian Yousaf Kaukab dwc2_writel(GINTSTS_USBRST, hsotg->regs + GINTSTS); 24638fc37b82SMian Yousaf Kaukab 24648fc37b82SMian Yousaf Kaukab /* Report disconnection if it is not already done. */ 24658fc37b82SMian Yousaf Kaukab dwc2_hsotg_disconnect(hsotg); 24668fc37b82SMian Yousaf Kaukab 24678fc37b82SMian Yousaf Kaukab if (usb_status & GOTGCTL_BSESVLD && connected) 24688fc37b82SMian Yousaf Kaukab dwc2_hsotg_core_init_disconnected(hsotg, true); 24698fc37b82SMian Yousaf Kaukab } 24708fc37b82SMian Yousaf Kaukab 247147a1685fSDinh Nguyen if (gintsts & GINTSTS_ENUMDONE) { 247295c8bc36SAntti Seppälä dwc2_writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); 247347a1685fSDinh Nguyen 24741f91b4ccSFelipe Balbi dwc2_hsotg_irq_enumdone(hsotg); 247547a1685fSDinh Nguyen } 247647a1685fSDinh Nguyen 247747a1685fSDinh Nguyen if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { 247895c8bc36SAntti Seppälä u32 daint = dwc2_readl(hsotg->regs + DAINT); 247995c8bc36SAntti Seppälä u32 daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); 248047a1685fSDinh Nguyen u32 daint_out, daint_in; 248147a1685fSDinh Nguyen int ep; 248247a1685fSDinh Nguyen 248347a1685fSDinh Nguyen daint &= daintmsk; 248447a1685fSDinh Nguyen daint_out = daint >> DAINT_OUTEP_SHIFT; 248547a1685fSDinh Nguyen daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); 248647a1685fSDinh Nguyen 248747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); 248847a1685fSDinh Nguyen 2489cec87f1dSMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps && daint_out; 2490cec87f1dSMian Yousaf Kaukab ep++, daint_out >>= 1) { 249147a1685fSDinh Nguyen if (daint_out & 1) 24921f91b4ccSFelipe Balbi dwc2_hsotg_epint(hsotg, ep, 0); 249347a1685fSDinh Nguyen } 249447a1685fSDinh Nguyen 2495cec87f1dSMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps && daint_in; 2496cec87f1dSMian Yousaf Kaukab ep++, daint_in >>= 1) { 249747a1685fSDinh Nguyen if (daint_in & 1) 24981f91b4ccSFelipe Balbi dwc2_hsotg_epint(hsotg, ep, 1); 249947a1685fSDinh Nguyen } 250047a1685fSDinh Nguyen } 250147a1685fSDinh Nguyen 250247a1685fSDinh Nguyen /* check both FIFOs */ 250347a1685fSDinh Nguyen 250447a1685fSDinh Nguyen if (gintsts & GINTSTS_NPTXFEMP) { 250547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "NPTxFEmp\n"); 250647a1685fSDinh Nguyen 250747a1685fSDinh Nguyen /* 250847a1685fSDinh Nguyen * Disable the interrupt to stop it happening again 250947a1685fSDinh Nguyen * unless one of these endpoint routines decides that 251047a1685fSDinh Nguyen * it needs re-enabling 251147a1685fSDinh Nguyen */ 251247a1685fSDinh Nguyen 25131f91b4ccSFelipe Balbi dwc2_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); 25141f91b4ccSFelipe Balbi dwc2_hsotg_irq_fifoempty(hsotg, false); 251547a1685fSDinh Nguyen } 251647a1685fSDinh Nguyen 251747a1685fSDinh Nguyen if (gintsts & GINTSTS_PTXFEMP) { 251847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "PTxFEmp\n"); 251947a1685fSDinh Nguyen 252047a1685fSDinh Nguyen /* See note in GINTSTS_NPTxFEmp */ 252147a1685fSDinh Nguyen 25221f91b4ccSFelipe Balbi dwc2_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); 25231f91b4ccSFelipe Balbi dwc2_hsotg_irq_fifoempty(hsotg, true); 252447a1685fSDinh Nguyen } 252547a1685fSDinh Nguyen 252647a1685fSDinh Nguyen if (gintsts & GINTSTS_RXFLVL) { 252747a1685fSDinh Nguyen /* 252847a1685fSDinh Nguyen * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, 25291f91b4ccSFelipe Balbi * we need to retry dwc2_hsotg_handle_rx if this is still 253047a1685fSDinh Nguyen * set. 253147a1685fSDinh Nguyen */ 253247a1685fSDinh Nguyen 25331f91b4ccSFelipe Balbi dwc2_hsotg_handle_rx(hsotg); 253447a1685fSDinh Nguyen } 253547a1685fSDinh Nguyen 253647a1685fSDinh Nguyen if (gintsts & GINTSTS_ERLYSUSP) { 253747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); 253895c8bc36SAntti Seppälä dwc2_writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS); 253947a1685fSDinh Nguyen } 254047a1685fSDinh Nguyen 254147a1685fSDinh Nguyen /* 254247a1685fSDinh Nguyen * these next two seem to crop-up occasionally causing the core 254347a1685fSDinh Nguyen * to shutdown the USB transfer, so try clearing them and logging 254447a1685fSDinh Nguyen * the occurrence. 254547a1685fSDinh Nguyen */ 254647a1685fSDinh Nguyen 254747a1685fSDinh Nguyen if (gintsts & GINTSTS_GOUTNAKEFF) { 254847a1685fSDinh Nguyen dev_info(hsotg->dev, "GOUTNakEff triggered\n"); 254947a1685fSDinh Nguyen 25503be99cd0SGregory Herrero __orr32(hsotg->regs + DCTL, DCTL_CGOUTNAK); 255147a1685fSDinh Nguyen 25521f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 255347a1685fSDinh Nguyen } 255447a1685fSDinh Nguyen 255547a1685fSDinh Nguyen if (gintsts & GINTSTS_GINNAKEFF) { 255647a1685fSDinh Nguyen dev_info(hsotg->dev, "GINNakEff triggered\n"); 255747a1685fSDinh Nguyen 25583be99cd0SGregory Herrero __orr32(hsotg->regs + DCTL, DCTL_CGNPINNAK); 255947a1685fSDinh Nguyen 25601f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 256147a1685fSDinh Nguyen } 256247a1685fSDinh Nguyen 2563ec1f9d9fSRoman Bacik if (gintsts & GINTSTS_INCOMPL_SOIN) { 2564ec1f9d9fSRoman Bacik u32 idx, epctl_reg; 2565ec1f9d9fSRoman Bacik struct dwc2_hsotg_ep *hs_ep; 2566ec1f9d9fSRoman Bacik 2567ec1f9d9fSRoman Bacik dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOIN\n", __func__); 2568ec1f9d9fSRoman Bacik for (idx = 1; idx < hsotg->num_of_eps; idx++) { 2569ec1f9d9fSRoman Bacik hs_ep = hsotg->eps_in[idx]; 2570ec1f9d9fSRoman Bacik 2571ec1f9d9fSRoman Bacik if (!hs_ep->isochronous || hs_ep->has_correct_parity) 2572ec1f9d9fSRoman Bacik continue; 2573ec1f9d9fSRoman Bacik 2574ec1f9d9fSRoman Bacik epctl_reg = DIEPCTL(idx); 2575ec1f9d9fSRoman Bacik dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg); 2576ec1f9d9fSRoman Bacik } 2577ec1f9d9fSRoman Bacik dwc2_writel(GINTSTS_INCOMPL_SOIN, hsotg->regs + GINTSTS); 2578ec1f9d9fSRoman Bacik } 2579ec1f9d9fSRoman Bacik 2580ec1f9d9fSRoman Bacik if (gintsts & GINTSTS_INCOMPL_SOOUT) { 2581ec1f9d9fSRoman Bacik u32 idx, epctl_reg; 2582ec1f9d9fSRoman Bacik struct dwc2_hsotg_ep *hs_ep; 2583ec1f9d9fSRoman Bacik 2584ec1f9d9fSRoman Bacik dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__); 2585ec1f9d9fSRoman Bacik for (idx = 1; idx < hsotg->num_of_eps; idx++) { 2586ec1f9d9fSRoman Bacik hs_ep = hsotg->eps_out[idx]; 2587ec1f9d9fSRoman Bacik 2588ec1f9d9fSRoman Bacik if (!hs_ep->isochronous || hs_ep->has_correct_parity) 2589ec1f9d9fSRoman Bacik continue; 2590ec1f9d9fSRoman Bacik 2591ec1f9d9fSRoman Bacik epctl_reg = DOEPCTL(idx); 2592ec1f9d9fSRoman Bacik dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg); 2593ec1f9d9fSRoman Bacik } 2594ec1f9d9fSRoman Bacik dwc2_writel(GINTSTS_INCOMPL_SOOUT, hsotg->regs + GINTSTS); 2595ec1f9d9fSRoman Bacik } 2596ec1f9d9fSRoman Bacik 259747a1685fSDinh Nguyen /* 259847a1685fSDinh Nguyen * if we've had fifo events, we should try and go around the 259947a1685fSDinh Nguyen * loop again to see if there's any point in returning yet. 260047a1685fSDinh Nguyen */ 260147a1685fSDinh Nguyen 260247a1685fSDinh Nguyen if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) 260347a1685fSDinh Nguyen goto irq_retry; 260447a1685fSDinh Nguyen 260547a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 260647a1685fSDinh Nguyen 260747a1685fSDinh Nguyen return IRQ_HANDLED; 260847a1685fSDinh Nguyen } 260947a1685fSDinh Nguyen 261047a1685fSDinh Nguyen /** 26111f91b4ccSFelipe Balbi * dwc2_hsotg_ep_enable - enable the given endpoint 261247a1685fSDinh Nguyen * @ep: The USB endpint to configure 261347a1685fSDinh Nguyen * @desc: The USB endpoint descriptor to configure with. 261447a1685fSDinh Nguyen * 261547a1685fSDinh Nguyen * This is called from the USB gadget code's usb_ep_enable(). 261647a1685fSDinh Nguyen */ 26171f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_enable(struct usb_ep *ep, 261847a1685fSDinh Nguyen const struct usb_endpoint_descriptor *desc) 261947a1685fSDinh Nguyen { 26201f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 2621941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 262247a1685fSDinh Nguyen unsigned long flags; 2623ca4c55adSMian Yousaf Kaukab unsigned int index = hs_ep->index; 262447a1685fSDinh Nguyen u32 epctrl_reg; 262547a1685fSDinh Nguyen u32 epctrl; 262647a1685fSDinh Nguyen u32 mps; 2627ca4c55adSMian Yousaf Kaukab unsigned int dir_in; 2628ca4c55adSMian Yousaf Kaukab unsigned int i, val, size; 262947a1685fSDinh Nguyen int ret = 0; 263047a1685fSDinh Nguyen 263147a1685fSDinh Nguyen dev_dbg(hsotg->dev, 263247a1685fSDinh Nguyen "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", 263347a1685fSDinh Nguyen __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, 263447a1685fSDinh Nguyen desc->wMaxPacketSize, desc->bInterval); 263547a1685fSDinh Nguyen 263647a1685fSDinh Nguyen /* not to be called for EP0 */ 26378c3d6092SVahram Aharonyan if (index == 0) { 26388c3d6092SVahram Aharonyan dev_err(hsotg->dev, "%s: called for EP 0\n", __func__); 26398c3d6092SVahram Aharonyan return -EINVAL; 26408c3d6092SVahram Aharonyan } 264147a1685fSDinh Nguyen 264247a1685fSDinh Nguyen dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; 264347a1685fSDinh Nguyen if (dir_in != hs_ep->dir_in) { 264447a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); 264547a1685fSDinh Nguyen return -EINVAL; 264647a1685fSDinh Nguyen } 264747a1685fSDinh Nguyen 264847a1685fSDinh Nguyen mps = usb_endpoint_maxp(desc); 264947a1685fSDinh Nguyen 26501f91b4ccSFelipe Balbi /* note, we handle this here instead of dwc2_hsotg_set_ep_maxpacket */ 265147a1685fSDinh Nguyen 265247a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 265395c8bc36SAntti Seppälä epctrl = dwc2_readl(hsotg->regs + epctrl_reg); 265447a1685fSDinh Nguyen 265547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", 265647a1685fSDinh Nguyen __func__, epctrl, epctrl_reg); 265747a1685fSDinh Nguyen 265847a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 265947a1685fSDinh Nguyen 266047a1685fSDinh Nguyen epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK); 266147a1685fSDinh Nguyen epctrl |= DXEPCTL_MPS(mps); 266247a1685fSDinh Nguyen 266347a1685fSDinh Nguyen /* 266447a1685fSDinh Nguyen * mark the endpoint as active, otherwise the core may ignore 266547a1685fSDinh Nguyen * transactions entirely for this endpoint 266647a1685fSDinh Nguyen */ 266747a1685fSDinh Nguyen epctrl |= DXEPCTL_USBACTEP; 266847a1685fSDinh Nguyen 266947a1685fSDinh Nguyen /* 267047a1685fSDinh Nguyen * set the NAK status on the endpoint, otherwise we might try and 267147a1685fSDinh Nguyen * do something with data that we've yet got a request to process 267247a1685fSDinh Nguyen * since the RXFIFO will take data for an endpoint even if the 267347a1685fSDinh Nguyen * size register hasn't been set. 267447a1685fSDinh Nguyen */ 267547a1685fSDinh Nguyen 267647a1685fSDinh Nguyen epctrl |= DXEPCTL_SNAK; 267747a1685fSDinh Nguyen 267847a1685fSDinh Nguyen /* update the endpoint state */ 26791f91b4ccSFelipe Balbi dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, dir_in); 268047a1685fSDinh Nguyen 268147a1685fSDinh Nguyen /* default, set to non-periodic */ 268247a1685fSDinh Nguyen hs_ep->isochronous = 0; 268347a1685fSDinh Nguyen hs_ep->periodic = 0; 268447a1685fSDinh Nguyen hs_ep->halted = 0; 268547a1685fSDinh Nguyen hs_ep->interval = desc->bInterval; 2686ec1f9d9fSRoman Bacik hs_ep->has_correct_parity = 0; 268747a1685fSDinh Nguyen 268847a1685fSDinh Nguyen if (hs_ep->interval > 1 && hs_ep->mc > 1) 268947a1685fSDinh Nguyen dev_err(hsotg->dev, "MC > 1 when interval is not 1\n"); 269047a1685fSDinh Nguyen 269147a1685fSDinh Nguyen switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { 269247a1685fSDinh Nguyen case USB_ENDPOINT_XFER_ISOC: 269347a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_ISO; 269447a1685fSDinh Nguyen epctrl |= DXEPCTL_SETEVENFR; 269547a1685fSDinh Nguyen hs_ep->isochronous = 1; 269647a1685fSDinh Nguyen if (dir_in) 269747a1685fSDinh Nguyen hs_ep->periodic = 1; 269847a1685fSDinh Nguyen break; 269947a1685fSDinh Nguyen 270047a1685fSDinh Nguyen case USB_ENDPOINT_XFER_BULK: 270147a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_BULK; 270247a1685fSDinh Nguyen break; 270347a1685fSDinh Nguyen 270447a1685fSDinh Nguyen case USB_ENDPOINT_XFER_INT: 2705b203d0a2SRobert Baldyga if (dir_in) 270647a1685fSDinh Nguyen hs_ep->periodic = 1; 270747a1685fSDinh Nguyen 270847a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_INTERRUPT; 270947a1685fSDinh Nguyen break; 271047a1685fSDinh Nguyen 271147a1685fSDinh Nguyen case USB_ENDPOINT_XFER_CONTROL: 271247a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_CONTROL; 271347a1685fSDinh Nguyen break; 271447a1685fSDinh Nguyen } 271547a1685fSDinh Nguyen 27164556e12cSMian Yousaf Kaukab /* If fifo is already allocated for this ep */ 27174556e12cSMian Yousaf Kaukab if (hs_ep->fifo_index) { 27184556e12cSMian Yousaf Kaukab size = hs_ep->ep.maxpacket * hs_ep->mc; 27194556e12cSMian Yousaf Kaukab /* If bigger fifo is required deallocate current one */ 27204556e12cSMian Yousaf Kaukab if (size > hs_ep->fifo_size) { 27214556e12cSMian Yousaf Kaukab hsotg->fifo_map &= ~(1 << hs_ep->fifo_index); 27224556e12cSMian Yousaf Kaukab hs_ep->fifo_index = 0; 27234556e12cSMian Yousaf Kaukab hs_ep->fifo_size = 0; 27244556e12cSMian Yousaf Kaukab } 27254556e12cSMian Yousaf Kaukab } 27264556e12cSMian Yousaf Kaukab 272747a1685fSDinh Nguyen /* 272847a1685fSDinh Nguyen * if the hardware has dedicated fifos, we must give each IN EP 272947a1685fSDinh Nguyen * a unique tx-fifo even if it is non-periodic. 273047a1685fSDinh Nguyen */ 27314556e12cSMian Yousaf Kaukab if (dir_in && hsotg->dedicated_fifos && !hs_ep->fifo_index) { 2732ca4c55adSMian Yousaf Kaukab u32 fifo_index = 0; 2733ca4c55adSMian Yousaf Kaukab u32 fifo_size = UINT_MAX; 2734b203d0a2SRobert Baldyga size = hs_ep->ep.maxpacket*hs_ep->mc; 27355f2196bdSMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; ++i) { 2736b203d0a2SRobert Baldyga if (hsotg->fifo_map & (1<<i)) 2737b203d0a2SRobert Baldyga continue; 273895c8bc36SAntti Seppälä val = dwc2_readl(hsotg->regs + DPTXFSIZN(i)); 2739b203d0a2SRobert Baldyga val = (val >> FIFOSIZE_DEPTH_SHIFT)*4; 2740b203d0a2SRobert Baldyga if (val < size) 2741b203d0a2SRobert Baldyga continue; 2742ca4c55adSMian Yousaf Kaukab /* Search for smallest acceptable fifo */ 2743ca4c55adSMian Yousaf Kaukab if (val < fifo_size) { 2744ca4c55adSMian Yousaf Kaukab fifo_size = val; 2745ca4c55adSMian Yousaf Kaukab fifo_index = i; 2746b203d0a2SRobert Baldyga } 2747ca4c55adSMian Yousaf Kaukab } 2748ca4c55adSMian Yousaf Kaukab if (!fifo_index) { 27495f2196bdSMian Yousaf Kaukab dev_err(hsotg->dev, 27505f2196bdSMian Yousaf Kaukab "%s: No suitable fifo found\n", __func__); 2751b585a48bSSudip Mukherjee ret = -ENOMEM; 2752b585a48bSSudip Mukherjee goto error; 2753b585a48bSSudip Mukherjee } 2754ca4c55adSMian Yousaf Kaukab hsotg->fifo_map |= 1 << fifo_index; 2755ca4c55adSMian Yousaf Kaukab epctrl |= DXEPCTL_TXFNUM(fifo_index); 2756ca4c55adSMian Yousaf Kaukab hs_ep->fifo_index = fifo_index; 2757ca4c55adSMian Yousaf Kaukab hs_ep->fifo_size = fifo_size; 2758b203d0a2SRobert Baldyga } 275947a1685fSDinh Nguyen 276047a1685fSDinh Nguyen /* for non control endpoints, set PID to D0 */ 276147a1685fSDinh Nguyen if (index) 276247a1685fSDinh Nguyen epctrl |= DXEPCTL_SETD0PID; 276347a1685fSDinh Nguyen 276447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", 276547a1685fSDinh Nguyen __func__, epctrl); 276647a1685fSDinh Nguyen 276795c8bc36SAntti Seppälä dwc2_writel(epctrl, hsotg->regs + epctrl_reg); 276847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", 276995c8bc36SAntti Seppälä __func__, dwc2_readl(hsotg->regs + epctrl_reg)); 277047a1685fSDinh Nguyen 277147a1685fSDinh Nguyen /* enable the endpoint interrupt */ 27721f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, index, dir_in, 1); 277347a1685fSDinh Nguyen 2774b585a48bSSudip Mukherjee error: 277547a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 277647a1685fSDinh Nguyen return ret; 277747a1685fSDinh Nguyen } 277847a1685fSDinh Nguyen 277947a1685fSDinh Nguyen /** 27801f91b4ccSFelipe Balbi * dwc2_hsotg_ep_disable - disable given endpoint 278147a1685fSDinh Nguyen * @ep: The endpoint to disable. 278247a1685fSDinh Nguyen */ 27831f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_disable(struct usb_ep *ep) 278447a1685fSDinh Nguyen { 27851f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 2786941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 278747a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 278847a1685fSDinh Nguyen int index = hs_ep->index; 278947a1685fSDinh Nguyen unsigned long flags; 279047a1685fSDinh Nguyen u32 epctrl_reg; 279147a1685fSDinh Nguyen u32 ctrl; 279247a1685fSDinh Nguyen 27931e011293SMarek Szyprowski dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); 279447a1685fSDinh Nguyen 2795c6f5c050SMian Yousaf Kaukab if (ep == &hsotg->eps_out[0]->ep) { 279647a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: called for ep0\n", __func__); 279747a1685fSDinh Nguyen return -EINVAL; 279847a1685fSDinh Nguyen } 279947a1685fSDinh Nguyen 280047a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 280147a1685fSDinh Nguyen 280247a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 280347a1685fSDinh Nguyen 2804b203d0a2SRobert Baldyga hsotg->fifo_map &= ~(1<<hs_ep->fifo_index); 2805b203d0a2SRobert Baldyga hs_ep->fifo_index = 0; 2806b203d0a2SRobert Baldyga hs_ep->fifo_size = 0; 280747a1685fSDinh Nguyen 280895c8bc36SAntti Seppälä ctrl = dwc2_readl(hsotg->regs + epctrl_reg); 280947a1685fSDinh Nguyen ctrl &= ~DXEPCTL_EPENA; 281047a1685fSDinh Nguyen ctrl &= ~DXEPCTL_USBACTEP; 281147a1685fSDinh Nguyen ctrl |= DXEPCTL_SNAK; 281247a1685fSDinh Nguyen 281347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 281495c8bc36SAntti Seppälä dwc2_writel(ctrl, hsotg->regs + epctrl_reg); 281547a1685fSDinh Nguyen 281647a1685fSDinh Nguyen /* disable endpoint interrupts */ 28171f91b4ccSFelipe Balbi dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); 281847a1685fSDinh Nguyen 28191141ea01SMian Yousaf Kaukab /* terminate all requests with shutdown */ 28201141ea01SMian Yousaf Kaukab kill_all_requests(hsotg, hs_ep, -ESHUTDOWN); 28211141ea01SMian Yousaf Kaukab 282247a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 282347a1685fSDinh Nguyen return 0; 282447a1685fSDinh Nguyen } 282547a1685fSDinh Nguyen 282647a1685fSDinh Nguyen /** 282747a1685fSDinh Nguyen * on_list - check request is on the given endpoint 282847a1685fSDinh Nguyen * @ep: The endpoint to check. 282947a1685fSDinh Nguyen * @test: The request to test if it is on the endpoint. 283047a1685fSDinh Nguyen */ 28311f91b4ccSFelipe Balbi static bool on_list(struct dwc2_hsotg_ep *ep, struct dwc2_hsotg_req *test) 283247a1685fSDinh Nguyen { 28331f91b4ccSFelipe Balbi struct dwc2_hsotg_req *req, *treq; 283447a1685fSDinh Nguyen 283547a1685fSDinh Nguyen list_for_each_entry_safe(req, treq, &ep->queue, queue) { 283647a1685fSDinh Nguyen if (req == test) 283747a1685fSDinh Nguyen return true; 283847a1685fSDinh Nguyen } 283947a1685fSDinh Nguyen 284047a1685fSDinh Nguyen return false; 284147a1685fSDinh Nguyen } 284247a1685fSDinh Nguyen 2843c524dd5fSMian Yousaf Kaukab static int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hs_otg, u32 reg, 2844c524dd5fSMian Yousaf Kaukab u32 bit, u32 timeout) 2845c524dd5fSMian Yousaf Kaukab { 2846c524dd5fSMian Yousaf Kaukab u32 i; 2847c524dd5fSMian Yousaf Kaukab 2848c524dd5fSMian Yousaf Kaukab for (i = 0; i < timeout; i++) { 2849c524dd5fSMian Yousaf Kaukab if (dwc2_readl(hs_otg->regs + reg) & bit) 2850c524dd5fSMian Yousaf Kaukab return 0; 2851c524dd5fSMian Yousaf Kaukab udelay(1); 2852c524dd5fSMian Yousaf Kaukab } 2853c524dd5fSMian Yousaf Kaukab 2854c524dd5fSMian Yousaf Kaukab return -ETIMEDOUT; 2855c524dd5fSMian Yousaf Kaukab } 2856c524dd5fSMian Yousaf Kaukab 2857c524dd5fSMian Yousaf Kaukab static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, 2858c524dd5fSMian Yousaf Kaukab struct dwc2_hsotg_ep *hs_ep) 2859c524dd5fSMian Yousaf Kaukab { 2860c524dd5fSMian Yousaf Kaukab u32 epctrl_reg; 2861c524dd5fSMian Yousaf Kaukab u32 epint_reg; 2862c524dd5fSMian Yousaf Kaukab 2863c524dd5fSMian Yousaf Kaukab epctrl_reg = hs_ep->dir_in ? DIEPCTL(hs_ep->index) : 2864c524dd5fSMian Yousaf Kaukab DOEPCTL(hs_ep->index); 2865c524dd5fSMian Yousaf Kaukab epint_reg = hs_ep->dir_in ? DIEPINT(hs_ep->index) : 2866c524dd5fSMian Yousaf Kaukab DOEPINT(hs_ep->index); 2867c524dd5fSMian Yousaf Kaukab 2868c524dd5fSMian Yousaf Kaukab dev_dbg(hsotg->dev, "%s: stopping transfer on %s\n", __func__, 2869c524dd5fSMian Yousaf Kaukab hs_ep->name); 2870c524dd5fSMian Yousaf Kaukab if (hs_ep->dir_in) { 2871c524dd5fSMian Yousaf Kaukab __orr32(hsotg->regs + epctrl_reg, DXEPCTL_SNAK); 2872c524dd5fSMian Yousaf Kaukab /* Wait for Nak effect */ 2873c524dd5fSMian Yousaf Kaukab if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, 2874c524dd5fSMian Yousaf Kaukab DXEPINT_INEPNAKEFF, 100)) 2875c524dd5fSMian Yousaf Kaukab dev_warn(hsotg->dev, 2876c524dd5fSMian Yousaf Kaukab "%s: timeout DIEPINT.NAKEFF\n", __func__); 2877c524dd5fSMian Yousaf Kaukab } else { 2878c524dd5fSMian Yousaf Kaukab /* Clear any pending nak effect interrupt */ 28790676c7e7SDu, Changbin dwc2_writel(GINTSTS_GOUTNAKEFF, hsotg->regs + GINTSTS); 2880c524dd5fSMian Yousaf Kaukab 28810676c7e7SDu, Changbin __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK); 2882c524dd5fSMian Yousaf Kaukab 2883c524dd5fSMian Yousaf Kaukab /* Wait for global nak to take effect */ 2884c524dd5fSMian Yousaf Kaukab if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 28850676c7e7SDu, Changbin GINTSTS_GOUTNAKEFF, 100)) 2886c524dd5fSMian Yousaf Kaukab dev_warn(hsotg->dev, 28870676c7e7SDu, Changbin "%s: timeout GINTSTS.GOUTNAKEFF\n", __func__); 2888c524dd5fSMian Yousaf Kaukab } 2889c524dd5fSMian Yousaf Kaukab 2890c524dd5fSMian Yousaf Kaukab /* Disable ep */ 2891c524dd5fSMian Yousaf Kaukab __orr32(hsotg->regs + epctrl_reg, DXEPCTL_EPDIS | DXEPCTL_SNAK); 2892c524dd5fSMian Yousaf Kaukab 2893c524dd5fSMian Yousaf Kaukab /* Wait for ep to be disabled */ 2894c524dd5fSMian Yousaf Kaukab if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, DXEPINT_EPDISBLD, 100)) 2895c524dd5fSMian Yousaf Kaukab dev_warn(hsotg->dev, 2896c524dd5fSMian Yousaf Kaukab "%s: timeout DOEPCTL.EPDisable\n", __func__); 2897c524dd5fSMian Yousaf Kaukab 2898c524dd5fSMian Yousaf Kaukab if (hs_ep->dir_in) { 2899c524dd5fSMian Yousaf Kaukab if (hsotg->dedicated_fifos) { 2900c524dd5fSMian Yousaf Kaukab dwc2_writel(GRSTCTL_TXFNUM(hs_ep->fifo_index) | 2901c524dd5fSMian Yousaf Kaukab GRSTCTL_TXFFLSH, hsotg->regs + GRSTCTL); 2902c524dd5fSMian Yousaf Kaukab /* Wait for fifo flush */ 2903c524dd5fSMian Yousaf Kaukab if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, 2904c524dd5fSMian Yousaf Kaukab GRSTCTL_TXFFLSH, 100)) 2905c524dd5fSMian Yousaf Kaukab dev_warn(hsotg->dev, 2906c524dd5fSMian Yousaf Kaukab "%s: timeout flushing fifos\n", 2907c524dd5fSMian Yousaf Kaukab __func__); 2908c524dd5fSMian Yousaf Kaukab } 2909c524dd5fSMian Yousaf Kaukab /* TODO: Flush shared tx fifo */ 2910c524dd5fSMian Yousaf Kaukab } else { 2911c524dd5fSMian Yousaf Kaukab /* Remove global NAKs */ 29120676c7e7SDu, Changbin __bic32(hsotg->regs + DCTL, DCTL_SGOUTNAK); 2913c524dd5fSMian Yousaf Kaukab } 2914c524dd5fSMian Yousaf Kaukab } 2915c524dd5fSMian Yousaf Kaukab 291647a1685fSDinh Nguyen /** 29171f91b4ccSFelipe Balbi * dwc2_hsotg_ep_dequeue - dequeue given endpoint 291847a1685fSDinh Nguyen * @ep: The endpoint to dequeue. 291947a1685fSDinh Nguyen * @req: The request to be removed from a queue. 292047a1685fSDinh Nguyen */ 29211f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) 292247a1685fSDinh Nguyen { 29231f91b4ccSFelipe Balbi struct dwc2_hsotg_req *hs_req = our_req(req); 29241f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 2925941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 292647a1685fSDinh Nguyen unsigned long flags; 292747a1685fSDinh Nguyen 29281e011293SMarek Szyprowski dev_dbg(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); 292947a1685fSDinh Nguyen 293047a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 293147a1685fSDinh Nguyen 293247a1685fSDinh Nguyen if (!on_list(hs_ep, hs_req)) { 293347a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 293447a1685fSDinh Nguyen return -EINVAL; 293547a1685fSDinh Nguyen } 293647a1685fSDinh Nguyen 2937c524dd5fSMian Yousaf Kaukab /* Dequeue already started request */ 2938c524dd5fSMian Yousaf Kaukab if (req == &hs_ep->req->req) 2939c524dd5fSMian Yousaf Kaukab dwc2_hsotg_ep_stop_xfr(hs, hs_ep); 2940c524dd5fSMian Yousaf Kaukab 29411f91b4ccSFelipe Balbi dwc2_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); 294247a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 294347a1685fSDinh Nguyen 294447a1685fSDinh Nguyen return 0; 294547a1685fSDinh Nguyen } 294647a1685fSDinh Nguyen 294747a1685fSDinh Nguyen /** 29481f91b4ccSFelipe Balbi * dwc2_hsotg_ep_sethalt - set halt on a given endpoint 294947a1685fSDinh Nguyen * @ep: The endpoint to set halt. 295047a1685fSDinh Nguyen * @value: Set or unset the halt. 295147a1685fSDinh Nguyen */ 29521f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value) 295347a1685fSDinh Nguyen { 29541f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 2955941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 295647a1685fSDinh Nguyen int index = hs_ep->index; 295747a1685fSDinh Nguyen u32 epreg; 295847a1685fSDinh Nguyen u32 epctl; 295947a1685fSDinh Nguyen u32 xfertype; 296047a1685fSDinh Nguyen 296147a1685fSDinh Nguyen dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); 296247a1685fSDinh Nguyen 296347a1685fSDinh Nguyen if (index == 0) { 296447a1685fSDinh Nguyen if (value) 29651f91b4ccSFelipe Balbi dwc2_hsotg_stall_ep0(hs); 296647a1685fSDinh Nguyen else 296747a1685fSDinh Nguyen dev_warn(hs->dev, 296847a1685fSDinh Nguyen "%s: can't clear halt on ep0\n", __func__); 296947a1685fSDinh Nguyen return 0; 297047a1685fSDinh Nguyen } 297147a1685fSDinh Nguyen 2972c6f5c050SMian Yousaf Kaukab if (hs_ep->dir_in) { 297347a1685fSDinh Nguyen epreg = DIEPCTL(index); 297495c8bc36SAntti Seppälä epctl = dwc2_readl(hs->regs + epreg); 297547a1685fSDinh Nguyen 297647a1685fSDinh Nguyen if (value) { 29775a350d53SFelipe Balbi epctl |= DXEPCTL_STALL | DXEPCTL_SNAK; 297847a1685fSDinh Nguyen if (epctl & DXEPCTL_EPENA) 297947a1685fSDinh Nguyen epctl |= DXEPCTL_EPDIS; 298047a1685fSDinh Nguyen } else { 298147a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 298247a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 298347a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 298447a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 298547a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 298647a1685fSDinh Nguyen } 298795c8bc36SAntti Seppälä dwc2_writel(epctl, hs->regs + epreg); 2988c6f5c050SMian Yousaf Kaukab } else { 298947a1685fSDinh Nguyen 299047a1685fSDinh Nguyen epreg = DOEPCTL(index); 299195c8bc36SAntti Seppälä epctl = dwc2_readl(hs->regs + epreg); 299247a1685fSDinh Nguyen 299347a1685fSDinh Nguyen if (value) 299447a1685fSDinh Nguyen epctl |= DXEPCTL_STALL; 299547a1685fSDinh Nguyen else { 299647a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 299747a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 299847a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 299947a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 300047a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 300147a1685fSDinh Nguyen } 300295c8bc36SAntti Seppälä dwc2_writel(epctl, hs->regs + epreg); 3003c6f5c050SMian Yousaf Kaukab } 300447a1685fSDinh Nguyen 300547a1685fSDinh Nguyen hs_ep->halted = value; 300647a1685fSDinh Nguyen 300747a1685fSDinh Nguyen return 0; 300847a1685fSDinh Nguyen } 300947a1685fSDinh Nguyen 301047a1685fSDinh Nguyen /** 30111f91b4ccSFelipe Balbi * dwc2_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held 301247a1685fSDinh Nguyen * @ep: The endpoint to set halt. 301347a1685fSDinh Nguyen * @value: Set or unset the halt. 301447a1685fSDinh Nguyen */ 30151f91b4ccSFelipe Balbi static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) 301647a1685fSDinh Nguyen { 30171f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 3018941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 301947a1685fSDinh Nguyen unsigned long flags = 0; 302047a1685fSDinh Nguyen int ret = 0; 302147a1685fSDinh Nguyen 302247a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 30231f91b4ccSFelipe Balbi ret = dwc2_hsotg_ep_sethalt(ep, value); 302447a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 302547a1685fSDinh Nguyen 302647a1685fSDinh Nguyen return ret; 302747a1685fSDinh Nguyen } 302847a1685fSDinh Nguyen 30291f91b4ccSFelipe Balbi static struct usb_ep_ops dwc2_hsotg_ep_ops = { 30301f91b4ccSFelipe Balbi .enable = dwc2_hsotg_ep_enable, 30311f91b4ccSFelipe Balbi .disable = dwc2_hsotg_ep_disable, 30321f91b4ccSFelipe Balbi .alloc_request = dwc2_hsotg_ep_alloc_request, 30331f91b4ccSFelipe Balbi .free_request = dwc2_hsotg_ep_free_request, 30341f91b4ccSFelipe Balbi .queue = dwc2_hsotg_ep_queue_lock, 30351f91b4ccSFelipe Balbi .dequeue = dwc2_hsotg_ep_dequeue, 30361f91b4ccSFelipe Balbi .set_halt = dwc2_hsotg_ep_sethalt_lock, 303747a1685fSDinh Nguyen /* note, don't believe we have any call for the fifo routines */ 303847a1685fSDinh Nguyen }; 303947a1685fSDinh Nguyen 304047a1685fSDinh Nguyen /** 30411f91b4ccSFelipe Balbi * dwc2_hsotg_init - initalize the usb core 304247a1685fSDinh Nguyen * @hsotg: The driver state 304347a1685fSDinh Nguyen */ 30441f91b4ccSFelipe Balbi static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) 304547a1685fSDinh Nguyen { 3046fa4a8d72SMian Yousaf Kaukab u32 trdtim; 3047ecd9a7adSPrzemek Rudy u32 usbcfg; 304847a1685fSDinh Nguyen /* unmask subset of endpoint interrupts */ 304947a1685fSDinh Nguyen 305095c8bc36SAntti Seppälä dwc2_writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | 305147a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK, 305247a1685fSDinh Nguyen hsotg->regs + DIEPMSK); 305347a1685fSDinh Nguyen 305495c8bc36SAntti Seppälä dwc2_writel(DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | 305547a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK, 305647a1685fSDinh Nguyen hsotg->regs + DOEPMSK); 305747a1685fSDinh Nguyen 305895c8bc36SAntti Seppälä dwc2_writel(0, hsotg->regs + DAINTMSK); 305947a1685fSDinh Nguyen 306047a1685fSDinh Nguyen /* Be in disconnected state until gadget is registered */ 306147a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 306247a1685fSDinh Nguyen 306347a1685fSDinh Nguyen /* setup fifos */ 306447a1685fSDinh Nguyen 306547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 306695c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + GRXFSIZ), 306795c8bc36SAntti Seppälä dwc2_readl(hsotg->regs + GNPTXFSIZ)); 306847a1685fSDinh Nguyen 30691f91b4ccSFelipe Balbi dwc2_hsotg_init_fifo(hsotg); 307047a1685fSDinh Nguyen 3071ecd9a7adSPrzemek Rudy /* keep other bits untouched (so e.g. forced modes are not lost) */ 3072ecd9a7adSPrzemek Rudy usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); 3073ecd9a7adSPrzemek Rudy usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP | 3074ecd9a7adSPrzemek Rudy GUSBCFG_HNPCAP); 3075ecd9a7adSPrzemek Rudy 307647a1685fSDinh Nguyen /* set the PLL on, remove the HNP/SRP and set the PHY */ 3077fa4a8d72SMian Yousaf Kaukab trdtim = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5; 3078ecd9a7adSPrzemek Rudy usbcfg |= hsotg->phyif | GUSBCFG_TOUTCAL(7) | 3079ecd9a7adSPrzemek Rudy (trdtim << GUSBCFG_USBTRDTIM_SHIFT); 3080ecd9a7adSPrzemek Rudy dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); 308147a1685fSDinh Nguyen 3082f5090044SGregory Herrero if (using_dma(hsotg)) 3083f5090044SGregory Herrero __orr32(hsotg->regs + GAHBCFG, GAHBCFG_DMA_EN); 308447a1685fSDinh Nguyen } 308547a1685fSDinh Nguyen 308647a1685fSDinh Nguyen /** 30871f91b4ccSFelipe Balbi * dwc2_hsotg_udc_start - prepare the udc for work 308847a1685fSDinh Nguyen * @gadget: The usb gadget state 308947a1685fSDinh Nguyen * @driver: The usb gadget driver 309047a1685fSDinh Nguyen * 309147a1685fSDinh Nguyen * Perform initialization to prepare udc device and driver 309247a1685fSDinh Nguyen * to work. 309347a1685fSDinh Nguyen */ 30941f91b4ccSFelipe Balbi static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, 309547a1685fSDinh Nguyen struct usb_gadget_driver *driver) 309647a1685fSDinh Nguyen { 3097941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 30985b9451f8SMarek Szyprowski unsigned long flags; 309947a1685fSDinh Nguyen int ret; 310047a1685fSDinh Nguyen 310147a1685fSDinh Nguyen if (!hsotg) { 310247a1685fSDinh Nguyen pr_err("%s: called with no device\n", __func__); 310347a1685fSDinh Nguyen return -ENODEV; 310447a1685fSDinh Nguyen } 310547a1685fSDinh Nguyen 310647a1685fSDinh Nguyen if (!driver) { 310747a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: no driver\n", __func__); 310847a1685fSDinh Nguyen return -EINVAL; 310947a1685fSDinh Nguyen } 311047a1685fSDinh Nguyen 311147a1685fSDinh Nguyen if (driver->max_speed < USB_SPEED_FULL) 311247a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: bad speed\n", __func__); 311347a1685fSDinh Nguyen 311447a1685fSDinh Nguyen if (!driver->setup) { 311547a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: missing entry points\n", __func__); 311647a1685fSDinh Nguyen return -EINVAL; 311747a1685fSDinh Nguyen } 311847a1685fSDinh Nguyen 311947a1685fSDinh Nguyen WARN_ON(hsotg->driver); 312047a1685fSDinh Nguyen 312147a1685fSDinh Nguyen driver->driver.bus = NULL; 312247a1685fSDinh Nguyen hsotg->driver = driver; 312347a1685fSDinh Nguyen hsotg->gadget.dev.of_node = hsotg->dev->of_node; 312447a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 312547a1685fSDinh Nguyen 312609a75e85SMarek Szyprowski if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) { 312709a75e85SMarek Szyprowski ret = dwc2_lowlevel_hw_enable(hsotg); 312809a75e85SMarek Szyprowski if (ret) 312947a1685fSDinh Nguyen goto err; 313047a1685fSDinh Nguyen } 313147a1685fSDinh Nguyen 3132f6c01592SGregory Herrero if (!IS_ERR_OR_NULL(hsotg->uphy)) 3133f6c01592SGregory Herrero otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget); 3134c816c47fSMarek Szyprowski 31355b9451f8SMarek Szyprowski spin_lock_irqsave(&hsotg->lock, flags); 31361f91b4ccSFelipe Balbi dwc2_hsotg_init(hsotg); 31371f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 3138dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 31395b9451f8SMarek Szyprowski spin_unlock_irqrestore(&hsotg->lock, flags); 31405b9451f8SMarek Szyprowski 314147a1685fSDinh Nguyen dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); 31425b9451f8SMarek Szyprowski 314347a1685fSDinh Nguyen return 0; 314447a1685fSDinh Nguyen 314547a1685fSDinh Nguyen err: 314647a1685fSDinh Nguyen hsotg->driver = NULL; 314747a1685fSDinh Nguyen return ret; 314847a1685fSDinh Nguyen } 314947a1685fSDinh Nguyen 315047a1685fSDinh Nguyen /** 31511f91b4ccSFelipe Balbi * dwc2_hsotg_udc_stop - stop the udc 315247a1685fSDinh Nguyen * @gadget: The usb gadget state 315347a1685fSDinh Nguyen * @driver: The usb gadget driver 315447a1685fSDinh Nguyen * 315547a1685fSDinh Nguyen * Stop udc hw block and stay tunned for future transmissions 315647a1685fSDinh Nguyen */ 31571f91b4ccSFelipe Balbi static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) 315847a1685fSDinh Nguyen { 3159941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 316047a1685fSDinh Nguyen unsigned long flags = 0; 316147a1685fSDinh Nguyen int ep; 316247a1685fSDinh Nguyen 316347a1685fSDinh Nguyen if (!hsotg) 316447a1685fSDinh Nguyen return -ENODEV; 316547a1685fSDinh Nguyen 316647a1685fSDinh Nguyen /* all endpoints should be shutdown */ 3167c6f5c050SMian Yousaf Kaukab for (ep = 1; ep < hsotg->num_of_eps; ep++) { 3168c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 31691f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 3170c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 31711f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 3172c6f5c050SMian Yousaf Kaukab } 317347a1685fSDinh Nguyen 317447a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 317547a1685fSDinh Nguyen 317647a1685fSDinh Nguyen hsotg->driver = NULL; 317747a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 3178dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 317947a1685fSDinh Nguyen 318047a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 318147a1685fSDinh Nguyen 3182f6c01592SGregory Herrero if (!IS_ERR_OR_NULL(hsotg->uphy)) 3183f6c01592SGregory Herrero otg_set_peripheral(hsotg->uphy->otg, NULL); 3184c816c47fSMarek Szyprowski 318509a75e85SMarek Szyprowski if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 318609a75e85SMarek Szyprowski dwc2_lowlevel_hw_disable(hsotg); 318747a1685fSDinh Nguyen 318847a1685fSDinh Nguyen return 0; 318947a1685fSDinh Nguyen } 319047a1685fSDinh Nguyen 319147a1685fSDinh Nguyen /** 31921f91b4ccSFelipe Balbi * dwc2_hsotg_gadget_getframe - read the frame number 319347a1685fSDinh Nguyen * @gadget: The usb gadget state 319447a1685fSDinh Nguyen * 319547a1685fSDinh Nguyen * Read the {micro} frame number 319647a1685fSDinh Nguyen */ 31971f91b4ccSFelipe Balbi static int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget) 319847a1685fSDinh Nguyen { 31991f91b4ccSFelipe Balbi return dwc2_hsotg_read_frameno(to_hsotg(gadget)); 320047a1685fSDinh Nguyen } 320147a1685fSDinh Nguyen 320247a1685fSDinh Nguyen /** 32031f91b4ccSFelipe Balbi * dwc2_hsotg_pullup - connect/disconnect the USB PHY 320447a1685fSDinh Nguyen * @gadget: The usb gadget state 320547a1685fSDinh Nguyen * @is_on: Current state of the USB PHY 320647a1685fSDinh Nguyen * 320747a1685fSDinh Nguyen * Connect/Disconnect the USB PHY pullup 320847a1685fSDinh Nguyen */ 32091f91b4ccSFelipe Balbi static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) 321047a1685fSDinh Nguyen { 3211941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 321247a1685fSDinh Nguyen unsigned long flags = 0; 321347a1685fSDinh Nguyen 321477ba9119SGregory Herrero dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on, 321577ba9119SGregory Herrero hsotg->op_state); 321677ba9119SGregory Herrero 321777ba9119SGregory Herrero /* Don't modify pullup state while in host mode */ 321877ba9119SGregory Herrero if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { 321977ba9119SGregory Herrero hsotg->enabled = is_on; 322077ba9119SGregory Herrero return 0; 322177ba9119SGregory Herrero } 322247a1685fSDinh Nguyen 322347a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 322447a1685fSDinh Nguyen if (is_on) { 3225dc6e69e6SMarek Szyprowski hsotg->enabled = 1; 32261f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 32271f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 322847a1685fSDinh Nguyen } else { 32291f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 32301f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 3231dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 323247a1685fSDinh Nguyen } 323347a1685fSDinh Nguyen 323447a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 323547a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 323647a1685fSDinh Nguyen 323747a1685fSDinh Nguyen return 0; 323847a1685fSDinh Nguyen } 323947a1685fSDinh Nguyen 32401f91b4ccSFelipe Balbi static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) 324183d98223SGregory Herrero { 324283d98223SGregory Herrero struct dwc2_hsotg *hsotg = to_hsotg(gadget); 324383d98223SGregory Herrero unsigned long flags; 324483d98223SGregory Herrero 324583d98223SGregory Herrero dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active); 324683d98223SGregory Herrero spin_lock_irqsave(&hsotg->lock, flags); 324783d98223SGregory Herrero 324818b2b37cSGregory Herrero /* 324918b2b37cSGregory Herrero * If controller is hibernated, it must exit from hibernation 325061f7223bSGregory Herrero * before being initialized / de-initialized 325118b2b37cSGregory Herrero */ 3252065d3931SGregory Herrero if (hsotg->lx_state == DWC2_L2) 325318b2b37cSGregory Herrero dwc2_exit_hibernation(hsotg, false); 3254065d3931SGregory Herrero 325561f7223bSGregory Herrero if (is_active) { 325661f7223bSGregory Herrero hsotg->op_state = OTG_STATE_B_PERIPHERAL; 325761f7223bSGregory Herrero 32581f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 325983d98223SGregory Herrero if (hsotg->enabled) 32601f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 326183d98223SGregory Herrero } else { 32621f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 32631f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 326483d98223SGregory Herrero } 326583d98223SGregory Herrero 326683d98223SGregory Herrero spin_unlock_irqrestore(&hsotg->lock, flags); 326783d98223SGregory Herrero return 0; 326883d98223SGregory Herrero } 326983d98223SGregory Herrero 3270596d696aSGregory Herrero /** 32711f91b4ccSFelipe Balbi * dwc2_hsotg_vbus_draw - report bMaxPower field 3272596d696aSGregory Herrero * @gadget: The usb gadget state 3273596d696aSGregory Herrero * @mA: Amount of current 3274596d696aSGregory Herrero * 3275596d696aSGregory Herrero * Report how much power the device may consume to the phy. 3276596d696aSGregory Herrero */ 32771f91b4ccSFelipe Balbi static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned mA) 3278596d696aSGregory Herrero { 3279596d696aSGregory Herrero struct dwc2_hsotg *hsotg = to_hsotg(gadget); 3280596d696aSGregory Herrero 3281596d696aSGregory Herrero if (IS_ERR_OR_NULL(hsotg->uphy)) 3282596d696aSGregory Herrero return -ENOTSUPP; 3283596d696aSGregory Herrero return usb_phy_set_power(hsotg->uphy, mA); 3284596d696aSGregory Herrero } 3285596d696aSGregory Herrero 32861f91b4ccSFelipe Balbi static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { 32871f91b4ccSFelipe Balbi .get_frame = dwc2_hsotg_gadget_getframe, 32881f91b4ccSFelipe Balbi .udc_start = dwc2_hsotg_udc_start, 32891f91b4ccSFelipe Balbi .udc_stop = dwc2_hsotg_udc_stop, 32901f91b4ccSFelipe Balbi .pullup = dwc2_hsotg_pullup, 32911f91b4ccSFelipe Balbi .vbus_session = dwc2_hsotg_vbus_session, 32921f91b4ccSFelipe Balbi .vbus_draw = dwc2_hsotg_vbus_draw, 329347a1685fSDinh Nguyen }; 329447a1685fSDinh Nguyen 329547a1685fSDinh Nguyen /** 32961f91b4ccSFelipe Balbi * dwc2_hsotg_initep - initialise a single endpoint 329747a1685fSDinh Nguyen * @hsotg: The device state. 329847a1685fSDinh Nguyen * @hs_ep: The endpoint to be initialised. 329947a1685fSDinh Nguyen * @epnum: The endpoint number 330047a1685fSDinh Nguyen * 330147a1685fSDinh Nguyen * Initialise the given endpoint (as part of the probe and device state 330247a1685fSDinh Nguyen * creation) to give to the gadget driver. Setup the endpoint name, any 330347a1685fSDinh Nguyen * direction information and other state that may be required. 330447a1685fSDinh Nguyen */ 33051f91b4ccSFelipe Balbi static void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, 33061f91b4ccSFelipe Balbi struct dwc2_hsotg_ep *hs_ep, 3307c6f5c050SMian Yousaf Kaukab int epnum, 3308c6f5c050SMian Yousaf Kaukab bool dir_in) 330947a1685fSDinh Nguyen { 331047a1685fSDinh Nguyen char *dir; 331147a1685fSDinh Nguyen 331247a1685fSDinh Nguyen if (epnum == 0) 331347a1685fSDinh Nguyen dir = ""; 3314c6f5c050SMian Yousaf Kaukab else if (dir_in) 331547a1685fSDinh Nguyen dir = "in"; 3316c6f5c050SMian Yousaf Kaukab else 3317c6f5c050SMian Yousaf Kaukab dir = "out"; 331847a1685fSDinh Nguyen 3319c6f5c050SMian Yousaf Kaukab hs_ep->dir_in = dir_in; 332047a1685fSDinh Nguyen hs_ep->index = epnum; 332147a1685fSDinh Nguyen 332247a1685fSDinh Nguyen snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); 332347a1685fSDinh Nguyen 332447a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->queue); 332547a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->ep.ep_list); 332647a1685fSDinh Nguyen 332747a1685fSDinh Nguyen /* add to the list of endpoints known by the gadget driver */ 332847a1685fSDinh Nguyen if (epnum) 332947a1685fSDinh Nguyen list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); 333047a1685fSDinh Nguyen 333147a1685fSDinh Nguyen hs_ep->parent = hsotg; 333247a1685fSDinh Nguyen hs_ep->ep.name = hs_ep->name; 333347a1685fSDinh Nguyen usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT); 33341f91b4ccSFelipe Balbi hs_ep->ep.ops = &dwc2_hsotg_ep_ops; 333547a1685fSDinh Nguyen 33362954522fSRobert Baldyga if (epnum == 0) { 33372954522fSRobert Baldyga hs_ep->ep.caps.type_control = true; 33382954522fSRobert Baldyga } else { 33392954522fSRobert Baldyga hs_ep->ep.caps.type_iso = true; 33402954522fSRobert Baldyga hs_ep->ep.caps.type_bulk = true; 33412954522fSRobert Baldyga hs_ep->ep.caps.type_int = true; 33422954522fSRobert Baldyga } 33432954522fSRobert Baldyga 33442954522fSRobert Baldyga if (dir_in) 33452954522fSRobert Baldyga hs_ep->ep.caps.dir_in = true; 33462954522fSRobert Baldyga else 33472954522fSRobert Baldyga hs_ep->ep.caps.dir_out = true; 33482954522fSRobert Baldyga 334947a1685fSDinh Nguyen /* 335047a1685fSDinh Nguyen * if we're using dma, we need to set the next-endpoint pointer 335147a1685fSDinh Nguyen * to be something valid. 335247a1685fSDinh Nguyen */ 335347a1685fSDinh Nguyen 335447a1685fSDinh Nguyen if (using_dma(hsotg)) { 335547a1685fSDinh Nguyen u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); 3356c6f5c050SMian Yousaf Kaukab if (dir_in) 335795c8bc36SAntti Seppälä dwc2_writel(next, hsotg->regs + DIEPCTL(epnum)); 3358c6f5c050SMian Yousaf Kaukab else 335995c8bc36SAntti Seppälä dwc2_writel(next, hsotg->regs + DOEPCTL(epnum)); 336047a1685fSDinh Nguyen } 336147a1685fSDinh Nguyen } 336247a1685fSDinh Nguyen 336347a1685fSDinh Nguyen /** 33641f91b4ccSFelipe Balbi * dwc2_hsotg_hw_cfg - read HW configuration registers 336547a1685fSDinh Nguyen * @param: The device state 336647a1685fSDinh Nguyen * 336747a1685fSDinh Nguyen * Read the USB core HW configuration registers 336847a1685fSDinh Nguyen */ 33691f91b4ccSFelipe Balbi static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) 337047a1685fSDinh Nguyen { 3371c6f5c050SMian Yousaf Kaukab u32 cfg; 3372c6f5c050SMian Yousaf Kaukab u32 ep_type; 3373c6f5c050SMian Yousaf Kaukab u32 i; 3374c6f5c050SMian Yousaf Kaukab 337547a1685fSDinh Nguyen /* check hardware configuration */ 337647a1685fSDinh Nguyen 337743e90349SJohn Youn hsotg->num_of_eps = hsotg->hw_params.num_dev_ep; 337843e90349SJohn Youn 3379c6f5c050SMian Yousaf Kaukab /* Add ep0 */ 3380c6f5c050SMian Yousaf Kaukab hsotg->num_of_eps++; 338147a1685fSDinh Nguyen 33821f91b4ccSFelipe Balbi hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, sizeof(struct dwc2_hsotg_ep), 3383c6f5c050SMian Yousaf Kaukab GFP_KERNEL); 3384c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_in[0]) 3385c6f5c050SMian Yousaf Kaukab return -ENOMEM; 33861f91b4ccSFelipe Balbi /* Same dwc2_hsotg_ep is used in both directions for ep0 */ 3387c6f5c050SMian Yousaf Kaukab hsotg->eps_out[0] = hsotg->eps_in[0]; 338847a1685fSDinh Nguyen 338943e90349SJohn Youn cfg = hsotg->hw_params.dev_ep_dirs; 3390251a17f5SRoshan Pius for (i = 1, cfg >>= 2; i < hsotg->num_of_eps; i++, cfg >>= 2) { 3391c6f5c050SMian Yousaf Kaukab ep_type = cfg & 3; 3392c6f5c050SMian Yousaf Kaukab /* Direction in or both */ 3393c6f5c050SMian Yousaf Kaukab if (!(ep_type & 2)) { 3394c6f5c050SMian Yousaf Kaukab hsotg->eps_in[i] = devm_kzalloc(hsotg->dev, 33951f91b4ccSFelipe Balbi sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 3396c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_in[i]) 3397c6f5c050SMian Yousaf Kaukab return -ENOMEM; 3398c6f5c050SMian Yousaf Kaukab } 3399c6f5c050SMian Yousaf Kaukab /* Direction out or both */ 3400c6f5c050SMian Yousaf Kaukab if (!(ep_type & 1)) { 3401c6f5c050SMian Yousaf Kaukab hsotg->eps_out[i] = devm_kzalloc(hsotg->dev, 34021f91b4ccSFelipe Balbi sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 3403c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_out[i]) 3404c6f5c050SMian Yousaf Kaukab return -ENOMEM; 3405c6f5c050SMian Yousaf Kaukab } 3406c6f5c050SMian Yousaf Kaukab } 3407c6f5c050SMian Yousaf Kaukab 340843e90349SJohn Youn hsotg->fifo_mem = hsotg->hw_params.total_fifo_size; 340943e90349SJohn Youn hsotg->dedicated_fifos = hsotg->hw_params.en_multiple_tx_fifo; 341047a1685fSDinh Nguyen 3411cff9eb75SMarek Szyprowski dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n", 3412cff9eb75SMarek Szyprowski hsotg->num_of_eps, 3413cff9eb75SMarek Szyprowski hsotg->dedicated_fifos ? "dedicated" : "shared", 3414cff9eb75SMarek Szyprowski hsotg->fifo_mem); 3415c6f5c050SMian Yousaf Kaukab return 0; 341647a1685fSDinh Nguyen } 341747a1685fSDinh Nguyen 341847a1685fSDinh Nguyen /** 34191f91b4ccSFelipe Balbi * dwc2_hsotg_dump - dump state of the udc 342047a1685fSDinh Nguyen * @param: The device state 342147a1685fSDinh Nguyen */ 34221f91b4ccSFelipe Balbi static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) 342347a1685fSDinh Nguyen { 342447a1685fSDinh Nguyen #ifdef DEBUG 342547a1685fSDinh Nguyen struct device *dev = hsotg->dev; 342647a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 342747a1685fSDinh Nguyen u32 val; 342847a1685fSDinh Nguyen int idx; 342947a1685fSDinh Nguyen 343047a1685fSDinh Nguyen dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", 343195c8bc36SAntti Seppälä dwc2_readl(regs + DCFG), dwc2_readl(regs + DCTL), 343295c8bc36SAntti Seppälä dwc2_readl(regs + DIEPMSK)); 343347a1685fSDinh Nguyen 3434f889f23dSMian Yousaf Kaukab dev_info(dev, "GAHBCFG=0x%08x, GHWCFG1=0x%08x\n", 343595c8bc36SAntti Seppälä dwc2_readl(regs + GAHBCFG), dwc2_readl(regs + GHWCFG1)); 343647a1685fSDinh Nguyen 343747a1685fSDinh Nguyen dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 343895c8bc36SAntti Seppälä dwc2_readl(regs + GRXFSIZ), dwc2_readl(regs + GNPTXFSIZ)); 343947a1685fSDinh Nguyen 344047a1685fSDinh Nguyen /* show periodic fifo settings */ 344147a1685fSDinh Nguyen 3442364f8e93SMian Yousaf Kaukab for (idx = 1; idx < hsotg->num_of_eps; idx++) { 344395c8bc36SAntti Seppälä val = dwc2_readl(regs + DPTXFSIZN(idx)); 344447a1685fSDinh Nguyen dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, 344547a1685fSDinh Nguyen val >> FIFOSIZE_DEPTH_SHIFT, 344647a1685fSDinh Nguyen val & FIFOSIZE_STARTADDR_MASK); 344747a1685fSDinh Nguyen } 344847a1685fSDinh Nguyen 3449364f8e93SMian Yousaf Kaukab for (idx = 0; idx < hsotg->num_of_eps; idx++) { 345047a1685fSDinh Nguyen dev_info(dev, 345147a1685fSDinh Nguyen "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, 345295c8bc36SAntti Seppälä dwc2_readl(regs + DIEPCTL(idx)), 345395c8bc36SAntti Seppälä dwc2_readl(regs + DIEPTSIZ(idx)), 345495c8bc36SAntti Seppälä dwc2_readl(regs + DIEPDMA(idx))); 345547a1685fSDinh Nguyen 345695c8bc36SAntti Seppälä val = dwc2_readl(regs + DOEPCTL(idx)); 345747a1685fSDinh Nguyen dev_info(dev, 345847a1685fSDinh Nguyen "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", 345995c8bc36SAntti Seppälä idx, dwc2_readl(regs + DOEPCTL(idx)), 346095c8bc36SAntti Seppälä dwc2_readl(regs + DOEPTSIZ(idx)), 346195c8bc36SAntti Seppälä dwc2_readl(regs + DOEPDMA(idx))); 346247a1685fSDinh Nguyen 346347a1685fSDinh Nguyen } 346447a1685fSDinh Nguyen 346547a1685fSDinh Nguyen dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", 346695c8bc36SAntti Seppälä dwc2_readl(regs + DVBUSDIS), dwc2_readl(regs + DVBUSPULSE)); 346747a1685fSDinh Nguyen #endif 346847a1685fSDinh Nguyen } 346947a1685fSDinh Nguyen 3470edd74be8SGregory Herrero #ifdef CONFIG_OF 34711f91b4ccSFelipe Balbi static void dwc2_hsotg_of_probe(struct dwc2_hsotg *hsotg) 3472edd74be8SGregory Herrero { 3473edd74be8SGregory Herrero struct device_node *np = hsotg->dev->of_node; 34740a176279SGregory Herrero u32 len = 0; 34750a176279SGregory Herrero u32 i = 0; 3476edd74be8SGregory Herrero 3477edd74be8SGregory Herrero /* Enable dma if requested in device tree */ 3478edd74be8SGregory Herrero hsotg->g_using_dma = of_property_read_bool(np, "g-use-dma"); 34790a176279SGregory Herrero 34800a176279SGregory Herrero /* 34810a176279SGregory Herrero * Register TX periodic fifo size per endpoint. 34820a176279SGregory Herrero * EP0 is excluded since it has no fifo configuration. 34830a176279SGregory Herrero */ 34840a176279SGregory Herrero if (!of_find_property(np, "g-tx-fifo-size", &len)) 34850a176279SGregory Herrero goto rx_fifo; 34860a176279SGregory Herrero 34870a176279SGregory Herrero len /= sizeof(u32); 34880a176279SGregory Herrero 34890a176279SGregory Herrero /* Read tx fifo sizes other than ep0 */ 34900a176279SGregory Herrero if (of_property_read_u32_array(np, "g-tx-fifo-size", 34910a176279SGregory Herrero &hsotg->g_tx_fifo_sz[1], len)) 34920a176279SGregory Herrero goto rx_fifo; 34930a176279SGregory Herrero 34940a176279SGregory Herrero /* Add ep0 */ 34950a176279SGregory Herrero len++; 34960a176279SGregory Herrero 34970a176279SGregory Herrero /* Make remaining TX fifos unavailable */ 34980a176279SGregory Herrero if (len < MAX_EPS_CHANNELS) { 34990a176279SGregory Herrero for (i = len; i < MAX_EPS_CHANNELS; i++) 35000a176279SGregory Herrero hsotg->g_tx_fifo_sz[i] = 0; 35010a176279SGregory Herrero } 35020a176279SGregory Herrero 35030a176279SGregory Herrero rx_fifo: 35040a176279SGregory Herrero /* Register RX fifo size */ 35050a176279SGregory Herrero of_property_read_u32(np, "g-rx-fifo-size", &hsotg->g_rx_fifo_sz); 35060a176279SGregory Herrero 35070a176279SGregory Herrero /* Register NPTX fifo size */ 35080a176279SGregory Herrero of_property_read_u32(np, "g-np-tx-fifo-size", 35090a176279SGregory Herrero &hsotg->g_np_g_tx_fifo_sz); 3510edd74be8SGregory Herrero } 3511edd74be8SGregory Herrero #else 35121f91b4ccSFelipe Balbi static inline void dwc2_hsotg_of_probe(struct dwc2_hsotg *hsotg) { } 3513edd74be8SGregory Herrero #endif 3514edd74be8SGregory Herrero 351547a1685fSDinh Nguyen /** 3516117777b2SDinh Nguyen * dwc2_gadget_init - init function for gadget 3517117777b2SDinh Nguyen * @dwc2: The data structure for the DWC2 driver. 3518117777b2SDinh Nguyen * @irq: The IRQ number for the controller. 351947a1685fSDinh Nguyen */ 3520117777b2SDinh Nguyen int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) 352147a1685fSDinh Nguyen { 3522117777b2SDinh Nguyen struct device *dev = hsotg->dev; 352347a1685fSDinh Nguyen int epnum; 352447a1685fSDinh Nguyen int ret; 352547a1685fSDinh Nguyen int i; 35260a176279SGregory Herrero u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE; 352747a1685fSDinh Nguyen 35280a176279SGregory Herrero /* Initialize to legacy fifo configuration values */ 35290a176279SGregory Herrero hsotg->g_rx_fifo_sz = 2048; 35300a176279SGregory Herrero hsotg->g_np_g_tx_fifo_sz = 1024; 35310a176279SGregory Herrero memcpy(&hsotg->g_tx_fifo_sz[1], p_tx_fifo, sizeof(p_tx_fifo)); 35320a176279SGregory Herrero /* Device tree specific probe */ 35331f91b4ccSFelipe Balbi dwc2_hsotg_of_probe(hsotg); 353443e90349SJohn Youn 353543e90349SJohn Youn /* Check against largest possible value. */ 353643e90349SJohn Youn if (hsotg->g_np_g_tx_fifo_sz > 353743e90349SJohn Youn hsotg->hw_params.dev_nperio_tx_fifo_size) { 353843e90349SJohn Youn dev_warn(dev, "Specified GNPTXFDEP=%d > %d\n", 353943e90349SJohn Youn hsotg->g_np_g_tx_fifo_sz, 354043e90349SJohn Youn hsotg->hw_params.dev_nperio_tx_fifo_size); 354143e90349SJohn Youn hsotg->g_np_g_tx_fifo_sz = 354243e90349SJohn Youn hsotg->hw_params.dev_nperio_tx_fifo_size; 354343e90349SJohn Youn } 354443e90349SJohn Youn 35450a176279SGregory Herrero /* Dump fifo information */ 35460a176279SGregory Herrero dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n", 35470a176279SGregory Herrero hsotg->g_np_g_tx_fifo_sz); 35480a176279SGregory Herrero dev_dbg(dev, "RXFIFO size: %d\n", hsotg->g_rx_fifo_sz); 35490a176279SGregory Herrero for (i = 0; i < MAX_EPS_CHANNELS; i++) 35500a176279SGregory Herrero dev_dbg(dev, "Periodic TXFIFO%2d size: %d\n", i, 35510a176279SGregory Herrero hsotg->g_tx_fifo_sz[i]); 355247a1685fSDinh Nguyen 355347a1685fSDinh Nguyen hsotg->gadget.max_speed = USB_SPEED_HIGH; 35541f91b4ccSFelipe Balbi hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; 355547a1685fSDinh Nguyen hsotg->gadget.name = dev_name(dev); 3556097ee662SGregory Herrero if (hsotg->dr_mode == USB_DR_MODE_OTG) 3557097ee662SGregory Herrero hsotg->gadget.is_otg = 1; 3558ec4cc657SMian Yousaf Kaukab else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 3559ec4cc657SMian Yousaf Kaukab hsotg->op_state = OTG_STATE_B_PERIPHERAL; 356047a1685fSDinh Nguyen 35611f91b4ccSFelipe Balbi ret = dwc2_hsotg_hw_cfg(hsotg); 3562c6f5c050SMian Yousaf Kaukab if (ret) { 3563c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret); 356409a75e85SMarek Szyprowski return ret; 3565c6f5c050SMian Yousaf Kaukab } 3566c6f5c050SMian Yousaf Kaukab 35673f95001dSMian Yousaf Kaukab hsotg->ctrl_buff = devm_kzalloc(hsotg->dev, 35683f95001dSMian Yousaf Kaukab DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 35693f95001dSMian Yousaf Kaukab if (!hsotg->ctrl_buff) { 35703f95001dSMian Yousaf Kaukab dev_err(dev, "failed to allocate ctrl request buff\n"); 357109a75e85SMarek Szyprowski return -ENOMEM; 35723f95001dSMian Yousaf Kaukab } 35733f95001dSMian Yousaf Kaukab 35743f95001dSMian Yousaf Kaukab hsotg->ep0_buff = devm_kzalloc(hsotg->dev, 35753f95001dSMian Yousaf Kaukab DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 35763f95001dSMian Yousaf Kaukab if (!hsotg->ep0_buff) { 35773f95001dSMian Yousaf Kaukab dev_err(dev, "failed to allocate ctrl reply buff\n"); 357809a75e85SMarek Szyprowski return -ENOMEM; 35793f95001dSMian Yousaf Kaukab } 35803f95001dSMian Yousaf Kaukab 35811f91b4ccSFelipe Balbi ret = devm_request_irq(hsotg->dev, irq, dwc2_hsotg_irq, IRQF_SHARED, 3582db8178c3SDinh Nguyen dev_name(hsotg->dev), hsotg); 3583eb3c56c5SMarek Szyprowski if (ret < 0) { 3584db8178c3SDinh Nguyen dev_err(dev, "cannot claim IRQ for gadget\n"); 358509a75e85SMarek Szyprowski return ret; 3586eb3c56c5SMarek Szyprowski } 3587eb3c56c5SMarek Szyprowski 358847a1685fSDinh Nguyen /* hsotg->num_of_eps holds number of EPs other than ep0 */ 358947a1685fSDinh Nguyen 359047a1685fSDinh Nguyen if (hsotg->num_of_eps == 0) { 359147a1685fSDinh Nguyen dev_err(dev, "wrong number of EPs (zero)\n"); 359209a75e85SMarek Szyprowski return -EINVAL; 359347a1685fSDinh Nguyen } 359447a1685fSDinh Nguyen 359547a1685fSDinh Nguyen /* setup endpoint information */ 359647a1685fSDinh Nguyen 359747a1685fSDinh Nguyen INIT_LIST_HEAD(&hsotg->gadget.ep_list); 3598c6f5c050SMian Yousaf Kaukab hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep; 359947a1685fSDinh Nguyen 360047a1685fSDinh Nguyen /* allocate EP0 request */ 360147a1685fSDinh Nguyen 36021f91b4ccSFelipe Balbi hsotg->ctrl_req = dwc2_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep, 360347a1685fSDinh Nguyen GFP_KERNEL); 360447a1685fSDinh Nguyen if (!hsotg->ctrl_req) { 360547a1685fSDinh Nguyen dev_err(dev, "failed to allocate ctrl req\n"); 360609a75e85SMarek Szyprowski return -ENOMEM; 360747a1685fSDinh Nguyen } 360847a1685fSDinh Nguyen 360947a1685fSDinh Nguyen /* initialise the endpoints now the core has been initialised */ 3610c6f5c050SMian Yousaf Kaukab for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) { 3611c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[epnum]) 36121f91b4ccSFelipe Balbi dwc2_hsotg_initep(hsotg, hsotg->eps_in[epnum], 3613c6f5c050SMian Yousaf Kaukab epnum, 1); 3614c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[epnum]) 36151f91b4ccSFelipe Balbi dwc2_hsotg_initep(hsotg, hsotg->eps_out[epnum], 3616c6f5c050SMian Yousaf Kaukab epnum, 0); 3617c6f5c050SMian Yousaf Kaukab } 361847a1685fSDinh Nguyen 3619117777b2SDinh Nguyen ret = usb_add_gadget_udc(dev, &hsotg->gadget); 362047a1685fSDinh Nguyen if (ret) 362109a75e85SMarek Szyprowski return ret; 362247a1685fSDinh Nguyen 36231f91b4ccSFelipe Balbi dwc2_hsotg_dump(hsotg); 362447a1685fSDinh Nguyen 362547a1685fSDinh Nguyen return 0; 362647a1685fSDinh Nguyen } 362747a1685fSDinh Nguyen 362847a1685fSDinh Nguyen /** 36291f91b4ccSFelipe Balbi * dwc2_hsotg_remove - remove function for hsotg driver 363047a1685fSDinh Nguyen * @pdev: The platform information for the driver 363147a1685fSDinh Nguyen */ 36321f91b4ccSFelipe Balbi int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg) 363347a1685fSDinh Nguyen { 363447a1685fSDinh Nguyen usb_del_gadget_udc(&hsotg->gadget); 363547a1685fSDinh Nguyen 363647a1685fSDinh Nguyen return 0; 363747a1685fSDinh Nguyen } 363847a1685fSDinh Nguyen 36391f91b4ccSFelipe Balbi int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) 364047a1685fSDinh Nguyen { 364147a1685fSDinh Nguyen unsigned long flags; 364247a1685fSDinh Nguyen 36439e779778SGregory Herrero if (hsotg->lx_state != DWC2_L0) 364409a75e85SMarek Szyprowski return 0; 36459e779778SGregory Herrero 3646dc6e69e6SMarek Szyprowski if (hsotg->driver) { 3647dc6e69e6SMarek Szyprowski int ep; 3648dc6e69e6SMarek Szyprowski 364947a1685fSDinh Nguyen dev_info(hsotg->dev, "suspending usb gadget %s\n", 365047a1685fSDinh Nguyen hsotg->driver->driver.name); 365147a1685fSDinh Nguyen 365247a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 3653dc6e69e6SMarek Szyprowski if (hsotg->enabled) 36541f91b4ccSFelipe Balbi dwc2_hsotg_core_disconnect(hsotg); 36551f91b4ccSFelipe Balbi dwc2_hsotg_disconnect(hsotg); 365647a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 365747a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 365847a1685fSDinh Nguyen 3659c6f5c050SMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps; ep++) { 3660c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 36611f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 3662c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 36631f91b4ccSFelipe Balbi dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 3664c6f5c050SMian Yousaf Kaukab } 366547a1685fSDinh Nguyen } 366647a1685fSDinh Nguyen 366709a75e85SMarek Szyprowski return 0; 366847a1685fSDinh Nguyen } 366947a1685fSDinh Nguyen 36701f91b4ccSFelipe Balbi int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg) 367147a1685fSDinh Nguyen { 367247a1685fSDinh Nguyen unsigned long flags; 367347a1685fSDinh Nguyen 36749e779778SGregory Herrero if (hsotg->lx_state == DWC2_L2) 367509a75e85SMarek Szyprowski return 0; 36769e779778SGregory Herrero 367747a1685fSDinh Nguyen if (hsotg->driver) { 367847a1685fSDinh Nguyen dev_info(hsotg->dev, "resuming usb gadget %s\n", 367947a1685fSDinh Nguyen hsotg->driver->driver.name); 3680d00b4142SRobert Baldyga 368147a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 36821f91b4ccSFelipe Balbi dwc2_hsotg_core_init_disconnected(hsotg, false); 3683dc6e69e6SMarek Szyprowski if (hsotg->enabled) 36841f91b4ccSFelipe Balbi dwc2_hsotg_core_connect(hsotg); 368547a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 3686dc6e69e6SMarek Szyprowski } 368747a1685fSDinh Nguyen 368809a75e85SMarek Szyprowski return 0; 368947a1685fSDinh Nguyen } 369058e52ff6SJohn Youn 369158e52ff6SJohn Youn /** 369258e52ff6SJohn Youn * dwc2_backup_device_registers() - Backup controller device registers. 369358e52ff6SJohn Youn * When suspending usb bus, registers needs to be backuped 369458e52ff6SJohn Youn * if controller power is disabled once suspended. 369558e52ff6SJohn Youn * 369658e52ff6SJohn Youn * @hsotg: Programming view of the DWC_otg controller 369758e52ff6SJohn Youn */ 369858e52ff6SJohn Youn int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg) 369958e52ff6SJohn Youn { 370058e52ff6SJohn Youn struct dwc2_dregs_backup *dr; 370158e52ff6SJohn Youn int i; 370258e52ff6SJohn Youn 370358e52ff6SJohn Youn dev_dbg(hsotg->dev, "%s\n", __func__); 370458e52ff6SJohn Youn 370558e52ff6SJohn Youn /* Backup dev regs */ 370658e52ff6SJohn Youn dr = &hsotg->dr_backup; 370758e52ff6SJohn Youn 370858e52ff6SJohn Youn dr->dcfg = dwc2_readl(hsotg->regs + DCFG); 370958e52ff6SJohn Youn dr->dctl = dwc2_readl(hsotg->regs + DCTL); 371058e52ff6SJohn Youn dr->daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); 371158e52ff6SJohn Youn dr->diepmsk = dwc2_readl(hsotg->regs + DIEPMSK); 371258e52ff6SJohn Youn dr->doepmsk = dwc2_readl(hsotg->regs + DOEPMSK); 371358e52ff6SJohn Youn 371458e52ff6SJohn Youn for (i = 0; i < hsotg->num_of_eps; i++) { 371558e52ff6SJohn Youn /* Backup IN EPs */ 371658e52ff6SJohn Youn dr->diepctl[i] = dwc2_readl(hsotg->regs + DIEPCTL(i)); 371758e52ff6SJohn Youn 371858e52ff6SJohn Youn /* Ensure DATA PID is correctly configured */ 371958e52ff6SJohn Youn if (dr->diepctl[i] & DXEPCTL_DPID) 372058e52ff6SJohn Youn dr->diepctl[i] |= DXEPCTL_SETD1PID; 372158e52ff6SJohn Youn else 372258e52ff6SJohn Youn dr->diepctl[i] |= DXEPCTL_SETD0PID; 372358e52ff6SJohn Youn 372458e52ff6SJohn Youn dr->dieptsiz[i] = dwc2_readl(hsotg->regs + DIEPTSIZ(i)); 372558e52ff6SJohn Youn dr->diepdma[i] = dwc2_readl(hsotg->regs + DIEPDMA(i)); 372658e52ff6SJohn Youn 372758e52ff6SJohn Youn /* Backup OUT EPs */ 372858e52ff6SJohn Youn dr->doepctl[i] = dwc2_readl(hsotg->regs + DOEPCTL(i)); 372958e52ff6SJohn Youn 373058e52ff6SJohn Youn /* Ensure DATA PID is correctly configured */ 373158e52ff6SJohn Youn if (dr->doepctl[i] & DXEPCTL_DPID) 373258e52ff6SJohn Youn dr->doepctl[i] |= DXEPCTL_SETD1PID; 373358e52ff6SJohn Youn else 373458e52ff6SJohn Youn dr->doepctl[i] |= DXEPCTL_SETD0PID; 373558e52ff6SJohn Youn 373658e52ff6SJohn Youn dr->doeptsiz[i] = dwc2_readl(hsotg->regs + DOEPTSIZ(i)); 373758e52ff6SJohn Youn dr->doepdma[i] = dwc2_readl(hsotg->regs + DOEPDMA(i)); 373858e52ff6SJohn Youn } 373958e52ff6SJohn Youn dr->valid = true; 374058e52ff6SJohn Youn return 0; 374158e52ff6SJohn Youn } 374258e52ff6SJohn Youn 374358e52ff6SJohn Youn /** 374458e52ff6SJohn Youn * dwc2_restore_device_registers() - Restore controller device registers. 374558e52ff6SJohn Youn * When resuming usb bus, device registers needs to be restored 374658e52ff6SJohn Youn * if controller power were disabled. 374758e52ff6SJohn Youn * 374858e52ff6SJohn Youn * @hsotg: Programming view of the DWC_otg controller 374958e52ff6SJohn Youn */ 375058e52ff6SJohn Youn int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg) 375158e52ff6SJohn Youn { 375258e52ff6SJohn Youn struct dwc2_dregs_backup *dr; 375358e52ff6SJohn Youn u32 dctl; 375458e52ff6SJohn Youn int i; 375558e52ff6SJohn Youn 375658e52ff6SJohn Youn dev_dbg(hsotg->dev, "%s\n", __func__); 375758e52ff6SJohn Youn 375858e52ff6SJohn Youn /* Restore dev regs */ 375958e52ff6SJohn Youn dr = &hsotg->dr_backup; 376058e52ff6SJohn Youn if (!dr->valid) { 376158e52ff6SJohn Youn dev_err(hsotg->dev, "%s: no device registers to restore\n", 376258e52ff6SJohn Youn __func__); 376358e52ff6SJohn Youn return -EINVAL; 376458e52ff6SJohn Youn } 376558e52ff6SJohn Youn dr->valid = false; 376658e52ff6SJohn Youn 376758e52ff6SJohn Youn dwc2_writel(dr->dcfg, hsotg->regs + DCFG); 376858e52ff6SJohn Youn dwc2_writel(dr->dctl, hsotg->regs + DCTL); 376958e52ff6SJohn Youn dwc2_writel(dr->daintmsk, hsotg->regs + DAINTMSK); 377058e52ff6SJohn Youn dwc2_writel(dr->diepmsk, hsotg->regs + DIEPMSK); 377158e52ff6SJohn Youn dwc2_writel(dr->doepmsk, hsotg->regs + DOEPMSK); 377258e52ff6SJohn Youn 377358e52ff6SJohn Youn for (i = 0; i < hsotg->num_of_eps; i++) { 377458e52ff6SJohn Youn /* Restore IN EPs */ 377558e52ff6SJohn Youn dwc2_writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i)); 377658e52ff6SJohn Youn dwc2_writel(dr->dieptsiz[i], hsotg->regs + DIEPTSIZ(i)); 377758e52ff6SJohn Youn dwc2_writel(dr->diepdma[i], hsotg->regs + DIEPDMA(i)); 377858e52ff6SJohn Youn 377958e52ff6SJohn Youn /* Restore OUT EPs */ 378058e52ff6SJohn Youn dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i)); 378158e52ff6SJohn Youn dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i)); 378258e52ff6SJohn Youn dwc2_writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i)); 378358e52ff6SJohn Youn } 378458e52ff6SJohn Youn 378558e52ff6SJohn Youn /* Set the Power-On Programming done bit */ 378658e52ff6SJohn Youn dctl = dwc2_readl(hsotg->regs + DCTL); 378758e52ff6SJohn Youn dctl |= DCTL_PWRONPRGDONE; 378858e52ff6SJohn Youn dwc2_writel(dctl, hsotg->regs + DCTL); 378958e52ff6SJohn Youn 379058e52ff6SJohn Youn return 0; 379158e52ff6SJohn Youn } 3792