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> 2347a1685fSDinh Nguyen #include <linux/debugfs.h> 247ad8096eSMarek Szyprowski #include <linux/mutex.h> 2547a1685fSDinh Nguyen #include <linux/seq_file.h> 2647a1685fSDinh Nguyen #include <linux/delay.h> 2747a1685fSDinh Nguyen #include <linux/io.h> 2847a1685fSDinh Nguyen #include <linux/slab.h> 2947a1685fSDinh Nguyen #include <linux/clk.h> 3047a1685fSDinh Nguyen #include <linux/regulator/consumer.h> 3147a1685fSDinh Nguyen #include <linux/of_platform.h> 3247a1685fSDinh Nguyen #include <linux/phy/phy.h> 3347a1685fSDinh Nguyen 3447a1685fSDinh Nguyen #include <linux/usb/ch9.h> 3547a1685fSDinh Nguyen #include <linux/usb/gadget.h> 3647a1685fSDinh Nguyen #include <linux/usb/phy.h> 3747a1685fSDinh Nguyen #include <linux/platform_data/s3c-hsotg.h> 38*9e14d0a5SGregory Herrero #include <linux/uaccess.h> 3947a1685fSDinh Nguyen 40f7c0b143SDinh Nguyen #include "core.h" 41941fcce4SDinh Nguyen #include "hw.h" 4247a1685fSDinh Nguyen 4347a1685fSDinh Nguyen /* conversion functions */ 4447a1685fSDinh Nguyen static inline struct s3c_hsotg_req *our_req(struct usb_request *req) 4547a1685fSDinh Nguyen { 4647a1685fSDinh Nguyen return container_of(req, struct s3c_hsotg_req, req); 4747a1685fSDinh Nguyen } 4847a1685fSDinh Nguyen 4947a1685fSDinh Nguyen static inline struct s3c_hsotg_ep *our_ep(struct usb_ep *ep) 5047a1685fSDinh Nguyen { 5147a1685fSDinh Nguyen return container_of(ep, struct s3c_hsotg_ep, ep); 5247a1685fSDinh Nguyen } 5347a1685fSDinh Nguyen 54941fcce4SDinh Nguyen static inline struct dwc2_hsotg *to_hsotg(struct usb_gadget *gadget) 5547a1685fSDinh Nguyen { 56941fcce4SDinh Nguyen return container_of(gadget, struct dwc2_hsotg, gadget); 5747a1685fSDinh Nguyen } 5847a1685fSDinh Nguyen 5947a1685fSDinh Nguyen static inline void __orr32(void __iomem *ptr, u32 val) 6047a1685fSDinh Nguyen { 6147a1685fSDinh Nguyen writel(readl(ptr) | val, ptr); 6247a1685fSDinh Nguyen } 6347a1685fSDinh Nguyen 6447a1685fSDinh Nguyen static inline void __bic32(void __iomem *ptr, u32 val) 6547a1685fSDinh Nguyen { 6647a1685fSDinh Nguyen writel(readl(ptr) & ~val, ptr); 6747a1685fSDinh Nguyen } 6847a1685fSDinh Nguyen 69c6f5c050SMian Yousaf Kaukab static inline struct s3c_hsotg_ep *index_to_ep(struct dwc2_hsotg *hsotg, 70c6f5c050SMian Yousaf Kaukab u32 ep_index, u32 dir_in) 71c6f5c050SMian Yousaf Kaukab { 72c6f5c050SMian Yousaf Kaukab if (dir_in) 73c6f5c050SMian Yousaf Kaukab return hsotg->eps_in[ep_index]; 74c6f5c050SMian Yousaf Kaukab else 75c6f5c050SMian Yousaf Kaukab return hsotg->eps_out[ep_index]; 76c6f5c050SMian Yousaf Kaukab } 77c6f5c050SMian Yousaf Kaukab 78997f4f81SMickael Maison /* forward declaration of functions */ 79941fcce4SDinh Nguyen static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg); 8047a1685fSDinh Nguyen 8147a1685fSDinh Nguyen /** 8247a1685fSDinh Nguyen * using_dma - return the DMA status of the driver. 8347a1685fSDinh Nguyen * @hsotg: The driver state. 8447a1685fSDinh Nguyen * 8547a1685fSDinh Nguyen * Return true if we're using DMA. 8647a1685fSDinh Nguyen * 8747a1685fSDinh Nguyen * Currently, we have the DMA support code worked into everywhere 8847a1685fSDinh Nguyen * that needs it, but the AMBA DMA implementation in the hardware can 8947a1685fSDinh Nguyen * only DMA from 32bit aligned addresses. This means that gadgets such 9047a1685fSDinh Nguyen * as the CDC Ethernet cannot work as they often pass packets which are 9147a1685fSDinh Nguyen * not 32bit aligned. 9247a1685fSDinh Nguyen * 9347a1685fSDinh Nguyen * Unfortunately the choice to use DMA or not is global to the controller 9447a1685fSDinh Nguyen * and seems to be only settable when the controller is being put through 9547a1685fSDinh Nguyen * a core reset. This means we either need to fix the gadgets to take 9647a1685fSDinh Nguyen * account of DMA alignment, or add bounce buffers (yuerk). 9747a1685fSDinh Nguyen * 98edd74be8SGregory Herrero * g_using_dma is set depending on dts flag. 9947a1685fSDinh Nguyen */ 100941fcce4SDinh Nguyen static inline bool using_dma(struct dwc2_hsotg *hsotg) 10147a1685fSDinh Nguyen { 102edd74be8SGregory Herrero return hsotg->g_using_dma; 10347a1685fSDinh Nguyen } 10447a1685fSDinh Nguyen 10547a1685fSDinh Nguyen /** 10647a1685fSDinh Nguyen * s3c_hsotg_en_gsint - enable one or more of the general interrupt 10747a1685fSDinh Nguyen * @hsotg: The device state 10847a1685fSDinh Nguyen * @ints: A bitmask of the interrupts to enable 10947a1685fSDinh Nguyen */ 110941fcce4SDinh Nguyen static void s3c_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints) 11147a1685fSDinh Nguyen { 11247a1685fSDinh Nguyen u32 gsintmsk = readl(hsotg->regs + GINTMSK); 11347a1685fSDinh Nguyen u32 new_gsintmsk; 11447a1685fSDinh Nguyen 11547a1685fSDinh Nguyen new_gsintmsk = gsintmsk | ints; 11647a1685fSDinh Nguyen 11747a1685fSDinh Nguyen if (new_gsintmsk != gsintmsk) { 11847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); 11947a1685fSDinh Nguyen writel(new_gsintmsk, hsotg->regs + GINTMSK); 12047a1685fSDinh Nguyen } 12147a1685fSDinh Nguyen } 12247a1685fSDinh Nguyen 12347a1685fSDinh Nguyen /** 12447a1685fSDinh Nguyen * s3c_hsotg_disable_gsint - disable one or more of the general interrupt 12547a1685fSDinh Nguyen * @hsotg: The device state 12647a1685fSDinh Nguyen * @ints: A bitmask of the interrupts to enable 12747a1685fSDinh Nguyen */ 128941fcce4SDinh Nguyen static void s3c_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints) 12947a1685fSDinh Nguyen { 13047a1685fSDinh Nguyen u32 gsintmsk = readl(hsotg->regs + GINTMSK); 13147a1685fSDinh Nguyen u32 new_gsintmsk; 13247a1685fSDinh Nguyen 13347a1685fSDinh Nguyen new_gsintmsk = gsintmsk & ~ints; 13447a1685fSDinh Nguyen 13547a1685fSDinh Nguyen if (new_gsintmsk != gsintmsk) 13647a1685fSDinh Nguyen writel(new_gsintmsk, hsotg->regs + GINTMSK); 13747a1685fSDinh Nguyen } 13847a1685fSDinh Nguyen 13947a1685fSDinh Nguyen /** 14047a1685fSDinh Nguyen * s3c_hsotg_ctrl_epint - enable/disable an endpoint irq 14147a1685fSDinh Nguyen * @hsotg: The device state 14247a1685fSDinh Nguyen * @ep: The endpoint index 14347a1685fSDinh Nguyen * @dir_in: True if direction is in. 14447a1685fSDinh Nguyen * @en: The enable value, true to enable 14547a1685fSDinh Nguyen * 14647a1685fSDinh Nguyen * Set or clear the mask for an individual endpoint's interrupt 14747a1685fSDinh Nguyen * request. 14847a1685fSDinh Nguyen */ 149941fcce4SDinh Nguyen static void s3c_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, 15047a1685fSDinh Nguyen unsigned int ep, unsigned int dir_in, 15147a1685fSDinh Nguyen unsigned int en) 15247a1685fSDinh Nguyen { 15347a1685fSDinh Nguyen unsigned long flags; 15447a1685fSDinh Nguyen u32 bit = 1 << ep; 15547a1685fSDinh Nguyen u32 daint; 15647a1685fSDinh Nguyen 15747a1685fSDinh Nguyen if (!dir_in) 15847a1685fSDinh Nguyen bit <<= 16; 15947a1685fSDinh Nguyen 16047a1685fSDinh Nguyen local_irq_save(flags); 16147a1685fSDinh Nguyen daint = readl(hsotg->regs + DAINTMSK); 16247a1685fSDinh Nguyen if (en) 16347a1685fSDinh Nguyen daint |= bit; 16447a1685fSDinh Nguyen else 16547a1685fSDinh Nguyen daint &= ~bit; 16647a1685fSDinh Nguyen writel(daint, hsotg->regs + DAINTMSK); 16747a1685fSDinh Nguyen local_irq_restore(flags); 16847a1685fSDinh Nguyen } 16947a1685fSDinh Nguyen 17047a1685fSDinh Nguyen /** 17147a1685fSDinh Nguyen * s3c_hsotg_init_fifo - initialise non-periodic FIFOs 17247a1685fSDinh Nguyen * @hsotg: The device instance. 17347a1685fSDinh Nguyen */ 174941fcce4SDinh Nguyen static void s3c_hsotg_init_fifo(struct dwc2_hsotg *hsotg) 17547a1685fSDinh Nguyen { 17647a1685fSDinh Nguyen unsigned int ep; 17747a1685fSDinh Nguyen unsigned int addr; 17847a1685fSDinh Nguyen int timeout; 17947a1685fSDinh Nguyen u32 val; 18047a1685fSDinh Nguyen 1817fcbc95cSGregory Herrero /* Reset fifo map if not correctly cleared during previous session */ 1827fcbc95cSGregory Herrero WARN_ON(hsotg->fifo_map); 1837fcbc95cSGregory Herrero hsotg->fifo_map = 0; 1847fcbc95cSGregory Herrero 1850a176279SGregory Herrero /* set RX/NPTX FIFO sizes */ 1860a176279SGregory Herrero writel(hsotg->g_rx_fifo_sz, hsotg->regs + GRXFSIZ); 1870a176279SGregory Herrero writel((hsotg->g_rx_fifo_sz << FIFOSIZE_STARTADDR_SHIFT) | 1880a176279SGregory Herrero (hsotg->g_np_g_tx_fifo_sz << FIFOSIZE_DEPTH_SHIFT), 1890a176279SGregory Herrero hsotg->regs + GNPTXFSIZ); 19047a1685fSDinh Nguyen 19147a1685fSDinh Nguyen /* 19247a1685fSDinh Nguyen * arange all the rest of the TX FIFOs, as some versions of this 19347a1685fSDinh Nguyen * block have overlapping default addresses. This also ensures 19447a1685fSDinh Nguyen * that if the settings have been changed, then they are set to 19547a1685fSDinh Nguyen * known values. 19647a1685fSDinh Nguyen */ 19747a1685fSDinh Nguyen 19847a1685fSDinh Nguyen /* start at the end of the GNPTXFSIZ, rounded up */ 1990a176279SGregory Herrero addr = hsotg->g_rx_fifo_sz + hsotg->g_np_g_tx_fifo_sz; 20047a1685fSDinh Nguyen 20147a1685fSDinh Nguyen /* 2020a176279SGregory Herrero * Configure fifos sizes from provided configuration and assign 203b203d0a2SRobert Baldyga * them to endpoints dynamically according to maxpacket size value of 204b203d0a2SRobert Baldyga * given endpoint. 20547a1685fSDinh Nguyen */ 2060a176279SGregory Herrero for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) { 2070a176279SGregory Herrero if (!hsotg->g_tx_fifo_sz[ep]) 2080a176279SGregory Herrero continue; 209b203d0a2SRobert Baldyga val = addr; 2100a176279SGregory Herrero val |= hsotg->g_tx_fifo_sz[ep] << FIFOSIZE_DEPTH_SHIFT; 2110a176279SGregory Herrero WARN_ONCE(addr + hsotg->g_tx_fifo_sz[ep] > hsotg->fifo_mem, 212b203d0a2SRobert Baldyga "insufficient fifo memory"); 2130a176279SGregory Herrero addr += hsotg->g_tx_fifo_sz[ep]; 21447a1685fSDinh Nguyen 21547a1685fSDinh Nguyen writel(val, hsotg->regs + DPTXFSIZN(ep)); 21647a1685fSDinh Nguyen } 21747a1685fSDinh Nguyen 21847a1685fSDinh Nguyen /* 21947a1685fSDinh Nguyen * according to p428 of the design guide, we need to ensure that 22047a1685fSDinh Nguyen * all fifos are flushed before continuing 22147a1685fSDinh Nguyen */ 22247a1685fSDinh Nguyen 22347a1685fSDinh Nguyen writel(GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | 22447a1685fSDinh Nguyen GRSTCTL_RXFFLSH, hsotg->regs + GRSTCTL); 22547a1685fSDinh Nguyen 22647a1685fSDinh Nguyen /* wait until the fifos are both flushed */ 22747a1685fSDinh Nguyen timeout = 100; 22847a1685fSDinh Nguyen while (1) { 22947a1685fSDinh Nguyen val = readl(hsotg->regs + GRSTCTL); 23047a1685fSDinh Nguyen 23147a1685fSDinh Nguyen if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0) 23247a1685fSDinh Nguyen break; 23347a1685fSDinh Nguyen 23447a1685fSDinh Nguyen if (--timeout == 0) { 23547a1685fSDinh Nguyen dev_err(hsotg->dev, 23647a1685fSDinh Nguyen "%s: timeout flushing fifos (GRSTCTL=%08x)\n", 23747a1685fSDinh Nguyen __func__, val); 23848b20bcbSGregory Herrero break; 23947a1685fSDinh Nguyen } 24047a1685fSDinh Nguyen 24147a1685fSDinh Nguyen udelay(1); 24247a1685fSDinh Nguyen } 24347a1685fSDinh Nguyen 24447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); 24547a1685fSDinh Nguyen } 24647a1685fSDinh Nguyen 24747a1685fSDinh Nguyen /** 24847a1685fSDinh Nguyen * @ep: USB endpoint to allocate request for. 24947a1685fSDinh Nguyen * @flags: Allocation flags 25047a1685fSDinh Nguyen * 25147a1685fSDinh Nguyen * Allocate a new USB request structure appropriate for the specified endpoint 25247a1685fSDinh Nguyen */ 25347a1685fSDinh Nguyen static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, 25447a1685fSDinh Nguyen gfp_t flags) 25547a1685fSDinh Nguyen { 25647a1685fSDinh Nguyen struct s3c_hsotg_req *req; 25747a1685fSDinh Nguyen 25847a1685fSDinh Nguyen req = kzalloc(sizeof(struct s3c_hsotg_req), flags); 25947a1685fSDinh Nguyen if (!req) 26047a1685fSDinh Nguyen return NULL; 26147a1685fSDinh Nguyen 26247a1685fSDinh Nguyen INIT_LIST_HEAD(&req->queue); 26347a1685fSDinh Nguyen 26447a1685fSDinh Nguyen return &req->req; 26547a1685fSDinh Nguyen } 26647a1685fSDinh Nguyen 26747a1685fSDinh Nguyen /** 26847a1685fSDinh Nguyen * is_ep_periodic - return true if the endpoint is in periodic mode. 26947a1685fSDinh Nguyen * @hs_ep: The endpoint to query. 27047a1685fSDinh Nguyen * 27147a1685fSDinh Nguyen * Returns true if the endpoint is in periodic mode, meaning it is being 27247a1685fSDinh Nguyen * used for an Interrupt or ISO transfer. 27347a1685fSDinh Nguyen */ 27447a1685fSDinh Nguyen static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep) 27547a1685fSDinh Nguyen { 27647a1685fSDinh Nguyen return hs_ep->periodic; 27747a1685fSDinh Nguyen } 27847a1685fSDinh Nguyen 27947a1685fSDinh Nguyen /** 28047a1685fSDinh Nguyen * s3c_hsotg_unmap_dma - unmap the DMA memory being used for the request 28147a1685fSDinh Nguyen * @hsotg: The device state. 28247a1685fSDinh Nguyen * @hs_ep: The endpoint for the request 28347a1685fSDinh Nguyen * @hs_req: The request being processed. 28447a1685fSDinh Nguyen * 28547a1685fSDinh Nguyen * This is the reverse of s3c_hsotg_map_dma(), called for the completion 28647a1685fSDinh Nguyen * of a request to ensure the buffer is ready for access by the caller. 28747a1685fSDinh Nguyen */ 288941fcce4SDinh Nguyen static void s3c_hsotg_unmap_dma(struct dwc2_hsotg *hsotg, 28947a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep, 29047a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req) 29147a1685fSDinh Nguyen { 29247a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 29347a1685fSDinh Nguyen 29447a1685fSDinh Nguyen /* ignore this if we're not moving any data */ 29547a1685fSDinh Nguyen if (hs_req->req.length == 0) 29647a1685fSDinh Nguyen return; 29747a1685fSDinh Nguyen 29847a1685fSDinh Nguyen usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); 29947a1685fSDinh Nguyen } 30047a1685fSDinh Nguyen 30147a1685fSDinh Nguyen /** 30247a1685fSDinh Nguyen * s3c_hsotg_write_fifo - write packet Data to the TxFIFO 30347a1685fSDinh Nguyen * @hsotg: The controller state. 30447a1685fSDinh Nguyen * @hs_ep: The endpoint we're going to write for. 30547a1685fSDinh Nguyen * @hs_req: The request to write data for. 30647a1685fSDinh Nguyen * 30747a1685fSDinh Nguyen * This is called when the TxFIFO has some space in it to hold a new 30847a1685fSDinh Nguyen * transmission and we have something to give it. The actual setup of 30947a1685fSDinh Nguyen * the data size is done elsewhere, so all we have to do is to actually 31047a1685fSDinh Nguyen * write the data. 31147a1685fSDinh Nguyen * 31247a1685fSDinh Nguyen * The return value is zero if there is more space (or nothing was done) 31347a1685fSDinh Nguyen * otherwise -ENOSPC is returned if the FIFO space was used up. 31447a1685fSDinh Nguyen * 31547a1685fSDinh Nguyen * This routine is only needed for PIO 31647a1685fSDinh Nguyen */ 317941fcce4SDinh Nguyen static int s3c_hsotg_write_fifo(struct dwc2_hsotg *hsotg, 31847a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep, 31947a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req) 32047a1685fSDinh Nguyen { 32147a1685fSDinh Nguyen bool periodic = is_ep_periodic(hs_ep); 32247a1685fSDinh Nguyen u32 gnptxsts = readl(hsotg->regs + GNPTXSTS); 32347a1685fSDinh Nguyen int buf_pos = hs_req->req.actual; 32447a1685fSDinh Nguyen int to_write = hs_ep->size_loaded; 32547a1685fSDinh Nguyen void *data; 32647a1685fSDinh Nguyen int can_write; 32747a1685fSDinh Nguyen int pkt_round; 32847a1685fSDinh Nguyen int max_transfer; 32947a1685fSDinh Nguyen 33047a1685fSDinh Nguyen to_write -= (buf_pos - hs_ep->last_load); 33147a1685fSDinh Nguyen 33247a1685fSDinh Nguyen /* if there's nothing to write, get out early */ 33347a1685fSDinh Nguyen if (to_write == 0) 33447a1685fSDinh Nguyen return 0; 33547a1685fSDinh Nguyen 33647a1685fSDinh Nguyen if (periodic && !hsotg->dedicated_fifos) { 33747a1685fSDinh Nguyen u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); 33847a1685fSDinh Nguyen int size_left; 33947a1685fSDinh Nguyen int size_done; 34047a1685fSDinh Nguyen 34147a1685fSDinh Nguyen /* 34247a1685fSDinh Nguyen * work out how much data was loaded so we can calculate 34347a1685fSDinh Nguyen * how much data is left in the fifo. 34447a1685fSDinh Nguyen */ 34547a1685fSDinh Nguyen 34647a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 34747a1685fSDinh Nguyen 34847a1685fSDinh Nguyen /* 34947a1685fSDinh Nguyen * if shared fifo, we cannot write anything until the 35047a1685fSDinh Nguyen * previous data has been completely sent. 35147a1685fSDinh Nguyen */ 35247a1685fSDinh Nguyen if (hs_ep->fifo_load != 0) { 35347a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 35447a1685fSDinh Nguyen return -ENOSPC; 35547a1685fSDinh Nguyen } 35647a1685fSDinh Nguyen 35747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", 35847a1685fSDinh Nguyen __func__, size_left, 35947a1685fSDinh Nguyen hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); 36047a1685fSDinh Nguyen 36147a1685fSDinh Nguyen /* how much of the data has moved */ 36247a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 36347a1685fSDinh Nguyen 36447a1685fSDinh Nguyen /* how much data is left in the fifo */ 36547a1685fSDinh Nguyen can_write = hs_ep->fifo_load - size_done; 36647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", 36747a1685fSDinh Nguyen __func__, can_write); 36847a1685fSDinh Nguyen 36947a1685fSDinh Nguyen can_write = hs_ep->fifo_size - can_write; 37047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", 37147a1685fSDinh Nguyen __func__, can_write); 37247a1685fSDinh Nguyen 37347a1685fSDinh Nguyen if (can_write <= 0) { 37447a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 37547a1685fSDinh Nguyen return -ENOSPC; 37647a1685fSDinh Nguyen } 37747a1685fSDinh Nguyen } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { 37847a1685fSDinh Nguyen can_write = readl(hsotg->regs + DTXFSTS(hs_ep->index)); 37947a1685fSDinh Nguyen 38047a1685fSDinh Nguyen can_write &= 0xffff; 38147a1685fSDinh Nguyen can_write *= 4; 38247a1685fSDinh Nguyen } else { 38347a1685fSDinh Nguyen if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) { 38447a1685fSDinh Nguyen dev_dbg(hsotg->dev, 38547a1685fSDinh Nguyen "%s: no queue slots available (0x%08x)\n", 38647a1685fSDinh Nguyen __func__, gnptxsts); 38747a1685fSDinh Nguyen 38847a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP); 38947a1685fSDinh Nguyen return -ENOSPC; 39047a1685fSDinh Nguyen } 39147a1685fSDinh Nguyen 39247a1685fSDinh Nguyen can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts); 39347a1685fSDinh Nguyen can_write *= 4; /* fifo size is in 32bit quantities. */ 39447a1685fSDinh Nguyen } 39547a1685fSDinh Nguyen 39647a1685fSDinh Nguyen max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; 39747a1685fSDinh Nguyen 39847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", 39947a1685fSDinh Nguyen __func__, gnptxsts, can_write, to_write, max_transfer); 40047a1685fSDinh Nguyen 40147a1685fSDinh Nguyen /* 40247a1685fSDinh Nguyen * limit to 512 bytes of data, it seems at least on the non-periodic 40347a1685fSDinh Nguyen * FIFO, requests of >512 cause the endpoint to get stuck with a 40447a1685fSDinh Nguyen * fragment of the end of the transfer in it. 40547a1685fSDinh Nguyen */ 40647a1685fSDinh Nguyen if (can_write > 512 && !periodic) 40747a1685fSDinh Nguyen can_write = 512; 40847a1685fSDinh Nguyen 40947a1685fSDinh Nguyen /* 41047a1685fSDinh Nguyen * limit the write to one max-packet size worth of data, but allow 41147a1685fSDinh Nguyen * the transfer to return that it did not run out of fifo space 41247a1685fSDinh Nguyen * doing it. 41347a1685fSDinh Nguyen */ 41447a1685fSDinh Nguyen if (to_write > max_transfer) { 41547a1685fSDinh Nguyen to_write = max_transfer; 41647a1685fSDinh Nguyen 41747a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 41847a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 41947a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, 42047a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 42147a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 42247a1685fSDinh Nguyen } 42347a1685fSDinh Nguyen 42447a1685fSDinh Nguyen /* see if we can write data */ 42547a1685fSDinh Nguyen 42647a1685fSDinh Nguyen if (to_write > can_write) { 42747a1685fSDinh Nguyen to_write = can_write; 42847a1685fSDinh Nguyen pkt_round = to_write % max_transfer; 42947a1685fSDinh Nguyen 43047a1685fSDinh Nguyen /* 43147a1685fSDinh Nguyen * Round the write down to an 43247a1685fSDinh Nguyen * exact number of packets. 43347a1685fSDinh Nguyen * 43447a1685fSDinh Nguyen * Note, we do not currently check to see if we can ever 43547a1685fSDinh Nguyen * write a full packet or not to the FIFO. 43647a1685fSDinh Nguyen */ 43747a1685fSDinh Nguyen 43847a1685fSDinh Nguyen if (pkt_round) 43947a1685fSDinh Nguyen to_write -= pkt_round; 44047a1685fSDinh Nguyen 44147a1685fSDinh Nguyen /* 44247a1685fSDinh Nguyen * enable correct FIFO interrupt to alert us when there 44347a1685fSDinh Nguyen * is more room left. 44447a1685fSDinh Nguyen */ 44547a1685fSDinh Nguyen 44647a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 44747a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 44847a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, 44947a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 45047a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 45147a1685fSDinh Nguyen } 45247a1685fSDinh Nguyen 45347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", 45447a1685fSDinh Nguyen to_write, hs_req->req.length, can_write, buf_pos); 45547a1685fSDinh Nguyen 45647a1685fSDinh Nguyen if (to_write <= 0) 45747a1685fSDinh Nguyen return -ENOSPC; 45847a1685fSDinh Nguyen 45947a1685fSDinh Nguyen hs_req->req.actual = buf_pos + to_write; 46047a1685fSDinh Nguyen hs_ep->total_data += to_write; 46147a1685fSDinh Nguyen 46247a1685fSDinh Nguyen if (periodic) 46347a1685fSDinh Nguyen hs_ep->fifo_load += to_write; 46447a1685fSDinh Nguyen 46547a1685fSDinh Nguyen to_write = DIV_ROUND_UP(to_write, 4); 46647a1685fSDinh Nguyen data = hs_req->req.buf + buf_pos; 46747a1685fSDinh Nguyen 46847a1685fSDinh Nguyen iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); 46947a1685fSDinh Nguyen 47047a1685fSDinh Nguyen return (to_write >= can_write) ? -ENOSPC : 0; 47147a1685fSDinh Nguyen } 47247a1685fSDinh Nguyen 47347a1685fSDinh Nguyen /** 47447a1685fSDinh Nguyen * get_ep_limit - get the maximum data legnth for this endpoint 47547a1685fSDinh Nguyen * @hs_ep: The endpoint 47647a1685fSDinh Nguyen * 47747a1685fSDinh Nguyen * Return the maximum data that can be queued in one go on a given endpoint 47847a1685fSDinh Nguyen * so that transfers that are too long can be split. 47947a1685fSDinh Nguyen */ 48047a1685fSDinh Nguyen static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) 48147a1685fSDinh Nguyen { 48247a1685fSDinh Nguyen int index = hs_ep->index; 48347a1685fSDinh Nguyen unsigned maxsize; 48447a1685fSDinh Nguyen unsigned maxpkt; 48547a1685fSDinh Nguyen 48647a1685fSDinh Nguyen if (index != 0) { 48747a1685fSDinh Nguyen maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; 48847a1685fSDinh Nguyen maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; 48947a1685fSDinh Nguyen } else { 49047a1685fSDinh Nguyen maxsize = 64+64; 49147a1685fSDinh Nguyen if (hs_ep->dir_in) 49247a1685fSDinh Nguyen maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; 49347a1685fSDinh Nguyen else 49447a1685fSDinh Nguyen maxpkt = 2; 49547a1685fSDinh Nguyen } 49647a1685fSDinh Nguyen 49747a1685fSDinh Nguyen /* we made the constant loading easier above by using +1 */ 49847a1685fSDinh Nguyen maxpkt--; 49947a1685fSDinh Nguyen maxsize--; 50047a1685fSDinh Nguyen 50147a1685fSDinh Nguyen /* 50247a1685fSDinh Nguyen * constrain by packet count if maxpkts*pktsize is greater 50347a1685fSDinh Nguyen * than the length register size. 50447a1685fSDinh Nguyen */ 50547a1685fSDinh Nguyen 50647a1685fSDinh Nguyen if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) 50747a1685fSDinh Nguyen maxsize = maxpkt * hs_ep->ep.maxpacket; 50847a1685fSDinh Nguyen 50947a1685fSDinh Nguyen return maxsize; 51047a1685fSDinh Nguyen } 51147a1685fSDinh Nguyen 51247a1685fSDinh Nguyen /** 51347a1685fSDinh Nguyen * s3c_hsotg_start_req - start a USB request from an endpoint's queue 51447a1685fSDinh Nguyen * @hsotg: The controller state. 51547a1685fSDinh Nguyen * @hs_ep: The endpoint to process a request for 51647a1685fSDinh Nguyen * @hs_req: The request to start. 51747a1685fSDinh Nguyen * @continuing: True if we are doing more for the current request. 51847a1685fSDinh Nguyen * 51947a1685fSDinh Nguyen * Start the given request running by setting the endpoint registers 52047a1685fSDinh Nguyen * appropriately, and writing any data to the FIFOs. 52147a1685fSDinh Nguyen */ 522941fcce4SDinh Nguyen static void s3c_hsotg_start_req(struct dwc2_hsotg *hsotg, 52347a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep, 52447a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req, 52547a1685fSDinh Nguyen bool continuing) 52647a1685fSDinh Nguyen { 52747a1685fSDinh Nguyen struct usb_request *ureq = &hs_req->req; 52847a1685fSDinh Nguyen int index = hs_ep->index; 52947a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 53047a1685fSDinh Nguyen u32 epctrl_reg; 53147a1685fSDinh Nguyen u32 epsize_reg; 53247a1685fSDinh Nguyen u32 epsize; 53347a1685fSDinh Nguyen u32 ctrl; 53447a1685fSDinh Nguyen unsigned length; 53547a1685fSDinh Nguyen unsigned packets; 53647a1685fSDinh Nguyen unsigned maxreq; 53747a1685fSDinh Nguyen 53847a1685fSDinh Nguyen if (index != 0) { 53947a1685fSDinh Nguyen if (hs_ep->req && !continuing) { 54047a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: active request\n", __func__); 54147a1685fSDinh Nguyen WARN_ON(1); 54247a1685fSDinh Nguyen return; 54347a1685fSDinh Nguyen } else if (hs_ep->req != hs_req && continuing) { 54447a1685fSDinh Nguyen dev_err(hsotg->dev, 54547a1685fSDinh Nguyen "%s: continue different req\n", __func__); 54647a1685fSDinh Nguyen WARN_ON(1); 54747a1685fSDinh Nguyen return; 54847a1685fSDinh Nguyen } 54947a1685fSDinh Nguyen } 55047a1685fSDinh Nguyen 55147a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 55247a1685fSDinh Nguyen epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 55347a1685fSDinh Nguyen 55447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", 55547a1685fSDinh Nguyen __func__, readl(hsotg->regs + epctrl_reg), index, 55647a1685fSDinh Nguyen hs_ep->dir_in ? "in" : "out"); 55747a1685fSDinh Nguyen 55847a1685fSDinh Nguyen /* If endpoint is stalled, we will restart request later */ 55947a1685fSDinh Nguyen ctrl = readl(hsotg->regs + epctrl_reg); 56047a1685fSDinh Nguyen 56147a1685fSDinh Nguyen if (ctrl & DXEPCTL_STALL) { 56247a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); 56347a1685fSDinh Nguyen return; 56447a1685fSDinh Nguyen } 56547a1685fSDinh Nguyen 56647a1685fSDinh Nguyen length = ureq->length - ureq->actual; 56747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", 56847a1685fSDinh Nguyen ureq->length, ureq->actual); 56947a1685fSDinh Nguyen if (0) 57047a1685fSDinh Nguyen dev_dbg(hsotg->dev, 5710cc4cf6fSFabio Estevam "REQ buf %p len %d dma %pad noi=%d zp=%d snok=%d\n", 57247a1685fSDinh Nguyen ureq->buf, length, &ureq->dma, 57347a1685fSDinh Nguyen ureq->no_interrupt, ureq->zero, ureq->short_not_ok); 57447a1685fSDinh Nguyen 57547a1685fSDinh Nguyen maxreq = get_ep_limit(hs_ep); 57647a1685fSDinh Nguyen if (length > maxreq) { 57747a1685fSDinh Nguyen int round = maxreq % hs_ep->ep.maxpacket; 57847a1685fSDinh Nguyen 57947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", 58047a1685fSDinh Nguyen __func__, length, maxreq, round); 58147a1685fSDinh Nguyen 58247a1685fSDinh Nguyen /* round down to multiple of packets */ 58347a1685fSDinh Nguyen if (round) 58447a1685fSDinh Nguyen maxreq -= round; 58547a1685fSDinh Nguyen 58647a1685fSDinh Nguyen length = maxreq; 58747a1685fSDinh Nguyen } 58847a1685fSDinh Nguyen 58947a1685fSDinh Nguyen if (length) 59047a1685fSDinh Nguyen packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); 59147a1685fSDinh Nguyen else 59247a1685fSDinh Nguyen packets = 1; /* send one packet if length is zero. */ 59347a1685fSDinh Nguyen 59447a1685fSDinh Nguyen if (hs_ep->isochronous && length > (hs_ep->mc * hs_ep->ep.maxpacket)) { 59547a1685fSDinh Nguyen dev_err(hsotg->dev, "req length > maxpacket*mc\n"); 59647a1685fSDinh Nguyen return; 59747a1685fSDinh Nguyen } 59847a1685fSDinh Nguyen 59947a1685fSDinh Nguyen if (dir_in && index != 0) 60047a1685fSDinh Nguyen if (hs_ep->isochronous) 60147a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(packets); 60247a1685fSDinh Nguyen else 60347a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(1); 60447a1685fSDinh Nguyen else 60547a1685fSDinh Nguyen epsize = 0; 60647a1685fSDinh Nguyen 60747a1685fSDinh Nguyen /* 608f71b5e25SMian Yousaf Kaukab * zero length packet should be programmed on its own and should not 609f71b5e25SMian Yousaf Kaukab * be counted in DIEPTSIZ.PktCnt with other packets. 61047a1685fSDinh Nguyen */ 611f71b5e25SMian Yousaf Kaukab if (dir_in && ureq->zero && !continuing) { 612f71b5e25SMian Yousaf Kaukab /* Test if zlp is actually required. */ 613f71b5e25SMian Yousaf Kaukab if ((ureq->length >= hs_ep->ep.maxpacket) && 614f71b5e25SMian Yousaf Kaukab !(ureq->length % hs_ep->ep.maxpacket)) 6158a20fa45SMian Yousaf Kaukab hs_ep->send_zlp = 1; 61647a1685fSDinh Nguyen } 61747a1685fSDinh Nguyen 61847a1685fSDinh Nguyen epsize |= DXEPTSIZ_PKTCNT(packets); 61947a1685fSDinh Nguyen epsize |= DXEPTSIZ_XFERSIZE(length); 62047a1685fSDinh Nguyen 62147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", 62247a1685fSDinh Nguyen __func__, packets, length, ureq->length, epsize, epsize_reg); 62347a1685fSDinh Nguyen 62447a1685fSDinh Nguyen /* store the request as the current one we're doing */ 62547a1685fSDinh Nguyen hs_ep->req = hs_req; 62647a1685fSDinh Nguyen 62747a1685fSDinh Nguyen /* write size / packets */ 62847a1685fSDinh Nguyen writel(epsize, hsotg->regs + epsize_reg); 62947a1685fSDinh Nguyen 63047a1685fSDinh Nguyen if (using_dma(hsotg) && !continuing) { 63147a1685fSDinh Nguyen unsigned int dma_reg; 63247a1685fSDinh Nguyen 63347a1685fSDinh Nguyen /* 63447a1685fSDinh Nguyen * write DMA address to control register, buffer already 63547a1685fSDinh Nguyen * synced by s3c_hsotg_ep_queue(). 63647a1685fSDinh Nguyen */ 63747a1685fSDinh Nguyen 63847a1685fSDinh Nguyen dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); 63947a1685fSDinh Nguyen writel(ureq->dma, hsotg->regs + dma_reg); 64047a1685fSDinh Nguyen 6410cc4cf6fSFabio Estevam dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n", 64247a1685fSDinh Nguyen __func__, &ureq->dma, dma_reg); 64347a1685fSDinh Nguyen } 64447a1685fSDinh Nguyen 64547a1685fSDinh Nguyen ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 64647a1685fSDinh Nguyen ctrl |= DXEPCTL_USBACTEP; 64747a1685fSDinh Nguyen 648fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state); 64947a1685fSDinh Nguyen 65047a1685fSDinh Nguyen /* For Setup request do not clear NAK */ 651fe0b94abSMian Yousaf Kaukab if (!(index == 0 && hsotg->ep0_state == DWC2_EP0_SETUP)) 65247a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 65347a1685fSDinh Nguyen 65447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 65547a1685fSDinh Nguyen writel(ctrl, hsotg->regs + epctrl_reg); 65647a1685fSDinh Nguyen 65747a1685fSDinh Nguyen /* 65847a1685fSDinh Nguyen * set these, it seems that DMA support increments past the end 65947a1685fSDinh Nguyen * of the packet buffer so we need to calculate the length from 66047a1685fSDinh Nguyen * this information. 66147a1685fSDinh Nguyen */ 66247a1685fSDinh Nguyen hs_ep->size_loaded = length; 66347a1685fSDinh Nguyen hs_ep->last_load = ureq->actual; 66447a1685fSDinh Nguyen 66547a1685fSDinh Nguyen if (dir_in && !using_dma(hsotg)) { 66647a1685fSDinh Nguyen /* set these anyway, we may need them for non-periodic in */ 66747a1685fSDinh Nguyen hs_ep->fifo_load = 0; 66847a1685fSDinh Nguyen 66947a1685fSDinh Nguyen s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); 67047a1685fSDinh Nguyen } 67147a1685fSDinh Nguyen 67247a1685fSDinh Nguyen /* 67347a1685fSDinh Nguyen * clear the INTknTXFEmpMsk when we start request, more as a aide 67447a1685fSDinh Nguyen * to debugging to see what is going on. 67547a1685fSDinh Nguyen */ 67647a1685fSDinh Nguyen if (dir_in) 67747a1685fSDinh Nguyen writel(DIEPMSK_INTKNTXFEMPMSK, 67847a1685fSDinh Nguyen hsotg->regs + DIEPINT(index)); 67947a1685fSDinh Nguyen 68047a1685fSDinh Nguyen /* 68147a1685fSDinh Nguyen * Note, trying to clear the NAK here causes problems with transmit 68247a1685fSDinh Nguyen * on the S3C6400 ending up with the TXFIFO becoming full. 68347a1685fSDinh Nguyen */ 68447a1685fSDinh Nguyen 68547a1685fSDinh Nguyen /* check ep is enabled */ 68647a1685fSDinh Nguyen if (!(readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA)) 6871a0ed863SMian Yousaf Kaukab dev_dbg(hsotg->dev, 68847a1685fSDinh Nguyen "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", 68947a1685fSDinh Nguyen index, readl(hsotg->regs + epctrl_reg)); 69047a1685fSDinh Nguyen 69147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", 69247a1685fSDinh Nguyen __func__, readl(hsotg->regs + epctrl_reg)); 69347a1685fSDinh Nguyen 69447a1685fSDinh Nguyen /* enable ep interrupts */ 69547a1685fSDinh Nguyen s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1); 69647a1685fSDinh Nguyen } 69747a1685fSDinh Nguyen 69847a1685fSDinh Nguyen /** 69947a1685fSDinh Nguyen * s3c_hsotg_map_dma - map the DMA memory being used for the request 70047a1685fSDinh Nguyen * @hsotg: The device state. 70147a1685fSDinh Nguyen * @hs_ep: The endpoint the request is on. 70247a1685fSDinh Nguyen * @req: The request being processed. 70347a1685fSDinh Nguyen * 70447a1685fSDinh Nguyen * We've been asked to queue a request, so ensure that the memory buffer 70547a1685fSDinh Nguyen * is correctly setup for DMA. If we've been passed an extant DMA address 70647a1685fSDinh Nguyen * then ensure the buffer has been synced to memory. If our buffer has no 70747a1685fSDinh Nguyen * DMA memory, then we map the memory and mark our request to allow us to 70847a1685fSDinh Nguyen * cleanup on completion. 70947a1685fSDinh Nguyen */ 710941fcce4SDinh Nguyen static int s3c_hsotg_map_dma(struct dwc2_hsotg *hsotg, 71147a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep, 71247a1685fSDinh Nguyen struct usb_request *req) 71347a1685fSDinh Nguyen { 71447a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = our_req(req); 71547a1685fSDinh Nguyen int ret; 71647a1685fSDinh Nguyen 71747a1685fSDinh Nguyen /* if the length is zero, ignore the DMA data */ 71847a1685fSDinh Nguyen if (hs_req->req.length == 0) 71947a1685fSDinh Nguyen return 0; 72047a1685fSDinh Nguyen 72147a1685fSDinh Nguyen ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); 72247a1685fSDinh Nguyen if (ret) 72347a1685fSDinh Nguyen goto dma_error; 72447a1685fSDinh Nguyen 72547a1685fSDinh Nguyen return 0; 72647a1685fSDinh Nguyen 72747a1685fSDinh Nguyen dma_error: 72847a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", 72947a1685fSDinh Nguyen __func__, req->buf, req->length); 73047a1685fSDinh Nguyen 73147a1685fSDinh Nguyen return -EIO; 73247a1685fSDinh Nguyen } 73347a1685fSDinh Nguyen 73447a1685fSDinh Nguyen static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, 73547a1685fSDinh Nguyen gfp_t gfp_flags) 73647a1685fSDinh Nguyen { 73747a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = our_req(req); 73847a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 739941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 74047a1685fSDinh Nguyen bool first; 74147a1685fSDinh Nguyen 74247a1685fSDinh Nguyen dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", 74347a1685fSDinh Nguyen ep->name, req, req->length, req->buf, req->no_interrupt, 74447a1685fSDinh Nguyen req->zero, req->short_not_ok); 74547a1685fSDinh Nguyen 74647a1685fSDinh Nguyen /* initialise status of the request */ 74747a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_req->queue); 74847a1685fSDinh Nguyen req->actual = 0; 74947a1685fSDinh Nguyen req->status = -EINPROGRESS; 75047a1685fSDinh Nguyen 75147a1685fSDinh Nguyen /* if we're using DMA, sync the buffers as necessary */ 75247a1685fSDinh Nguyen if (using_dma(hs)) { 75347a1685fSDinh Nguyen int ret = s3c_hsotg_map_dma(hs, hs_ep, req); 75447a1685fSDinh Nguyen if (ret) 75547a1685fSDinh Nguyen return ret; 75647a1685fSDinh Nguyen } 75747a1685fSDinh Nguyen 75847a1685fSDinh Nguyen first = list_empty(&hs_ep->queue); 75947a1685fSDinh Nguyen list_add_tail(&hs_req->queue, &hs_ep->queue); 76047a1685fSDinh Nguyen 76147a1685fSDinh Nguyen if (first) 76247a1685fSDinh Nguyen s3c_hsotg_start_req(hs, hs_ep, hs_req, false); 76347a1685fSDinh Nguyen 76447a1685fSDinh Nguyen return 0; 76547a1685fSDinh Nguyen } 76647a1685fSDinh Nguyen 76747a1685fSDinh Nguyen static int s3c_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, 76847a1685fSDinh Nguyen gfp_t gfp_flags) 76947a1685fSDinh Nguyen { 77047a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 771941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 77247a1685fSDinh Nguyen unsigned long flags = 0; 77347a1685fSDinh Nguyen int ret = 0; 77447a1685fSDinh Nguyen 77547a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 77647a1685fSDinh Nguyen ret = s3c_hsotg_ep_queue(ep, req, gfp_flags); 77747a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 77847a1685fSDinh Nguyen 77947a1685fSDinh Nguyen return ret; 78047a1685fSDinh Nguyen } 78147a1685fSDinh Nguyen 78247a1685fSDinh Nguyen static void s3c_hsotg_ep_free_request(struct usb_ep *ep, 78347a1685fSDinh Nguyen struct usb_request *req) 78447a1685fSDinh Nguyen { 78547a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = our_req(req); 78647a1685fSDinh Nguyen 78747a1685fSDinh Nguyen kfree(hs_req); 78847a1685fSDinh Nguyen } 78947a1685fSDinh Nguyen 79047a1685fSDinh Nguyen /** 79147a1685fSDinh Nguyen * s3c_hsotg_complete_oursetup - setup completion callback 79247a1685fSDinh Nguyen * @ep: The endpoint the request was on. 79347a1685fSDinh Nguyen * @req: The request completed. 79447a1685fSDinh Nguyen * 79547a1685fSDinh Nguyen * Called on completion of any requests the driver itself 79647a1685fSDinh Nguyen * submitted that need cleaning up. 79747a1685fSDinh Nguyen */ 79847a1685fSDinh Nguyen static void s3c_hsotg_complete_oursetup(struct usb_ep *ep, 79947a1685fSDinh Nguyen struct usb_request *req) 80047a1685fSDinh Nguyen { 80147a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 802941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 80347a1685fSDinh Nguyen 80447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); 80547a1685fSDinh Nguyen 80647a1685fSDinh Nguyen s3c_hsotg_ep_free_request(ep, req); 80747a1685fSDinh Nguyen } 80847a1685fSDinh Nguyen 80947a1685fSDinh Nguyen /** 81047a1685fSDinh Nguyen * ep_from_windex - convert control wIndex value to endpoint 81147a1685fSDinh Nguyen * @hsotg: The driver state. 81247a1685fSDinh Nguyen * @windex: The control request wIndex field (in host order). 81347a1685fSDinh Nguyen * 81447a1685fSDinh Nguyen * Convert the given wIndex into a pointer to an driver endpoint 81547a1685fSDinh Nguyen * structure, or return NULL if it is not a valid endpoint. 81647a1685fSDinh Nguyen */ 817941fcce4SDinh Nguyen static struct s3c_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, 81847a1685fSDinh Nguyen u32 windex) 81947a1685fSDinh Nguyen { 820c6f5c050SMian Yousaf Kaukab struct s3c_hsotg_ep *ep; 82147a1685fSDinh Nguyen int dir = (windex & USB_DIR_IN) ? 1 : 0; 82247a1685fSDinh Nguyen int idx = windex & 0x7F; 82347a1685fSDinh Nguyen 82447a1685fSDinh Nguyen if (windex >= 0x100) 82547a1685fSDinh Nguyen return NULL; 82647a1685fSDinh Nguyen 82747a1685fSDinh Nguyen if (idx > hsotg->num_of_eps) 82847a1685fSDinh Nguyen return NULL; 82947a1685fSDinh Nguyen 830c6f5c050SMian Yousaf Kaukab ep = index_to_ep(hsotg, idx, dir); 831c6f5c050SMian Yousaf Kaukab 83247a1685fSDinh Nguyen if (idx && ep->dir_in != dir) 83347a1685fSDinh Nguyen return NULL; 83447a1685fSDinh Nguyen 83547a1685fSDinh Nguyen return ep; 83647a1685fSDinh Nguyen } 83747a1685fSDinh Nguyen 83847a1685fSDinh Nguyen /** 839*9e14d0a5SGregory Herrero * s3c_hsotg_set_test_mode - Enable usb Test Modes 840*9e14d0a5SGregory Herrero * @hsotg: The driver state. 841*9e14d0a5SGregory Herrero * @testmode: requested usb test mode 842*9e14d0a5SGregory Herrero * Enable usb Test Mode requested by the Host. 843*9e14d0a5SGregory Herrero */ 844*9e14d0a5SGregory Herrero static int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode) 845*9e14d0a5SGregory Herrero { 846*9e14d0a5SGregory Herrero int dctl = readl(hsotg->regs + DCTL); 847*9e14d0a5SGregory Herrero 848*9e14d0a5SGregory Herrero dctl &= ~DCTL_TSTCTL_MASK; 849*9e14d0a5SGregory Herrero switch (testmode) { 850*9e14d0a5SGregory Herrero case TEST_J: 851*9e14d0a5SGregory Herrero case TEST_K: 852*9e14d0a5SGregory Herrero case TEST_SE0_NAK: 853*9e14d0a5SGregory Herrero case TEST_PACKET: 854*9e14d0a5SGregory Herrero case TEST_FORCE_EN: 855*9e14d0a5SGregory Herrero dctl |= testmode << DCTL_TSTCTL_SHIFT; 856*9e14d0a5SGregory Herrero break; 857*9e14d0a5SGregory Herrero default: 858*9e14d0a5SGregory Herrero return -EINVAL; 859*9e14d0a5SGregory Herrero } 860*9e14d0a5SGregory Herrero writel(dctl, hsotg->regs + DCTL); 861*9e14d0a5SGregory Herrero return 0; 862*9e14d0a5SGregory Herrero } 863*9e14d0a5SGregory Herrero 864*9e14d0a5SGregory Herrero /** 86547a1685fSDinh Nguyen * s3c_hsotg_send_reply - send reply to control request 86647a1685fSDinh Nguyen * @hsotg: The device state 86747a1685fSDinh Nguyen * @ep: Endpoint 0 86847a1685fSDinh Nguyen * @buff: Buffer for request 86947a1685fSDinh Nguyen * @length: Length of reply. 87047a1685fSDinh Nguyen * 87147a1685fSDinh Nguyen * Create a request and queue it on the given endpoint. This is useful as 87247a1685fSDinh Nguyen * an internal method of sending replies to certain control requests, etc. 87347a1685fSDinh Nguyen */ 874941fcce4SDinh Nguyen static int s3c_hsotg_send_reply(struct dwc2_hsotg *hsotg, 87547a1685fSDinh Nguyen struct s3c_hsotg_ep *ep, 87647a1685fSDinh Nguyen void *buff, 87747a1685fSDinh Nguyen int length) 87847a1685fSDinh Nguyen { 87947a1685fSDinh Nguyen struct usb_request *req; 88047a1685fSDinh Nguyen int ret; 88147a1685fSDinh Nguyen 88247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); 88347a1685fSDinh Nguyen 88447a1685fSDinh Nguyen req = s3c_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); 88547a1685fSDinh Nguyen hsotg->ep0_reply = req; 88647a1685fSDinh Nguyen if (!req) { 88747a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); 88847a1685fSDinh Nguyen return -ENOMEM; 88947a1685fSDinh Nguyen } 89047a1685fSDinh Nguyen 89147a1685fSDinh Nguyen req->buf = hsotg->ep0_buff; 89247a1685fSDinh Nguyen req->length = length; 893f71b5e25SMian Yousaf Kaukab /* 894f71b5e25SMian Yousaf Kaukab * zero flag is for sending zlp in DATA IN stage. It has no impact on 895f71b5e25SMian Yousaf Kaukab * STATUS stage. 896f71b5e25SMian Yousaf Kaukab */ 897f71b5e25SMian Yousaf Kaukab req->zero = 0; 89847a1685fSDinh Nguyen req->complete = s3c_hsotg_complete_oursetup; 89947a1685fSDinh Nguyen 90047a1685fSDinh Nguyen if (length) 90147a1685fSDinh Nguyen memcpy(req->buf, buff, length); 90247a1685fSDinh Nguyen 90347a1685fSDinh Nguyen ret = s3c_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); 90447a1685fSDinh Nguyen if (ret) { 90547a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); 90647a1685fSDinh Nguyen return ret; 90747a1685fSDinh Nguyen } 90847a1685fSDinh Nguyen 90947a1685fSDinh Nguyen return 0; 91047a1685fSDinh Nguyen } 91147a1685fSDinh Nguyen 91247a1685fSDinh Nguyen /** 91347a1685fSDinh Nguyen * s3c_hsotg_process_req_status - process request GET_STATUS 91447a1685fSDinh Nguyen * @hsotg: The device state 91547a1685fSDinh Nguyen * @ctrl: USB control request 91647a1685fSDinh Nguyen */ 917941fcce4SDinh Nguyen static int s3c_hsotg_process_req_status(struct dwc2_hsotg *hsotg, 91847a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 91947a1685fSDinh Nguyen { 920c6f5c050SMian Yousaf Kaukab struct s3c_hsotg_ep *ep0 = hsotg->eps_out[0]; 92147a1685fSDinh Nguyen struct s3c_hsotg_ep *ep; 92247a1685fSDinh Nguyen __le16 reply; 92347a1685fSDinh Nguyen int ret; 92447a1685fSDinh Nguyen 92547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); 92647a1685fSDinh Nguyen 92747a1685fSDinh Nguyen if (!ep0->dir_in) { 92847a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: direction out?\n", __func__); 92947a1685fSDinh Nguyen return -EINVAL; 93047a1685fSDinh Nguyen } 93147a1685fSDinh Nguyen 93247a1685fSDinh Nguyen switch (ctrl->bRequestType & USB_RECIP_MASK) { 93347a1685fSDinh Nguyen case USB_RECIP_DEVICE: 93447a1685fSDinh Nguyen reply = cpu_to_le16(0); /* bit 0 => self powered, 93547a1685fSDinh Nguyen * bit 1 => remote wakeup */ 93647a1685fSDinh Nguyen break; 93747a1685fSDinh Nguyen 93847a1685fSDinh Nguyen case USB_RECIP_INTERFACE: 93947a1685fSDinh Nguyen /* currently, the data result should be zero */ 94047a1685fSDinh Nguyen reply = cpu_to_le16(0); 94147a1685fSDinh Nguyen break; 94247a1685fSDinh Nguyen 94347a1685fSDinh Nguyen case USB_RECIP_ENDPOINT: 94447a1685fSDinh Nguyen ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); 94547a1685fSDinh Nguyen if (!ep) 94647a1685fSDinh Nguyen return -ENOENT; 94747a1685fSDinh Nguyen 94847a1685fSDinh Nguyen reply = cpu_to_le16(ep->halted ? 1 : 0); 94947a1685fSDinh Nguyen break; 95047a1685fSDinh Nguyen 95147a1685fSDinh Nguyen default: 95247a1685fSDinh Nguyen return 0; 95347a1685fSDinh Nguyen } 95447a1685fSDinh Nguyen 95547a1685fSDinh Nguyen if (le16_to_cpu(ctrl->wLength) != 2) 95647a1685fSDinh Nguyen return -EINVAL; 95747a1685fSDinh Nguyen 95847a1685fSDinh Nguyen ret = s3c_hsotg_send_reply(hsotg, ep0, &reply, 2); 95947a1685fSDinh Nguyen if (ret) { 96047a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); 96147a1685fSDinh Nguyen return ret; 96247a1685fSDinh Nguyen } 96347a1685fSDinh Nguyen 96447a1685fSDinh Nguyen return 1; 96547a1685fSDinh Nguyen } 96647a1685fSDinh Nguyen 96747a1685fSDinh Nguyen static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value); 96847a1685fSDinh Nguyen 96947a1685fSDinh Nguyen /** 97047a1685fSDinh Nguyen * get_ep_head - return the first request on the endpoint 97147a1685fSDinh Nguyen * @hs_ep: The controller endpoint to get 97247a1685fSDinh Nguyen * 97347a1685fSDinh Nguyen * Get the first request on the endpoint. 97447a1685fSDinh Nguyen */ 97547a1685fSDinh Nguyen static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep) 97647a1685fSDinh Nguyen { 97747a1685fSDinh Nguyen if (list_empty(&hs_ep->queue)) 97847a1685fSDinh Nguyen return NULL; 97947a1685fSDinh Nguyen 98047a1685fSDinh Nguyen return list_first_entry(&hs_ep->queue, struct s3c_hsotg_req, queue); 98147a1685fSDinh Nguyen } 98247a1685fSDinh Nguyen 98347a1685fSDinh Nguyen /** 98447a1685fSDinh Nguyen * s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE 98547a1685fSDinh Nguyen * @hsotg: The device state 98647a1685fSDinh Nguyen * @ctrl: USB control request 98747a1685fSDinh Nguyen */ 988941fcce4SDinh Nguyen static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, 98947a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 99047a1685fSDinh Nguyen { 991c6f5c050SMian Yousaf Kaukab struct s3c_hsotg_ep *ep0 = hsotg->eps_out[0]; 99247a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req; 99347a1685fSDinh Nguyen bool restart; 99447a1685fSDinh Nguyen bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); 99547a1685fSDinh Nguyen struct s3c_hsotg_ep *ep; 99647a1685fSDinh Nguyen int ret; 99747a1685fSDinh Nguyen bool halted; 998*9e14d0a5SGregory Herrero u32 recip; 999*9e14d0a5SGregory Herrero u32 wValue; 1000*9e14d0a5SGregory Herrero u32 wIndex; 100147a1685fSDinh Nguyen 100247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", 100347a1685fSDinh Nguyen __func__, set ? "SET" : "CLEAR"); 100447a1685fSDinh Nguyen 1005*9e14d0a5SGregory Herrero wValue = le16_to_cpu(ctrl->wValue); 1006*9e14d0a5SGregory Herrero wIndex = le16_to_cpu(ctrl->wIndex); 1007*9e14d0a5SGregory Herrero recip = ctrl->bRequestType & USB_RECIP_MASK; 1008*9e14d0a5SGregory Herrero 1009*9e14d0a5SGregory Herrero switch (recip) { 1010*9e14d0a5SGregory Herrero case USB_RECIP_DEVICE: 1011*9e14d0a5SGregory Herrero switch (wValue) { 1012*9e14d0a5SGregory Herrero case USB_DEVICE_TEST_MODE: 1013*9e14d0a5SGregory Herrero if ((wIndex & 0xff) != 0) 1014*9e14d0a5SGregory Herrero return -EINVAL; 1015*9e14d0a5SGregory Herrero if (!set) 1016*9e14d0a5SGregory Herrero return -EINVAL; 1017*9e14d0a5SGregory Herrero 1018*9e14d0a5SGregory Herrero hsotg->test_mode = wIndex >> 8; 1019*9e14d0a5SGregory Herrero ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); 1020*9e14d0a5SGregory Herrero if (ret) { 1021*9e14d0a5SGregory Herrero dev_err(hsotg->dev, 1022*9e14d0a5SGregory Herrero "%s: failed to send reply\n", __func__); 1023*9e14d0a5SGregory Herrero return ret; 1024*9e14d0a5SGregory Herrero } 1025*9e14d0a5SGregory Herrero break; 1026*9e14d0a5SGregory Herrero default: 1027*9e14d0a5SGregory Herrero return -ENOENT; 1028*9e14d0a5SGregory Herrero } 1029*9e14d0a5SGregory Herrero break; 1030*9e14d0a5SGregory Herrero 1031*9e14d0a5SGregory Herrero case USB_RECIP_ENDPOINT: 1032*9e14d0a5SGregory Herrero ep = ep_from_windex(hsotg, wIndex); 103347a1685fSDinh Nguyen if (!ep) { 103447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", 1035*9e14d0a5SGregory Herrero __func__, wIndex); 103647a1685fSDinh Nguyen return -ENOENT; 103747a1685fSDinh Nguyen } 103847a1685fSDinh Nguyen 1039*9e14d0a5SGregory Herrero switch (wValue) { 104047a1685fSDinh Nguyen case USB_ENDPOINT_HALT: 104147a1685fSDinh Nguyen halted = ep->halted; 104247a1685fSDinh Nguyen 104347a1685fSDinh Nguyen s3c_hsotg_ep_sethalt(&ep->ep, set); 104447a1685fSDinh Nguyen 104547a1685fSDinh Nguyen ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); 104647a1685fSDinh Nguyen if (ret) { 104747a1685fSDinh Nguyen dev_err(hsotg->dev, 104847a1685fSDinh Nguyen "%s: failed to send reply\n", __func__); 104947a1685fSDinh Nguyen return ret; 105047a1685fSDinh Nguyen } 105147a1685fSDinh Nguyen 105247a1685fSDinh Nguyen /* 105347a1685fSDinh Nguyen * we have to complete all requests for ep if it was 105447a1685fSDinh Nguyen * halted, and the halt was cleared by CLEAR_FEATURE 105547a1685fSDinh Nguyen */ 105647a1685fSDinh Nguyen 105747a1685fSDinh Nguyen if (!set && halted) { 105847a1685fSDinh Nguyen /* 105947a1685fSDinh Nguyen * If we have request in progress, 106047a1685fSDinh Nguyen * then complete it 106147a1685fSDinh Nguyen */ 106247a1685fSDinh Nguyen if (ep->req) { 106347a1685fSDinh Nguyen hs_req = ep->req; 106447a1685fSDinh Nguyen ep->req = NULL; 106547a1685fSDinh Nguyen list_del_init(&hs_req->queue); 1066c00dd4a6SGregory Herrero if (hs_req->req.complete) { 1067c00dd4a6SGregory Herrero spin_unlock(&hsotg->lock); 1068c00dd4a6SGregory Herrero usb_gadget_giveback_request( 1069c00dd4a6SGregory Herrero &ep->ep, &hs_req->req); 1070c00dd4a6SGregory Herrero spin_lock(&hsotg->lock); 1071c00dd4a6SGregory Herrero } 107247a1685fSDinh Nguyen } 107347a1685fSDinh Nguyen 107447a1685fSDinh Nguyen /* If we have pending request, then start it */ 1075c00dd4a6SGregory Herrero if (!ep->req) { 107647a1685fSDinh Nguyen restart = !list_empty(&ep->queue); 107747a1685fSDinh Nguyen if (restart) { 107847a1685fSDinh Nguyen hs_req = get_ep_head(ep); 107947a1685fSDinh Nguyen s3c_hsotg_start_req(hsotg, ep, 108047a1685fSDinh Nguyen hs_req, false); 108147a1685fSDinh Nguyen } 108247a1685fSDinh Nguyen } 1083c00dd4a6SGregory Herrero } 108447a1685fSDinh Nguyen 108547a1685fSDinh Nguyen break; 108647a1685fSDinh Nguyen 108747a1685fSDinh Nguyen default: 108847a1685fSDinh Nguyen return -ENOENT; 108947a1685fSDinh Nguyen } 1090*9e14d0a5SGregory Herrero break; 1091*9e14d0a5SGregory Herrero default: 1092*9e14d0a5SGregory Herrero return -ENOENT; 1093*9e14d0a5SGregory Herrero } 109447a1685fSDinh Nguyen return 1; 109547a1685fSDinh Nguyen } 109647a1685fSDinh Nguyen 1097941fcce4SDinh Nguyen static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg); 109847a1685fSDinh Nguyen 109947a1685fSDinh Nguyen /** 110047a1685fSDinh Nguyen * s3c_hsotg_stall_ep0 - stall ep0 110147a1685fSDinh Nguyen * @hsotg: The device state 110247a1685fSDinh Nguyen * 110347a1685fSDinh Nguyen * Set stall for ep0 as response for setup request. 110447a1685fSDinh Nguyen */ 1105941fcce4SDinh Nguyen static void s3c_hsotg_stall_ep0(struct dwc2_hsotg *hsotg) 1106e9ebe7c3SJingoo Han { 1107c6f5c050SMian Yousaf Kaukab struct s3c_hsotg_ep *ep0 = hsotg->eps_out[0]; 110847a1685fSDinh Nguyen u32 reg; 110947a1685fSDinh Nguyen u32 ctrl; 111047a1685fSDinh Nguyen 111147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); 111247a1685fSDinh Nguyen reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; 111347a1685fSDinh Nguyen 111447a1685fSDinh Nguyen /* 111547a1685fSDinh Nguyen * DxEPCTL_Stall will be cleared by EP once it has 111647a1685fSDinh Nguyen * taken effect, so no need to clear later. 111747a1685fSDinh Nguyen */ 111847a1685fSDinh Nguyen 111947a1685fSDinh Nguyen ctrl = readl(hsotg->regs + reg); 112047a1685fSDinh Nguyen ctrl |= DXEPCTL_STALL; 112147a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; 112247a1685fSDinh Nguyen writel(ctrl, hsotg->regs + reg); 112347a1685fSDinh Nguyen 112447a1685fSDinh Nguyen dev_dbg(hsotg->dev, 112547a1685fSDinh Nguyen "written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n", 112647a1685fSDinh Nguyen ctrl, reg, readl(hsotg->regs + reg)); 112747a1685fSDinh Nguyen 112847a1685fSDinh Nguyen /* 112947a1685fSDinh Nguyen * complete won't be called, so we enqueue 113047a1685fSDinh Nguyen * setup request here 113147a1685fSDinh Nguyen */ 113247a1685fSDinh Nguyen s3c_hsotg_enqueue_setup(hsotg); 113347a1685fSDinh Nguyen } 113447a1685fSDinh Nguyen 113547a1685fSDinh Nguyen /** 113647a1685fSDinh Nguyen * s3c_hsotg_process_control - process a control request 113747a1685fSDinh Nguyen * @hsotg: The device state 113847a1685fSDinh Nguyen * @ctrl: The control request received 113947a1685fSDinh Nguyen * 114047a1685fSDinh Nguyen * The controller has received the SETUP phase of a control request, and 114147a1685fSDinh Nguyen * needs to work out what to do next (and whether to pass it on to the 114247a1685fSDinh Nguyen * gadget driver). 114347a1685fSDinh Nguyen */ 1144941fcce4SDinh Nguyen static void s3c_hsotg_process_control(struct dwc2_hsotg *hsotg, 114547a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 114647a1685fSDinh Nguyen { 1147c6f5c050SMian Yousaf Kaukab struct s3c_hsotg_ep *ep0 = hsotg->eps_out[0]; 114847a1685fSDinh Nguyen int ret = 0; 114947a1685fSDinh Nguyen u32 dcfg; 115047a1685fSDinh Nguyen 115147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ctrl Req=%02x, Type=%02x, V=%04x, L=%04x\n", 115247a1685fSDinh Nguyen ctrl->bRequest, ctrl->bRequestType, 115347a1685fSDinh Nguyen ctrl->wValue, ctrl->wLength); 115447a1685fSDinh Nguyen 1155fe0b94abSMian Yousaf Kaukab if (ctrl->wLength == 0) { 115647a1685fSDinh Nguyen ep0->dir_in = 1; 1157fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_STATUS_IN; 1158fe0b94abSMian Yousaf Kaukab } else if (ctrl->bRequestType & USB_DIR_IN) { 1159fe0b94abSMian Yousaf Kaukab ep0->dir_in = 1; 1160fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_DATA_IN; 1161fe0b94abSMian Yousaf Kaukab } else { 1162fe0b94abSMian Yousaf Kaukab ep0->dir_in = 0; 1163fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_DATA_OUT; 1164fe0b94abSMian Yousaf Kaukab } 116547a1685fSDinh Nguyen 116647a1685fSDinh Nguyen if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 116747a1685fSDinh Nguyen switch (ctrl->bRequest) { 116847a1685fSDinh Nguyen case USB_REQ_SET_ADDRESS: 11696d713c15SMian Yousaf Kaukab hsotg->connected = 1; 117047a1685fSDinh Nguyen dcfg = readl(hsotg->regs + DCFG); 117147a1685fSDinh Nguyen dcfg &= ~DCFG_DEVADDR_MASK; 1172d5dbd3f7SPaul Zimmerman dcfg |= (le16_to_cpu(ctrl->wValue) << 1173d5dbd3f7SPaul Zimmerman DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK; 117447a1685fSDinh Nguyen writel(dcfg, hsotg->regs + DCFG); 117547a1685fSDinh Nguyen 117647a1685fSDinh Nguyen dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); 117747a1685fSDinh Nguyen 117847a1685fSDinh Nguyen ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); 117947a1685fSDinh Nguyen return; 118047a1685fSDinh Nguyen 118147a1685fSDinh Nguyen case USB_REQ_GET_STATUS: 118247a1685fSDinh Nguyen ret = s3c_hsotg_process_req_status(hsotg, ctrl); 118347a1685fSDinh Nguyen break; 118447a1685fSDinh Nguyen 118547a1685fSDinh Nguyen case USB_REQ_CLEAR_FEATURE: 118647a1685fSDinh Nguyen case USB_REQ_SET_FEATURE: 118747a1685fSDinh Nguyen ret = s3c_hsotg_process_req_feature(hsotg, ctrl); 118847a1685fSDinh Nguyen break; 118947a1685fSDinh Nguyen } 119047a1685fSDinh Nguyen } 119147a1685fSDinh Nguyen 119247a1685fSDinh Nguyen /* as a fallback, try delivering it to the driver to deal with */ 119347a1685fSDinh Nguyen 119447a1685fSDinh Nguyen if (ret == 0 && hsotg->driver) { 119547a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 119647a1685fSDinh Nguyen ret = hsotg->driver->setup(&hsotg->gadget, ctrl); 119747a1685fSDinh Nguyen spin_lock(&hsotg->lock); 119847a1685fSDinh Nguyen if (ret < 0) 119947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); 120047a1685fSDinh Nguyen } 120147a1685fSDinh Nguyen 120247a1685fSDinh Nguyen /* 120347a1685fSDinh Nguyen * the request is either unhandlable, or is not formatted correctly 120447a1685fSDinh Nguyen * so respond with a STALL for the status stage to indicate failure. 120547a1685fSDinh Nguyen */ 120647a1685fSDinh Nguyen 120747a1685fSDinh Nguyen if (ret < 0) 120847a1685fSDinh Nguyen s3c_hsotg_stall_ep0(hsotg); 120947a1685fSDinh Nguyen } 121047a1685fSDinh Nguyen 121147a1685fSDinh Nguyen /** 121247a1685fSDinh Nguyen * s3c_hsotg_complete_setup - completion of a setup transfer 121347a1685fSDinh Nguyen * @ep: The endpoint the request was on. 121447a1685fSDinh Nguyen * @req: The request completed. 121547a1685fSDinh Nguyen * 121647a1685fSDinh Nguyen * Called on completion of any requests the driver itself submitted for 121747a1685fSDinh Nguyen * EP0 setup packets 121847a1685fSDinh Nguyen */ 121947a1685fSDinh Nguyen static void s3c_hsotg_complete_setup(struct usb_ep *ep, 122047a1685fSDinh Nguyen struct usb_request *req) 122147a1685fSDinh Nguyen { 122247a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 1223941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 122447a1685fSDinh Nguyen 122547a1685fSDinh Nguyen if (req->status < 0) { 122647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); 122747a1685fSDinh Nguyen return; 122847a1685fSDinh Nguyen } 122947a1685fSDinh Nguyen 123047a1685fSDinh Nguyen spin_lock(&hsotg->lock); 123147a1685fSDinh Nguyen if (req->actual == 0) 123247a1685fSDinh Nguyen s3c_hsotg_enqueue_setup(hsotg); 123347a1685fSDinh Nguyen else 123447a1685fSDinh Nguyen s3c_hsotg_process_control(hsotg, req->buf); 123547a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 123647a1685fSDinh Nguyen } 123747a1685fSDinh Nguyen 123847a1685fSDinh Nguyen /** 123947a1685fSDinh Nguyen * s3c_hsotg_enqueue_setup - start a request for EP0 packets 124047a1685fSDinh Nguyen * @hsotg: The device state. 124147a1685fSDinh Nguyen * 124247a1685fSDinh Nguyen * Enqueue a request on EP0 if necessary to received any SETUP packets 124347a1685fSDinh Nguyen * received from the host. 124447a1685fSDinh Nguyen */ 1245941fcce4SDinh Nguyen static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg) 124647a1685fSDinh Nguyen { 124747a1685fSDinh Nguyen struct usb_request *req = hsotg->ctrl_req; 124847a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = our_req(req); 124947a1685fSDinh Nguyen int ret; 125047a1685fSDinh Nguyen 125147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); 125247a1685fSDinh Nguyen 125347a1685fSDinh Nguyen req->zero = 0; 125447a1685fSDinh Nguyen req->length = 8; 125547a1685fSDinh Nguyen req->buf = hsotg->ctrl_buff; 125647a1685fSDinh Nguyen req->complete = s3c_hsotg_complete_setup; 125747a1685fSDinh Nguyen 125847a1685fSDinh Nguyen if (!list_empty(&hs_req->queue)) { 125947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s already queued???\n", __func__); 126047a1685fSDinh Nguyen return; 126147a1685fSDinh Nguyen } 126247a1685fSDinh Nguyen 1263c6f5c050SMian Yousaf Kaukab hsotg->eps_out[0]->dir_in = 0; 12648a20fa45SMian Yousaf Kaukab hsotg->eps_out[0]->send_zlp = 0; 1265fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = DWC2_EP0_SETUP; 126647a1685fSDinh Nguyen 1267c6f5c050SMian Yousaf Kaukab ret = s3c_hsotg_ep_queue(&hsotg->eps_out[0]->ep, req, GFP_ATOMIC); 126847a1685fSDinh Nguyen if (ret < 0) { 126947a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); 127047a1685fSDinh Nguyen /* 127147a1685fSDinh Nguyen * Don't think there's much we can do other than watch the 127247a1685fSDinh Nguyen * driver fail. 127347a1685fSDinh Nguyen */ 127447a1685fSDinh Nguyen } 127547a1685fSDinh Nguyen } 127647a1685fSDinh Nguyen 1277fe0b94abSMian Yousaf Kaukab static void s3c_hsotg_program_zlp(struct dwc2_hsotg *hsotg, 1278fe0b94abSMian Yousaf Kaukab struct s3c_hsotg_ep *hs_ep) 1279fe0b94abSMian Yousaf Kaukab { 1280fe0b94abSMian Yousaf Kaukab u32 ctrl; 1281fe0b94abSMian Yousaf Kaukab u8 index = hs_ep->index; 1282fe0b94abSMian Yousaf Kaukab u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 1283fe0b94abSMian Yousaf Kaukab u32 epsiz_reg = hs_ep->dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 1284fe0b94abSMian Yousaf Kaukab 1285fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n", index); 1286fe0b94abSMian Yousaf Kaukab 1287fe0b94abSMian Yousaf Kaukab writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 1288fe0b94abSMian Yousaf Kaukab DXEPTSIZ_XFERSIZE(0), hsotg->regs + 1289fe0b94abSMian Yousaf Kaukab epsiz_reg); 1290fe0b94abSMian Yousaf Kaukab 1291fe0b94abSMian Yousaf Kaukab ctrl = readl(hsotg->regs + epctl_reg); 1292fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 1293fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 1294fe0b94abSMian Yousaf Kaukab ctrl |= DXEPCTL_USBACTEP; 1295fe0b94abSMian Yousaf Kaukab writel(ctrl, hsotg->regs + epctl_reg); 1296fe0b94abSMian Yousaf Kaukab } 1297fe0b94abSMian Yousaf Kaukab 129847a1685fSDinh Nguyen /** 129947a1685fSDinh Nguyen * s3c_hsotg_complete_request - complete a request given to us 130047a1685fSDinh Nguyen * @hsotg: The device state. 130147a1685fSDinh Nguyen * @hs_ep: The endpoint the request was on. 130247a1685fSDinh Nguyen * @hs_req: The request to complete. 130347a1685fSDinh Nguyen * @result: The result code (0 => Ok, otherwise errno) 130447a1685fSDinh Nguyen * 130547a1685fSDinh Nguyen * The given request has finished, so call the necessary completion 130647a1685fSDinh Nguyen * if it has one and then look to see if we can start a new request 130747a1685fSDinh Nguyen * on the endpoint. 130847a1685fSDinh Nguyen * 130947a1685fSDinh Nguyen * Note, expects the ep to already be locked as appropriate. 131047a1685fSDinh Nguyen */ 1311941fcce4SDinh Nguyen static void s3c_hsotg_complete_request(struct dwc2_hsotg *hsotg, 131247a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep, 131347a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req, 131447a1685fSDinh Nguyen int result) 131547a1685fSDinh Nguyen { 131647a1685fSDinh Nguyen bool restart; 131747a1685fSDinh Nguyen 131847a1685fSDinh Nguyen if (!hs_req) { 131947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); 132047a1685fSDinh Nguyen return; 132147a1685fSDinh Nguyen } 132247a1685fSDinh Nguyen 132347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", 132447a1685fSDinh Nguyen hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); 132547a1685fSDinh Nguyen 132647a1685fSDinh Nguyen /* 132747a1685fSDinh Nguyen * only replace the status if we've not already set an error 132847a1685fSDinh Nguyen * from a previous transaction 132947a1685fSDinh Nguyen */ 133047a1685fSDinh Nguyen 133147a1685fSDinh Nguyen if (hs_req->req.status == -EINPROGRESS) 133247a1685fSDinh Nguyen hs_req->req.status = result; 133347a1685fSDinh Nguyen 133447a1685fSDinh Nguyen hs_ep->req = NULL; 133547a1685fSDinh Nguyen list_del_init(&hs_req->queue); 133647a1685fSDinh Nguyen 133747a1685fSDinh Nguyen if (using_dma(hsotg)) 133847a1685fSDinh Nguyen s3c_hsotg_unmap_dma(hsotg, hs_ep, hs_req); 133947a1685fSDinh Nguyen 134047a1685fSDinh Nguyen /* 134147a1685fSDinh Nguyen * call the complete request with the locks off, just in case the 134247a1685fSDinh Nguyen * request tries to queue more work for this endpoint. 134347a1685fSDinh Nguyen */ 134447a1685fSDinh Nguyen 134547a1685fSDinh Nguyen if (hs_req->req.complete) { 134647a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 1347304f7e5eSMichal Sojka usb_gadget_giveback_request(&hs_ep->ep, &hs_req->req); 134847a1685fSDinh Nguyen spin_lock(&hsotg->lock); 134947a1685fSDinh Nguyen } 135047a1685fSDinh Nguyen 135147a1685fSDinh Nguyen /* 135247a1685fSDinh Nguyen * Look to see if there is anything else to do. Note, the completion 135347a1685fSDinh Nguyen * of the previous request may have caused a new request to be started 135447a1685fSDinh Nguyen * so be careful when doing this. 135547a1685fSDinh Nguyen */ 135647a1685fSDinh Nguyen 135747a1685fSDinh Nguyen if (!hs_ep->req && result >= 0) { 135847a1685fSDinh Nguyen restart = !list_empty(&hs_ep->queue); 135947a1685fSDinh Nguyen if (restart) { 136047a1685fSDinh Nguyen hs_req = get_ep_head(hs_ep); 136147a1685fSDinh Nguyen s3c_hsotg_start_req(hsotg, hs_ep, hs_req, false); 136247a1685fSDinh Nguyen } 136347a1685fSDinh Nguyen } 136447a1685fSDinh Nguyen } 136547a1685fSDinh Nguyen 136647a1685fSDinh Nguyen /** 136747a1685fSDinh Nguyen * s3c_hsotg_rx_data - receive data from the FIFO for an endpoint 136847a1685fSDinh Nguyen * @hsotg: The device state. 136947a1685fSDinh Nguyen * @ep_idx: The endpoint index for the data 137047a1685fSDinh Nguyen * @size: The size of data in the fifo, in bytes 137147a1685fSDinh Nguyen * 137247a1685fSDinh Nguyen * The FIFO status shows there is data to read from the FIFO for a given 137347a1685fSDinh Nguyen * endpoint, so sort out whether we need to read the data into a request 137447a1685fSDinh Nguyen * that has been made for that endpoint. 137547a1685fSDinh Nguyen */ 1376941fcce4SDinh Nguyen static void s3c_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size) 137747a1685fSDinh Nguyen { 1378c6f5c050SMian Yousaf Kaukab struct s3c_hsotg_ep *hs_ep = hsotg->eps_out[ep_idx]; 137947a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = hs_ep->req; 138047a1685fSDinh Nguyen void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx); 138147a1685fSDinh Nguyen int to_read; 138247a1685fSDinh Nguyen int max_req; 138347a1685fSDinh Nguyen int read_ptr; 138447a1685fSDinh Nguyen 138547a1685fSDinh Nguyen 138647a1685fSDinh Nguyen if (!hs_req) { 138747a1685fSDinh Nguyen u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx)); 138847a1685fSDinh Nguyen int ptr; 138947a1685fSDinh Nguyen 13906b448af4SRobert Baldyga dev_dbg(hsotg->dev, 139147a1685fSDinh Nguyen "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", 139247a1685fSDinh Nguyen __func__, size, ep_idx, epctl); 139347a1685fSDinh Nguyen 139447a1685fSDinh Nguyen /* dump the data from the FIFO, we've nothing we can do */ 139547a1685fSDinh Nguyen for (ptr = 0; ptr < size; ptr += 4) 139647a1685fSDinh Nguyen (void)readl(fifo); 139747a1685fSDinh Nguyen 139847a1685fSDinh Nguyen return; 139947a1685fSDinh Nguyen } 140047a1685fSDinh Nguyen 140147a1685fSDinh Nguyen to_read = size; 140247a1685fSDinh Nguyen read_ptr = hs_req->req.actual; 140347a1685fSDinh Nguyen max_req = hs_req->req.length - read_ptr; 140447a1685fSDinh Nguyen 140547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", 140647a1685fSDinh Nguyen __func__, to_read, max_req, read_ptr, hs_req->req.length); 140747a1685fSDinh Nguyen 140847a1685fSDinh Nguyen if (to_read > max_req) { 140947a1685fSDinh Nguyen /* 141047a1685fSDinh Nguyen * more data appeared than we where willing 141147a1685fSDinh Nguyen * to deal with in this request. 141247a1685fSDinh Nguyen */ 141347a1685fSDinh Nguyen 141447a1685fSDinh Nguyen /* currently we don't deal this */ 141547a1685fSDinh Nguyen WARN_ON_ONCE(1); 141647a1685fSDinh Nguyen } 141747a1685fSDinh Nguyen 141847a1685fSDinh Nguyen hs_ep->total_data += to_read; 141947a1685fSDinh Nguyen hs_req->req.actual += to_read; 142047a1685fSDinh Nguyen to_read = DIV_ROUND_UP(to_read, 4); 142147a1685fSDinh Nguyen 142247a1685fSDinh Nguyen /* 142347a1685fSDinh Nguyen * note, we might over-write the buffer end by 3 bytes depending on 142447a1685fSDinh Nguyen * alignment of the data. 142547a1685fSDinh Nguyen */ 142647a1685fSDinh Nguyen ioread32_rep(fifo, hs_req->req.buf + read_ptr, to_read); 142747a1685fSDinh Nguyen } 142847a1685fSDinh Nguyen 142947a1685fSDinh Nguyen /** 1430fe0b94abSMian Yousaf Kaukab * s3c_hsotg_ep0_zlp - send/receive zero-length packet on control endpoint 143147a1685fSDinh Nguyen * @hsotg: The device instance 1432fe0b94abSMian Yousaf Kaukab * @dir_in: If IN zlp 143347a1685fSDinh Nguyen * 143447a1685fSDinh Nguyen * Generate a zero-length IN packet request for terminating a SETUP 143547a1685fSDinh Nguyen * transaction. 143647a1685fSDinh Nguyen * 143747a1685fSDinh Nguyen * Note, since we don't write any data to the TxFIFO, then it is 143847a1685fSDinh Nguyen * currently believed that we do not need to wait for any space in 143947a1685fSDinh Nguyen * the TxFIFO. 144047a1685fSDinh Nguyen */ 1441fe0b94abSMian Yousaf Kaukab static void s3c_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in) 144247a1685fSDinh Nguyen { 1443c6f5c050SMian Yousaf Kaukab /* eps_out[0] is used in both directions */ 1444fe0b94abSMian Yousaf Kaukab hsotg->eps_out[0]->dir_in = dir_in; 1445fe0b94abSMian Yousaf Kaukab hsotg->ep0_state = dir_in ? DWC2_EP0_STATUS_IN : DWC2_EP0_STATUS_OUT; 144647a1685fSDinh Nguyen 1447fe0b94abSMian Yousaf Kaukab s3c_hsotg_program_zlp(hsotg, hsotg->eps_out[0]); 144847a1685fSDinh Nguyen } 144947a1685fSDinh Nguyen 145047a1685fSDinh Nguyen /** 145147a1685fSDinh Nguyen * s3c_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO 145247a1685fSDinh Nguyen * @hsotg: The device instance 145347a1685fSDinh Nguyen * @epnum: The endpoint received from 145447a1685fSDinh Nguyen * 145547a1685fSDinh Nguyen * The RXFIFO has delivered an OutDone event, which means that the data 145647a1685fSDinh Nguyen * transfer for an OUT endpoint has been completed, either by a short 145747a1685fSDinh Nguyen * packet or by the finish of a transfer. 145847a1685fSDinh Nguyen */ 1459fe0b94abSMian Yousaf Kaukab static void s3c_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) 146047a1685fSDinh Nguyen { 146147a1685fSDinh Nguyen u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum)); 1462c6f5c050SMian Yousaf Kaukab struct s3c_hsotg_ep *hs_ep = hsotg->eps_out[epnum]; 146347a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = hs_ep->req; 146447a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 146547a1685fSDinh Nguyen unsigned size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 146647a1685fSDinh Nguyen int result = 0; 146747a1685fSDinh Nguyen 146847a1685fSDinh Nguyen if (!hs_req) { 146947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no request active\n", __func__); 147047a1685fSDinh Nguyen return; 147147a1685fSDinh Nguyen } 147247a1685fSDinh Nguyen 1473fe0b94abSMian Yousaf Kaukab if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_OUT) { 1474fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "zlp packet received\n"); 1475fe0b94abSMian Yousaf Kaukab s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 1476fe0b94abSMian Yousaf Kaukab s3c_hsotg_enqueue_setup(hsotg); 1477fe0b94abSMian Yousaf Kaukab return; 1478fe0b94abSMian Yousaf Kaukab } 1479fe0b94abSMian Yousaf Kaukab 148047a1685fSDinh Nguyen if (using_dma(hsotg)) { 148147a1685fSDinh Nguyen unsigned size_done; 148247a1685fSDinh Nguyen 148347a1685fSDinh Nguyen /* 148447a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much 148547a1685fSDinh Nguyen * is left in the endpoint size register and then working it 148647a1685fSDinh Nguyen * out from the amount we loaded for the transfer. 148747a1685fSDinh Nguyen * 148847a1685fSDinh Nguyen * We need to do this as DMA pointers are always 32bit aligned 148947a1685fSDinh Nguyen * so may overshoot/undershoot the transfer. 149047a1685fSDinh Nguyen */ 149147a1685fSDinh Nguyen 149247a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 149347a1685fSDinh Nguyen size_done += hs_ep->last_load; 149447a1685fSDinh Nguyen 149547a1685fSDinh Nguyen req->actual = size_done; 149647a1685fSDinh Nguyen } 149747a1685fSDinh Nguyen 149847a1685fSDinh Nguyen /* if there is more request to do, schedule new transfer */ 149947a1685fSDinh Nguyen if (req->actual < req->length && size_left == 0) { 150047a1685fSDinh Nguyen s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); 150147a1685fSDinh Nguyen return; 150247a1685fSDinh Nguyen } 150347a1685fSDinh Nguyen 150447a1685fSDinh Nguyen if (req->actual < req->length && req->short_not_ok) { 150547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", 150647a1685fSDinh Nguyen __func__, req->actual, req->length); 150747a1685fSDinh Nguyen 150847a1685fSDinh Nguyen /* 150947a1685fSDinh Nguyen * todo - what should we return here? there's no one else 151047a1685fSDinh Nguyen * even bothering to check the status. 151147a1685fSDinh Nguyen */ 151247a1685fSDinh Nguyen } 151347a1685fSDinh Nguyen 1514fe0b94abSMian Yousaf Kaukab if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_DATA_OUT) { 1515fe0b94abSMian Yousaf Kaukab /* Move to STATUS IN */ 1516fe0b94abSMian Yousaf Kaukab s3c_hsotg_ep0_zlp(hsotg, true); 1517fe0b94abSMian Yousaf Kaukab return; 151847a1685fSDinh Nguyen } 151947a1685fSDinh Nguyen 152047a1685fSDinh Nguyen s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result); 152147a1685fSDinh Nguyen } 152247a1685fSDinh Nguyen 152347a1685fSDinh Nguyen /** 152447a1685fSDinh Nguyen * s3c_hsotg_read_frameno - read current frame number 152547a1685fSDinh Nguyen * @hsotg: The device instance 152647a1685fSDinh Nguyen * 152747a1685fSDinh Nguyen * Return the current frame number 152847a1685fSDinh Nguyen */ 1529941fcce4SDinh Nguyen static u32 s3c_hsotg_read_frameno(struct dwc2_hsotg *hsotg) 153047a1685fSDinh Nguyen { 153147a1685fSDinh Nguyen u32 dsts; 153247a1685fSDinh Nguyen 153347a1685fSDinh Nguyen dsts = readl(hsotg->regs + DSTS); 153447a1685fSDinh Nguyen dsts &= DSTS_SOFFN_MASK; 153547a1685fSDinh Nguyen dsts >>= DSTS_SOFFN_SHIFT; 153647a1685fSDinh Nguyen 153747a1685fSDinh Nguyen return dsts; 153847a1685fSDinh Nguyen } 153947a1685fSDinh Nguyen 154047a1685fSDinh Nguyen /** 154147a1685fSDinh Nguyen * s3c_hsotg_handle_rx - RX FIFO has data 154247a1685fSDinh Nguyen * @hsotg: The device instance 154347a1685fSDinh Nguyen * 154447a1685fSDinh Nguyen * The IRQ handler has detected that the RX FIFO has some data in it 154547a1685fSDinh Nguyen * that requires processing, so find out what is in there and do the 154647a1685fSDinh Nguyen * appropriate read. 154747a1685fSDinh Nguyen * 154847a1685fSDinh Nguyen * The RXFIFO is a true FIFO, the packets coming out are still in packet 154947a1685fSDinh Nguyen * chunks, so if you have x packets received on an endpoint you'll get x 155047a1685fSDinh Nguyen * FIFO events delivered, each with a packet's worth of data in it. 155147a1685fSDinh Nguyen * 155247a1685fSDinh Nguyen * When using DMA, we should not be processing events from the RXFIFO 155347a1685fSDinh Nguyen * as the actual data should be sent to the memory directly and we turn 155447a1685fSDinh Nguyen * on the completion interrupts to get notifications of transfer completion. 155547a1685fSDinh Nguyen */ 1556941fcce4SDinh Nguyen static void s3c_hsotg_handle_rx(struct dwc2_hsotg *hsotg) 155747a1685fSDinh Nguyen { 155847a1685fSDinh Nguyen u32 grxstsr = readl(hsotg->regs + GRXSTSP); 155947a1685fSDinh Nguyen u32 epnum, status, size; 156047a1685fSDinh Nguyen 156147a1685fSDinh Nguyen WARN_ON(using_dma(hsotg)); 156247a1685fSDinh Nguyen 156347a1685fSDinh Nguyen epnum = grxstsr & GRXSTS_EPNUM_MASK; 156447a1685fSDinh Nguyen status = grxstsr & GRXSTS_PKTSTS_MASK; 156547a1685fSDinh Nguyen 156647a1685fSDinh Nguyen size = grxstsr & GRXSTS_BYTECNT_MASK; 156747a1685fSDinh Nguyen size >>= GRXSTS_BYTECNT_SHIFT; 156847a1685fSDinh Nguyen 156947a1685fSDinh Nguyen if (1) 157047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", 157147a1685fSDinh Nguyen __func__, grxstsr, size, epnum); 157247a1685fSDinh Nguyen 157347a1685fSDinh Nguyen switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { 157447a1685fSDinh Nguyen case GRXSTS_PKTSTS_GLOBALOUTNAK: 157547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GLOBALOUTNAK\n"); 157647a1685fSDinh Nguyen break; 157747a1685fSDinh Nguyen 157847a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTDONE: 157947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", 158047a1685fSDinh Nguyen s3c_hsotg_read_frameno(hsotg)); 158147a1685fSDinh Nguyen 158247a1685fSDinh Nguyen if (!using_dma(hsotg)) 1583fe0b94abSMian Yousaf Kaukab s3c_hsotg_handle_outdone(hsotg, epnum); 158447a1685fSDinh Nguyen break; 158547a1685fSDinh Nguyen 158647a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPDONE: 158747a1685fSDinh Nguyen dev_dbg(hsotg->dev, 158847a1685fSDinh Nguyen "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 158947a1685fSDinh Nguyen s3c_hsotg_read_frameno(hsotg), 159047a1685fSDinh Nguyen readl(hsotg->regs + DOEPCTL(0))); 1591fe0b94abSMian Yousaf Kaukab /* 1592fe0b94abSMian Yousaf Kaukab * Call s3c_hsotg_handle_outdone here if it was not called from 1593fe0b94abSMian Yousaf Kaukab * GRXSTS_PKTSTS_OUTDONE. That is, if the core didn't 1594fe0b94abSMian Yousaf Kaukab * generate GRXSTS_PKTSTS_OUTDONE for setup packet. 1595fe0b94abSMian Yousaf Kaukab */ 1596fe0b94abSMian Yousaf Kaukab if (hsotg->ep0_state == DWC2_EP0_SETUP) 1597fe0b94abSMian Yousaf Kaukab s3c_hsotg_handle_outdone(hsotg, epnum); 159847a1685fSDinh Nguyen break; 159947a1685fSDinh Nguyen 160047a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTRX: 160147a1685fSDinh Nguyen s3c_hsotg_rx_data(hsotg, epnum, size); 160247a1685fSDinh Nguyen break; 160347a1685fSDinh Nguyen 160447a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPRX: 160547a1685fSDinh Nguyen dev_dbg(hsotg->dev, 160647a1685fSDinh Nguyen "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 160747a1685fSDinh Nguyen s3c_hsotg_read_frameno(hsotg), 160847a1685fSDinh Nguyen readl(hsotg->regs + DOEPCTL(0))); 160947a1685fSDinh Nguyen 1610fe0b94abSMian Yousaf Kaukab WARN_ON(hsotg->ep0_state != DWC2_EP0_SETUP); 1611fe0b94abSMian Yousaf Kaukab 161247a1685fSDinh Nguyen s3c_hsotg_rx_data(hsotg, epnum, size); 161347a1685fSDinh Nguyen break; 161447a1685fSDinh Nguyen 161547a1685fSDinh Nguyen default: 161647a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: unknown status %08x\n", 161747a1685fSDinh Nguyen __func__, grxstsr); 161847a1685fSDinh Nguyen 161947a1685fSDinh Nguyen s3c_hsotg_dump(hsotg); 162047a1685fSDinh Nguyen break; 162147a1685fSDinh Nguyen } 162247a1685fSDinh Nguyen } 162347a1685fSDinh Nguyen 162447a1685fSDinh Nguyen /** 162547a1685fSDinh Nguyen * s3c_hsotg_ep0_mps - turn max packet size into register setting 162647a1685fSDinh Nguyen * @mps: The maximum packet size in bytes. 162747a1685fSDinh Nguyen */ 162847a1685fSDinh Nguyen static u32 s3c_hsotg_ep0_mps(unsigned int mps) 162947a1685fSDinh Nguyen { 163047a1685fSDinh Nguyen switch (mps) { 163147a1685fSDinh Nguyen case 64: 163247a1685fSDinh Nguyen return D0EPCTL_MPS_64; 163347a1685fSDinh Nguyen case 32: 163447a1685fSDinh Nguyen return D0EPCTL_MPS_32; 163547a1685fSDinh Nguyen case 16: 163647a1685fSDinh Nguyen return D0EPCTL_MPS_16; 163747a1685fSDinh Nguyen case 8: 163847a1685fSDinh Nguyen return D0EPCTL_MPS_8; 163947a1685fSDinh Nguyen } 164047a1685fSDinh Nguyen 164147a1685fSDinh Nguyen /* bad max packet size, warn and return invalid result */ 164247a1685fSDinh Nguyen WARN_ON(1); 164347a1685fSDinh Nguyen return (u32)-1; 164447a1685fSDinh Nguyen } 164547a1685fSDinh Nguyen 164647a1685fSDinh Nguyen /** 164747a1685fSDinh Nguyen * s3c_hsotg_set_ep_maxpacket - set endpoint's max-packet field 164847a1685fSDinh Nguyen * @hsotg: The driver state. 164947a1685fSDinh Nguyen * @ep: The index number of the endpoint 165047a1685fSDinh Nguyen * @mps: The maximum packet size in bytes 165147a1685fSDinh Nguyen * 165247a1685fSDinh Nguyen * Configure the maximum packet size for the given endpoint, updating 165347a1685fSDinh Nguyen * the hardware control registers to reflect this. 165447a1685fSDinh Nguyen */ 1655941fcce4SDinh Nguyen static void s3c_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg, 1656c6f5c050SMian Yousaf Kaukab unsigned int ep, unsigned int mps, unsigned int dir_in) 165747a1685fSDinh Nguyen { 1658c6f5c050SMian Yousaf Kaukab struct s3c_hsotg_ep *hs_ep; 165947a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 166047a1685fSDinh Nguyen u32 mpsval; 166147a1685fSDinh Nguyen u32 mcval; 166247a1685fSDinh Nguyen u32 reg; 166347a1685fSDinh Nguyen 1664c6f5c050SMian Yousaf Kaukab hs_ep = index_to_ep(hsotg, ep, dir_in); 1665c6f5c050SMian Yousaf Kaukab if (!hs_ep) 1666c6f5c050SMian Yousaf Kaukab return; 1667c6f5c050SMian Yousaf Kaukab 166847a1685fSDinh Nguyen if (ep == 0) { 166947a1685fSDinh Nguyen /* EP0 is a special case */ 167047a1685fSDinh Nguyen mpsval = s3c_hsotg_ep0_mps(mps); 167147a1685fSDinh Nguyen if (mpsval > 3) 167247a1685fSDinh Nguyen goto bad_mps; 167347a1685fSDinh Nguyen hs_ep->ep.maxpacket = mps; 167447a1685fSDinh Nguyen hs_ep->mc = 1; 167547a1685fSDinh Nguyen } else { 167647a1685fSDinh Nguyen mpsval = mps & DXEPCTL_MPS_MASK; 167747a1685fSDinh Nguyen if (mpsval > 1024) 167847a1685fSDinh Nguyen goto bad_mps; 167947a1685fSDinh Nguyen mcval = ((mps >> 11) & 0x3) + 1; 168047a1685fSDinh Nguyen hs_ep->mc = mcval; 168147a1685fSDinh Nguyen if (mcval > 3) 168247a1685fSDinh Nguyen goto bad_mps; 168347a1685fSDinh Nguyen hs_ep->ep.maxpacket = mpsval; 168447a1685fSDinh Nguyen } 168547a1685fSDinh Nguyen 1686c6f5c050SMian Yousaf Kaukab if (dir_in) { 168747a1685fSDinh Nguyen reg = readl(regs + DIEPCTL(ep)); 168847a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 168947a1685fSDinh Nguyen reg |= mpsval; 169047a1685fSDinh Nguyen writel(reg, regs + DIEPCTL(ep)); 1691c6f5c050SMian Yousaf Kaukab } else { 169247a1685fSDinh Nguyen reg = readl(regs + DOEPCTL(ep)); 169347a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 169447a1685fSDinh Nguyen reg |= mpsval; 169547a1685fSDinh Nguyen writel(reg, regs + DOEPCTL(ep)); 169647a1685fSDinh Nguyen } 169747a1685fSDinh Nguyen 169847a1685fSDinh Nguyen return; 169947a1685fSDinh Nguyen 170047a1685fSDinh Nguyen bad_mps: 170147a1685fSDinh Nguyen dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); 170247a1685fSDinh Nguyen } 170347a1685fSDinh Nguyen 170447a1685fSDinh Nguyen /** 170547a1685fSDinh Nguyen * s3c_hsotg_txfifo_flush - flush Tx FIFO 170647a1685fSDinh Nguyen * @hsotg: The driver state 170747a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 170847a1685fSDinh Nguyen */ 1709941fcce4SDinh Nguyen static void s3c_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx) 171047a1685fSDinh Nguyen { 171147a1685fSDinh Nguyen int timeout; 171247a1685fSDinh Nguyen int val; 171347a1685fSDinh Nguyen 171447a1685fSDinh Nguyen writel(GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH, 171547a1685fSDinh Nguyen hsotg->regs + GRSTCTL); 171647a1685fSDinh Nguyen 171747a1685fSDinh Nguyen /* wait until the fifo is flushed */ 171847a1685fSDinh Nguyen timeout = 100; 171947a1685fSDinh Nguyen 172047a1685fSDinh Nguyen while (1) { 172147a1685fSDinh Nguyen val = readl(hsotg->regs + GRSTCTL); 172247a1685fSDinh Nguyen 172347a1685fSDinh Nguyen if ((val & (GRSTCTL_TXFFLSH)) == 0) 172447a1685fSDinh Nguyen break; 172547a1685fSDinh Nguyen 172647a1685fSDinh Nguyen if (--timeout == 0) { 172747a1685fSDinh Nguyen dev_err(hsotg->dev, 172847a1685fSDinh Nguyen "%s: timeout flushing fifo (GRSTCTL=%08x)\n", 172947a1685fSDinh Nguyen __func__, val); 1730e0cbe595SMarek Szyprowski break; 173147a1685fSDinh Nguyen } 173247a1685fSDinh Nguyen 173347a1685fSDinh Nguyen udelay(1); 173447a1685fSDinh Nguyen } 173547a1685fSDinh Nguyen } 173647a1685fSDinh Nguyen 173747a1685fSDinh Nguyen /** 173847a1685fSDinh Nguyen * s3c_hsotg_trytx - check to see if anything needs transmitting 173947a1685fSDinh Nguyen * @hsotg: The driver state 174047a1685fSDinh Nguyen * @hs_ep: The driver endpoint to check. 174147a1685fSDinh Nguyen * 174247a1685fSDinh Nguyen * Check to see if there is a request that has data to send, and if so 174347a1685fSDinh Nguyen * make an attempt to write data into the FIFO. 174447a1685fSDinh Nguyen */ 1745941fcce4SDinh Nguyen static int s3c_hsotg_trytx(struct dwc2_hsotg *hsotg, 174647a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep) 174747a1685fSDinh Nguyen { 174847a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = hs_ep->req; 174947a1685fSDinh Nguyen 175047a1685fSDinh Nguyen if (!hs_ep->dir_in || !hs_req) { 175147a1685fSDinh Nguyen /** 175247a1685fSDinh Nguyen * if request is not enqueued, we disable interrupts 175347a1685fSDinh Nguyen * for endpoints, excepting ep0 175447a1685fSDinh Nguyen */ 175547a1685fSDinh Nguyen if (hs_ep->index != 0) 175647a1685fSDinh Nguyen s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, 175747a1685fSDinh Nguyen hs_ep->dir_in, 0); 175847a1685fSDinh Nguyen return 0; 175947a1685fSDinh Nguyen } 176047a1685fSDinh Nguyen 176147a1685fSDinh Nguyen if (hs_req->req.actual < hs_req->req.length) { 176247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "trying to write more for ep%d\n", 176347a1685fSDinh Nguyen hs_ep->index); 176447a1685fSDinh Nguyen return s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); 176547a1685fSDinh Nguyen } 176647a1685fSDinh Nguyen 176747a1685fSDinh Nguyen return 0; 176847a1685fSDinh Nguyen } 176947a1685fSDinh Nguyen 177047a1685fSDinh Nguyen /** 177147a1685fSDinh Nguyen * s3c_hsotg_complete_in - complete IN transfer 177247a1685fSDinh Nguyen * @hsotg: The device state. 177347a1685fSDinh Nguyen * @hs_ep: The endpoint that has just completed. 177447a1685fSDinh Nguyen * 177547a1685fSDinh Nguyen * An IN transfer has been completed, update the transfer's state and then 177647a1685fSDinh Nguyen * call the relevant completion routines. 177747a1685fSDinh Nguyen */ 1778941fcce4SDinh Nguyen static void s3c_hsotg_complete_in(struct dwc2_hsotg *hsotg, 177947a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep) 178047a1685fSDinh Nguyen { 178147a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = hs_ep->req; 178247a1685fSDinh Nguyen u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); 178347a1685fSDinh Nguyen int size_left, size_done; 178447a1685fSDinh Nguyen 178547a1685fSDinh Nguyen if (!hs_req) { 178647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "XferCompl but no req\n"); 178747a1685fSDinh Nguyen return; 178847a1685fSDinh Nguyen } 178947a1685fSDinh Nguyen 179047a1685fSDinh Nguyen /* Finish ZLP handling for IN EP0 transactions */ 1791fe0b94abSMian Yousaf Kaukab if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) { 1792fe0b94abSMian Yousaf Kaukab dev_dbg(hsotg->dev, "zlp packet sent\n"); 179347a1685fSDinh Nguyen s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 1794*9e14d0a5SGregory Herrero if (hsotg->test_mode) { 1795*9e14d0a5SGregory Herrero int ret; 1796*9e14d0a5SGregory Herrero 1797*9e14d0a5SGregory Herrero ret = s3c_hsotg_set_test_mode(hsotg, hsotg->test_mode); 1798*9e14d0a5SGregory Herrero if (ret < 0) { 1799*9e14d0a5SGregory Herrero dev_dbg(hsotg->dev, "Invalid Test #%d\n", 1800*9e14d0a5SGregory Herrero hsotg->test_mode); 1801*9e14d0a5SGregory Herrero s3c_hsotg_stall_ep0(hsotg); 1802*9e14d0a5SGregory Herrero return; 1803*9e14d0a5SGregory Herrero } 1804*9e14d0a5SGregory Herrero } 1805fe0b94abSMian Yousaf Kaukab s3c_hsotg_enqueue_setup(hsotg); 180647a1685fSDinh Nguyen return; 180747a1685fSDinh Nguyen } 180847a1685fSDinh Nguyen 180947a1685fSDinh Nguyen /* 181047a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much is left 181147a1685fSDinh Nguyen * in the endpoint size register and then working it out from 181247a1685fSDinh Nguyen * the amount we loaded for the transfer. 181347a1685fSDinh Nguyen * 181447a1685fSDinh Nguyen * We do this even for DMA, as the transfer may have incremented 181547a1685fSDinh Nguyen * past the end of the buffer (DMA transfers are always 32bit 181647a1685fSDinh Nguyen * aligned). 181747a1685fSDinh Nguyen */ 181847a1685fSDinh Nguyen 181947a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 182047a1685fSDinh Nguyen 182147a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 182247a1685fSDinh Nguyen size_done += hs_ep->last_load; 182347a1685fSDinh Nguyen 182447a1685fSDinh Nguyen if (hs_req->req.actual != size_done) 182547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", 182647a1685fSDinh Nguyen __func__, hs_req->req.actual, size_done); 182747a1685fSDinh Nguyen 182847a1685fSDinh Nguyen hs_req->req.actual = size_done; 182947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", 183047a1685fSDinh Nguyen hs_req->req.length, hs_req->req.actual, hs_req->req.zero); 183147a1685fSDinh Nguyen 183247a1685fSDinh Nguyen if (!size_left && hs_req->req.actual < hs_req->req.length) { 183347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); 183447a1685fSDinh Nguyen s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); 1835fe0b94abSMian Yousaf Kaukab return; 1836fe0b94abSMian Yousaf Kaukab } 1837fe0b94abSMian Yousaf Kaukab 1838f71b5e25SMian Yousaf Kaukab /* Zlp for all endpoints, for ep0 only in DATA IN stage */ 18398a20fa45SMian Yousaf Kaukab if (hs_ep->send_zlp) { 1840f71b5e25SMian Yousaf Kaukab s3c_hsotg_program_zlp(hsotg, hs_ep); 18418a20fa45SMian Yousaf Kaukab hs_ep->send_zlp = 0; 1842f71b5e25SMian Yousaf Kaukab /* transfer will be completed on next complete interrupt */ 1843f71b5e25SMian Yousaf Kaukab return; 1844f71b5e25SMian Yousaf Kaukab } 1845f71b5e25SMian Yousaf Kaukab 1846fe0b94abSMian Yousaf Kaukab if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_DATA_IN) { 1847fe0b94abSMian Yousaf Kaukab /* Move to STATUS OUT */ 1848fe0b94abSMian Yousaf Kaukab s3c_hsotg_ep0_zlp(hsotg, false); 1849fe0b94abSMian Yousaf Kaukab return; 1850fe0b94abSMian Yousaf Kaukab } 1851fe0b94abSMian Yousaf Kaukab 185247a1685fSDinh Nguyen s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 185347a1685fSDinh Nguyen } 185447a1685fSDinh Nguyen 185547a1685fSDinh Nguyen /** 185647a1685fSDinh Nguyen * s3c_hsotg_epint - handle an in/out endpoint interrupt 185747a1685fSDinh Nguyen * @hsotg: The driver state 185847a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 185947a1685fSDinh Nguyen * @dir_in: Set if this is an IN endpoint 186047a1685fSDinh Nguyen * 186147a1685fSDinh Nguyen * Process and clear any interrupt pending for an individual endpoint 186247a1685fSDinh Nguyen */ 1863941fcce4SDinh Nguyen static void s3c_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, 186447a1685fSDinh Nguyen int dir_in) 186547a1685fSDinh Nguyen { 1866c6f5c050SMian Yousaf Kaukab struct s3c_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in); 186747a1685fSDinh Nguyen u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 186847a1685fSDinh Nguyen u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 186947a1685fSDinh Nguyen u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); 187047a1685fSDinh Nguyen u32 ints; 187147a1685fSDinh Nguyen u32 ctrl; 187247a1685fSDinh Nguyen 187347a1685fSDinh Nguyen ints = readl(hsotg->regs + epint_reg); 187447a1685fSDinh Nguyen ctrl = readl(hsotg->regs + epctl_reg); 187547a1685fSDinh Nguyen 187647a1685fSDinh Nguyen /* Clear endpoint interrupts */ 187747a1685fSDinh Nguyen writel(ints, hsotg->regs + epint_reg); 187847a1685fSDinh Nguyen 1879c6f5c050SMian Yousaf Kaukab if (!hs_ep) { 1880c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n", 1881c6f5c050SMian Yousaf Kaukab __func__, idx, dir_in ? "in" : "out"); 1882c6f5c050SMian Yousaf Kaukab return; 1883c6f5c050SMian Yousaf Kaukab } 1884c6f5c050SMian Yousaf Kaukab 188547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", 188647a1685fSDinh Nguyen __func__, idx, dir_in ? "in" : "out", ints); 188747a1685fSDinh Nguyen 1888b787d755SMian Yousaf Kaukab /* Don't process XferCompl interrupt if it is a setup packet */ 1889b787d755SMian Yousaf Kaukab if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD))) 1890b787d755SMian Yousaf Kaukab ints &= ~DXEPINT_XFERCOMPL; 1891b787d755SMian Yousaf Kaukab 189247a1685fSDinh Nguyen if (ints & DXEPINT_XFERCOMPL) { 189347a1685fSDinh Nguyen if (hs_ep->isochronous && hs_ep->interval == 1) { 189447a1685fSDinh Nguyen if (ctrl & DXEPCTL_EOFRNUM) 189547a1685fSDinh Nguyen ctrl |= DXEPCTL_SETEVENFR; 189647a1685fSDinh Nguyen else 189747a1685fSDinh Nguyen ctrl |= DXEPCTL_SETODDFR; 189847a1685fSDinh Nguyen writel(ctrl, hsotg->regs + epctl_reg); 189947a1685fSDinh Nguyen } 190047a1685fSDinh Nguyen 190147a1685fSDinh Nguyen dev_dbg(hsotg->dev, 190247a1685fSDinh Nguyen "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", 190347a1685fSDinh Nguyen __func__, readl(hsotg->regs + epctl_reg), 190447a1685fSDinh Nguyen readl(hsotg->regs + epsiz_reg)); 190547a1685fSDinh Nguyen 190647a1685fSDinh Nguyen /* 190747a1685fSDinh Nguyen * we get OutDone from the FIFO, so we only need to look 190847a1685fSDinh Nguyen * at completing IN requests here 190947a1685fSDinh Nguyen */ 191047a1685fSDinh Nguyen if (dir_in) { 191147a1685fSDinh Nguyen s3c_hsotg_complete_in(hsotg, hs_ep); 191247a1685fSDinh Nguyen 191347a1685fSDinh Nguyen if (idx == 0 && !hs_ep->req) 191447a1685fSDinh Nguyen s3c_hsotg_enqueue_setup(hsotg); 191547a1685fSDinh Nguyen } else if (using_dma(hsotg)) { 191647a1685fSDinh Nguyen /* 191747a1685fSDinh Nguyen * We're using DMA, we need to fire an OutDone here 191847a1685fSDinh Nguyen * as we ignore the RXFIFO. 191947a1685fSDinh Nguyen */ 192047a1685fSDinh Nguyen 1921fe0b94abSMian Yousaf Kaukab s3c_hsotg_handle_outdone(hsotg, idx); 192247a1685fSDinh Nguyen } 192347a1685fSDinh Nguyen } 192447a1685fSDinh Nguyen 192547a1685fSDinh Nguyen if (ints & DXEPINT_EPDISBLD) { 192647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); 192747a1685fSDinh Nguyen 192847a1685fSDinh Nguyen if (dir_in) { 192947a1685fSDinh Nguyen int epctl = readl(hsotg->regs + epctl_reg); 193047a1685fSDinh Nguyen 1931b203d0a2SRobert Baldyga s3c_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); 193247a1685fSDinh Nguyen 193347a1685fSDinh Nguyen if ((epctl & DXEPCTL_STALL) && 193447a1685fSDinh Nguyen (epctl & DXEPCTL_EPTYPE_BULK)) { 193547a1685fSDinh Nguyen int dctl = readl(hsotg->regs + DCTL); 193647a1685fSDinh Nguyen 193747a1685fSDinh Nguyen dctl |= DCTL_CGNPINNAK; 193847a1685fSDinh Nguyen writel(dctl, hsotg->regs + DCTL); 193947a1685fSDinh Nguyen } 194047a1685fSDinh Nguyen } 194147a1685fSDinh Nguyen } 194247a1685fSDinh Nguyen 194347a1685fSDinh Nguyen if (ints & DXEPINT_AHBERR) 194447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); 194547a1685fSDinh Nguyen 194647a1685fSDinh Nguyen if (ints & DXEPINT_SETUP) { /* Setup or Timeout */ 194747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); 194847a1685fSDinh Nguyen 194947a1685fSDinh Nguyen if (using_dma(hsotg) && idx == 0) { 195047a1685fSDinh Nguyen /* 195147a1685fSDinh Nguyen * this is the notification we've received a 195247a1685fSDinh Nguyen * setup packet. In non-DMA mode we'd get this 195347a1685fSDinh Nguyen * from the RXFIFO, instead we need to process 195447a1685fSDinh Nguyen * the setup here. 195547a1685fSDinh Nguyen */ 195647a1685fSDinh Nguyen 195747a1685fSDinh Nguyen if (dir_in) 195847a1685fSDinh Nguyen WARN_ON_ONCE(1); 195947a1685fSDinh Nguyen else 1960fe0b94abSMian Yousaf Kaukab s3c_hsotg_handle_outdone(hsotg, 0); 196147a1685fSDinh Nguyen } 196247a1685fSDinh Nguyen } 196347a1685fSDinh Nguyen 196447a1685fSDinh Nguyen if (ints & DXEPINT_BACK2BACKSETUP) 196547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); 196647a1685fSDinh Nguyen 196747a1685fSDinh Nguyen if (dir_in && !hs_ep->isochronous) { 196847a1685fSDinh Nguyen /* not sure if this is important, but we'll clear it anyway */ 196947a1685fSDinh Nguyen if (ints & DIEPMSK_INTKNTXFEMPMSK) { 197047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", 197147a1685fSDinh Nguyen __func__, idx); 197247a1685fSDinh Nguyen } 197347a1685fSDinh Nguyen 197447a1685fSDinh Nguyen /* this probably means something bad is happening */ 197547a1685fSDinh Nguyen if (ints & DIEPMSK_INTKNEPMISMSK) { 197647a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", 197747a1685fSDinh Nguyen __func__, idx); 197847a1685fSDinh Nguyen } 197947a1685fSDinh Nguyen 198047a1685fSDinh Nguyen /* FIFO has space or is empty (see GAHBCFG) */ 198147a1685fSDinh Nguyen if (hsotg->dedicated_fifos && 198247a1685fSDinh Nguyen ints & DIEPMSK_TXFIFOEMPTY) { 198347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", 198447a1685fSDinh Nguyen __func__, idx); 198547a1685fSDinh Nguyen if (!using_dma(hsotg)) 198647a1685fSDinh Nguyen s3c_hsotg_trytx(hsotg, hs_ep); 198747a1685fSDinh Nguyen } 198847a1685fSDinh Nguyen } 198947a1685fSDinh Nguyen } 199047a1685fSDinh Nguyen 199147a1685fSDinh Nguyen /** 199247a1685fSDinh Nguyen * s3c_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) 199347a1685fSDinh Nguyen * @hsotg: The device state. 199447a1685fSDinh Nguyen * 199547a1685fSDinh Nguyen * Handle updating the device settings after the enumeration phase has 199647a1685fSDinh Nguyen * been completed. 199747a1685fSDinh Nguyen */ 1998941fcce4SDinh Nguyen static void s3c_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg) 199947a1685fSDinh Nguyen { 200047a1685fSDinh Nguyen u32 dsts = readl(hsotg->regs + DSTS); 20019b2667f1SJingoo Han int ep0_mps = 0, ep_mps = 8; 200247a1685fSDinh Nguyen 200347a1685fSDinh Nguyen /* 200447a1685fSDinh Nguyen * This should signal the finish of the enumeration phase 200547a1685fSDinh Nguyen * of the USB handshaking, so we should now know what rate 200647a1685fSDinh Nguyen * we connected at. 200747a1685fSDinh Nguyen */ 200847a1685fSDinh Nguyen 200947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); 201047a1685fSDinh Nguyen 201147a1685fSDinh Nguyen /* 201247a1685fSDinh Nguyen * note, since we're limited by the size of transfer on EP0, and 201347a1685fSDinh Nguyen * it seems IN transfers must be a even number of packets we do 201447a1685fSDinh Nguyen * not advertise a 64byte MPS on EP0. 201547a1685fSDinh Nguyen */ 201647a1685fSDinh Nguyen 201747a1685fSDinh Nguyen /* catch both EnumSpd_FS and EnumSpd_FS48 */ 201847a1685fSDinh Nguyen switch (dsts & DSTS_ENUMSPD_MASK) { 201947a1685fSDinh Nguyen case DSTS_ENUMSPD_FS: 202047a1685fSDinh Nguyen case DSTS_ENUMSPD_FS48: 202147a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_FULL; 202247a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 202347a1685fSDinh Nguyen ep_mps = 1023; 202447a1685fSDinh Nguyen break; 202547a1685fSDinh Nguyen 202647a1685fSDinh Nguyen case DSTS_ENUMSPD_HS: 202747a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_HIGH; 202847a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 202947a1685fSDinh Nguyen ep_mps = 1024; 203047a1685fSDinh Nguyen break; 203147a1685fSDinh Nguyen 203247a1685fSDinh Nguyen case DSTS_ENUMSPD_LS: 203347a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_LOW; 203447a1685fSDinh Nguyen /* 203547a1685fSDinh Nguyen * note, we don't actually support LS in this driver at the 203647a1685fSDinh Nguyen * moment, and the documentation seems to imply that it isn't 203747a1685fSDinh Nguyen * supported by the PHYs on some of the devices. 203847a1685fSDinh Nguyen */ 203947a1685fSDinh Nguyen break; 204047a1685fSDinh Nguyen } 204147a1685fSDinh Nguyen dev_info(hsotg->dev, "new device is %s\n", 204247a1685fSDinh Nguyen usb_speed_string(hsotg->gadget.speed)); 204347a1685fSDinh Nguyen 204447a1685fSDinh Nguyen /* 204547a1685fSDinh Nguyen * we should now know the maximum packet size for an 204647a1685fSDinh Nguyen * endpoint, so set the endpoints to a default value. 204747a1685fSDinh Nguyen */ 204847a1685fSDinh Nguyen 204947a1685fSDinh Nguyen if (ep0_mps) { 205047a1685fSDinh Nguyen int i; 2051c6f5c050SMian Yousaf Kaukab /* Initialize ep0 for both in and out directions */ 2052c6f5c050SMian Yousaf Kaukab s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 1); 2053c6f5c050SMian Yousaf Kaukab s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0); 2054c6f5c050SMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; i++) { 2055c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[i]) 2056c6f5c050SMian Yousaf Kaukab s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 1); 2057c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[i]) 2058c6f5c050SMian Yousaf Kaukab s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 0); 2059c6f5c050SMian Yousaf Kaukab } 206047a1685fSDinh Nguyen } 206147a1685fSDinh Nguyen 206247a1685fSDinh Nguyen /* ensure after enumeration our EP0 is active */ 206347a1685fSDinh Nguyen 206447a1685fSDinh Nguyen s3c_hsotg_enqueue_setup(hsotg); 206547a1685fSDinh Nguyen 206647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 206747a1685fSDinh Nguyen readl(hsotg->regs + DIEPCTL0), 206847a1685fSDinh Nguyen readl(hsotg->regs + DOEPCTL0)); 206947a1685fSDinh Nguyen } 207047a1685fSDinh Nguyen 207147a1685fSDinh Nguyen /** 207247a1685fSDinh Nguyen * kill_all_requests - remove all requests from the endpoint's queue 207347a1685fSDinh Nguyen * @hsotg: The device state. 207447a1685fSDinh Nguyen * @ep: The endpoint the requests may be on. 207547a1685fSDinh Nguyen * @result: The result code to use. 207647a1685fSDinh Nguyen * 207747a1685fSDinh Nguyen * Go through the requests on the given endpoint and mark them 207847a1685fSDinh Nguyen * completed with the given result code. 207947a1685fSDinh Nguyen */ 2080941fcce4SDinh Nguyen static void kill_all_requests(struct dwc2_hsotg *hsotg, 208147a1685fSDinh Nguyen struct s3c_hsotg_ep *ep, 20826b448af4SRobert Baldyga int result) 208347a1685fSDinh Nguyen { 208447a1685fSDinh Nguyen struct s3c_hsotg_req *req, *treq; 2085b203d0a2SRobert Baldyga unsigned size; 208647a1685fSDinh Nguyen 20876b448af4SRobert Baldyga ep->req = NULL; 208847a1685fSDinh Nguyen 20896b448af4SRobert Baldyga list_for_each_entry_safe(req, treq, &ep->queue, queue) 209047a1685fSDinh Nguyen s3c_hsotg_complete_request(hsotg, ep, req, 209147a1685fSDinh Nguyen result); 20926b448af4SRobert Baldyga 2093b203d0a2SRobert Baldyga if (!hsotg->dedicated_fifos) 2094b203d0a2SRobert Baldyga return; 2095b203d0a2SRobert Baldyga size = (readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4; 2096b203d0a2SRobert Baldyga if (size < ep->fifo_size) 2097b203d0a2SRobert Baldyga s3c_hsotg_txfifo_flush(hsotg, ep->fifo_index); 209847a1685fSDinh Nguyen } 209947a1685fSDinh Nguyen 210047a1685fSDinh Nguyen /** 210147a1685fSDinh Nguyen * s3c_hsotg_disconnect - disconnect service 210247a1685fSDinh Nguyen * @hsotg: The device state. 210347a1685fSDinh Nguyen * 210447a1685fSDinh Nguyen * The device has been disconnected. Remove all current 210547a1685fSDinh Nguyen * transactions and signal the gadget driver that this 210647a1685fSDinh Nguyen * has happened. 210747a1685fSDinh Nguyen */ 21084ace06e8SMarek Szyprowski void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg) 210947a1685fSDinh Nguyen { 211047a1685fSDinh Nguyen unsigned ep; 211147a1685fSDinh Nguyen 21124ace06e8SMarek Szyprowski if (!hsotg->connected) 21134ace06e8SMarek Szyprowski return; 21144ace06e8SMarek Szyprowski 21154ace06e8SMarek Szyprowski hsotg->connected = 0; 2116*9e14d0a5SGregory Herrero hsotg->test_mode = 0; 2117c6f5c050SMian Yousaf Kaukab 2118c6f5c050SMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps; ep++) { 2119c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 2120c6f5c050SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_in[ep], 2121c6f5c050SMian Yousaf Kaukab -ESHUTDOWN); 2122c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 2123c6f5c050SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_out[ep], 2124c6f5c050SMian Yousaf Kaukab -ESHUTDOWN); 2125c6f5c050SMian Yousaf Kaukab } 212647a1685fSDinh Nguyen 212747a1685fSDinh Nguyen call_gadget(hsotg, disconnect); 212847a1685fSDinh Nguyen } 21294ace06e8SMarek Szyprowski EXPORT_SYMBOL_GPL(s3c_hsotg_disconnect); 213047a1685fSDinh Nguyen 213147a1685fSDinh Nguyen /** 213247a1685fSDinh Nguyen * s3c_hsotg_irq_fifoempty - TX FIFO empty interrupt handler 213347a1685fSDinh Nguyen * @hsotg: The device state: 213447a1685fSDinh Nguyen * @periodic: True if this is a periodic FIFO interrupt 213547a1685fSDinh Nguyen */ 2136941fcce4SDinh Nguyen static void s3c_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) 213747a1685fSDinh Nguyen { 213847a1685fSDinh Nguyen struct s3c_hsotg_ep *ep; 213947a1685fSDinh Nguyen int epno, ret; 214047a1685fSDinh Nguyen 214147a1685fSDinh Nguyen /* look through for any more data to transmit */ 214247a1685fSDinh Nguyen for (epno = 0; epno < hsotg->num_of_eps; epno++) { 2143c6f5c050SMian Yousaf Kaukab ep = index_to_ep(hsotg, epno, 1); 2144c6f5c050SMian Yousaf Kaukab 2145c6f5c050SMian Yousaf Kaukab if (!ep) 2146c6f5c050SMian Yousaf Kaukab continue; 214747a1685fSDinh Nguyen 214847a1685fSDinh Nguyen if (!ep->dir_in) 214947a1685fSDinh Nguyen continue; 215047a1685fSDinh Nguyen 215147a1685fSDinh Nguyen if ((periodic && !ep->periodic) || 215247a1685fSDinh Nguyen (!periodic && ep->periodic)) 215347a1685fSDinh Nguyen continue; 215447a1685fSDinh Nguyen 215547a1685fSDinh Nguyen ret = s3c_hsotg_trytx(hsotg, ep); 215647a1685fSDinh Nguyen if (ret < 0) 215747a1685fSDinh Nguyen break; 215847a1685fSDinh Nguyen } 215947a1685fSDinh Nguyen } 216047a1685fSDinh Nguyen 216147a1685fSDinh Nguyen /* IRQ flags which will trigger a retry around the IRQ loop */ 216247a1685fSDinh Nguyen #define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ 216347a1685fSDinh Nguyen GINTSTS_PTXFEMP | \ 216447a1685fSDinh Nguyen GINTSTS_RXFLVL) 216547a1685fSDinh Nguyen 216647a1685fSDinh Nguyen /** 216747a1685fSDinh Nguyen * s3c_hsotg_corereset - issue softreset to the core 216847a1685fSDinh Nguyen * @hsotg: The device state 216947a1685fSDinh Nguyen * 217047a1685fSDinh Nguyen * Issue a soft reset to the core, and await the core finishing it. 217147a1685fSDinh Nguyen */ 2172941fcce4SDinh Nguyen static int s3c_hsotg_corereset(struct dwc2_hsotg *hsotg) 217347a1685fSDinh Nguyen { 217447a1685fSDinh Nguyen int timeout; 217547a1685fSDinh Nguyen u32 grstctl; 217647a1685fSDinh Nguyen 217747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "resetting core\n"); 217847a1685fSDinh Nguyen 217947a1685fSDinh Nguyen /* issue soft reset */ 218047a1685fSDinh Nguyen writel(GRSTCTL_CSFTRST, hsotg->regs + GRSTCTL); 218147a1685fSDinh Nguyen 218247a1685fSDinh Nguyen timeout = 10000; 218347a1685fSDinh Nguyen do { 218447a1685fSDinh Nguyen grstctl = readl(hsotg->regs + GRSTCTL); 218547a1685fSDinh Nguyen } while ((grstctl & GRSTCTL_CSFTRST) && timeout-- > 0); 218647a1685fSDinh Nguyen 218747a1685fSDinh Nguyen if (grstctl & GRSTCTL_CSFTRST) { 218847a1685fSDinh Nguyen dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); 218947a1685fSDinh Nguyen return -EINVAL; 219047a1685fSDinh Nguyen } 219147a1685fSDinh Nguyen 219247a1685fSDinh Nguyen timeout = 10000; 219347a1685fSDinh Nguyen 219447a1685fSDinh Nguyen while (1) { 219547a1685fSDinh Nguyen u32 grstctl = readl(hsotg->regs + GRSTCTL); 219647a1685fSDinh Nguyen 219747a1685fSDinh Nguyen if (timeout-- < 0) { 219847a1685fSDinh Nguyen dev_info(hsotg->dev, 219947a1685fSDinh Nguyen "%s: reset failed, GRSTCTL=%08x\n", 220047a1685fSDinh Nguyen __func__, grstctl); 220147a1685fSDinh Nguyen return -ETIMEDOUT; 220247a1685fSDinh Nguyen } 220347a1685fSDinh Nguyen 220447a1685fSDinh Nguyen if (!(grstctl & GRSTCTL_AHBIDLE)) 220547a1685fSDinh Nguyen continue; 220647a1685fSDinh Nguyen 220747a1685fSDinh Nguyen break; /* reset done */ 220847a1685fSDinh Nguyen } 220947a1685fSDinh Nguyen 221047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "reset successful\n"); 221147a1685fSDinh Nguyen return 0; 221247a1685fSDinh Nguyen } 221347a1685fSDinh Nguyen 221447a1685fSDinh Nguyen /** 221547a1685fSDinh Nguyen * s3c_hsotg_core_init - issue softreset to the core 221647a1685fSDinh Nguyen * @hsotg: The device state 221747a1685fSDinh Nguyen * 221847a1685fSDinh Nguyen * Issue a soft reset to the core, and await the core finishing it. 221947a1685fSDinh Nguyen */ 2220510ffaa4SDinh Nguyen void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg) 222147a1685fSDinh Nguyen { 222247a1685fSDinh Nguyen s3c_hsotg_corereset(hsotg); 222347a1685fSDinh Nguyen 222447a1685fSDinh Nguyen /* 222547a1685fSDinh Nguyen * we must now enable ep0 ready for host detection and then 222647a1685fSDinh Nguyen * set configuration. 222747a1685fSDinh Nguyen */ 222847a1685fSDinh Nguyen 222947a1685fSDinh Nguyen /* set the PLL on, remove the HNP/SRP and set the PHY */ 223047a1685fSDinh Nguyen writel(hsotg->phyif | GUSBCFG_TOUTCAL(7) | 223147a1685fSDinh Nguyen (0x5 << 10), hsotg->regs + GUSBCFG); 223247a1685fSDinh Nguyen 223347a1685fSDinh Nguyen s3c_hsotg_init_fifo(hsotg); 223447a1685fSDinh Nguyen 223547a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 223647a1685fSDinh Nguyen 223747a1685fSDinh Nguyen writel(1 << 18 | DCFG_DEVSPD_HS, hsotg->regs + DCFG); 223847a1685fSDinh Nguyen 223947a1685fSDinh Nguyen /* Clear any pending OTG interrupts */ 224047a1685fSDinh Nguyen writel(0xffffffff, hsotg->regs + GOTGINT); 224147a1685fSDinh Nguyen 224247a1685fSDinh Nguyen /* Clear any pending interrupts */ 224347a1685fSDinh Nguyen writel(0xffffffff, hsotg->regs + GINTSTS); 224447a1685fSDinh Nguyen 224547a1685fSDinh Nguyen writel(GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT | 224647a1685fSDinh Nguyen GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | 224747a1685fSDinh Nguyen GINTSTS_CONIDSTSCHNG | GINTSTS_USBRST | 224847a1685fSDinh Nguyen GINTSTS_ENUMDONE | GINTSTS_OTGINT | 224947a1685fSDinh Nguyen GINTSTS_USBSUSP | GINTSTS_WKUPINT, 225047a1685fSDinh Nguyen hsotg->regs + GINTMSK); 225147a1685fSDinh Nguyen 225247a1685fSDinh Nguyen if (using_dma(hsotg)) 225347a1685fSDinh Nguyen writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN | 22545f05048eSGregory Herrero (GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT), 225547a1685fSDinh Nguyen hsotg->regs + GAHBCFG); 225647a1685fSDinh Nguyen else 225747a1685fSDinh Nguyen writel(((hsotg->dedicated_fifos) ? (GAHBCFG_NP_TXF_EMP_LVL | 225847a1685fSDinh Nguyen GAHBCFG_P_TXF_EMP_LVL) : 0) | 225947a1685fSDinh Nguyen GAHBCFG_GLBL_INTR_EN, 226047a1685fSDinh Nguyen hsotg->regs + GAHBCFG); 226147a1685fSDinh Nguyen 226247a1685fSDinh Nguyen /* 226347a1685fSDinh Nguyen * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts 226447a1685fSDinh Nguyen * when we have no data to transfer. Otherwise we get being flooded by 226547a1685fSDinh Nguyen * interrupts. 226647a1685fSDinh Nguyen */ 226747a1685fSDinh Nguyen 22686ff2e832SMian Yousaf Kaukab writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ? 22696ff2e832SMian Yousaf Kaukab DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) | 227047a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | 227147a1685fSDinh Nguyen DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | 227247a1685fSDinh Nguyen DIEPMSK_INTKNEPMISMSK, 227347a1685fSDinh Nguyen hsotg->regs + DIEPMSK); 227447a1685fSDinh Nguyen 227547a1685fSDinh Nguyen /* 227647a1685fSDinh Nguyen * don't need XferCompl, we get that from RXFIFO in slave mode. In 227747a1685fSDinh Nguyen * DMA mode we may need this. 227847a1685fSDinh Nguyen */ 227947a1685fSDinh Nguyen writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK | 228047a1685fSDinh Nguyen DIEPMSK_TIMEOUTMSK) : 0) | 228147a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | 228247a1685fSDinh Nguyen DOEPMSK_SETUPMSK, 228347a1685fSDinh Nguyen hsotg->regs + DOEPMSK); 228447a1685fSDinh Nguyen 228547a1685fSDinh Nguyen writel(0, hsotg->regs + DAINTMSK); 228647a1685fSDinh Nguyen 228747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 228847a1685fSDinh Nguyen readl(hsotg->regs + DIEPCTL0), 228947a1685fSDinh Nguyen readl(hsotg->regs + DOEPCTL0)); 229047a1685fSDinh Nguyen 229147a1685fSDinh Nguyen /* enable in and out endpoint interrupts */ 229247a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT); 229347a1685fSDinh Nguyen 229447a1685fSDinh Nguyen /* 229547a1685fSDinh Nguyen * Enable the RXFIFO when in slave mode, as this is how we collect 229647a1685fSDinh Nguyen * the data. In DMA mode, we get events from the FIFO but also 229747a1685fSDinh Nguyen * things we cannot process, so do not use it. 229847a1685fSDinh Nguyen */ 229947a1685fSDinh Nguyen if (!using_dma(hsotg)) 230047a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL); 230147a1685fSDinh Nguyen 230247a1685fSDinh Nguyen /* Enable interrupts for EP0 in and out */ 230347a1685fSDinh Nguyen s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1); 230447a1685fSDinh Nguyen s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1); 230547a1685fSDinh Nguyen 230647a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); 230747a1685fSDinh Nguyen udelay(10); /* see openiboot */ 230847a1685fSDinh Nguyen __bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); 230947a1685fSDinh Nguyen 231047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL)); 231147a1685fSDinh Nguyen 231247a1685fSDinh Nguyen /* 231347a1685fSDinh Nguyen * DxEPCTL_USBActEp says RO in manual, but seems to be set by 231447a1685fSDinh Nguyen * writing to the EPCTL register.. 231547a1685fSDinh Nguyen */ 231647a1685fSDinh Nguyen 231747a1685fSDinh Nguyen /* set to read 1 8byte packet */ 231847a1685fSDinh Nguyen writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 231947a1685fSDinh Nguyen DXEPTSIZ_XFERSIZE(8), hsotg->regs + DOEPTSIZ0); 232047a1685fSDinh Nguyen 2321c6f5c050SMian Yousaf Kaukab writel(s3c_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 232247a1685fSDinh Nguyen DXEPCTL_CNAK | DXEPCTL_EPENA | 232347a1685fSDinh Nguyen DXEPCTL_USBACTEP, 232447a1685fSDinh Nguyen hsotg->regs + DOEPCTL0); 232547a1685fSDinh Nguyen 232647a1685fSDinh Nguyen /* enable, but don't activate EP0in */ 2327c6f5c050SMian Yousaf Kaukab writel(s3c_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 232847a1685fSDinh Nguyen DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0); 232947a1685fSDinh Nguyen 233047a1685fSDinh Nguyen s3c_hsotg_enqueue_setup(hsotg); 233147a1685fSDinh Nguyen 233247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 233347a1685fSDinh Nguyen readl(hsotg->regs + DIEPCTL0), 233447a1685fSDinh Nguyen readl(hsotg->regs + DOEPCTL0)); 233547a1685fSDinh Nguyen 233647a1685fSDinh Nguyen /* clear global NAKs */ 2337ad38dc5dSMarek Szyprowski writel(DCTL_CGOUTNAK | DCTL_CGNPINNAK | DCTL_SFTDISCON, 233847a1685fSDinh Nguyen hsotg->regs + DCTL); 233947a1685fSDinh Nguyen 234047a1685fSDinh Nguyen /* must be at-least 3ms to allow bus to see disconnect */ 234147a1685fSDinh Nguyen mdelay(3); 234247a1685fSDinh Nguyen 2343ac3c81f3SMarek Szyprowski hsotg->last_rst = jiffies; 2344ad38dc5dSMarek Szyprowski } 2345ac3c81f3SMarek Szyprowski 2346941fcce4SDinh Nguyen static void s3c_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) 2347ad38dc5dSMarek Szyprowski { 2348ad38dc5dSMarek Szyprowski /* set the soft-disconnect bit */ 2349ad38dc5dSMarek Szyprowski __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 2350ad38dc5dSMarek Szyprowski } 2351ad38dc5dSMarek Szyprowski 2352510ffaa4SDinh Nguyen void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) 2353ad38dc5dSMarek Szyprowski { 235447a1685fSDinh Nguyen /* remove the soft-disconnect and let's go */ 235547a1685fSDinh Nguyen __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON); 235647a1685fSDinh Nguyen } 235747a1685fSDinh Nguyen 235847a1685fSDinh Nguyen /** 235947a1685fSDinh Nguyen * s3c_hsotg_irq - handle device interrupt 236047a1685fSDinh Nguyen * @irq: The IRQ number triggered 236147a1685fSDinh Nguyen * @pw: The pw value when registered the handler. 236247a1685fSDinh Nguyen */ 236347a1685fSDinh Nguyen static irqreturn_t s3c_hsotg_irq(int irq, void *pw) 236447a1685fSDinh Nguyen { 2365941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = pw; 236647a1685fSDinh Nguyen int retry_count = 8; 236747a1685fSDinh Nguyen u32 gintsts; 236847a1685fSDinh Nguyen u32 gintmsk; 236947a1685fSDinh Nguyen 237047a1685fSDinh Nguyen spin_lock(&hsotg->lock); 237147a1685fSDinh Nguyen irq_retry: 237247a1685fSDinh Nguyen gintsts = readl(hsotg->regs + GINTSTS); 237347a1685fSDinh Nguyen gintmsk = readl(hsotg->regs + GINTMSK); 237447a1685fSDinh Nguyen 237547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", 237647a1685fSDinh Nguyen __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); 237747a1685fSDinh Nguyen 237847a1685fSDinh Nguyen gintsts &= gintmsk; 237947a1685fSDinh Nguyen 238047a1685fSDinh Nguyen if (gintsts & GINTSTS_ENUMDONE) { 238147a1685fSDinh Nguyen writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); 238247a1685fSDinh Nguyen 238347a1685fSDinh Nguyen s3c_hsotg_irq_enumdone(hsotg); 238447a1685fSDinh Nguyen } 238547a1685fSDinh Nguyen 238647a1685fSDinh Nguyen if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { 238747a1685fSDinh Nguyen u32 daint = readl(hsotg->regs + DAINT); 238847a1685fSDinh Nguyen u32 daintmsk = readl(hsotg->regs + DAINTMSK); 238947a1685fSDinh Nguyen u32 daint_out, daint_in; 239047a1685fSDinh Nguyen int ep; 239147a1685fSDinh Nguyen 239247a1685fSDinh Nguyen daint &= daintmsk; 239347a1685fSDinh Nguyen daint_out = daint >> DAINT_OUTEP_SHIFT; 239447a1685fSDinh Nguyen daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); 239547a1685fSDinh Nguyen 239647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); 239747a1685fSDinh Nguyen 2398cec87f1dSMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps && daint_out; 2399cec87f1dSMian Yousaf Kaukab ep++, daint_out >>= 1) { 240047a1685fSDinh Nguyen if (daint_out & 1) 240147a1685fSDinh Nguyen s3c_hsotg_epint(hsotg, ep, 0); 240247a1685fSDinh Nguyen } 240347a1685fSDinh Nguyen 2404cec87f1dSMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps && daint_in; 2405cec87f1dSMian Yousaf Kaukab ep++, daint_in >>= 1) { 240647a1685fSDinh Nguyen if (daint_in & 1) 240747a1685fSDinh Nguyen s3c_hsotg_epint(hsotg, ep, 1); 240847a1685fSDinh Nguyen } 240947a1685fSDinh Nguyen } 241047a1685fSDinh Nguyen 241147a1685fSDinh Nguyen if (gintsts & GINTSTS_USBRST) { 241247a1685fSDinh Nguyen 241347a1685fSDinh Nguyen u32 usb_status = readl(hsotg->regs + GOTGCTL); 241447a1685fSDinh Nguyen 24159599815dSMarek Szyprowski dev_dbg(hsotg->dev, "%s: USBRst\n", __func__); 241647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", 241747a1685fSDinh Nguyen readl(hsotg->regs + GNPTXSTS)); 241847a1685fSDinh Nguyen 241947a1685fSDinh Nguyen writel(GINTSTS_USBRST, hsotg->regs + GINTSTS); 242047a1685fSDinh Nguyen 24216d713c15SMian Yousaf Kaukab /* Report disconnection if it is not already done. */ 24226d713c15SMian Yousaf Kaukab s3c_hsotg_disconnect(hsotg); 24236d713c15SMian Yousaf Kaukab 242447a1685fSDinh Nguyen if (usb_status & GOTGCTL_BSESVLD) { 242547a1685fSDinh Nguyen if (time_after(jiffies, hsotg->last_rst + 242647a1685fSDinh Nguyen msecs_to_jiffies(200))) { 242747a1685fSDinh Nguyen 2428c6f5c050SMian Yousaf Kaukab kill_all_requests(hsotg, hsotg->eps_out[0], 24296b448af4SRobert Baldyga -ECONNRESET); 243047a1685fSDinh Nguyen 2431ad38dc5dSMarek Szyprowski s3c_hsotg_core_init_disconnected(hsotg); 2432ad38dc5dSMarek Szyprowski s3c_hsotg_core_connect(hsotg); 243347a1685fSDinh Nguyen } 243447a1685fSDinh Nguyen } 243547a1685fSDinh Nguyen } 243647a1685fSDinh Nguyen 243747a1685fSDinh Nguyen /* check both FIFOs */ 243847a1685fSDinh Nguyen 243947a1685fSDinh Nguyen if (gintsts & GINTSTS_NPTXFEMP) { 244047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "NPTxFEmp\n"); 244147a1685fSDinh Nguyen 244247a1685fSDinh Nguyen /* 244347a1685fSDinh Nguyen * Disable the interrupt to stop it happening again 244447a1685fSDinh Nguyen * unless one of these endpoint routines decides that 244547a1685fSDinh Nguyen * it needs re-enabling 244647a1685fSDinh Nguyen */ 244747a1685fSDinh Nguyen 244847a1685fSDinh Nguyen s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); 244947a1685fSDinh Nguyen s3c_hsotg_irq_fifoempty(hsotg, false); 245047a1685fSDinh Nguyen } 245147a1685fSDinh Nguyen 245247a1685fSDinh Nguyen if (gintsts & GINTSTS_PTXFEMP) { 245347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "PTxFEmp\n"); 245447a1685fSDinh Nguyen 245547a1685fSDinh Nguyen /* See note in GINTSTS_NPTxFEmp */ 245647a1685fSDinh Nguyen 245747a1685fSDinh Nguyen s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); 245847a1685fSDinh Nguyen s3c_hsotg_irq_fifoempty(hsotg, true); 245947a1685fSDinh Nguyen } 246047a1685fSDinh Nguyen 246147a1685fSDinh Nguyen if (gintsts & GINTSTS_RXFLVL) { 246247a1685fSDinh Nguyen /* 246347a1685fSDinh Nguyen * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, 246447a1685fSDinh Nguyen * we need to retry s3c_hsotg_handle_rx if this is still 246547a1685fSDinh Nguyen * set. 246647a1685fSDinh Nguyen */ 246747a1685fSDinh Nguyen 246847a1685fSDinh Nguyen s3c_hsotg_handle_rx(hsotg); 246947a1685fSDinh Nguyen } 247047a1685fSDinh Nguyen 247147a1685fSDinh Nguyen if (gintsts & GINTSTS_ERLYSUSP) { 247247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); 247347a1685fSDinh Nguyen writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS); 247447a1685fSDinh Nguyen } 247547a1685fSDinh Nguyen 247647a1685fSDinh Nguyen /* 247747a1685fSDinh Nguyen * these next two seem to crop-up occasionally causing the core 247847a1685fSDinh Nguyen * to shutdown the USB transfer, so try clearing them and logging 247947a1685fSDinh Nguyen * the occurrence. 248047a1685fSDinh Nguyen */ 248147a1685fSDinh Nguyen 248247a1685fSDinh Nguyen if (gintsts & GINTSTS_GOUTNAKEFF) { 248347a1685fSDinh Nguyen dev_info(hsotg->dev, "GOUTNakEff triggered\n"); 248447a1685fSDinh Nguyen 248547a1685fSDinh Nguyen writel(DCTL_CGOUTNAK, hsotg->regs + DCTL); 248647a1685fSDinh Nguyen 248747a1685fSDinh Nguyen s3c_hsotg_dump(hsotg); 248847a1685fSDinh Nguyen } 248947a1685fSDinh Nguyen 249047a1685fSDinh Nguyen if (gintsts & GINTSTS_GINNAKEFF) { 249147a1685fSDinh Nguyen dev_info(hsotg->dev, "GINNakEff triggered\n"); 249247a1685fSDinh Nguyen 249347a1685fSDinh Nguyen writel(DCTL_CGNPINNAK, hsotg->regs + DCTL); 249447a1685fSDinh Nguyen 249547a1685fSDinh Nguyen s3c_hsotg_dump(hsotg); 249647a1685fSDinh Nguyen } 249747a1685fSDinh Nguyen 249847a1685fSDinh Nguyen /* 249947a1685fSDinh Nguyen * if we've had fifo events, we should try and go around the 250047a1685fSDinh Nguyen * loop again to see if there's any point in returning yet. 250147a1685fSDinh Nguyen */ 250247a1685fSDinh Nguyen 250347a1685fSDinh Nguyen if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) 250447a1685fSDinh Nguyen goto irq_retry; 250547a1685fSDinh Nguyen 250647a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 250747a1685fSDinh Nguyen 250847a1685fSDinh Nguyen return IRQ_HANDLED; 250947a1685fSDinh Nguyen } 251047a1685fSDinh Nguyen 251147a1685fSDinh Nguyen /** 251247a1685fSDinh Nguyen * s3c_hsotg_ep_enable - enable the given endpoint 251347a1685fSDinh Nguyen * @ep: The USB endpint to configure 251447a1685fSDinh Nguyen * @desc: The USB endpoint descriptor to configure with. 251547a1685fSDinh Nguyen * 251647a1685fSDinh Nguyen * This is called from the USB gadget code's usb_ep_enable(). 251747a1685fSDinh Nguyen */ 251847a1685fSDinh Nguyen static int s3c_hsotg_ep_enable(struct usb_ep *ep, 251947a1685fSDinh Nguyen const struct usb_endpoint_descriptor *desc) 252047a1685fSDinh Nguyen { 252147a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 2522941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 252347a1685fSDinh Nguyen unsigned long flags; 2524ca4c55adSMian Yousaf Kaukab unsigned int index = hs_ep->index; 252547a1685fSDinh Nguyen u32 epctrl_reg; 252647a1685fSDinh Nguyen u32 epctrl; 252747a1685fSDinh Nguyen u32 mps; 2528ca4c55adSMian Yousaf Kaukab unsigned int dir_in; 2529ca4c55adSMian Yousaf Kaukab unsigned int i, val, size; 253047a1685fSDinh Nguyen int ret = 0; 253147a1685fSDinh Nguyen 253247a1685fSDinh Nguyen dev_dbg(hsotg->dev, 253347a1685fSDinh Nguyen "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", 253447a1685fSDinh Nguyen __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, 253547a1685fSDinh Nguyen desc->wMaxPacketSize, desc->bInterval); 253647a1685fSDinh Nguyen 253747a1685fSDinh Nguyen /* not to be called for EP0 */ 253847a1685fSDinh Nguyen WARN_ON(index == 0); 253947a1685fSDinh Nguyen 254047a1685fSDinh Nguyen dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; 254147a1685fSDinh Nguyen if (dir_in != hs_ep->dir_in) { 254247a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); 254347a1685fSDinh Nguyen return -EINVAL; 254447a1685fSDinh Nguyen } 254547a1685fSDinh Nguyen 254647a1685fSDinh Nguyen mps = usb_endpoint_maxp(desc); 254747a1685fSDinh Nguyen 254847a1685fSDinh Nguyen /* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */ 254947a1685fSDinh Nguyen 255047a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 255147a1685fSDinh Nguyen epctrl = readl(hsotg->regs + epctrl_reg); 255247a1685fSDinh Nguyen 255347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", 255447a1685fSDinh Nguyen __func__, epctrl, epctrl_reg); 255547a1685fSDinh Nguyen 255647a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 255747a1685fSDinh Nguyen 255847a1685fSDinh Nguyen epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK); 255947a1685fSDinh Nguyen epctrl |= DXEPCTL_MPS(mps); 256047a1685fSDinh Nguyen 256147a1685fSDinh Nguyen /* 256247a1685fSDinh Nguyen * mark the endpoint as active, otherwise the core may ignore 256347a1685fSDinh Nguyen * transactions entirely for this endpoint 256447a1685fSDinh Nguyen */ 256547a1685fSDinh Nguyen epctrl |= DXEPCTL_USBACTEP; 256647a1685fSDinh Nguyen 256747a1685fSDinh Nguyen /* 256847a1685fSDinh Nguyen * set the NAK status on the endpoint, otherwise we might try and 256947a1685fSDinh Nguyen * do something with data that we've yet got a request to process 257047a1685fSDinh Nguyen * since the RXFIFO will take data for an endpoint even if the 257147a1685fSDinh Nguyen * size register hasn't been set. 257247a1685fSDinh Nguyen */ 257347a1685fSDinh Nguyen 257447a1685fSDinh Nguyen epctrl |= DXEPCTL_SNAK; 257547a1685fSDinh Nguyen 257647a1685fSDinh Nguyen /* update the endpoint state */ 2577c6f5c050SMian Yousaf Kaukab s3c_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, dir_in); 257847a1685fSDinh Nguyen 257947a1685fSDinh Nguyen /* default, set to non-periodic */ 258047a1685fSDinh Nguyen hs_ep->isochronous = 0; 258147a1685fSDinh Nguyen hs_ep->periodic = 0; 258247a1685fSDinh Nguyen hs_ep->halted = 0; 258347a1685fSDinh Nguyen hs_ep->interval = desc->bInterval; 258447a1685fSDinh Nguyen 258547a1685fSDinh Nguyen if (hs_ep->interval > 1 && hs_ep->mc > 1) 258647a1685fSDinh Nguyen dev_err(hsotg->dev, "MC > 1 when interval is not 1\n"); 258747a1685fSDinh Nguyen 258847a1685fSDinh Nguyen switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { 258947a1685fSDinh Nguyen case USB_ENDPOINT_XFER_ISOC: 259047a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_ISO; 259147a1685fSDinh Nguyen epctrl |= DXEPCTL_SETEVENFR; 259247a1685fSDinh Nguyen hs_ep->isochronous = 1; 259347a1685fSDinh Nguyen if (dir_in) 259447a1685fSDinh Nguyen hs_ep->periodic = 1; 259547a1685fSDinh Nguyen break; 259647a1685fSDinh Nguyen 259747a1685fSDinh Nguyen case USB_ENDPOINT_XFER_BULK: 259847a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_BULK; 259947a1685fSDinh Nguyen break; 260047a1685fSDinh Nguyen 260147a1685fSDinh Nguyen case USB_ENDPOINT_XFER_INT: 2602b203d0a2SRobert Baldyga if (dir_in) 260347a1685fSDinh Nguyen hs_ep->periodic = 1; 260447a1685fSDinh Nguyen 260547a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_INTERRUPT; 260647a1685fSDinh Nguyen break; 260747a1685fSDinh Nguyen 260847a1685fSDinh Nguyen case USB_ENDPOINT_XFER_CONTROL: 260947a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_CONTROL; 261047a1685fSDinh Nguyen break; 261147a1685fSDinh Nguyen } 261247a1685fSDinh Nguyen 26134556e12cSMian Yousaf Kaukab /* If fifo is already allocated for this ep */ 26144556e12cSMian Yousaf Kaukab if (hs_ep->fifo_index) { 26154556e12cSMian Yousaf Kaukab size = hs_ep->ep.maxpacket * hs_ep->mc; 26164556e12cSMian Yousaf Kaukab /* If bigger fifo is required deallocate current one */ 26174556e12cSMian Yousaf Kaukab if (size > hs_ep->fifo_size) { 26184556e12cSMian Yousaf Kaukab hsotg->fifo_map &= ~(1 << hs_ep->fifo_index); 26194556e12cSMian Yousaf Kaukab hs_ep->fifo_index = 0; 26204556e12cSMian Yousaf Kaukab hs_ep->fifo_size = 0; 26214556e12cSMian Yousaf Kaukab } 26224556e12cSMian Yousaf Kaukab } 26234556e12cSMian Yousaf Kaukab 262447a1685fSDinh Nguyen /* 262547a1685fSDinh Nguyen * if the hardware has dedicated fifos, we must give each IN EP 262647a1685fSDinh Nguyen * a unique tx-fifo even if it is non-periodic. 262747a1685fSDinh Nguyen */ 26284556e12cSMian Yousaf Kaukab if (dir_in && hsotg->dedicated_fifos && !hs_ep->fifo_index) { 2629ca4c55adSMian Yousaf Kaukab u32 fifo_index = 0; 2630ca4c55adSMian Yousaf Kaukab u32 fifo_size = UINT_MAX; 2631b203d0a2SRobert Baldyga size = hs_ep->ep.maxpacket*hs_ep->mc; 26325f2196bdSMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; ++i) { 2633b203d0a2SRobert Baldyga if (hsotg->fifo_map & (1<<i)) 2634b203d0a2SRobert Baldyga continue; 2635b203d0a2SRobert Baldyga val = readl(hsotg->regs + DPTXFSIZN(i)); 2636b203d0a2SRobert Baldyga val = (val >> FIFOSIZE_DEPTH_SHIFT)*4; 2637b203d0a2SRobert Baldyga if (val < size) 2638b203d0a2SRobert Baldyga continue; 2639ca4c55adSMian Yousaf Kaukab /* Search for smallest acceptable fifo */ 2640ca4c55adSMian Yousaf Kaukab if (val < fifo_size) { 2641ca4c55adSMian Yousaf Kaukab fifo_size = val; 2642ca4c55adSMian Yousaf Kaukab fifo_index = i; 2643b203d0a2SRobert Baldyga } 2644ca4c55adSMian Yousaf Kaukab } 2645ca4c55adSMian Yousaf Kaukab if (!fifo_index) { 26465f2196bdSMian Yousaf Kaukab dev_err(hsotg->dev, 26475f2196bdSMian Yousaf Kaukab "%s: No suitable fifo found\n", __func__); 2648b585a48bSSudip Mukherjee ret = -ENOMEM; 2649b585a48bSSudip Mukherjee goto error; 2650b585a48bSSudip Mukherjee } 2651ca4c55adSMian Yousaf Kaukab hsotg->fifo_map |= 1 << fifo_index; 2652ca4c55adSMian Yousaf Kaukab epctrl |= DXEPCTL_TXFNUM(fifo_index); 2653ca4c55adSMian Yousaf Kaukab hs_ep->fifo_index = fifo_index; 2654ca4c55adSMian Yousaf Kaukab hs_ep->fifo_size = fifo_size; 2655b203d0a2SRobert Baldyga } 265647a1685fSDinh Nguyen 265747a1685fSDinh Nguyen /* for non control endpoints, set PID to D0 */ 265847a1685fSDinh Nguyen if (index) 265947a1685fSDinh Nguyen epctrl |= DXEPCTL_SETD0PID; 266047a1685fSDinh Nguyen 266147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", 266247a1685fSDinh Nguyen __func__, epctrl); 266347a1685fSDinh Nguyen 266447a1685fSDinh Nguyen writel(epctrl, hsotg->regs + epctrl_reg); 266547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", 266647a1685fSDinh Nguyen __func__, readl(hsotg->regs + epctrl_reg)); 266747a1685fSDinh Nguyen 266847a1685fSDinh Nguyen /* enable the endpoint interrupt */ 266947a1685fSDinh Nguyen s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1); 267047a1685fSDinh Nguyen 2671b585a48bSSudip Mukherjee error: 267247a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 267347a1685fSDinh Nguyen return ret; 267447a1685fSDinh Nguyen } 267547a1685fSDinh Nguyen 267647a1685fSDinh Nguyen /** 267747a1685fSDinh Nguyen * s3c_hsotg_ep_disable - disable given endpoint 267847a1685fSDinh Nguyen * @ep: The endpoint to disable. 267947a1685fSDinh Nguyen */ 268062f4f065SRobert Baldyga static int s3c_hsotg_ep_disable_force(struct usb_ep *ep, bool force) 268147a1685fSDinh Nguyen { 268247a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 2683941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = hs_ep->parent; 268447a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 268547a1685fSDinh Nguyen int index = hs_ep->index; 268647a1685fSDinh Nguyen unsigned long flags; 268747a1685fSDinh Nguyen u32 epctrl_reg; 268847a1685fSDinh Nguyen u32 ctrl; 268947a1685fSDinh Nguyen 26901e011293SMarek Szyprowski dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); 269147a1685fSDinh Nguyen 2692c6f5c050SMian Yousaf Kaukab if (ep == &hsotg->eps_out[0]->ep) { 269347a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: called for ep0\n", __func__); 269447a1685fSDinh Nguyen return -EINVAL; 269547a1685fSDinh Nguyen } 269647a1685fSDinh Nguyen 269747a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 269847a1685fSDinh Nguyen 269947a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 270047a1685fSDinh Nguyen 2701b203d0a2SRobert Baldyga hsotg->fifo_map &= ~(1<<hs_ep->fifo_index); 2702b203d0a2SRobert Baldyga hs_ep->fifo_index = 0; 2703b203d0a2SRobert Baldyga hs_ep->fifo_size = 0; 270447a1685fSDinh Nguyen 270547a1685fSDinh Nguyen ctrl = readl(hsotg->regs + epctrl_reg); 270647a1685fSDinh Nguyen ctrl &= ~DXEPCTL_EPENA; 270747a1685fSDinh Nguyen ctrl &= ~DXEPCTL_USBACTEP; 270847a1685fSDinh Nguyen ctrl |= DXEPCTL_SNAK; 270947a1685fSDinh Nguyen 271047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 271147a1685fSDinh Nguyen writel(ctrl, hsotg->regs + epctrl_reg); 271247a1685fSDinh Nguyen 271347a1685fSDinh Nguyen /* disable endpoint interrupts */ 271447a1685fSDinh Nguyen s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); 271547a1685fSDinh Nguyen 27161141ea01SMian Yousaf Kaukab /* terminate all requests with shutdown */ 27171141ea01SMian Yousaf Kaukab kill_all_requests(hsotg, hs_ep, -ESHUTDOWN); 27181141ea01SMian Yousaf Kaukab 271947a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 272047a1685fSDinh Nguyen return 0; 272147a1685fSDinh Nguyen } 272247a1685fSDinh Nguyen 272362f4f065SRobert Baldyga static int s3c_hsotg_ep_disable(struct usb_ep *ep) 272462f4f065SRobert Baldyga { 272562f4f065SRobert Baldyga return s3c_hsotg_ep_disable_force(ep, false); 272662f4f065SRobert Baldyga } 272747a1685fSDinh Nguyen /** 272847a1685fSDinh Nguyen * on_list - check request is on the given endpoint 272947a1685fSDinh Nguyen * @ep: The endpoint to check. 273047a1685fSDinh Nguyen * @test: The request to test if it is on the endpoint. 273147a1685fSDinh Nguyen */ 273247a1685fSDinh Nguyen static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test) 273347a1685fSDinh Nguyen { 273447a1685fSDinh Nguyen struct s3c_hsotg_req *req, *treq; 273547a1685fSDinh Nguyen 273647a1685fSDinh Nguyen list_for_each_entry_safe(req, treq, &ep->queue, queue) { 273747a1685fSDinh Nguyen if (req == test) 273847a1685fSDinh Nguyen return true; 273947a1685fSDinh Nguyen } 274047a1685fSDinh Nguyen 274147a1685fSDinh Nguyen return false; 274247a1685fSDinh Nguyen } 274347a1685fSDinh Nguyen 274447a1685fSDinh Nguyen /** 274547a1685fSDinh Nguyen * s3c_hsotg_ep_dequeue - dequeue given endpoint 274647a1685fSDinh Nguyen * @ep: The endpoint to dequeue. 274747a1685fSDinh Nguyen * @req: The request to be removed from a queue. 274847a1685fSDinh Nguyen */ 274947a1685fSDinh Nguyen static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) 275047a1685fSDinh Nguyen { 275147a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = our_req(req); 275247a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 2753941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 275447a1685fSDinh Nguyen unsigned long flags; 275547a1685fSDinh Nguyen 27561e011293SMarek Szyprowski dev_dbg(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); 275747a1685fSDinh Nguyen 275847a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 275947a1685fSDinh Nguyen 276047a1685fSDinh Nguyen if (!on_list(hs_ep, hs_req)) { 276147a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 276247a1685fSDinh Nguyen return -EINVAL; 276347a1685fSDinh Nguyen } 276447a1685fSDinh Nguyen 276547a1685fSDinh Nguyen s3c_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); 276647a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 276747a1685fSDinh Nguyen 276847a1685fSDinh Nguyen return 0; 276947a1685fSDinh Nguyen } 277047a1685fSDinh Nguyen 277147a1685fSDinh Nguyen /** 277247a1685fSDinh Nguyen * s3c_hsotg_ep_sethalt - set halt on a given endpoint 277347a1685fSDinh Nguyen * @ep: The endpoint to set halt. 277447a1685fSDinh Nguyen * @value: Set or unset the halt. 277547a1685fSDinh Nguyen */ 277647a1685fSDinh Nguyen static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) 277747a1685fSDinh Nguyen { 277847a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 2779941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 278047a1685fSDinh Nguyen int index = hs_ep->index; 278147a1685fSDinh Nguyen u32 epreg; 278247a1685fSDinh Nguyen u32 epctl; 278347a1685fSDinh Nguyen u32 xfertype; 278447a1685fSDinh Nguyen 278547a1685fSDinh Nguyen dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); 278647a1685fSDinh Nguyen 278747a1685fSDinh Nguyen if (index == 0) { 278847a1685fSDinh Nguyen if (value) 278947a1685fSDinh Nguyen s3c_hsotg_stall_ep0(hs); 279047a1685fSDinh Nguyen else 279147a1685fSDinh Nguyen dev_warn(hs->dev, 279247a1685fSDinh Nguyen "%s: can't clear halt on ep0\n", __func__); 279347a1685fSDinh Nguyen return 0; 279447a1685fSDinh Nguyen } 279547a1685fSDinh Nguyen 2796c6f5c050SMian Yousaf Kaukab if (hs_ep->dir_in) { 279747a1685fSDinh Nguyen epreg = DIEPCTL(index); 279847a1685fSDinh Nguyen epctl = readl(hs->regs + epreg); 279947a1685fSDinh Nguyen 280047a1685fSDinh Nguyen if (value) { 280147a1685fSDinh Nguyen epctl |= DXEPCTL_STALL + DXEPCTL_SNAK; 280247a1685fSDinh Nguyen if (epctl & DXEPCTL_EPENA) 280347a1685fSDinh Nguyen epctl |= DXEPCTL_EPDIS; 280447a1685fSDinh Nguyen } else { 280547a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 280647a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 280747a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 280847a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 280947a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 281047a1685fSDinh Nguyen } 281147a1685fSDinh Nguyen writel(epctl, hs->regs + epreg); 2812c6f5c050SMian Yousaf Kaukab } else { 281347a1685fSDinh Nguyen 281447a1685fSDinh Nguyen epreg = DOEPCTL(index); 281547a1685fSDinh Nguyen epctl = readl(hs->regs + epreg); 281647a1685fSDinh Nguyen 281747a1685fSDinh Nguyen if (value) 281847a1685fSDinh Nguyen epctl |= DXEPCTL_STALL; 281947a1685fSDinh Nguyen else { 282047a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 282147a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 282247a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 282347a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 282447a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 282547a1685fSDinh Nguyen } 282647a1685fSDinh Nguyen writel(epctl, hs->regs + epreg); 2827c6f5c050SMian Yousaf Kaukab } 282847a1685fSDinh Nguyen 282947a1685fSDinh Nguyen hs_ep->halted = value; 283047a1685fSDinh Nguyen 283147a1685fSDinh Nguyen return 0; 283247a1685fSDinh Nguyen } 283347a1685fSDinh Nguyen 283447a1685fSDinh Nguyen /** 283547a1685fSDinh Nguyen * s3c_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held 283647a1685fSDinh Nguyen * @ep: The endpoint to set halt. 283747a1685fSDinh Nguyen * @value: Set or unset the halt. 283847a1685fSDinh Nguyen */ 283947a1685fSDinh Nguyen static int s3c_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) 284047a1685fSDinh Nguyen { 284147a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 2842941fcce4SDinh Nguyen struct dwc2_hsotg *hs = hs_ep->parent; 284347a1685fSDinh Nguyen unsigned long flags = 0; 284447a1685fSDinh Nguyen int ret = 0; 284547a1685fSDinh Nguyen 284647a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 284747a1685fSDinh Nguyen ret = s3c_hsotg_ep_sethalt(ep, value); 284847a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 284947a1685fSDinh Nguyen 285047a1685fSDinh Nguyen return ret; 285147a1685fSDinh Nguyen } 285247a1685fSDinh Nguyen 285347a1685fSDinh Nguyen static struct usb_ep_ops s3c_hsotg_ep_ops = { 285447a1685fSDinh Nguyen .enable = s3c_hsotg_ep_enable, 285547a1685fSDinh Nguyen .disable = s3c_hsotg_ep_disable, 285647a1685fSDinh Nguyen .alloc_request = s3c_hsotg_ep_alloc_request, 285747a1685fSDinh Nguyen .free_request = s3c_hsotg_ep_free_request, 285847a1685fSDinh Nguyen .queue = s3c_hsotg_ep_queue_lock, 285947a1685fSDinh Nguyen .dequeue = s3c_hsotg_ep_dequeue, 286047a1685fSDinh Nguyen .set_halt = s3c_hsotg_ep_sethalt_lock, 286147a1685fSDinh Nguyen /* note, don't believe we have any call for the fifo routines */ 286247a1685fSDinh Nguyen }; 286347a1685fSDinh Nguyen 286447a1685fSDinh Nguyen /** 286547a1685fSDinh Nguyen * s3c_hsotg_phy_enable - enable platform phy dev 286647a1685fSDinh Nguyen * @hsotg: The driver state 286747a1685fSDinh Nguyen * 286847a1685fSDinh Nguyen * A wrapper for platform code responsible for controlling 286947a1685fSDinh Nguyen * low-level USB code 287047a1685fSDinh Nguyen */ 2871941fcce4SDinh Nguyen static void s3c_hsotg_phy_enable(struct dwc2_hsotg *hsotg) 287247a1685fSDinh Nguyen { 287347a1685fSDinh Nguyen struct platform_device *pdev = to_platform_device(hsotg->dev); 287447a1685fSDinh Nguyen 287547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev); 287647a1685fSDinh Nguyen 2877ca2c5ba8SKamil Debski if (hsotg->uphy) 2878ca2c5ba8SKamil Debski usb_phy_init(hsotg->uphy); 2879ca2c5ba8SKamil Debski else if (hsotg->plat && hsotg->plat->phy_init) 2880ca2c5ba8SKamil Debski hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); 2881ca2c5ba8SKamil Debski else { 288247a1685fSDinh Nguyen phy_init(hsotg->phy); 288347a1685fSDinh Nguyen phy_power_on(hsotg->phy); 2884ca2c5ba8SKamil Debski } 288547a1685fSDinh Nguyen } 288647a1685fSDinh Nguyen 288747a1685fSDinh Nguyen /** 288847a1685fSDinh Nguyen * s3c_hsotg_phy_disable - disable platform phy dev 288947a1685fSDinh Nguyen * @hsotg: The driver state 289047a1685fSDinh Nguyen * 289147a1685fSDinh Nguyen * A wrapper for platform code responsible for controlling 289247a1685fSDinh Nguyen * low-level USB code 289347a1685fSDinh Nguyen */ 2894941fcce4SDinh Nguyen static void s3c_hsotg_phy_disable(struct dwc2_hsotg *hsotg) 289547a1685fSDinh Nguyen { 289647a1685fSDinh Nguyen struct platform_device *pdev = to_platform_device(hsotg->dev); 289747a1685fSDinh Nguyen 2898ca2c5ba8SKamil Debski if (hsotg->uphy) 2899ca2c5ba8SKamil Debski usb_phy_shutdown(hsotg->uphy); 2900ca2c5ba8SKamil Debski else if (hsotg->plat && hsotg->plat->phy_exit) 2901ca2c5ba8SKamil Debski hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); 2902ca2c5ba8SKamil Debski else { 290347a1685fSDinh Nguyen phy_power_off(hsotg->phy); 290447a1685fSDinh Nguyen phy_exit(hsotg->phy); 2905ca2c5ba8SKamil Debski } 290647a1685fSDinh Nguyen } 290747a1685fSDinh Nguyen 290847a1685fSDinh Nguyen /** 290947a1685fSDinh Nguyen * s3c_hsotg_init - initalize the usb core 291047a1685fSDinh Nguyen * @hsotg: The driver state 291147a1685fSDinh Nguyen */ 2912941fcce4SDinh Nguyen static void s3c_hsotg_init(struct dwc2_hsotg *hsotg) 291347a1685fSDinh Nguyen { 291447a1685fSDinh Nguyen /* unmask subset of endpoint interrupts */ 291547a1685fSDinh Nguyen 291647a1685fSDinh Nguyen writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | 291747a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK, 291847a1685fSDinh Nguyen hsotg->regs + DIEPMSK); 291947a1685fSDinh Nguyen 292047a1685fSDinh Nguyen writel(DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | 292147a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK, 292247a1685fSDinh Nguyen hsotg->regs + DOEPMSK); 292347a1685fSDinh Nguyen 292447a1685fSDinh Nguyen writel(0, hsotg->regs + DAINTMSK); 292547a1685fSDinh Nguyen 292647a1685fSDinh Nguyen /* Be in disconnected state until gadget is registered */ 292747a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 292847a1685fSDinh Nguyen 292947a1685fSDinh Nguyen if (0) { 293047a1685fSDinh Nguyen /* post global nak until we're ready */ 293147a1685fSDinh Nguyen writel(DCTL_SGNPINNAK | DCTL_SGOUTNAK, 293247a1685fSDinh Nguyen hsotg->regs + DCTL); 293347a1685fSDinh Nguyen } 293447a1685fSDinh Nguyen 293547a1685fSDinh Nguyen /* setup fifos */ 293647a1685fSDinh Nguyen 293747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 293847a1685fSDinh Nguyen readl(hsotg->regs + GRXFSIZ), 293947a1685fSDinh Nguyen readl(hsotg->regs + GNPTXFSIZ)); 294047a1685fSDinh Nguyen 294147a1685fSDinh Nguyen s3c_hsotg_init_fifo(hsotg); 294247a1685fSDinh Nguyen 294347a1685fSDinh Nguyen /* set the PLL on, remove the HNP/SRP and set the PHY */ 294447a1685fSDinh Nguyen writel(GUSBCFG_PHYIF16 | GUSBCFG_TOUTCAL(7) | (0x5 << 10), 294547a1685fSDinh Nguyen hsotg->regs + GUSBCFG); 294647a1685fSDinh Nguyen 2947f5090044SGregory Herrero if (using_dma(hsotg)) 2948f5090044SGregory Herrero __orr32(hsotg->regs + GAHBCFG, GAHBCFG_DMA_EN); 294947a1685fSDinh Nguyen } 295047a1685fSDinh Nguyen 295147a1685fSDinh Nguyen /** 295247a1685fSDinh Nguyen * s3c_hsotg_udc_start - prepare the udc for work 295347a1685fSDinh Nguyen * @gadget: The usb gadget state 295447a1685fSDinh Nguyen * @driver: The usb gadget driver 295547a1685fSDinh Nguyen * 295647a1685fSDinh Nguyen * Perform initialization to prepare udc device and driver 295747a1685fSDinh Nguyen * to work. 295847a1685fSDinh Nguyen */ 295947a1685fSDinh Nguyen static int s3c_hsotg_udc_start(struct usb_gadget *gadget, 296047a1685fSDinh Nguyen struct usb_gadget_driver *driver) 296147a1685fSDinh Nguyen { 2962941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 29635b9451f8SMarek Szyprowski unsigned long flags; 296447a1685fSDinh Nguyen int ret; 296547a1685fSDinh Nguyen 296647a1685fSDinh Nguyen if (!hsotg) { 296747a1685fSDinh Nguyen pr_err("%s: called with no device\n", __func__); 296847a1685fSDinh Nguyen return -ENODEV; 296947a1685fSDinh Nguyen } 297047a1685fSDinh Nguyen 297147a1685fSDinh Nguyen if (!driver) { 297247a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: no driver\n", __func__); 297347a1685fSDinh Nguyen return -EINVAL; 297447a1685fSDinh Nguyen } 297547a1685fSDinh Nguyen 297647a1685fSDinh Nguyen if (driver->max_speed < USB_SPEED_FULL) 297747a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: bad speed\n", __func__); 297847a1685fSDinh Nguyen 297947a1685fSDinh Nguyen if (!driver->setup) { 298047a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: missing entry points\n", __func__); 298147a1685fSDinh Nguyen return -EINVAL; 298247a1685fSDinh Nguyen } 298347a1685fSDinh Nguyen 29847ad8096eSMarek Szyprowski mutex_lock(&hsotg->init_mutex); 298547a1685fSDinh Nguyen WARN_ON(hsotg->driver); 298647a1685fSDinh Nguyen 298747a1685fSDinh Nguyen driver->driver.bus = NULL; 298847a1685fSDinh Nguyen hsotg->driver = driver; 298947a1685fSDinh Nguyen hsotg->gadget.dev.of_node = hsotg->dev->of_node; 299047a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 299147a1685fSDinh Nguyen 2992d00b4142SRobert Baldyga clk_enable(hsotg->clk); 2993d00b4142SRobert Baldyga 299447a1685fSDinh Nguyen ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), 299547a1685fSDinh Nguyen hsotg->supplies); 299647a1685fSDinh Nguyen if (ret) { 299747a1685fSDinh Nguyen dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret); 299847a1685fSDinh Nguyen goto err; 299947a1685fSDinh Nguyen } 300047a1685fSDinh Nguyen 3001c816c47fSMarek Szyprowski s3c_hsotg_phy_enable(hsotg); 3002f6c01592SGregory Herrero if (!IS_ERR_OR_NULL(hsotg->uphy)) 3003f6c01592SGregory Herrero otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget); 3004c816c47fSMarek Szyprowski 30055b9451f8SMarek Szyprowski spin_lock_irqsave(&hsotg->lock, flags); 30065b9451f8SMarek Szyprowski s3c_hsotg_init(hsotg); 30075b9451f8SMarek Szyprowski s3c_hsotg_core_init_disconnected(hsotg); 3008dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 30095b9451f8SMarek Szyprowski spin_unlock_irqrestore(&hsotg->lock, flags); 30105b9451f8SMarek Szyprowski 301147a1685fSDinh Nguyen dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); 30125b9451f8SMarek Szyprowski 30137ad8096eSMarek Szyprowski mutex_unlock(&hsotg->init_mutex); 30147ad8096eSMarek Szyprowski 301547a1685fSDinh Nguyen return 0; 301647a1685fSDinh Nguyen 301747a1685fSDinh Nguyen err: 30187ad8096eSMarek Szyprowski mutex_unlock(&hsotg->init_mutex); 301947a1685fSDinh Nguyen hsotg->driver = NULL; 302047a1685fSDinh Nguyen return ret; 302147a1685fSDinh Nguyen } 302247a1685fSDinh Nguyen 302347a1685fSDinh Nguyen /** 302447a1685fSDinh Nguyen * s3c_hsotg_udc_stop - stop the udc 302547a1685fSDinh Nguyen * @gadget: The usb gadget state 302647a1685fSDinh Nguyen * @driver: The usb gadget driver 302747a1685fSDinh Nguyen * 302847a1685fSDinh Nguyen * Stop udc hw block and stay tunned for future transmissions 302947a1685fSDinh Nguyen */ 303022835b80SFelipe Balbi static int s3c_hsotg_udc_stop(struct usb_gadget *gadget) 303147a1685fSDinh Nguyen { 3032941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 303347a1685fSDinh Nguyen unsigned long flags = 0; 303447a1685fSDinh Nguyen int ep; 303547a1685fSDinh Nguyen 303647a1685fSDinh Nguyen if (!hsotg) 303747a1685fSDinh Nguyen return -ENODEV; 303847a1685fSDinh Nguyen 30397ad8096eSMarek Szyprowski mutex_lock(&hsotg->init_mutex); 30407ad8096eSMarek Szyprowski 304147a1685fSDinh Nguyen /* all endpoints should be shutdown */ 3042c6f5c050SMian Yousaf Kaukab for (ep = 1; ep < hsotg->num_of_eps; ep++) { 3043c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 3044c6f5c050SMian Yousaf Kaukab s3c_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 3045c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 3046c6f5c050SMian Yousaf Kaukab s3c_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 3047c6f5c050SMian Yousaf Kaukab } 304847a1685fSDinh Nguyen 304947a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 305047a1685fSDinh Nguyen 305147a1685fSDinh Nguyen hsotg->driver = NULL; 305247a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 3053dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 305447a1685fSDinh Nguyen 305547a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 305647a1685fSDinh Nguyen 3057f6c01592SGregory Herrero if (!IS_ERR_OR_NULL(hsotg->uphy)) 3058f6c01592SGregory Herrero otg_set_peripheral(hsotg->uphy->otg, NULL); 3059c816c47fSMarek Szyprowski s3c_hsotg_phy_disable(hsotg); 3060c816c47fSMarek Szyprowski 306147a1685fSDinh Nguyen regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); 306247a1685fSDinh Nguyen 3063d00b4142SRobert Baldyga clk_disable(hsotg->clk); 3064d00b4142SRobert Baldyga 30657ad8096eSMarek Szyprowski mutex_unlock(&hsotg->init_mutex); 30667ad8096eSMarek Szyprowski 306747a1685fSDinh Nguyen return 0; 306847a1685fSDinh Nguyen } 306947a1685fSDinh Nguyen 307047a1685fSDinh Nguyen /** 307147a1685fSDinh Nguyen * s3c_hsotg_gadget_getframe - read the frame number 307247a1685fSDinh Nguyen * @gadget: The usb gadget state 307347a1685fSDinh Nguyen * 307447a1685fSDinh Nguyen * Read the {micro} frame number 307547a1685fSDinh Nguyen */ 307647a1685fSDinh Nguyen static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget) 307747a1685fSDinh Nguyen { 307847a1685fSDinh Nguyen return s3c_hsotg_read_frameno(to_hsotg(gadget)); 307947a1685fSDinh Nguyen } 308047a1685fSDinh Nguyen 308147a1685fSDinh Nguyen /** 308247a1685fSDinh Nguyen * s3c_hsotg_pullup - connect/disconnect the USB PHY 308347a1685fSDinh Nguyen * @gadget: The usb gadget state 308447a1685fSDinh Nguyen * @is_on: Current state of the USB PHY 308547a1685fSDinh Nguyen * 308647a1685fSDinh Nguyen * Connect/Disconnect the USB PHY pullup 308747a1685fSDinh Nguyen */ 308847a1685fSDinh Nguyen static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on) 308947a1685fSDinh Nguyen { 3090941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = to_hsotg(gadget); 309147a1685fSDinh Nguyen unsigned long flags = 0; 309247a1685fSDinh Nguyen 3093d784f1e5SAndrzej Pietrasiewicz dev_dbg(hsotg->dev, "%s: is_on: %d\n", __func__, is_on); 309447a1685fSDinh Nguyen 30957ad8096eSMarek Szyprowski mutex_lock(&hsotg->init_mutex); 309647a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 309747a1685fSDinh Nguyen if (is_on) { 3098d00b4142SRobert Baldyga clk_enable(hsotg->clk); 3099dc6e69e6SMarek Szyprowski hsotg->enabled = 1; 3100ad38dc5dSMarek Szyprowski s3c_hsotg_core_connect(hsotg); 310147a1685fSDinh Nguyen } else { 31025b9451f8SMarek Szyprowski s3c_hsotg_core_disconnect(hsotg); 31036d13673eSGregory Herrero s3c_hsotg_disconnect(hsotg); 3104dc6e69e6SMarek Szyprowski hsotg->enabled = 0; 3105d00b4142SRobert Baldyga clk_disable(hsotg->clk); 310647a1685fSDinh Nguyen } 310747a1685fSDinh Nguyen 310847a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 310947a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 31107ad8096eSMarek Szyprowski mutex_unlock(&hsotg->init_mutex); 311147a1685fSDinh Nguyen 311247a1685fSDinh Nguyen return 0; 311347a1685fSDinh Nguyen } 311447a1685fSDinh Nguyen 311583d98223SGregory Herrero static int s3c_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) 311683d98223SGregory Herrero { 311783d98223SGregory Herrero struct dwc2_hsotg *hsotg = to_hsotg(gadget); 311883d98223SGregory Herrero unsigned long flags; 311983d98223SGregory Herrero 312083d98223SGregory Herrero dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active); 312183d98223SGregory Herrero spin_lock_irqsave(&hsotg->lock, flags); 312283d98223SGregory Herrero 312383d98223SGregory Herrero if (is_active) { 312483d98223SGregory Herrero /* Kill any ep0 requests as controller will be reinitialized */ 312583d98223SGregory Herrero kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); 312683d98223SGregory Herrero s3c_hsotg_core_init_disconnected(hsotg); 312783d98223SGregory Herrero if (hsotg->enabled) 312883d98223SGregory Herrero s3c_hsotg_core_connect(hsotg); 312983d98223SGregory Herrero } else { 313083d98223SGregory Herrero s3c_hsotg_core_disconnect(hsotg); 313183d98223SGregory Herrero s3c_hsotg_disconnect(hsotg); 313283d98223SGregory Herrero } 313383d98223SGregory Herrero 313483d98223SGregory Herrero spin_unlock_irqrestore(&hsotg->lock, flags); 313583d98223SGregory Herrero return 0; 313683d98223SGregory Herrero } 313783d98223SGregory Herrero 3138596d696aSGregory Herrero /** 3139596d696aSGregory Herrero * s3c_hsotg_vbus_draw - report bMaxPower field 3140596d696aSGregory Herrero * @gadget: The usb gadget state 3141596d696aSGregory Herrero * @mA: Amount of current 3142596d696aSGregory Herrero * 3143596d696aSGregory Herrero * Report how much power the device may consume to the phy. 3144596d696aSGregory Herrero */ 3145596d696aSGregory Herrero static int s3c_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned mA) 3146596d696aSGregory Herrero { 3147596d696aSGregory Herrero struct dwc2_hsotg *hsotg = to_hsotg(gadget); 3148596d696aSGregory Herrero 3149596d696aSGregory Herrero if (IS_ERR_OR_NULL(hsotg->uphy)) 3150596d696aSGregory Herrero return -ENOTSUPP; 3151596d696aSGregory Herrero return usb_phy_set_power(hsotg->uphy, mA); 3152596d696aSGregory Herrero } 3153596d696aSGregory Herrero 315447a1685fSDinh Nguyen static const struct usb_gadget_ops s3c_hsotg_gadget_ops = { 315547a1685fSDinh Nguyen .get_frame = s3c_hsotg_gadget_getframe, 315647a1685fSDinh Nguyen .udc_start = s3c_hsotg_udc_start, 315747a1685fSDinh Nguyen .udc_stop = s3c_hsotg_udc_stop, 315847a1685fSDinh Nguyen .pullup = s3c_hsotg_pullup, 315983d98223SGregory Herrero .vbus_session = s3c_hsotg_vbus_session, 3160596d696aSGregory Herrero .vbus_draw = s3c_hsotg_vbus_draw, 316147a1685fSDinh Nguyen }; 316247a1685fSDinh Nguyen 316347a1685fSDinh Nguyen /** 316447a1685fSDinh Nguyen * s3c_hsotg_initep - initialise a single endpoint 316547a1685fSDinh Nguyen * @hsotg: The device state. 316647a1685fSDinh Nguyen * @hs_ep: The endpoint to be initialised. 316747a1685fSDinh Nguyen * @epnum: The endpoint number 316847a1685fSDinh Nguyen * 316947a1685fSDinh Nguyen * Initialise the given endpoint (as part of the probe and device state 317047a1685fSDinh Nguyen * creation) to give to the gadget driver. Setup the endpoint name, any 317147a1685fSDinh Nguyen * direction information and other state that may be required. 317247a1685fSDinh Nguyen */ 3173941fcce4SDinh Nguyen static void s3c_hsotg_initep(struct dwc2_hsotg *hsotg, 317447a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep, 3175c6f5c050SMian Yousaf Kaukab int epnum, 3176c6f5c050SMian Yousaf Kaukab bool dir_in) 317747a1685fSDinh Nguyen { 317847a1685fSDinh Nguyen char *dir; 317947a1685fSDinh Nguyen 318047a1685fSDinh Nguyen if (epnum == 0) 318147a1685fSDinh Nguyen dir = ""; 3182c6f5c050SMian Yousaf Kaukab else if (dir_in) 318347a1685fSDinh Nguyen dir = "in"; 3184c6f5c050SMian Yousaf Kaukab else 3185c6f5c050SMian Yousaf Kaukab dir = "out"; 318647a1685fSDinh Nguyen 3187c6f5c050SMian Yousaf Kaukab hs_ep->dir_in = dir_in; 318847a1685fSDinh Nguyen hs_ep->index = epnum; 318947a1685fSDinh Nguyen 319047a1685fSDinh Nguyen snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); 319147a1685fSDinh Nguyen 319247a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->queue); 319347a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->ep.ep_list); 319447a1685fSDinh Nguyen 319547a1685fSDinh Nguyen /* add to the list of endpoints known by the gadget driver */ 319647a1685fSDinh Nguyen if (epnum) 319747a1685fSDinh Nguyen list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); 319847a1685fSDinh Nguyen 319947a1685fSDinh Nguyen hs_ep->parent = hsotg; 320047a1685fSDinh Nguyen hs_ep->ep.name = hs_ep->name; 320147a1685fSDinh Nguyen usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT); 320247a1685fSDinh Nguyen hs_ep->ep.ops = &s3c_hsotg_ep_ops; 320347a1685fSDinh Nguyen 320447a1685fSDinh Nguyen /* 320547a1685fSDinh Nguyen * if we're using dma, we need to set the next-endpoint pointer 320647a1685fSDinh Nguyen * to be something valid. 320747a1685fSDinh Nguyen */ 320847a1685fSDinh Nguyen 320947a1685fSDinh Nguyen if (using_dma(hsotg)) { 321047a1685fSDinh Nguyen u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); 3211c6f5c050SMian Yousaf Kaukab if (dir_in) 321247a1685fSDinh Nguyen writel(next, hsotg->regs + DIEPCTL(epnum)); 3213c6f5c050SMian Yousaf Kaukab else 321447a1685fSDinh Nguyen writel(next, hsotg->regs + DOEPCTL(epnum)); 321547a1685fSDinh Nguyen } 321647a1685fSDinh Nguyen } 321747a1685fSDinh Nguyen 321847a1685fSDinh Nguyen /** 321947a1685fSDinh Nguyen * s3c_hsotg_hw_cfg - read HW configuration registers 322047a1685fSDinh Nguyen * @param: The device state 322147a1685fSDinh Nguyen * 322247a1685fSDinh Nguyen * Read the USB core HW configuration registers 322347a1685fSDinh Nguyen */ 3224c6f5c050SMian Yousaf Kaukab static int s3c_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) 322547a1685fSDinh Nguyen { 3226c6f5c050SMian Yousaf Kaukab u32 cfg; 3227c6f5c050SMian Yousaf Kaukab u32 ep_type; 3228c6f5c050SMian Yousaf Kaukab u32 i; 3229c6f5c050SMian Yousaf Kaukab 323047a1685fSDinh Nguyen /* check hardware configuration */ 323147a1685fSDinh Nguyen 3232c6f5c050SMian Yousaf Kaukab cfg = readl(hsotg->regs + GHWCFG2); 3233c6f5c050SMian Yousaf Kaukab hsotg->num_of_eps = (cfg >> 10) & 0xF; 3234c6f5c050SMian Yousaf Kaukab /* Add ep0 */ 3235c6f5c050SMian Yousaf Kaukab hsotg->num_of_eps++; 323647a1685fSDinh Nguyen 3237c6f5c050SMian Yousaf Kaukab hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, sizeof(struct s3c_hsotg_ep), 3238c6f5c050SMian Yousaf Kaukab GFP_KERNEL); 3239c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_in[0]) 3240c6f5c050SMian Yousaf Kaukab return -ENOMEM; 3241c6f5c050SMian Yousaf Kaukab /* Same s3c_hsotg_ep is used in both directions for ep0 */ 3242c6f5c050SMian Yousaf Kaukab hsotg->eps_out[0] = hsotg->eps_in[0]; 324347a1685fSDinh Nguyen 3244c6f5c050SMian Yousaf Kaukab cfg = readl(hsotg->regs + GHWCFG1); 3245c6f5c050SMian Yousaf Kaukab for (i = 1; i < hsotg->num_of_eps; i++, cfg >>= 2) { 3246c6f5c050SMian Yousaf Kaukab ep_type = cfg & 3; 3247c6f5c050SMian Yousaf Kaukab /* Direction in or both */ 3248c6f5c050SMian Yousaf Kaukab if (!(ep_type & 2)) { 3249c6f5c050SMian Yousaf Kaukab hsotg->eps_in[i] = devm_kzalloc(hsotg->dev, 3250c6f5c050SMian Yousaf Kaukab sizeof(struct s3c_hsotg_ep), GFP_KERNEL); 3251c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_in[i]) 3252c6f5c050SMian Yousaf Kaukab return -ENOMEM; 3253c6f5c050SMian Yousaf Kaukab } 3254c6f5c050SMian Yousaf Kaukab /* Direction out or both */ 3255c6f5c050SMian Yousaf Kaukab if (!(ep_type & 1)) { 3256c6f5c050SMian Yousaf Kaukab hsotg->eps_out[i] = devm_kzalloc(hsotg->dev, 3257c6f5c050SMian Yousaf Kaukab sizeof(struct s3c_hsotg_ep), GFP_KERNEL); 3258c6f5c050SMian Yousaf Kaukab if (!hsotg->eps_out[i]) 3259c6f5c050SMian Yousaf Kaukab return -ENOMEM; 3260c6f5c050SMian Yousaf Kaukab } 3261c6f5c050SMian Yousaf Kaukab } 3262c6f5c050SMian Yousaf Kaukab 3263c6f5c050SMian Yousaf Kaukab cfg = readl(hsotg->regs + GHWCFG3); 3264c6f5c050SMian Yousaf Kaukab hsotg->fifo_mem = (cfg >> 16); 3265c6f5c050SMian Yousaf Kaukab 3266c6f5c050SMian Yousaf Kaukab cfg = readl(hsotg->regs + GHWCFG4); 3267c6f5c050SMian Yousaf Kaukab hsotg->dedicated_fifos = (cfg >> 25) & 1; 326847a1685fSDinh Nguyen 3269cff9eb75SMarek Szyprowski dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n", 3270cff9eb75SMarek Szyprowski hsotg->num_of_eps, 3271cff9eb75SMarek Szyprowski hsotg->dedicated_fifos ? "dedicated" : "shared", 3272cff9eb75SMarek Szyprowski hsotg->fifo_mem); 3273c6f5c050SMian Yousaf Kaukab return 0; 327447a1685fSDinh Nguyen } 327547a1685fSDinh Nguyen 327647a1685fSDinh Nguyen /** 327747a1685fSDinh Nguyen * s3c_hsotg_dump - dump state of the udc 327847a1685fSDinh Nguyen * @param: The device state 327947a1685fSDinh Nguyen */ 3280941fcce4SDinh Nguyen static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg) 328147a1685fSDinh Nguyen { 328247a1685fSDinh Nguyen #ifdef DEBUG 328347a1685fSDinh Nguyen struct device *dev = hsotg->dev; 328447a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 328547a1685fSDinh Nguyen u32 val; 328647a1685fSDinh Nguyen int idx; 328747a1685fSDinh Nguyen 328847a1685fSDinh Nguyen dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", 328947a1685fSDinh Nguyen readl(regs + DCFG), readl(regs + DCTL), 329047a1685fSDinh Nguyen readl(regs + DIEPMSK)); 329147a1685fSDinh Nguyen 329247a1685fSDinh Nguyen dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n", 329347a1685fSDinh Nguyen readl(regs + GAHBCFG), readl(regs + 0x44)); 329447a1685fSDinh Nguyen 329547a1685fSDinh Nguyen dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 329647a1685fSDinh Nguyen readl(regs + GRXFSIZ), readl(regs + GNPTXFSIZ)); 329747a1685fSDinh Nguyen 329847a1685fSDinh Nguyen /* show periodic fifo settings */ 329947a1685fSDinh Nguyen 3300364f8e93SMian Yousaf Kaukab for (idx = 1; idx < hsotg->num_of_eps; idx++) { 330147a1685fSDinh Nguyen val = readl(regs + DPTXFSIZN(idx)); 330247a1685fSDinh Nguyen dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, 330347a1685fSDinh Nguyen val >> FIFOSIZE_DEPTH_SHIFT, 330447a1685fSDinh Nguyen val & FIFOSIZE_STARTADDR_MASK); 330547a1685fSDinh Nguyen } 330647a1685fSDinh Nguyen 3307364f8e93SMian Yousaf Kaukab for (idx = 0; idx < hsotg->num_of_eps; idx++) { 330847a1685fSDinh Nguyen dev_info(dev, 330947a1685fSDinh Nguyen "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, 331047a1685fSDinh Nguyen readl(regs + DIEPCTL(idx)), 331147a1685fSDinh Nguyen readl(regs + DIEPTSIZ(idx)), 331247a1685fSDinh Nguyen readl(regs + DIEPDMA(idx))); 331347a1685fSDinh Nguyen 331447a1685fSDinh Nguyen val = readl(regs + DOEPCTL(idx)); 331547a1685fSDinh Nguyen dev_info(dev, 331647a1685fSDinh Nguyen "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", 331747a1685fSDinh Nguyen idx, readl(regs + DOEPCTL(idx)), 331847a1685fSDinh Nguyen readl(regs + DOEPTSIZ(idx)), 331947a1685fSDinh Nguyen readl(regs + DOEPDMA(idx))); 332047a1685fSDinh Nguyen 332147a1685fSDinh Nguyen } 332247a1685fSDinh Nguyen 332347a1685fSDinh Nguyen dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", 332447a1685fSDinh Nguyen readl(regs + DVBUSDIS), readl(regs + DVBUSPULSE)); 332547a1685fSDinh Nguyen #endif 332647a1685fSDinh Nguyen } 332747a1685fSDinh Nguyen 332847a1685fSDinh Nguyen /** 3329*9e14d0a5SGregory Herrero * testmode_write - debugfs: change usb test mode 3330*9e14d0a5SGregory Herrero * @seq: The seq file to write to. 3331*9e14d0a5SGregory Herrero * @v: Unused parameter. 3332*9e14d0a5SGregory Herrero * 3333*9e14d0a5SGregory Herrero * This debugfs entry modify the current usb test mode. 3334*9e14d0a5SGregory Herrero */ 3335*9e14d0a5SGregory Herrero static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t 3336*9e14d0a5SGregory Herrero count, loff_t *ppos) 3337*9e14d0a5SGregory Herrero { 3338*9e14d0a5SGregory Herrero struct seq_file *s = file->private_data; 3339*9e14d0a5SGregory Herrero struct dwc2_hsotg *hsotg = s->private; 3340*9e14d0a5SGregory Herrero unsigned long flags; 3341*9e14d0a5SGregory Herrero u32 testmode = 0; 3342*9e14d0a5SGregory Herrero char buf[32]; 3343*9e14d0a5SGregory Herrero 3344*9e14d0a5SGregory Herrero if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 3345*9e14d0a5SGregory Herrero return -EFAULT; 3346*9e14d0a5SGregory Herrero 3347*9e14d0a5SGregory Herrero if (!strncmp(buf, "test_j", 6)) 3348*9e14d0a5SGregory Herrero testmode = TEST_J; 3349*9e14d0a5SGregory Herrero else if (!strncmp(buf, "test_k", 6)) 3350*9e14d0a5SGregory Herrero testmode = TEST_K; 3351*9e14d0a5SGregory Herrero else if (!strncmp(buf, "test_se0_nak", 12)) 3352*9e14d0a5SGregory Herrero testmode = TEST_SE0_NAK; 3353*9e14d0a5SGregory Herrero else if (!strncmp(buf, "test_packet", 11)) 3354*9e14d0a5SGregory Herrero testmode = TEST_PACKET; 3355*9e14d0a5SGregory Herrero else if (!strncmp(buf, "test_force_enable", 17)) 3356*9e14d0a5SGregory Herrero testmode = TEST_FORCE_EN; 3357*9e14d0a5SGregory Herrero else 3358*9e14d0a5SGregory Herrero testmode = 0; 3359*9e14d0a5SGregory Herrero 3360*9e14d0a5SGregory Herrero spin_lock_irqsave(&hsotg->lock, flags); 3361*9e14d0a5SGregory Herrero s3c_hsotg_set_test_mode(hsotg, testmode); 3362*9e14d0a5SGregory Herrero spin_unlock_irqrestore(&hsotg->lock, flags); 3363*9e14d0a5SGregory Herrero return count; 3364*9e14d0a5SGregory Herrero } 3365*9e14d0a5SGregory Herrero 3366*9e14d0a5SGregory Herrero /** 3367*9e14d0a5SGregory Herrero * testmode_show - debugfs: show usb test mode state 3368*9e14d0a5SGregory Herrero * @seq: The seq file to write to. 3369*9e14d0a5SGregory Herrero * @v: Unused parameter. 3370*9e14d0a5SGregory Herrero * 3371*9e14d0a5SGregory Herrero * This debugfs entry shows which usb test mode is currently enabled. 3372*9e14d0a5SGregory Herrero */ 3373*9e14d0a5SGregory Herrero static int testmode_show(struct seq_file *s, void *unused) 3374*9e14d0a5SGregory Herrero { 3375*9e14d0a5SGregory Herrero struct dwc2_hsotg *hsotg = s->private; 3376*9e14d0a5SGregory Herrero unsigned long flags; 3377*9e14d0a5SGregory Herrero int dctl; 3378*9e14d0a5SGregory Herrero 3379*9e14d0a5SGregory Herrero spin_lock_irqsave(&hsotg->lock, flags); 3380*9e14d0a5SGregory Herrero dctl = readl(hsotg->regs + DCTL); 3381*9e14d0a5SGregory Herrero dctl &= DCTL_TSTCTL_MASK; 3382*9e14d0a5SGregory Herrero dctl >>= DCTL_TSTCTL_SHIFT; 3383*9e14d0a5SGregory Herrero spin_unlock_irqrestore(&hsotg->lock, flags); 3384*9e14d0a5SGregory Herrero 3385*9e14d0a5SGregory Herrero switch (dctl) { 3386*9e14d0a5SGregory Herrero case 0: 3387*9e14d0a5SGregory Herrero seq_puts(s, "no test\n"); 3388*9e14d0a5SGregory Herrero break; 3389*9e14d0a5SGregory Herrero case TEST_J: 3390*9e14d0a5SGregory Herrero seq_puts(s, "test_j\n"); 3391*9e14d0a5SGregory Herrero break; 3392*9e14d0a5SGregory Herrero case TEST_K: 3393*9e14d0a5SGregory Herrero seq_puts(s, "test_k\n"); 3394*9e14d0a5SGregory Herrero break; 3395*9e14d0a5SGregory Herrero case TEST_SE0_NAK: 3396*9e14d0a5SGregory Herrero seq_puts(s, "test_se0_nak\n"); 3397*9e14d0a5SGregory Herrero break; 3398*9e14d0a5SGregory Herrero case TEST_PACKET: 3399*9e14d0a5SGregory Herrero seq_puts(s, "test_packet\n"); 3400*9e14d0a5SGregory Herrero break; 3401*9e14d0a5SGregory Herrero case TEST_FORCE_EN: 3402*9e14d0a5SGregory Herrero seq_puts(s, "test_force_enable\n"); 3403*9e14d0a5SGregory Herrero break; 3404*9e14d0a5SGregory Herrero default: 3405*9e14d0a5SGregory Herrero seq_printf(s, "UNKNOWN %d\n", dctl); 3406*9e14d0a5SGregory Herrero } 3407*9e14d0a5SGregory Herrero 3408*9e14d0a5SGregory Herrero return 0; 3409*9e14d0a5SGregory Herrero } 3410*9e14d0a5SGregory Herrero 3411*9e14d0a5SGregory Herrero static int testmode_open(struct inode *inode, struct file *file) 3412*9e14d0a5SGregory Herrero { 3413*9e14d0a5SGregory Herrero return single_open(file, testmode_show, inode->i_private); 3414*9e14d0a5SGregory Herrero } 3415*9e14d0a5SGregory Herrero 3416*9e14d0a5SGregory Herrero static const struct file_operations testmode_fops = { 3417*9e14d0a5SGregory Herrero .owner = THIS_MODULE, 3418*9e14d0a5SGregory Herrero .open = testmode_open, 3419*9e14d0a5SGregory Herrero .write = testmode_write, 3420*9e14d0a5SGregory Herrero .read = seq_read, 3421*9e14d0a5SGregory Herrero .llseek = seq_lseek, 3422*9e14d0a5SGregory Herrero .release = single_release, 3423*9e14d0a5SGregory Herrero }; 3424*9e14d0a5SGregory Herrero 3425*9e14d0a5SGregory Herrero /** 342647a1685fSDinh Nguyen * state_show - debugfs: show overall driver and device state. 342747a1685fSDinh Nguyen * @seq: The seq file to write to. 342847a1685fSDinh Nguyen * @v: Unused parameter. 342947a1685fSDinh Nguyen * 343047a1685fSDinh Nguyen * This debugfs entry shows the overall state of the hardware and 343147a1685fSDinh Nguyen * some general information about each of the endpoints available 343247a1685fSDinh Nguyen * to the system. 343347a1685fSDinh Nguyen */ 343447a1685fSDinh Nguyen static int state_show(struct seq_file *seq, void *v) 343547a1685fSDinh Nguyen { 3436941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = seq->private; 343747a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 343847a1685fSDinh Nguyen int idx; 343947a1685fSDinh Nguyen 344047a1685fSDinh Nguyen seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n", 344147a1685fSDinh Nguyen readl(regs + DCFG), 344247a1685fSDinh Nguyen readl(regs + DCTL), 344347a1685fSDinh Nguyen readl(regs + DSTS)); 344447a1685fSDinh Nguyen 344547a1685fSDinh Nguyen seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n", 344647a1685fSDinh Nguyen readl(regs + DIEPMSK), readl(regs + DOEPMSK)); 344747a1685fSDinh Nguyen 344847a1685fSDinh Nguyen seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n", 344947a1685fSDinh Nguyen readl(regs + GINTMSK), 345047a1685fSDinh Nguyen readl(regs + GINTSTS)); 345147a1685fSDinh Nguyen 345247a1685fSDinh Nguyen seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n", 345347a1685fSDinh Nguyen readl(regs + DAINTMSK), 345447a1685fSDinh Nguyen readl(regs + DAINT)); 345547a1685fSDinh Nguyen 345647a1685fSDinh Nguyen seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n", 345747a1685fSDinh Nguyen readl(regs + GNPTXSTS), 345847a1685fSDinh Nguyen readl(regs + GRXSTSR)); 345947a1685fSDinh Nguyen 346047a1685fSDinh Nguyen seq_puts(seq, "\nEndpoint status:\n"); 346147a1685fSDinh Nguyen 3462364f8e93SMian Yousaf Kaukab for (idx = 0; idx < hsotg->num_of_eps; idx++) { 346347a1685fSDinh Nguyen u32 in, out; 346447a1685fSDinh Nguyen 346547a1685fSDinh Nguyen in = readl(regs + DIEPCTL(idx)); 346647a1685fSDinh Nguyen out = readl(regs + DOEPCTL(idx)); 346747a1685fSDinh Nguyen 346847a1685fSDinh Nguyen seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x", 346947a1685fSDinh Nguyen idx, in, out); 347047a1685fSDinh Nguyen 347147a1685fSDinh Nguyen in = readl(regs + DIEPTSIZ(idx)); 347247a1685fSDinh Nguyen out = readl(regs + DOEPTSIZ(idx)); 347347a1685fSDinh Nguyen 347447a1685fSDinh Nguyen seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x", 347547a1685fSDinh Nguyen in, out); 347647a1685fSDinh Nguyen 347747a1685fSDinh Nguyen seq_puts(seq, "\n"); 347847a1685fSDinh Nguyen } 347947a1685fSDinh Nguyen 348047a1685fSDinh Nguyen return 0; 348147a1685fSDinh Nguyen } 348247a1685fSDinh Nguyen 348347a1685fSDinh Nguyen static int state_open(struct inode *inode, struct file *file) 348447a1685fSDinh Nguyen { 348547a1685fSDinh Nguyen return single_open(file, state_show, inode->i_private); 348647a1685fSDinh Nguyen } 348747a1685fSDinh Nguyen 348847a1685fSDinh Nguyen static const struct file_operations state_fops = { 348947a1685fSDinh Nguyen .owner = THIS_MODULE, 349047a1685fSDinh Nguyen .open = state_open, 349147a1685fSDinh Nguyen .read = seq_read, 349247a1685fSDinh Nguyen .llseek = seq_lseek, 349347a1685fSDinh Nguyen .release = single_release, 349447a1685fSDinh Nguyen }; 349547a1685fSDinh Nguyen 349647a1685fSDinh Nguyen /** 349747a1685fSDinh Nguyen * fifo_show - debugfs: show the fifo information 349847a1685fSDinh Nguyen * @seq: The seq_file to write data to. 349947a1685fSDinh Nguyen * @v: Unused parameter. 350047a1685fSDinh Nguyen * 350147a1685fSDinh Nguyen * Show the FIFO information for the overall fifo and all the 350247a1685fSDinh Nguyen * periodic transmission FIFOs. 350347a1685fSDinh Nguyen */ 350447a1685fSDinh Nguyen static int fifo_show(struct seq_file *seq, void *v) 350547a1685fSDinh Nguyen { 3506941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = seq->private; 350747a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 350847a1685fSDinh Nguyen u32 val; 350947a1685fSDinh Nguyen int idx; 351047a1685fSDinh Nguyen 351147a1685fSDinh Nguyen seq_puts(seq, "Non-periodic FIFOs:\n"); 351247a1685fSDinh Nguyen seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ)); 351347a1685fSDinh Nguyen 351447a1685fSDinh Nguyen val = readl(regs + GNPTXFSIZ); 351547a1685fSDinh Nguyen seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n", 351647a1685fSDinh Nguyen val >> FIFOSIZE_DEPTH_SHIFT, 351747a1685fSDinh Nguyen val & FIFOSIZE_DEPTH_MASK); 351847a1685fSDinh Nguyen 351947a1685fSDinh Nguyen seq_puts(seq, "\nPeriodic TXFIFOs:\n"); 352047a1685fSDinh Nguyen 3521364f8e93SMian Yousaf Kaukab for (idx = 1; idx < hsotg->num_of_eps; idx++) { 352247a1685fSDinh Nguyen val = readl(regs + DPTXFSIZN(idx)); 352347a1685fSDinh Nguyen 352447a1685fSDinh Nguyen seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx, 352547a1685fSDinh Nguyen val >> FIFOSIZE_DEPTH_SHIFT, 352647a1685fSDinh Nguyen val & FIFOSIZE_STARTADDR_MASK); 352747a1685fSDinh Nguyen } 352847a1685fSDinh Nguyen 352947a1685fSDinh Nguyen return 0; 353047a1685fSDinh Nguyen } 353147a1685fSDinh Nguyen 353247a1685fSDinh Nguyen static int fifo_open(struct inode *inode, struct file *file) 353347a1685fSDinh Nguyen { 353447a1685fSDinh Nguyen return single_open(file, fifo_show, inode->i_private); 353547a1685fSDinh Nguyen } 353647a1685fSDinh Nguyen 353747a1685fSDinh Nguyen static const struct file_operations fifo_fops = { 353847a1685fSDinh Nguyen .owner = THIS_MODULE, 353947a1685fSDinh Nguyen .open = fifo_open, 354047a1685fSDinh Nguyen .read = seq_read, 354147a1685fSDinh Nguyen .llseek = seq_lseek, 354247a1685fSDinh Nguyen .release = single_release, 354347a1685fSDinh Nguyen }; 354447a1685fSDinh Nguyen 354547a1685fSDinh Nguyen 354647a1685fSDinh Nguyen static const char *decode_direction(int is_in) 354747a1685fSDinh Nguyen { 354847a1685fSDinh Nguyen return is_in ? "in" : "out"; 354947a1685fSDinh Nguyen } 355047a1685fSDinh Nguyen 355147a1685fSDinh Nguyen /** 355247a1685fSDinh Nguyen * ep_show - debugfs: show the state of an endpoint. 355347a1685fSDinh Nguyen * @seq: The seq_file to write data to. 355447a1685fSDinh Nguyen * @v: Unused parameter. 355547a1685fSDinh Nguyen * 355647a1685fSDinh Nguyen * This debugfs entry shows the state of the given endpoint (one is 355747a1685fSDinh Nguyen * registered for each available). 355847a1685fSDinh Nguyen */ 355947a1685fSDinh Nguyen static int ep_show(struct seq_file *seq, void *v) 356047a1685fSDinh Nguyen { 356147a1685fSDinh Nguyen struct s3c_hsotg_ep *ep = seq->private; 3562941fcce4SDinh Nguyen struct dwc2_hsotg *hsotg = ep->parent; 356347a1685fSDinh Nguyen struct s3c_hsotg_req *req; 356447a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 356547a1685fSDinh Nguyen int index = ep->index; 356647a1685fSDinh Nguyen int show_limit = 15; 356747a1685fSDinh Nguyen unsigned long flags; 356847a1685fSDinh Nguyen 356947a1685fSDinh Nguyen seq_printf(seq, "Endpoint index %d, named %s, dir %s:\n", 357047a1685fSDinh Nguyen ep->index, ep->ep.name, decode_direction(ep->dir_in)); 357147a1685fSDinh Nguyen 357247a1685fSDinh Nguyen /* first show the register state */ 357347a1685fSDinh Nguyen 357447a1685fSDinh Nguyen seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n", 357547a1685fSDinh Nguyen readl(regs + DIEPCTL(index)), 357647a1685fSDinh Nguyen readl(regs + DOEPCTL(index))); 357747a1685fSDinh Nguyen 357847a1685fSDinh Nguyen seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n", 357947a1685fSDinh Nguyen readl(regs + DIEPDMA(index)), 358047a1685fSDinh Nguyen readl(regs + DOEPDMA(index))); 358147a1685fSDinh Nguyen 358247a1685fSDinh Nguyen seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n", 358347a1685fSDinh Nguyen readl(regs + DIEPINT(index)), 358447a1685fSDinh Nguyen readl(regs + DOEPINT(index))); 358547a1685fSDinh Nguyen 358647a1685fSDinh Nguyen seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n", 358747a1685fSDinh Nguyen readl(regs + DIEPTSIZ(index)), 358847a1685fSDinh Nguyen readl(regs + DOEPTSIZ(index))); 358947a1685fSDinh Nguyen 359047a1685fSDinh Nguyen seq_puts(seq, "\n"); 359147a1685fSDinh Nguyen seq_printf(seq, "mps %d\n", ep->ep.maxpacket); 359247a1685fSDinh Nguyen seq_printf(seq, "total_data=%ld\n", ep->total_data); 359347a1685fSDinh Nguyen 359447a1685fSDinh Nguyen seq_printf(seq, "request list (%p,%p):\n", 359547a1685fSDinh Nguyen ep->queue.next, ep->queue.prev); 359647a1685fSDinh Nguyen 359747a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 359847a1685fSDinh Nguyen 359947a1685fSDinh Nguyen list_for_each_entry(req, &ep->queue, queue) { 360047a1685fSDinh Nguyen if (--show_limit < 0) { 360147a1685fSDinh Nguyen seq_puts(seq, "not showing more requests...\n"); 360247a1685fSDinh Nguyen break; 360347a1685fSDinh Nguyen } 360447a1685fSDinh Nguyen 360547a1685fSDinh Nguyen seq_printf(seq, "%c req %p: %d bytes @%p, ", 360647a1685fSDinh Nguyen req == ep->req ? '*' : ' ', 360747a1685fSDinh Nguyen req, req->req.length, req->req.buf); 360847a1685fSDinh Nguyen seq_printf(seq, "%d done, res %d\n", 360947a1685fSDinh Nguyen req->req.actual, req->req.status); 361047a1685fSDinh Nguyen } 361147a1685fSDinh Nguyen 361247a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 361347a1685fSDinh Nguyen 361447a1685fSDinh Nguyen return 0; 361547a1685fSDinh Nguyen } 361647a1685fSDinh Nguyen 361747a1685fSDinh Nguyen static int ep_open(struct inode *inode, struct file *file) 361847a1685fSDinh Nguyen { 361947a1685fSDinh Nguyen return single_open(file, ep_show, inode->i_private); 362047a1685fSDinh Nguyen } 362147a1685fSDinh Nguyen 362247a1685fSDinh Nguyen static const struct file_operations ep_fops = { 362347a1685fSDinh Nguyen .owner = THIS_MODULE, 362447a1685fSDinh Nguyen .open = ep_open, 362547a1685fSDinh Nguyen .read = seq_read, 362647a1685fSDinh Nguyen .llseek = seq_lseek, 362747a1685fSDinh Nguyen .release = single_release, 362847a1685fSDinh Nguyen }; 362947a1685fSDinh Nguyen 363047a1685fSDinh Nguyen /** 363147a1685fSDinh Nguyen * s3c_hsotg_create_debug - create debugfs directory and files 363247a1685fSDinh Nguyen * @hsotg: The driver state 363347a1685fSDinh Nguyen * 363447a1685fSDinh Nguyen * Create the debugfs files to allow the user to get information 363547a1685fSDinh Nguyen * about the state of the system. The directory name is created 363647a1685fSDinh Nguyen * with the same name as the device itself, in case we end up 363747a1685fSDinh Nguyen * with multiple blocks in future systems. 363847a1685fSDinh Nguyen */ 3639941fcce4SDinh Nguyen static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg) 364047a1685fSDinh Nguyen { 364147a1685fSDinh Nguyen struct dentry *root; 364247a1685fSDinh Nguyen unsigned epidx; 364347a1685fSDinh Nguyen 364447a1685fSDinh Nguyen root = debugfs_create_dir(dev_name(hsotg->dev), NULL); 364547a1685fSDinh Nguyen hsotg->debug_root = root; 364647a1685fSDinh Nguyen if (IS_ERR(root)) { 364747a1685fSDinh Nguyen dev_err(hsotg->dev, "cannot create debug root\n"); 364847a1685fSDinh Nguyen return; 364947a1685fSDinh Nguyen } 365047a1685fSDinh Nguyen 365147a1685fSDinh Nguyen /* create general state file */ 365247a1685fSDinh Nguyen 365347a1685fSDinh Nguyen hsotg->debug_file = debugfs_create_file("state", 0444, root, 365447a1685fSDinh Nguyen hsotg, &state_fops); 365547a1685fSDinh Nguyen 365647a1685fSDinh Nguyen if (IS_ERR(hsotg->debug_file)) 365747a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to create state\n", __func__); 365847a1685fSDinh Nguyen 3659*9e14d0a5SGregory Herrero hsotg->debug_testmode = debugfs_create_file("testmode", 3660*9e14d0a5SGregory Herrero S_IRUGO | S_IWUSR, root, 3661*9e14d0a5SGregory Herrero hsotg, &testmode_fops); 3662*9e14d0a5SGregory Herrero 3663*9e14d0a5SGregory Herrero if (IS_ERR(hsotg->debug_testmode)) 3664*9e14d0a5SGregory Herrero dev_err(hsotg->dev, "%s: failed to create testmode\n", 3665*9e14d0a5SGregory Herrero __func__); 3666*9e14d0a5SGregory Herrero 366747a1685fSDinh Nguyen hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root, 366847a1685fSDinh Nguyen hsotg, &fifo_fops); 366947a1685fSDinh Nguyen 367047a1685fSDinh Nguyen if (IS_ERR(hsotg->debug_fifo)) 367147a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__); 367247a1685fSDinh Nguyen 3673c6f5c050SMian Yousaf Kaukab /* Create one file for each out endpoint */ 367447a1685fSDinh Nguyen for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { 3675c6f5c050SMian Yousaf Kaukab struct s3c_hsotg_ep *ep; 367647a1685fSDinh Nguyen 3677c6f5c050SMian Yousaf Kaukab ep = hsotg->eps_out[epidx]; 3678c6f5c050SMian Yousaf Kaukab if (ep) { 367947a1685fSDinh Nguyen ep->debugfs = debugfs_create_file(ep->name, 0444, 368047a1685fSDinh Nguyen root, ep, &ep_fops); 368147a1685fSDinh Nguyen 368247a1685fSDinh Nguyen if (IS_ERR(ep->debugfs)) 368347a1685fSDinh Nguyen dev_err(hsotg->dev, "failed to create %s debug file\n", 368447a1685fSDinh Nguyen ep->name); 368547a1685fSDinh Nguyen } 368647a1685fSDinh Nguyen } 3687c6f5c050SMian Yousaf Kaukab /* Create one file for each in endpoint. EP0 is handled with out eps */ 3688c6f5c050SMian Yousaf Kaukab for (epidx = 1; epidx < hsotg->num_of_eps; epidx++) { 3689c6f5c050SMian Yousaf Kaukab struct s3c_hsotg_ep *ep; 3690c6f5c050SMian Yousaf Kaukab 3691c6f5c050SMian Yousaf Kaukab ep = hsotg->eps_in[epidx]; 3692c6f5c050SMian Yousaf Kaukab if (ep) { 3693c6f5c050SMian Yousaf Kaukab ep->debugfs = debugfs_create_file(ep->name, 0444, 3694c6f5c050SMian Yousaf Kaukab root, ep, &ep_fops); 3695c6f5c050SMian Yousaf Kaukab 3696c6f5c050SMian Yousaf Kaukab if (IS_ERR(ep->debugfs)) 3697c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "failed to create %s debug file\n", 3698c6f5c050SMian Yousaf Kaukab ep->name); 3699c6f5c050SMian Yousaf Kaukab } 3700c6f5c050SMian Yousaf Kaukab } 3701c6f5c050SMian Yousaf Kaukab } 370247a1685fSDinh Nguyen 370347a1685fSDinh Nguyen /** 370447a1685fSDinh Nguyen * s3c_hsotg_delete_debug - cleanup debugfs entries 370547a1685fSDinh Nguyen * @hsotg: The driver state 370647a1685fSDinh Nguyen * 370747a1685fSDinh Nguyen * Cleanup (remove) the debugfs files for use on module exit. 370847a1685fSDinh Nguyen */ 3709941fcce4SDinh Nguyen static void s3c_hsotg_delete_debug(struct dwc2_hsotg *hsotg) 371047a1685fSDinh Nguyen { 371147a1685fSDinh Nguyen unsigned epidx; 371247a1685fSDinh Nguyen 371347a1685fSDinh Nguyen for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { 3714c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[epidx]) 3715c6f5c050SMian Yousaf Kaukab debugfs_remove(hsotg->eps_in[epidx]->debugfs); 3716c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[epidx]) 3717c6f5c050SMian Yousaf Kaukab debugfs_remove(hsotg->eps_out[epidx]->debugfs); 371847a1685fSDinh Nguyen } 371947a1685fSDinh Nguyen 372047a1685fSDinh Nguyen debugfs_remove(hsotg->debug_file); 3721*9e14d0a5SGregory Herrero debugfs_remove(hsotg->debug_testmode); 372247a1685fSDinh Nguyen debugfs_remove(hsotg->debug_fifo); 372347a1685fSDinh Nguyen debugfs_remove(hsotg->debug_root); 372447a1685fSDinh Nguyen } 372547a1685fSDinh Nguyen 3726edd74be8SGregory Herrero #ifdef CONFIG_OF 3727edd74be8SGregory Herrero static void s3c_hsotg_of_probe(struct dwc2_hsotg *hsotg) 3728edd74be8SGregory Herrero { 3729edd74be8SGregory Herrero struct device_node *np = hsotg->dev->of_node; 37300a176279SGregory Herrero u32 len = 0; 37310a176279SGregory Herrero u32 i = 0; 3732edd74be8SGregory Herrero 3733edd74be8SGregory Herrero /* Enable dma if requested in device tree */ 3734edd74be8SGregory Herrero hsotg->g_using_dma = of_property_read_bool(np, "g-use-dma"); 37350a176279SGregory Herrero 37360a176279SGregory Herrero /* 37370a176279SGregory Herrero * Register TX periodic fifo size per endpoint. 37380a176279SGregory Herrero * EP0 is excluded since it has no fifo configuration. 37390a176279SGregory Herrero */ 37400a176279SGregory Herrero if (!of_find_property(np, "g-tx-fifo-size", &len)) 37410a176279SGregory Herrero goto rx_fifo; 37420a176279SGregory Herrero 37430a176279SGregory Herrero len /= sizeof(u32); 37440a176279SGregory Herrero 37450a176279SGregory Herrero /* Read tx fifo sizes other than ep0 */ 37460a176279SGregory Herrero if (of_property_read_u32_array(np, "g-tx-fifo-size", 37470a176279SGregory Herrero &hsotg->g_tx_fifo_sz[1], len)) 37480a176279SGregory Herrero goto rx_fifo; 37490a176279SGregory Herrero 37500a176279SGregory Herrero /* Add ep0 */ 37510a176279SGregory Herrero len++; 37520a176279SGregory Herrero 37530a176279SGregory Herrero /* Make remaining TX fifos unavailable */ 37540a176279SGregory Herrero if (len < MAX_EPS_CHANNELS) { 37550a176279SGregory Herrero for (i = len; i < MAX_EPS_CHANNELS; i++) 37560a176279SGregory Herrero hsotg->g_tx_fifo_sz[i] = 0; 37570a176279SGregory Herrero } 37580a176279SGregory Herrero 37590a176279SGregory Herrero rx_fifo: 37600a176279SGregory Herrero /* Register RX fifo size */ 37610a176279SGregory Herrero of_property_read_u32(np, "g-rx-fifo-size", &hsotg->g_rx_fifo_sz); 37620a176279SGregory Herrero 37630a176279SGregory Herrero /* Register NPTX fifo size */ 37640a176279SGregory Herrero of_property_read_u32(np, "g-np-tx-fifo-size", 37650a176279SGregory Herrero &hsotg->g_np_g_tx_fifo_sz); 3766edd74be8SGregory Herrero } 3767edd74be8SGregory Herrero #else 3768edd74be8SGregory Herrero static inline void s3c_hsotg_of_probe(struct dwc2_hsotg *hsotg) { } 3769edd74be8SGregory Herrero #endif 3770edd74be8SGregory Herrero 377147a1685fSDinh Nguyen /** 3772117777b2SDinh Nguyen * dwc2_gadget_init - init function for gadget 3773117777b2SDinh Nguyen * @dwc2: The data structure for the DWC2 driver. 3774117777b2SDinh Nguyen * @irq: The IRQ number for the controller. 377547a1685fSDinh Nguyen */ 3776117777b2SDinh Nguyen int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) 377747a1685fSDinh Nguyen { 3778117777b2SDinh Nguyen struct device *dev = hsotg->dev; 3779117777b2SDinh Nguyen struct s3c_hsotg_plat *plat = dev->platform_data; 378047a1685fSDinh Nguyen int epnum; 378147a1685fSDinh Nguyen int ret; 378247a1685fSDinh Nguyen int i; 37830a176279SGregory Herrero u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE; 378447a1685fSDinh Nguyen 37851b59fc7eSKamil Debski /* Set default UTMI width */ 37861b59fc7eSKamil Debski hsotg->phyif = GUSBCFG_PHYIF16; 37871b59fc7eSKamil Debski 3788edd74be8SGregory Herrero s3c_hsotg_of_probe(hsotg); 3789edd74be8SGregory Herrero 37900a176279SGregory Herrero /* Initialize to legacy fifo configuration values */ 37910a176279SGregory Herrero hsotg->g_rx_fifo_sz = 2048; 37920a176279SGregory Herrero hsotg->g_np_g_tx_fifo_sz = 1024; 37930a176279SGregory Herrero memcpy(&hsotg->g_tx_fifo_sz[1], p_tx_fifo, sizeof(p_tx_fifo)); 37940a176279SGregory Herrero /* Device tree specific probe */ 37950a176279SGregory Herrero s3c_hsotg_of_probe(hsotg); 37960a176279SGregory Herrero /* Dump fifo information */ 37970a176279SGregory Herrero dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n", 37980a176279SGregory Herrero hsotg->g_np_g_tx_fifo_sz); 37990a176279SGregory Herrero dev_dbg(dev, "RXFIFO size: %d\n", hsotg->g_rx_fifo_sz); 38000a176279SGregory Herrero for (i = 0; i < MAX_EPS_CHANNELS; i++) 38010a176279SGregory Herrero dev_dbg(dev, "Periodic TXFIFO%2d size: %d\n", i, 38020a176279SGregory Herrero hsotg->g_tx_fifo_sz[i]); 380347a1685fSDinh Nguyen /* 3804135b3c43SYunzhi Li * If platform probe couldn't find a generic PHY or an old style 3805135b3c43SYunzhi Li * USB PHY, fall back to pdata 380647a1685fSDinh Nguyen */ 3807135b3c43SYunzhi Li if (IS_ERR_OR_NULL(hsotg->phy) && IS_ERR_OR_NULL(hsotg->uphy)) { 3808117777b2SDinh Nguyen plat = dev_get_platdata(dev); 380947a1685fSDinh Nguyen if (!plat) { 3810117777b2SDinh Nguyen dev_err(dev, 381147a1685fSDinh Nguyen "no platform data or transceiver defined\n"); 381247a1685fSDinh Nguyen return -EPROBE_DEFER; 381347a1685fSDinh Nguyen } 381447a1685fSDinh Nguyen hsotg->plat = plat; 3815135b3c43SYunzhi Li } else if (hsotg->phy) { 38161b59fc7eSKamil Debski /* 38171b59fc7eSKamil Debski * If using the generic PHY framework, check if the PHY bus 38181b59fc7eSKamil Debski * width is 8-bit and set the phyif appropriately. 38191b59fc7eSKamil Debski */ 3820135b3c43SYunzhi Li if (phy_get_bus_width(hsotg->phy) == 8) 38211b59fc7eSKamil Debski hsotg->phyif = GUSBCFG_PHYIF8; 38221b59fc7eSKamil Debski } 382347a1685fSDinh Nguyen 3824117777b2SDinh Nguyen hsotg->clk = devm_clk_get(dev, "otg"); 382547a1685fSDinh Nguyen if (IS_ERR(hsotg->clk)) { 38268d736d8aSDinh Nguyen hsotg->clk = NULL; 3827f415fbd1SDinh Nguyen dev_dbg(dev, "cannot get otg clock\n"); 382847a1685fSDinh Nguyen } 382947a1685fSDinh Nguyen 383047a1685fSDinh Nguyen hsotg->gadget.max_speed = USB_SPEED_HIGH; 383147a1685fSDinh Nguyen hsotg->gadget.ops = &s3c_hsotg_gadget_ops; 383247a1685fSDinh Nguyen hsotg->gadget.name = dev_name(dev); 383347a1685fSDinh Nguyen 383447a1685fSDinh Nguyen /* reset the system */ 383547a1685fSDinh Nguyen 3836f415fbd1SDinh Nguyen ret = clk_prepare_enable(hsotg->clk); 3837f415fbd1SDinh Nguyen if (ret) { 3838f415fbd1SDinh Nguyen dev_err(dev, "failed to enable otg clk\n"); 3839f415fbd1SDinh Nguyen goto err_clk; 3840f415fbd1SDinh Nguyen } 3841f415fbd1SDinh Nguyen 384247a1685fSDinh Nguyen 384347a1685fSDinh Nguyen /* regulators */ 384447a1685fSDinh Nguyen 384547a1685fSDinh Nguyen for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) 384647a1685fSDinh Nguyen hsotg->supplies[i].supply = s3c_hsotg_supply_names[i]; 384747a1685fSDinh Nguyen 384847a1685fSDinh Nguyen ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies), 384947a1685fSDinh Nguyen hsotg->supplies); 385047a1685fSDinh Nguyen if (ret) { 385147a1685fSDinh Nguyen dev_err(dev, "failed to request supplies: %d\n", ret); 385247a1685fSDinh Nguyen goto err_clk; 385347a1685fSDinh Nguyen } 385447a1685fSDinh Nguyen 385547a1685fSDinh Nguyen ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), 385647a1685fSDinh Nguyen hsotg->supplies); 385747a1685fSDinh Nguyen 385847a1685fSDinh Nguyen if (ret) { 3859941fcce4SDinh Nguyen dev_err(dev, "failed to enable supplies: %d\n", ret); 3860c139ec27SMian Yousaf Kaukab goto err_clk; 386147a1685fSDinh Nguyen } 386247a1685fSDinh Nguyen 386347a1685fSDinh Nguyen /* usb phy enable */ 386447a1685fSDinh Nguyen s3c_hsotg_phy_enable(hsotg); 386547a1685fSDinh Nguyen 38661b7a66b4SGregory Herrero /* 38671b7a66b4SGregory Herrero * Force Device mode before initialization. 38681b7a66b4SGregory Herrero * This allows correctly configuring fifo for device mode. 38691b7a66b4SGregory Herrero */ 38701b7a66b4SGregory Herrero __bic32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEHOSTMODE); 38711b7a66b4SGregory Herrero __orr32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEDEVMODE); 38721b7a66b4SGregory Herrero 38731b7a66b4SGregory Herrero /* 38741b7a66b4SGregory Herrero * According to Synopsys databook, this sleep is needed for the force 38751b7a66b4SGregory Herrero * device mode to take effect. 38761b7a66b4SGregory Herrero */ 38771b7a66b4SGregory Herrero msleep(25); 38781b7a66b4SGregory Herrero 387947a1685fSDinh Nguyen s3c_hsotg_corereset(hsotg); 3880c6f5c050SMian Yousaf Kaukab ret = s3c_hsotg_hw_cfg(hsotg); 3881c6f5c050SMian Yousaf Kaukab if (ret) { 3882c6f5c050SMian Yousaf Kaukab dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret); 3883c6f5c050SMian Yousaf Kaukab goto err_clk; 3884c6f5c050SMian Yousaf Kaukab } 3885c6f5c050SMian Yousaf Kaukab 3886cff9eb75SMarek Szyprowski s3c_hsotg_init(hsotg); 388747a1685fSDinh Nguyen 38881b7a66b4SGregory Herrero /* Switch back to default configuration */ 38891b7a66b4SGregory Herrero __bic32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEDEVMODE); 38901b7a66b4SGregory Herrero 38913f95001dSMian Yousaf Kaukab hsotg->ctrl_buff = devm_kzalloc(hsotg->dev, 38923f95001dSMian Yousaf Kaukab DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 38933f95001dSMian Yousaf Kaukab if (!hsotg->ctrl_buff) { 38943f95001dSMian Yousaf Kaukab dev_err(dev, "failed to allocate ctrl request buff\n"); 38953f95001dSMian Yousaf Kaukab ret = -ENOMEM; 38963f95001dSMian Yousaf Kaukab goto err_supplies; 38973f95001dSMian Yousaf Kaukab } 38983f95001dSMian Yousaf Kaukab 38993f95001dSMian Yousaf Kaukab hsotg->ep0_buff = devm_kzalloc(hsotg->dev, 39003f95001dSMian Yousaf Kaukab DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 39013f95001dSMian Yousaf Kaukab if (!hsotg->ep0_buff) { 39023f95001dSMian Yousaf Kaukab dev_err(dev, "failed to allocate ctrl reply buff\n"); 39033f95001dSMian Yousaf Kaukab ret = -ENOMEM; 39043f95001dSMian Yousaf Kaukab goto err_supplies; 39053f95001dSMian Yousaf Kaukab } 39063f95001dSMian Yousaf Kaukab 3907db8178c3SDinh Nguyen ret = devm_request_irq(hsotg->dev, irq, s3c_hsotg_irq, IRQF_SHARED, 3908db8178c3SDinh Nguyen dev_name(hsotg->dev), hsotg); 3909eb3c56c5SMarek Szyprowski if (ret < 0) { 3910eb3c56c5SMarek Szyprowski s3c_hsotg_phy_disable(hsotg); 3911eb3c56c5SMarek Szyprowski clk_disable_unprepare(hsotg->clk); 3912eb3c56c5SMarek Szyprowski regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), 3913eb3c56c5SMarek Szyprowski hsotg->supplies); 3914db8178c3SDinh Nguyen dev_err(dev, "cannot claim IRQ for gadget\n"); 3915c139ec27SMian Yousaf Kaukab goto err_supplies; 3916eb3c56c5SMarek Szyprowski } 3917eb3c56c5SMarek Szyprowski 391847a1685fSDinh Nguyen /* hsotg->num_of_eps holds number of EPs other than ep0 */ 391947a1685fSDinh Nguyen 392047a1685fSDinh Nguyen if (hsotg->num_of_eps == 0) { 392147a1685fSDinh Nguyen dev_err(dev, "wrong number of EPs (zero)\n"); 392247a1685fSDinh Nguyen ret = -EINVAL; 392347a1685fSDinh Nguyen goto err_supplies; 392447a1685fSDinh Nguyen } 392547a1685fSDinh Nguyen 392647a1685fSDinh Nguyen /* setup endpoint information */ 392747a1685fSDinh Nguyen 392847a1685fSDinh Nguyen INIT_LIST_HEAD(&hsotg->gadget.ep_list); 3929c6f5c050SMian Yousaf Kaukab hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep; 393047a1685fSDinh Nguyen 393147a1685fSDinh Nguyen /* allocate EP0 request */ 393247a1685fSDinh Nguyen 3933c6f5c050SMian Yousaf Kaukab hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep, 393447a1685fSDinh Nguyen GFP_KERNEL); 393547a1685fSDinh Nguyen if (!hsotg->ctrl_req) { 393647a1685fSDinh Nguyen dev_err(dev, "failed to allocate ctrl req\n"); 393747a1685fSDinh Nguyen ret = -ENOMEM; 3938c6f5c050SMian Yousaf Kaukab goto err_supplies; 393947a1685fSDinh Nguyen } 394047a1685fSDinh Nguyen 394147a1685fSDinh Nguyen /* initialise the endpoints now the core has been initialised */ 3942c6f5c050SMian Yousaf Kaukab for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) { 3943c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[epnum]) 3944c6f5c050SMian Yousaf Kaukab s3c_hsotg_initep(hsotg, hsotg->eps_in[epnum], 3945c6f5c050SMian Yousaf Kaukab epnum, 1); 3946c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[epnum]) 3947c6f5c050SMian Yousaf Kaukab s3c_hsotg_initep(hsotg, hsotg->eps_out[epnum], 3948c6f5c050SMian Yousaf Kaukab epnum, 0); 3949c6f5c050SMian Yousaf Kaukab } 395047a1685fSDinh Nguyen 395147a1685fSDinh Nguyen /* disable power and clock */ 39523a8146aaSMarek Szyprowski s3c_hsotg_phy_disable(hsotg); 395347a1685fSDinh Nguyen 395447a1685fSDinh Nguyen ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), 395547a1685fSDinh Nguyen hsotg->supplies); 395647a1685fSDinh Nguyen if (ret) { 3957117777b2SDinh Nguyen dev_err(dev, "failed to disable supplies: %d\n", ret); 3958c6f5c050SMian Yousaf Kaukab goto err_supplies; 395947a1685fSDinh Nguyen } 396047a1685fSDinh Nguyen 3961117777b2SDinh Nguyen ret = usb_add_gadget_udc(dev, &hsotg->gadget); 396247a1685fSDinh Nguyen if (ret) 3963c6f5c050SMian Yousaf Kaukab goto err_supplies; 396447a1685fSDinh Nguyen 396547a1685fSDinh Nguyen s3c_hsotg_create_debug(hsotg); 396647a1685fSDinh Nguyen 396747a1685fSDinh Nguyen s3c_hsotg_dump(hsotg); 396847a1685fSDinh Nguyen 396947a1685fSDinh Nguyen return 0; 397047a1685fSDinh Nguyen 397147a1685fSDinh Nguyen err_supplies: 397247a1685fSDinh Nguyen s3c_hsotg_phy_disable(hsotg); 397347a1685fSDinh Nguyen err_clk: 397447a1685fSDinh Nguyen clk_disable_unprepare(hsotg->clk); 397547a1685fSDinh Nguyen 397647a1685fSDinh Nguyen return ret; 397747a1685fSDinh Nguyen } 3978117777b2SDinh Nguyen EXPORT_SYMBOL_GPL(dwc2_gadget_init); 397947a1685fSDinh Nguyen 398047a1685fSDinh Nguyen /** 398147a1685fSDinh Nguyen * s3c_hsotg_remove - remove function for hsotg driver 398247a1685fSDinh Nguyen * @pdev: The platform information for the driver 398347a1685fSDinh Nguyen */ 3984117777b2SDinh Nguyen int s3c_hsotg_remove(struct dwc2_hsotg *hsotg) 398547a1685fSDinh Nguyen { 398647a1685fSDinh Nguyen usb_del_gadget_udc(&hsotg->gadget); 398747a1685fSDinh Nguyen s3c_hsotg_delete_debug(hsotg); 398847a1685fSDinh Nguyen clk_disable_unprepare(hsotg->clk); 398947a1685fSDinh Nguyen 399047a1685fSDinh Nguyen return 0; 399147a1685fSDinh Nguyen } 3992117777b2SDinh Nguyen EXPORT_SYMBOL_GPL(s3c_hsotg_remove); 399347a1685fSDinh Nguyen 3994117777b2SDinh Nguyen int s3c_hsotg_suspend(struct dwc2_hsotg *hsotg) 399547a1685fSDinh Nguyen { 399647a1685fSDinh Nguyen unsigned long flags; 399747a1685fSDinh Nguyen int ret = 0; 399847a1685fSDinh Nguyen 39997ad8096eSMarek Szyprowski mutex_lock(&hsotg->init_mutex); 40007ad8096eSMarek Szyprowski 4001dc6e69e6SMarek Szyprowski if (hsotg->driver) { 4002dc6e69e6SMarek Szyprowski int ep; 4003dc6e69e6SMarek Szyprowski 400447a1685fSDinh Nguyen dev_info(hsotg->dev, "suspending usb gadget %s\n", 400547a1685fSDinh Nguyen hsotg->driver->driver.name); 400647a1685fSDinh Nguyen 400747a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 4008dc6e69e6SMarek Szyprowski if (hsotg->enabled) 40097b093f77SMarek Szyprowski s3c_hsotg_core_disconnect(hsotg); 401047a1685fSDinh Nguyen s3c_hsotg_disconnect(hsotg); 401147a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 401247a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 401347a1685fSDinh Nguyen 40147b093f77SMarek Szyprowski s3c_hsotg_phy_disable(hsotg); 40157b093f77SMarek Szyprowski 4016c6f5c050SMian Yousaf Kaukab for (ep = 0; ep < hsotg->num_of_eps; ep++) { 4017c6f5c050SMian Yousaf Kaukab if (hsotg->eps_in[ep]) 4018c6f5c050SMian Yousaf Kaukab s3c_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 4019c6f5c050SMian Yousaf Kaukab if (hsotg->eps_out[ep]) 4020c6f5c050SMian Yousaf Kaukab s3c_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 4021c6f5c050SMian Yousaf Kaukab } 402247a1685fSDinh Nguyen 402347a1685fSDinh Nguyen ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), 402447a1685fSDinh Nguyen hsotg->supplies); 4025d00b4142SRobert Baldyga clk_disable(hsotg->clk); 402647a1685fSDinh Nguyen } 402747a1685fSDinh Nguyen 40287ad8096eSMarek Szyprowski mutex_unlock(&hsotg->init_mutex); 40297ad8096eSMarek Szyprowski 403047a1685fSDinh Nguyen return ret; 403147a1685fSDinh Nguyen } 4032117777b2SDinh Nguyen EXPORT_SYMBOL_GPL(s3c_hsotg_suspend); 403347a1685fSDinh Nguyen 4034117777b2SDinh Nguyen int s3c_hsotg_resume(struct dwc2_hsotg *hsotg) 403547a1685fSDinh Nguyen { 403647a1685fSDinh Nguyen unsigned long flags; 403747a1685fSDinh Nguyen int ret = 0; 403847a1685fSDinh Nguyen 40397ad8096eSMarek Szyprowski mutex_lock(&hsotg->init_mutex); 40407ad8096eSMarek Szyprowski 404147a1685fSDinh Nguyen if (hsotg->driver) { 404247a1685fSDinh Nguyen dev_info(hsotg->dev, "resuming usb gadget %s\n", 404347a1685fSDinh Nguyen hsotg->driver->driver.name); 4044d00b4142SRobert Baldyga 4045d00b4142SRobert Baldyga clk_enable(hsotg->clk); 404647a1685fSDinh Nguyen ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), 404747a1685fSDinh Nguyen hsotg->supplies); 404847a1685fSDinh Nguyen 404947a1685fSDinh Nguyen s3c_hsotg_phy_enable(hsotg); 405047a1685fSDinh Nguyen 405147a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 4052ad38dc5dSMarek Szyprowski s3c_hsotg_core_init_disconnected(hsotg); 4053dc6e69e6SMarek Szyprowski if (hsotg->enabled) 4054ad38dc5dSMarek Szyprowski s3c_hsotg_core_connect(hsotg); 405547a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 4056dc6e69e6SMarek Szyprowski } 40577ad8096eSMarek Szyprowski mutex_unlock(&hsotg->init_mutex); 405847a1685fSDinh Nguyen 405947a1685fSDinh Nguyen return ret; 406047a1685fSDinh Nguyen } 4061117777b2SDinh Nguyen EXPORT_SYMBOL_GPL(s3c_hsotg_resume); 4062