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