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