xref: /rk3399_ARM-atf/drivers/st/usb/stm32mp1_usb.c (revision 9a138eb5f29f6747e181a1b3b4199ad57721a3e0)
1*9a138eb5SPatrick Delaunay /*
2*9a138eb5SPatrick Delaunay  * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
3*9a138eb5SPatrick Delaunay  *
4*9a138eb5SPatrick Delaunay  * SPDX-License-Identifier: BSD-3-Clause
5*9a138eb5SPatrick Delaunay  */
6*9a138eb5SPatrick Delaunay 
7*9a138eb5SPatrick Delaunay #include <stdint.h>
8*9a138eb5SPatrick Delaunay 
9*9a138eb5SPatrick Delaunay #include <arch_helpers.h>
10*9a138eb5SPatrick Delaunay #include <common/debug.h>
11*9a138eb5SPatrick Delaunay #include <drivers/delay_timer.h>
12*9a138eb5SPatrick Delaunay #include <drivers/st/stm32mp1_usb.h>
13*9a138eb5SPatrick Delaunay #include <lib/mmio.h>
14*9a138eb5SPatrick Delaunay 
15*9a138eb5SPatrick Delaunay #include <platform_def.h>
16*9a138eb5SPatrick Delaunay 
17*9a138eb5SPatrick Delaunay #define USB_OTG_MODE_DEVICE			0U
18*9a138eb5SPatrick Delaunay #define USB_OTG_MODE_HOST			1U
19*9a138eb5SPatrick Delaunay #define USB_OTG_MODE_DRD			2U
20*9a138eb5SPatrick Delaunay 
21*9a138eb5SPatrick Delaunay #define EP_TYPE_CTRL				0U
22*9a138eb5SPatrick Delaunay #define EP_TYPE_ISOC				1U
23*9a138eb5SPatrick Delaunay #define EP_TYPE_BULK				2U
24*9a138eb5SPatrick Delaunay #define EP_TYPE_INTR				3U
25*9a138eb5SPatrick Delaunay 
26*9a138eb5SPatrick Delaunay #define USBD_FIFO_FLUSH_TIMEOUT_US		1000U
27*9a138eb5SPatrick Delaunay #define EP0_FIFO_SIZE				64U
28*9a138eb5SPatrick Delaunay 
29*9a138eb5SPatrick Delaunay /* OTG registers offsets */
30*9a138eb5SPatrick Delaunay #define OTG_GOTGINT				0x004U
31*9a138eb5SPatrick Delaunay #define OTG_GAHBCFG				0x008U
32*9a138eb5SPatrick Delaunay #define OTG_GUSBCFG				0x00CU
33*9a138eb5SPatrick Delaunay #define OTG_GRSTCTL				0x010U
34*9a138eb5SPatrick Delaunay #define OTG_GINTSTS				0x014U
35*9a138eb5SPatrick Delaunay #define OTG_GINTMSK				0x018U
36*9a138eb5SPatrick Delaunay #define OTG_GRXSTSP				0x020U
37*9a138eb5SPatrick Delaunay #define OTG_GLPMCFG				0x054U
38*9a138eb5SPatrick Delaunay #define OTG_DCFG				0x800U
39*9a138eb5SPatrick Delaunay #define OTG_DCTL				0x804U
40*9a138eb5SPatrick Delaunay #define OTG_DSTS				0x808U
41*9a138eb5SPatrick Delaunay #define OTG_DIEPMSK				0x810U
42*9a138eb5SPatrick Delaunay #define OTG_DOEPMSK				0x814U
43*9a138eb5SPatrick Delaunay #define OTG_DAINT				0x818U
44*9a138eb5SPatrick Delaunay #define OTG_DAINTMSK				0x81CU
45*9a138eb5SPatrick Delaunay #define OTG_DIEPEMPMSK				0x834U
46*9a138eb5SPatrick Delaunay 
47*9a138eb5SPatrick Delaunay /* Definitions for OTG_DIEPx registers */
48*9a138eb5SPatrick Delaunay #define OTG_DIEP_BASE				0x900U
49*9a138eb5SPatrick Delaunay #define OTG_DIEP_SIZE				0x20U
50*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL				0x00U
51*9a138eb5SPatrick Delaunay #define OTG_DIEPINT				0x08U
52*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ				0x10U
53*9a138eb5SPatrick Delaunay #define OTG_DIEPDMA				0x14U
54*9a138eb5SPatrick Delaunay #define OTG_DTXFSTS				0x18U
55*9a138eb5SPatrick Delaunay #define OTG_DIEP_MAX_NB				9U
56*9a138eb5SPatrick Delaunay 
57*9a138eb5SPatrick Delaunay /* Definitions for OTG_DOEPx registers */
58*9a138eb5SPatrick Delaunay #define OTG_DOEP_BASE				0xB00U
59*9a138eb5SPatrick Delaunay #define OTG_DOEP_SIZE				0x20U
60*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL				0x00U
61*9a138eb5SPatrick Delaunay #define OTG_DOEPINT				0x08U
62*9a138eb5SPatrick Delaunay #define OTG_DOEPTSIZ				0x10U
63*9a138eb5SPatrick Delaunay #define OTG_DOEPDMA				0x14U
64*9a138eb5SPatrick Delaunay #define OTG_D0EP_MAX_NB				9U
65*9a138eb5SPatrick Delaunay 
66*9a138eb5SPatrick Delaunay /* Definitions for OTG_DAINT registers */
67*9a138eb5SPatrick Delaunay #define OTG_DAINT_OUT_MASK			GENMASK(31, 16)
68*9a138eb5SPatrick Delaunay #define OTG_DAINT_OUT_SHIFT			16U
69*9a138eb5SPatrick Delaunay #define OTG_DAINT_IN_MASK			GENMASK(15, 0)
70*9a138eb5SPatrick Delaunay #define OTG_DAINT_IN_SHIFT			0U
71*9a138eb5SPatrick Delaunay 
72*9a138eb5SPatrick Delaunay #define OTG_DAINT_EP0_IN			BIT(16)
73*9a138eb5SPatrick Delaunay #define OTG_DAINT_EP0_OUT			BIT(0)
74*9a138eb5SPatrick Delaunay 
75*9a138eb5SPatrick Delaunay /* Definitions for FIFOs */
76*9a138eb5SPatrick Delaunay #define OTG_FIFO_BASE				0x1000U
77*9a138eb5SPatrick Delaunay #define OTG_FIFO_SIZE				0x1000U
78*9a138eb5SPatrick Delaunay 
79*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GOTGINT register */
80*9a138eb5SPatrick Delaunay #define OTG_GOTGINT_SEDET			BIT(2)
81*9a138eb5SPatrick Delaunay 
82*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GAHBCFG register */
83*9a138eb5SPatrick Delaunay #define OTG_GAHBCFG_GINT			BIT(0)
84*9a138eb5SPatrick Delaunay 
85*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GUSBCFG register */
86*9a138eb5SPatrick Delaunay #define OTG_GUSBCFG_TRDT			GENMASK(13, 10)
87*9a138eb5SPatrick Delaunay #define OTG_GUSBCFG_TRDT_SHIFT			10U
88*9a138eb5SPatrick Delaunay 
89*9a138eb5SPatrick Delaunay #define USBD_HS_TRDT_VALUE			9U
90*9a138eb5SPatrick Delaunay 
91*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GRSTCTL register */
92*9a138eb5SPatrick Delaunay #define OTG_GRSTCTL_RXFFLSH			BIT(4)
93*9a138eb5SPatrick Delaunay #define OTG_GRSTCTL_TXFFLSH			BIT(5)
94*9a138eb5SPatrick Delaunay #define OTG_GRSTCTL_TXFNUM_SHIFT		6U
95*9a138eb5SPatrick Delaunay 
96*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GINTSTS register */
97*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_CMOD			BIT(0)
98*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_MMIS			BIT(1)
99*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_OTGINT			BIT(2)
100*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_SOF				BIT(3)
101*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_RXFLVL			BIT(4)
102*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_USBSUSP			BIT(11)
103*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_USBRST			BIT(12)
104*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_ENUMDNE			BIT(13)
105*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_IEPINT			BIT(18)
106*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_OEPINT			BIT(19)
107*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_IISOIXFR			BIT(20)
108*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_IPXFR_INCOMPISOOUT		BIT(21)
109*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_LPMINT			BIT(27)
110*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_SRQINT			BIT(30)
111*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_WKUPINT			BIT(31)
112*9a138eb5SPatrick Delaunay 
113*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GRXSTSP register */
114*9a138eb5SPatrick Delaunay #define OTG_GRXSTSP_EPNUM			GENMASK(3, 0)
115*9a138eb5SPatrick Delaunay #define OTG_GRXSTSP_BCNT			GENMASK(14, 4)
116*9a138eb5SPatrick Delaunay #define OTG_GRXSTSP_BCNT_SHIFT			4U
117*9a138eb5SPatrick Delaunay #define OTG_GRXSTSP_PKTSTS			GENMASK(20, 17)
118*9a138eb5SPatrick Delaunay #define OTG_GRXSTSP_PKTSTS_SHIFT		17U
119*9a138eb5SPatrick Delaunay 
120*9a138eb5SPatrick Delaunay #define STS_GOUT_NAK				1U
121*9a138eb5SPatrick Delaunay #define STS_DATA_UPDT				2U
122*9a138eb5SPatrick Delaunay #define STS_XFER_COMP				3U
123*9a138eb5SPatrick Delaunay #define STS_SETUP_COMP				4U
124*9a138eb5SPatrick Delaunay #define STS_SETUP_UPDT				6U
125*9a138eb5SPatrick Delaunay 
126*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GLPMCFG register */
127*9a138eb5SPatrick Delaunay #define OTG_GLPMCFG_BESL			GENMASK(5, 2)
128*9a138eb5SPatrick Delaunay 
129*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DCFG register */
130*9a138eb5SPatrick Delaunay #define OTG_DCFG_DAD				GENMASK(10, 4)
131*9a138eb5SPatrick Delaunay #define OTG_DCFG_DAD_SHIFT			4U
132*9a138eb5SPatrick Delaunay 
133*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DCTL register */
134*9a138eb5SPatrick Delaunay #define OTG_DCTL_RWUSIG				BIT(0)
135*9a138eb5SPatrick Delaunay #define OTG_DCTL_SDIS				BIT(1)
136*9a138eb5SPatrick Delaunay #define OTG_DCTL_CGINAK				BIT(8)
137*9a138eb5SPatrick Delaunay 
138*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DSTS register */
139*9a138eb5SPatrick Delaunay #define OTG_DSTS_SUSPSTS			BIT(0)
140*9a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_MASK			GENMASK(2, 1)
141*9a138eb5SPatrick Delaunay #define OTG_DSTS_FNSOF0				BIT(8)
142*9a138eb5SPatrick Delaunay 
143*9a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD(val)			((val) << 1)
144*9a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ	OTG_DSTS_ENUMSPD(0U)
145*9a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ	OTG_DSTS_ENUMSPD(1U)
146*9a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_LS_PHY_6MHZ		OTG_DSTS_ENUMSPD(2U)
147*9a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_FS_PHY_48MHZ		OTG_DSTS_ENUMSPD(3U)
148*9a138eb5SPatrick Delaunay 
149*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DIEPMSK register */
150*9a138eb5SPatrick Delaunay #define OTG_DIEPMSK_XFRCM			BIT(0)
151*9a138eb5SPatrick Delaunay #define OTG_DIEPMSK_EPDM			BIT(1)
152*9a138eb5SPatrick Delaunay #define OTG_DIEPMSK_TOM				BIT(3)
153*9a138eb5SPatrick Delaunay 
154*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DOEPMSK register */
155*9a138eb5SPatrick Delaunay #define OTG_DOEPMSK_XFRCM			BIT(0)
156*9a138eb5SPatrick Delaunay #define OTG_DOEPMSK_EPDM			BIT(1)
157*9a138eb5SPatrick Delaunay #define OTG_DOEPMSK_STUPM			BIT(3)
158*9a138eb5SPatrick Delaunay 
159*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DIEPCTLx registers */
160*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_MPSIZ			GENMASK(10, 0)
161*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_STALL			BIT(21)
162*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_CNAK			BIT(26)
163*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_SD0PID_SEVNFRM		BIT(28)
164*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_SODDFRM			BIT(29)
165*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_EPDIS			BIT(30)
166*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_EPENA			BIT(31)
167*9a138eb5SPatrick Delaunay 
168*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DIEPINTx registers */
169*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_XFRC			BIT(0)
170*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_EPDISD			BIT(1)
171*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_TOC				BIT(3)
172*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_ITTXFE			BIT(4)
173*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_INEPNE			BIT(6)
174*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_TXFE			BIT(7)
175*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_TXFE_SHIFT			7U
176*9a138eb5SPatrick Delaunay 
177*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_MASK			(BIT(13) | BIT(11) | GENMASK(9, 0))
178*9a138eb5SPatrick Delaunay 
179*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DIEPTSIZx registers */
180*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_XFRSIZ			GENMASK(18, 0)
181*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_PKTCNT			GENMASK(28, 19)
182*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_PKTCNT_SHIFT		19U
183*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_MCNT_MASK			GENMASK(30, 29)
184*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_MCNT_DATA0			BIT(29)
185*9a138eb5SPatrick Delaunay 
186*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_PKTCNT_1			BIT(19)
187*9a138eb5SPatrick Delaunay 
188*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DTXFSTSx registers */
189*9a138eb5SPatrick Delaunay #define OTG_DTXFSTS_INEPTFSAV			GENMASK(15, 0)
190*9a138eb5SPatrick Delaunay 
191*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DOEPCTLx registers */
192*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL_STALL			BIT(21)
193*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL_CNAK			BIT(26)
194*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL_SD0PID_SEVNFRM		BIT(28) /* other than endpoint 0 */
195*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL_SD1PID_SODDFRM		BIT(29) /* other than endpoint 0 */
196*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL_EPDIS			BIT(30)
197*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL_EPENA			BIT(31)
198*9a138eb5SPatrick Delaunay 
199*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DOEPTSIZx registers */
200*9a138eb5SPatrick Delaunay #define OTG_DOEPTSIZ_XFRSIZ			GENMASK(18, 0)
201*9a138eb5SPatrick Delaunay #define OTG_DOEPTSIZ_PKTCNT			GENMASK(28, 19)
202*9a138eb5SPatrick Delaunay #define OTG_DOEPTSIZ_RXDPID_STUPCNT		GENMASK(30, 29)
203*9a138eb5SPatrick Delaunay 
204*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DOEPINTx registers */
205*9a138eb5SPatrick Delaunay #define OTG_DOEPINT_XFRC			BIT(0)
206*9a138eb5SPatrick Delaunay #define OTG_DOEPINT_STUP			BIT(3)
207*9a138eb5SPatrick Delaunay #define OTG_DOEPINT_OTEPDIS			BIT(4)
208*9a138eb5SPatrick Delaunay 
209*9a138eb5SPatrick Delaunay #define OTG_DOEPINT_MASK			(GENMASK(15, 12) | GENMASK(9, 8) | GENMASK(6, 0))
210*9a138eb5SPatrick Delaunay 
211*9a138eb5SPatrick Delaunay #define EP_NB					15U
212*9a138eb5SPatrick Delaunay #define EP_ALL					0x10U
213*9a138eb5SPatrick Delaunay 
214*9a138eb5SPatrick Delaunay /*
215*9a138eb5SPatrick Delaunay  * Flush TX FIFO.
216*9a138eb5SPatrick Delaunay  * handle: PCD handle.
217*9a138eb5SPatrick Delaunay  * num: FIFO number.
218*9a138eb5SPatrick Delaunay  *	   This parameter can be a value from 1 to 15 or EP_ALL.
219*9a138eb5SPatrick Delaunay  *	   EP_ALL= 0x10 means Flush all TX FIFOs
220*9a138eb5SPatrick Delaunay  * return: USB status.
221*9a138eb5SPatrick Delaunay  */
222*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_flush_tx_fifo(void *handle, uint32_t num)
223*9a138eb5SPatrick Delaunay {
224*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
225*9a138eb5SPatrick Delaunay 	uint64_t timeout = timeout_init_us(USBD_FIFO_FLUSH_TIMEOUT_US);
226*9a138eb5SPatrick Delaunay 
227*9a138eb5SPatrick Delaunay 	mmio_write_32(usb_base_addr + OTG_GRSTCTL,
228*9a138eb5SPatrick Delaunay 		      OTG_GRSTCTL_TXFFLSH | (uint32_t)(num << OTG_GRSTCTL_TXFNUM_SHIFT));
229*9a138eb5SPatrick Delaunay 
230*9a138eb5SPatrick Delaunay 	while ((mmio_read_32(usb_base_addr + OTG_GRSTCTL) &
231*9a138eb5SPatrick Delaunay 		OTG_GRSTCTL_TXFFLSH) == OTG_GRSTCTL_TXFFLSH) {
232*9a138eb5SPatrick Delaunay 		if (timeout_elapsed(timeout)) {
233*9a138eb5SPatrick Delaunay 			return USBD_TIMEOUT;
234*9a138eb5SPatrick Delaunay 		}
235*9a138eb5SPatrick Delaunay 	}
236*9a138eb5SPatrick Delaunay 
237*9a138eb5SPatrick Delaunay 	return USBD_OK;
238*9a138eb5SPatrick Delaunay }
239*9a138eb5SPatrick Delaunay 
240*9a138eb5SPatrick Delaunay /*
241*9a138eb5SPatrick Delaunay  * Flush RX FIFO.
242*9a138eb5SPatrick Delaunay  * handle: PCD handle.
243*9a138eb5SPatrick Delaunay  * return: USB status.
244*9a138eb5SPatrick Delaunay  */
245*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_flush_rx_fifo(void *handle)
246*9a138eb5SPatrick Delaunay {
247*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
248*9a138eb5SPatrick Delaunay 	uint64_t timeout = timeout_init_us(USBD_FIFO_FLUSH_TIMEOUT_US);
249*9a138eb5SPatrick Delaunay 
250*9a138eb5SPatrick Delaunay 	mmio_write_32(usb_base_addr + OTG_GRSTCTL, OTG_GRSTCTL_RXFFLSH);
251*9a138eb5SPatrick Delaunay 
252*9a138eb5SPatrick Delaunay 	while ((mmio_read_32(usb_base_addr + OTG_GRSTCTL) &
253*9a138eb5SPatrick Delaunay 		 OTG_GRSTCTL_RXFFLSH) == OTG_GRSTCTL_RXFFLSH) {
254*9a138eb5SPatrick Delaunay 		if (timeout_elapsed(timeout)) {
255*9a138eb5SPatrick Delaunay 			return USBD_TIMEOUT;
256*9a138eb5SPatrick Delaunay 		}
257*9a138eb5SPatrick Delaunay 	}
258*9a138eb5SPatrick Delaunay 
259*9a138eb5SPatrick Delaunay 	return USBD_OK;
260*9a138eb5SPatrick Delaunay }
261*9a138eb5SPatrick Delaunay 
262*9a138eb5SPatrick Delaunay /*
263*9a138eb5SPatrick Delaunay  * Return the global USB interrupt status.
264*9a138eb5SPatrick Delaunay  * handle: PCD handle.
265*9a138eb5SPatrick Delaunay  * return: Interrupt register value.
266*9a138eb5SPatrick Delaunay  */
267*9a138eb5SPatrick Delaunay static uint32_t usb_dwc2_read_int(void *handle)
268*9a138eb5SPatrick Delaunay {
269*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
270*9a138eb5SPatrick Delaunay 
271*9a138eb5SPatrick Delaunay 	return mmio_read_32(usb_base_addr + OTG_GINTSTS) &
272*9a138eb5SPatrick Delaunay 	       mmio_read_32(usb_base_addr + OTG_GINTMSK);
273*9a138eb5SPatrick Delaunay }
274*9a138eb5SPatrick Delaunay 
275*9a138eb5SPatrick Delaunay /*
276*9a138eb5SPatrick Delaunay  * Return the USB device OUT endpoints interrupt.
277*9a138eb5SPatrick Delaunay  * handle: PCD handle.
278*9a138eb5SPatrick Delaunay  * return: Device OUT endpoint interrupts.
279*9a138eb5SPatrick Delaunay  */
280*9a138eb5SPatrick Delaunay static uint32_t usb_dwc2_all_out_ep_int(void *handle)
281*9a138eb5SPatrick Delaunay {
282*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
283*9a138eb5SPatrick Delaunay 
284*9a138eb5SPatrick Delaunay 	return ((mmio_read_32(usb_base_addr + OTG_DAINT) &
285*9a138eb5SPatrick Delaunay 		 mmio_read_32(usb_base_addr + OTG_DAINTMSK)) &
286*9a138eb5SPatrick Delaunay 		OTG_DAINT_OUT_MASK) >> OTG_DAINT_OUT_SHIFT;
287*9a138eb5SPatrick Delaunay }
288*9a138eb5SPatrick Delaunay 
289*9a138eb5SPatrick Delaunay /*
290*9a138eb5SPatrick Delaunay  * Return the USB device IN endpoints interrupt.
291*9a138eb5SPatrick Delaunay  * handle: PCD handle.
292*9a138eb5SPatrick Delaunay  * return: Device IN endpoint interrupts.
293*9a138eb5SPatrick Delaunay  */
294*9a138eb5SPatrick Delaunay static uint32_t usb_dwc2_all_in_ep_int(void *handle)
295*9a138eb5SPatrick Delaunay {
296*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
297*9a138eb5SPatrick Delaunay 
298*9a138eb5SPatrick Delaunay 	return ((mmio_read_32(usb_base_addr + OTG_DAINT) &
299*9a138eb5SPatrick Delaunay 		 mmio_read_32(usb_base_addr + OTG_DAINTMSK)) &
300*9a138eb5SPatrick Delaunay 		OTG_DAINT_IN_MASK) >> OTG_DAINT_IN_SHIFT;
301*9a138eb5SPatrick Delaunay }
302*9a138eb5SPatrick Delaunay 
303*9a138eb5SPatrick Delaunay /*
304*9a138eb5SPatrick Delaunay  * Return Device OUT EP interrupt register.
305*9a138eb5SPatrick Delaunay  * handle: PCD handle.
306*9a138eb5SPatrick Delaunay  * epnum: Endpoint number.
307*9a138eb5SPatrick Delaunay  *         This parameter can be a value from 0 to 15.
308*9a138eb5SPatrick Delaunay  * return: Device OUT EP Interrupt register.
309*9a138eb5SPatrick Delaunay  */
310*9a138eb5SPatrick Delaunay static uint32_t usb_dwc2_out_ep_int(void *handle, uint8_t epnum)
311*9a138eb5SPatrick Delaunay {
312*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
313*9a138eb5SPatrick Delaunay 
314*9a138eb5SPatrick Delaunay 	return mmio_read_32(usb_base_addr + OTG_DOEP_BASE +
315*9a138eb5SPatrick Delaunay 			    (epnum * OTG_DOEP_SIZE) + OTG_DOEPINT) &
316*9a138eb5SPatrick Delaunay 	       mmio_read_32(usb_base_addr + OTG_DOEPMSK);
317*9a138eb5SPatrick Delaunay }
318*9a138eb5SPatrick Delaunay 
319*9a138eb5SPatrick Delaunay /*
320*9a138eb5SPatrick Delaunay  * Return Device IN EP interrupt register.
321*9a138eb5SPatrick Delaunay  * handle: PCD handle.
322*9a138eb5SPatrick Delaunay  * epnum: Endpoint number.
323*9a138eb5SPatrick Delaunay  *         This parameter can be a value from 0 to 15.
324*9a138eb5SPatrick Delaunay  * return: Device IN EP Interrupt register.
325*9a138eb5SPatrick Delaunay  */
326*9a138eb5SPatrick Delaunay static uint32_t usb_dwc2_in_ep_int(void *handle, uint8_t epnum)
327*9a138eb5SPatrick Delaunay {
328*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
329*9a138eb5SPatrick Delaunay 	uint32_t msk;
330*9a138eb5SPatrick Delaunay 	uint32_t emp;
331*9a138eb5SPatrick Delaunay 
332*9a138eb5SPatrick Delaunay 	msk = mmio_read_32(usb_base_addr + OTG_DIEPMSK);
333*9a138eb5SPatrick Delaunay 	emp = mmio_read_32(usb_base_addr + OTG_DIEPEMPMSK);
334*9a138eb5SPatrick Delaunay 	msk |= ((emp >> epnum) << OTG_DIEPINT_TXFE_SHIFT) & OTG_DIEPINT_TXFE;
335*9a138eb5SPatrick Delaunay 
336*9a138eb5SPatrick Delaunay 	return mmio_read_32(usb_base_addr + OTG_DIEP_BASE +
337*9a138eb5SPatrick Delaunay 			    (epnum * OTG_DIEP_SIZE) + OTG_DIEPINT) & msk;
338*9a138eb5SPatrick Delaunay }
339*9a138eb5SPatrick Delaunay 
340*9a138eb5SPatrick Delaunay /*
341*9a138eb5SPatrick Delaunay  * Return USB core mode.
342*9a138eb5SPatrick Delaunay  * handle: PCD handle.
343*9a138eb5SPatrick Delaunay  * return: Core mode.
344*9a138eb5SPatrick Delaunay  *         This parameter can be 0 (host) or 1 (device).
345*9a138eb5SPatrick Delaunay  */
346*9a138eb5SPatrick Delaunay static uint32_t usb_dwc2_get_mode(void *handle)
347*9a138eb5SPatrick Delaunay {
348*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
349*9a138eb5SPatrick Delaunay 
350*9a138eb5SPatrick Delaunay 	return mmio_read_32(usb_base_addr + OTG_GINTSTS) & OTG_GINTSTS_CMOD;
351*9a138eb5SPatrick Delaunay }
352*9a138eb5SPatrick Delaunay 
353*9a138eb5SPatrick Delaunay /*
354*9a138eb5SPatrick Delaunay  * Activate EP0 for detup transactions.
355*9a138eb5SPatrick Delaunay  * handle: PCD handle.
356*9a138eb5SPatrick Delaunay  * return: USB status.
357*9a138eb5SPatrick Delaunay  */
358*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_activate_setup(void *handle)
359*9a138eb5SPatrick Delaunay {
360*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
361*9a138eb5SPatrick Delaunay 	uintptr_t reg_offset = usb_base_addr + OTG_DIEP_BASE;
362*9a138eb5SPatrick Delaunay 
363*9a138eb5SPatrick Delaunay 	/* Set the MPS of the IN EP based on the enumeration speed */
364*9a138eb5SPatrick Delaunay 	mmio_clrbits_32(reg_offset + OTG_DIEPCTL, OTG_DIEPCTL_MPSIZ);
365*9a138eb5SPatrick Delaunay 
366*9a138eb5SPatrick Delaunay 	if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_ENUMSPD_MASK) ==
367*9a138eb5SPatrick Delaunay 	    OTG_DSTS_ENUMSPD_LS_PHY_6MHZ) {
368*9a138eb5SPatrick Delaunay 		mmio_setbits_32(reg_offset + OTG_DIEPCTL, 3U);
369*9a138eb5SPatrick Delaunay 	}
370*9a138eb5SPatrick Delaunay 
371*9a138eb5SPatrick Delaunay 	mmio_setbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_CGINAK);
372*9a138eb5SPatrick Delaunay 
373*9a138eb5SPatrick Delaunay 	return USBD_OK;
374*9a138eb5SPatrick Delaunay }
375*9a138eb5SPatrick Delaunay 
376*9a138eb5SPatrick Delaunay /*
377*9a138eb5SPatrick Delaunay  * Prepare the EP0 to start the first control setup.
378*9a138eb5SPatrick Delaunay  * handle: Selected device.
379*9a138eb5SPatrick Delaunay  * return: USB status.
380*9a138eb5SPatrick Delaunay  */
381*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_ep0_out_start(void *handle)
382*9a138eb5SPatrick Delaunay {
383*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
384*9a138eb5SPatrick Delaunay 	uintptr_t reg_offset = usb_base_addr + OTG_DIEP_BASE + OTG_DIEPTSIZ;
385*9a138eb5SPatrick Delaunay 	uint32_t reg_value = 0U;
386*9a138eb5SPatrick Delaunay 
387*9a138eb5SPatrick Delaunay 	/* PKTCNT = 1 and XFRSIZ = 24 bytes for endpoint 0 */
388*9a138eb5SPatrick Delaunay 	reg_value |= OTG_DIEPTSIZ_PKTCNT_1;
389*9a138eb5SPatrick Delaunay 	reg_value |= (EP0_FIFO_SIZE & OTG_DIEPTSIZ_XFRSIZ);
390*9a138eb5SPatrick Delaunay 	reg_value |= OTG_DOEPTSIZ_RXDPID_STUPCNT;
391*9a138eb5SPatrick Delaunay 
392*9a138eb5SPatrick Delaunay 	mmio_write_32(reg_offset, reg_value);
393*9a138eb5SPatrick Delaunay 
394*9a138eb5SPatrick Delaunay 	return USBD_OK;
395*9a138eb5SPatrick Delaunay }
396*9a138eb5SPatrick Delaunay 
397*9a138eb5SPatrick Delaunay /*
398*9a138eb5SPatrick Delaunay  * Write a packet into the TX FIFO associated with the EP/channel.
399*9a138eb5SPatrick Delaunay  * handle: Selected device.
400*9a138eb5SPatrick Delaunay  * src: Pointer to source buffer.
401*9a138eb5SPatrick Delaunay  * ch_ep_num: Endpoint or host channel number.
402*9a138eb5SPatrick Delaunay  * len: Number of bytes to write.
403*9a138eb5SPatrick Delaunay  * return: USB status.
404*9a138eb5SPatrick Delaunay  */
405*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_write_packet(void *handle, uint8_t *src,
406*9a138eb5SPatrick Delaunay 					  uint8_t ch_ep_num, uint16_t len)
407*9a138eb5SPatrick Delaunay {
408*9a138eb5SPatrick Delaunay 	uint32_t reg_offset;
409*9a138eb5SPatrick Delaunay 	uint32_t count32b = (len + 3U) / 4U;
410*9a138eb5SPatrick Delaunay 	uint32_t i;
411*9a138eb5SPatrick Delaunay 
412*9a138eb5SPatrick Delaunay 	reg_offset = (uintptr_t)handle + OTG_FIFO_BASE +
413*9a138eb5SPatrick Delaunay 		     (ch_ep_num * OTG_FIFO_SIZE);
414*9a138eb5SPatrick Delaunay 
415*9a138eb5SPatrick Delaunay 	for (i = 0U; i < count32b; i++) {
416*9a138eb5SPatrick Delaunay 		uint32_t src_copy = 0U;
417*9a138eb5SPatrick Delaunay 		uint32_t j;
418*9a138eb5SPatrick Delaunay 
419*9a138eb5SPatrick Delaunay 		/* Data written to FIFO need to be 4 bytes aligned */
420*9a138eb5SPatrick Delaunay 		for (j = 0U; j < 4U; j++) {
421*9a138eb5SPatrick Delaunay 			src_copy += (*(src + j)) << (8U * j);
422*9a138eb5SPatrick Delaunay 		}
423*9a138eb5SPatrick Delaunay 
424*9a138eb5SPatrick Delaunay 		mmio_write_32(reg_offset, src_copy);
425*9a138eb5SPatrick Delaunay 		src += 4U;
426*9a138eb5SPatrick Delaunay 	}
427*9a138eb5SPatrick Delaunay 
428*9a138eb5SPatrick Delaunay 	return USBD_OK;
429*9a138eb5SPatrick Delaunay }
430*9a138eb5SPatrick Delaunay 
431*9a138eb5SPatrick Delaunay /*
432*9a138eb5SPatrick Delaunay  * Read a packet from the RX FIFO associated with the EP/channel.
433*9a138eb5SPatrick Delaunay  * handle: Selected device.
434*9a138eb5SPatrick Delaunay  * dst: Destination pointer.
435*9a138eb5SPatrick Delaunay  * len: Number of bytes to read.
436*9a138eb5SPatrick Delaunay  * return: Pointer to destination buffer.
437*9a138eb5SPatrick Delaunay  */
438*9a138eb5SPatrick Delaunay static void *usb_dwc2_read_packet(void *handle, uint8_t *dest, uint16_t len)
439*9a138eb5SPatrick Delaunay {
440*9a138eb5SPatrick Delaunay 	uint32_t reg_offset;
441*9a138eb5SPatrick Delaunay 	uint32_t count32b = (len + 3U) / 4U;
442*9a138eb5SPatrick Delaunay 	uint32_t i;
443*9a138eb5SPatrick Delaunay 
444*9a138eb5SPatrick Delaunay 	VERBOSE("read packet length %i to 0x%lx\n", len, (uintptr_t)dest);
445*9a138eb5SPatrick Delaunay 
446*9a138eb5SPatrick Delaunay 	reg_offset = (uintptr_t)handle + OTG_FIFO_BASE;
447*9a138eb5SPatrick Delaunay 
448*9a138eb5SPatrick Delaunay 	for (i = 0U; i < count32b; i++) {
449*9a138eb5SPatrick Delaunay 		*(uint32_t *)dest = mmio_read_32(reg_offset);
450*9a138eb5SPatrick Delaunay 		dest += 4U;
451*9a138eb5SPatrick Delaunay 		dsb();
452*9a138eb5SPatrick Delaunay 	}
453*9a138eb5SPatrick Delaunay 
454*9a138eb5SPatrick Delaunay 	return (void *)dest;
455*9a138eb5SPatrick Delaunay }
456*9a138eb5SPatrick Delaunay 
457*9a138eb5SPatrick Delaunay /*
458*9a138eb5SPatrick Delaunay  * Setup and start a transfer over an EP.
459*9a138eb5SPatrick Delaunay  * handle: Selected device
460*9a138eb5SPatrick Delaunay  * ep: Pointer to endpoint structure.
461*9a138eb5SPatrick Delaunay  * return: USB status.
462*9a138eb5SPatrick Delaunay  */
463*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_ep_start_xfer(void *handle, struct usbd_ep *ep)
464*9a138eb5SPatrick Delaunay {
465*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
466*9a138eb5SPatrick Delaunay 	uint32_t reg_offset;
467*9a138eb5SPatrick Delaunay 	uint32_t reg_value;
468*9a138eb5SPatrick Delaunay 	uint32_t clear_value;
469*9a138eb5SPatrick Delaunay 
470*9a138eb5SPatrick Delaunay 	if (ep->is_in) {
471*9a138eb5SPatrick Delaunay 		reg_offset = usb_base_addr + OTG_DIEP_BASE + (ep->num * OTG_DIEP_SIZE);
472*9a138eb5SPatrick Delaunay 		clear_value = OTG_DIEPTSIZ_PKTCNT | OTG_DIEPTSIZ_XFRSIZ;
473*9a138eb5SPatrick Delaunay 		if (ep->xfer_len == 0U) {
474*9a138eb5SPatrick Delaunay 			reg_value = OTG_DIEPTSIZ_PKTCNT_1;
475*9a138eb5SPatrick Delaunay 		} else {
476*9a138eb5SPatrick Delaunay 			/*
477*9a138eb5SPatrick Delaunay 			 * Program the transfer size and packet count
478*9a138eb5SPatrick Delaunay 			 * as follows:
479*9a138eb5SPatrick Delaunay 			 * xfersize = N * maxpacket + short_packet
480*9a138eb5SPatrick Delaunay 			 * pktcnt = N + (short_packet exist ? 1 : 0)
481*9a138eb5SPatrick Delaunay 			 */
482*9a138eb5SPatrick Delaunay 			reg_value = (OTG_DIEPTSIZ_PKTCNT &
483*9a138eb5SPatrick Delaunay 				     (((ep->xfer_len + ep->maxpacket - 1U) /
484*9a138eb5SPatrick Delaunay 				       ep->maxpacket) << OTG_DIEPTSIZ_PKTCNT_SHIFT))
485*9a138eb5SPatrick Delaunay 				    | ep->xfer_len;
486*9a138eb5SPatrick Delaunay 
487*9a138eb5SPatrick Delaunay 			if (ep->type == EP_TYPE_ISOC) {
488*9a138eb5SPatrick Delaunay 				clear_value |= OTG_DIEPTSIZ_MCNT_MASK;
489*9a138eb5SPatrick Delaunay 				reg_value |= OTG_DIEPTSIZ_MCNT_DATA0;
490*9a138eb5SPatrick Delaunay 			}
491*9a138eb5SPatrick Delaunay 		}
492*9a138eb5SPatrick Delaunay 
493*9a138eb5SPatrick Delaunay 		mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ, clear_value, reg_value);
494*9a138eb5SPatrick Delaunay 
495*9a138eb5SPatrick Delaunay 		if ((ep->type != EP_TYPE_ISOC) && (ep->xfer_len > 0U)) {
496*9a138eb5SPatrick Delaunay 			/* Enable the TX FIFO empty interrupt for this EP */
497*9a138eb5SPatrick Delaunay 			mmio_setbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(ep->num));
498*9a138eb5SPatrick Delaunay 		}
499*9a138eb5SPatrick Delaunay 
500*9a138eb5SPatrick Delaunay 		/* EP enable, IN data in FIFO */
501*9a138eb5SPatrick Delaunay 		reg_value = OTG_DIEPCTL_CNAK | OTG_DIEPCTL_EPENA;
502*9a138eb5SPatrick Delaunay 
503*9a138eb5SPatrick Delaunay 		if (ep->type == EP_TYPE_ISOC) {
504*9a138eb5SPatrick Delaunay 			if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_FNSOF0) == 0U) {
505*9a138eb5SPatrick Delaunay 				reg_value |= OTG_DIEPCTL_SODDFRM;
506*9a138eb5SPatrick Delaunay 			} else {
507*9a138eb5SPatrick Delaunay 				reg_value |= OTG_DIEPCTL_SD0PID_SEVNFRM;
508*9a138eb5SPatrick Delaunay 			}
509*9a138eb5SPatrick Delaunay 		}
510*9a138eb5SPatrick Delaunay 
511*9a138eb5SPatrick Delaunay 		mmio_setbits_32(reg_offset + OTG_DIEPCTL, reg_value);
512*9a138eb5SPatrick Delaunay 
513*9a138eb5SPatrick Delaunay 		if (ep->type == EP_TYPE_ISOC) {
514*9a138eb5SPatrick Delaunay 			usb_dwc2_write_packet(handle, ep->xfer_buff, ep->num, ep->xfer_len);
515*9a138eb5SPatrick Delaunay 		}
516*9a138eb5SPatrick Delaunay 	} else {
517*9a138eb5SPatrick Delaunay 		reg_offset = usb_base_addr + OTG_DOEP_BASE + (ep->num * OTG_DOEP_SIZE);
518*9a138eb5SPatrick Delaunay 		/*
519*9a138eb5SPatrick Delaunay 		 * Program the transfer size and packet count as follows:
520*9a138eb5SPatrick Delaunay 		 * pktcnt = N
521*9a138eb5SPatrick Delaunay 		 * xfersize = N * maxpacket
522*9a138eb5SPatrick Delaunay 		 */
523*9a138eb5SPatrick Delaunay 		if (ep->xfer_len == 0U) {
524*9a138eb5SPatrick Delaunay 			reg_value = ep->maxpacket | OTG_DIEPTSIZ_PKTCNT_1;
525*9a138eb5SPatrick Delaunay 		} else {
526*9a138eb5SPatrick Delaunay 			uint16_t pktcnt = (ep->xfer_len + ep->maxpacket - 1U) / ep->maxpacket;
527*9a138eb5SPatrick Delaunay 
528*9a138eb5SPatrick Delaunay 			reg_value = (pktcnt << OTG_DIEPTSIZ_PKTCNT_SHIFT) |
529*9a138eb5SPatrick Delaunay 				    (ep->maxpacket * pktcnt);
530*9a138eb5SPatrick Delaunay 		}
531*9a138eb5SPatrick Delaunay 
532*9a138eb5SPatrick Delaunay 		mmio_clrsetbits_32(reg_offset + OTG_DOEPTSIZ,
533*9a138eb5SPatrick Delaunay 				   OTG_DOEPTSIZ_XFRSIZ & OTG_DOEPTSIZ_PKTCNT,
534*9a138eb5SPatrick Delaunay 				   reg_value);
535*9a138eb5SPatrick Delaunay 
536*9a138eb5SPatrick Delaunay 		/* EP enable */
537*9a138eb5SPatrick Delaunay 		reg_value = OTG_DOEPCTL_CNAK | OTG_DOEPCTL_EPENA;
538*9a138eb5SPatrick Delaunay 
539*9a138eb5SPatrick Delaunay 		if (ep->type == EP_TYPE_ISOC) {
540*9a138eb5SPatrick Delaunay 			if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_FNSOF0) == 0U) {
541*9a138eb5SPatrick Delaunay 				reg_value |= OTG_DOEPCTL_SD1PID_SODDFRM;
542*9a138eb5SPatrick Delaunay 			} else {
543*9a138eb5SPatrick Delaunay 				reg_value |= OTG_DOEPCTL_SD0PID_SEVNFRM;
544*9a138eb5SPatrick Delaunay 			}
545*9a138eb5SPatrick Delaunay 		}
546*9a138eb5SPatrick Delaunay 
547*9a138eb5SPatrick Delaunay 		mmio_setbits_32(reg_offset + OTG_DOEPCTL, reg_value);
548*9a138eb5SPatrick Delaunay 	}
549*9a138eb5SPatrick Delaunay 
550*9a138eb5SPatrick Delaunay 	return USBD_OK;
551*9a138eb5SPatrick Delaunay }
552*9a138eb5SPatrick Delaunay 
553*9a138eb5SPatrick Delaunay /*
554*9a138eb5SPatrick Delaunay  * Setup and start a transfer over the EP0.
555*9a138eb5SPatrick Delaunay  * handle: Selected device.
556*9a138eb5SPatrick Delaunay  * ep: Pointer to endpoint structure.
557*9a138eb5SPatrick Delaunay  * return: USB status.
558*9a138eb5SPatrick Delaunay  */
559*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_ep0_start_xfer(void *handle, struct usbd_ep *ep)
560*9a138eb5SPatrick Delaunay {
561*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
562*9a138eb5SPatrick Delaunay 	uint32_t reg_offset;
563*9a138eb5SPatrick Delaunay 	uint32_t reg_value;
564*9a138eb5SPatrick Delaunay 
565*9a138eb5SPatrick Delaunay 	if (ep->is_in) {
566*9a138eb5SPatrick Delaunay 		reg_offset = usb_base_addr + OTG_DIEP_BASE +
567*9a138eb5SPatrick Delaunay 			     (ep->num * OTG_DIEP_SIZE);
568*9a138eb5SPatrick Delaunay 
569*9a138eb5SPatrick Delaunay 		if (ep->xfer_len == 0U) {
570*9a138eb5SPatrick Delaunay 			reg_value = OTG_DIEPTSIZ_PKTCNT_1;
571*9a138eb5SPatrick Delaunay 		} else {
572*9a138eb5SPatrick Delaunay 			/*
573*9a138eb5SPatrick Delaunay 			 * Program the transfer size and packet count
574*9a138eb5SPatrick Delaunay 			 * as follows:
575*9a138eb5SPatrick Delaunay 			 * xfersize = N * maxpacket + short_packet
576*9a138eb5SPatrick Delaunay 			 * pktcnt = N + (short_packet exist ? 1 : 0)
577*9a138eb5SPatrick Delaunay 			 */
578*9a138eb5SPatrick Delaunay 
579*9a138eb5SPatrick Delaunay 			if (ep->xfer_len > ep->maxpacket) {
580*9a138eb5SPatrick Delaunay 				ep->xfer_len = ep->maxpacket;
581*9a138eb5SPatrick Delaunay 			}
582*9a138eb5SPatrick Delaunay 
583*9a138eb5SPatrick Delaunay 			reg_value = OTG_DIEPTSIZ_PKTCNT_1 | ep->xfer_len;
584*9a138eb5SPatrick Delaunay 		}
585*9a138eb5SPatrick Delaunay 
586*9a138eb5SPatrick Delaunay 		mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ,
587*9a138eb5SPatrick Delaunay 				   OTG_DIEPTSIZ_XFRSIZ | OTG_DIEPTSIZ_PKTCNT,
588*9a138eb5SPatrick Delaunay 				   reg_value);
589*9a138eb5SPatrick Delaunay 
590*9a138eb5SPatrick Delaunay 		/* Enable the TX FIFO empty interrupt for this EP */
591*9a138eb5SPatrick Delaunay 		if (ep->xfer_len > 0U) {
592*9a138eb5SPatrick Delaunay 			mmio_setbits_32(usb_base_addr +	OTG_DIEPEMPMSK,
593*9a138eb5SPatrick Delaunay 					BIT(ep->num));
594*9a138eb5SPatrick Delaunay 		}
595*9a138eb5SPatrick Delaunay 
596*9a138eb5SPatrick Delaunay 		/* EP enable, IN data in FIFO */
597*9a138eb5SPatrick Delaunay 		mmio_setbits_32(reg_offset + OTG_DIEPCTL,
598*9a138eb5SPatrick Delaunay 				OTG_DIEPCTL_CNAK | OTG_DIEPCTL_EPENA);
599*9a138eb5SPatrick Delaunay 	} else {
600*9a138eb5SPatrick Delaunay 		reg_offset = usb_base_addr + OTG_DOEP_BASE +
601*9a138eb5SPatrick Delaunay 			     (ep->num * OTG_DOEP_SIZE);
602*9a138eb5SPatrick Delaunay 
603*9a138eb5SPatrick Delaunay 		/*
604*9a138eb5SPatrick Delaunay 		 * Program the transfer size and packet count as follows:
605*9a138eb5SPatrick Delaunay 		 * pktcnt = N
606*9a138eb5SPatrick Delaunay 		 * xfersize = N * maxpacket
607*9a138eb5SPatrick Delaunay 		 */
608*9a138eb5SPatrick Delaunay 		if (ep->xfer_len > 0U) {
609*9a138eb5SPatrick Delaunay 			ep->xfer_len = ep->maxpacket;
610*9a138eb5SPatrick Delaunay 		}
611*9a138eb5SPatrick Delaunay 
612*9a138eb5SPatrick Delaunay 		reg_value = OTG_DIEPTSIZ_PKTCNT_1 | ep->maxpacket;
613*9a138eb5SPatrick Delaunay 
614*9a138eb5SPatrick Delaunay 		mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ,
615*9a138eb5SPatrick Delaunay 				   OTG_DIEPTSIZ_XFRSIZ | OTG_DIEPTSIZ_PKTCNT,
616*9a138eb5SPatrick Delaunay 				   reg_value);
617*9a138eb5SPatrick Delaunay 
618*9a138eb5SPatrick Delaunay 		/* EP enable */
619*9a138eb5SPatrick Delaunay 		mmio_setbits_32(reg_offset + OTG_DOEPCTL,
620*9a138eb5SPatrick Delaunay 				OTG_DOEPCTL_CNAK | OTG_DOEPCTL_EPENA);
621*9a138eb5SPatrick Delaunay 	}
622*9a138eb5SPatrick Delaunay 
623*9a138eb5SPatrick Delaunay 	return USBD_OK;
624*9a138eb5SPatrick Delaunay }
625*9a138eb5SPatrick Delaunay 
626*9a138eb5SPatrick Delaunay /*
627*9a138eb5SPatrick Delaunay  * Set a stall condition over an EP.
628*9a138eb5SPatrick Delaunay  * handle: Selected device.
629*9a138eb5SPatrick Delaunay  * ep: Pointer to endpoint structure.
630*9a138eb5SPatrick Delaunay  * return: USB status.
631*9a138eb5SPatrick Delaunay  */
632*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_ep_set_stall(void *handle, struct usbd_ep *ep)
633*9a138eb5SPatrick Delaunay {
634*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
635*9a138eb5SPatrick Delaunay 	uint32_t reg_offset;
636*9a138eb5SPatrick Delaunay 	uint32_t reg_value;
637*9a138eb5SPatrick Delaunay 
638*9a138eb5SPatrick Delaunay 	if (ep->is_in) {
639*9a138eb5SPatrick Delaunay 		reg_offset = usb_base_addr + OTG_DIEP_BASE +
640*9a138eb5SPatrick Delaunay 			     (ep->num * OTG_DIEP_SIZE);
641*9a138eb5SPatrick Delaunay 		reg_value = mmio_read_32(reg_offset + OTG_DIEPCTL);
642*9a138eb5SPatrick Delaunay 
643*9a138eb5SPatrick Delaunay 		if ((reg_value & OTG_DIEPCTL_EPENA) == 0U) {
644*9a138eb5SPatrick Delaunay 			reg_value &= ~OTG_DIEPCTL_EPDIS;
645*9a138eb5SPatrick Delaunay 		}
646*9a138eb5SPatrick Delaunay 
647*9a138eb5SPatrick Delaunay 		reg_value |= OTG_DIEPCTL_STALL;
648*9a138eb5SPatrick Delaunay 
649*9a138eb5SPatrick Delaunay 		mmio_write_32(reg_offset + OTG_DIEPCTL, reg_value);
650*9a138eb5SPatrick Delaunay 	} else {
651*9a138eb5SPatrick Delaunay 		reg_offset = usb_base_addr + OTG_DOEP_BASE +
652*9a138eb5SPatrick Delaunay 			     (ep->num * OTG_DOEP_SIZE);
653*9a138eb5SPatrick Delaunay 		reg_value = mmio_read_32(reg_offset + OTG_DOEPCTL);
654*9a138eb5SPatrick Delaunay 
655*9a138eb5SPatrick Delaunay 		if ((reg_value & OTG_DOEPCTL_EPENA) == 0U) {
656*9a138eb5SPatrick Delaunay 			reg_value &= ~OTG_DOEPCTL_EPDIS;
657*9a138eb5SPatrick Delaunay 		}
658*9a138eb5SPatrick Delaunay 
659*9a138eb5SPatrick Delaunay 		reg_value |= OTG_DOEPCTL_STALL;
660*9a138eb5SPatrick Delaunay 
661*9a138eb5SPatrick Delaunay 		mmio_write_32(reg_offset + OTG_DOEPCTL, reg_value);
662*9a138eb5SPatrick Delaunay 	}
663*9a138eb5SPatrick Delaunay 
664*9a138eb5SPatrick Delaunay 	return USBD_OK;
665*9a138eb5SPatrick Delaunay }
666*9a138eb5SPatrick Delaunay 
667*9a138eb5SPatrick Delaunay /*
668*9a138eb5SPatrick Delaunay  * Stop the USB device mode.
669*9a138eb5SPatrick Delaunay  * handle: Selected device.
670*9a138eb5SPatrick Delaunay  * return: USB status.
671*9a138eb5SPatrick Delaunay  */
672*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_stop_device(void *handle)
673*9a138eb5SPatrick Delaunay {
674*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
675*9a138eb5SPatrick Delaunay 	uint32_t i;
676*9a138eb5SPatrick Delaunay 
677*9a138eb5SPatrick Delaunay 	/* Disable Int */
678*9a138eb5SPatrick Delaunay 	mmio_clrbits_32(usb_base_addr + OTG_GAHBCFG, OTG_GAHBCFG_GINT);
679*9a138eb5SPatrick Delaunay 
680*9a138eb5SPatrick Delaunay 	/* Clear pending interrupts */
681*9a138eb5SPatrick Delaunay 	for (i = 0U; i < EP_NB; i++) {
682*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_DIEP_BASE + (i * OTG_DIEP_SIZE) + OTG_DIEPINT,
683*9a138eb5SPatrick Delaunay 			      OTG_DIEPINT_MASK);
684*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_DOEP_BASE + (i * OTG_DOEP_SIZE) + OTG_DOEPINT,
685*9a138eb5SPatrick Delaunay 			      OTG_DOEPINT_MASK);
686*9a138eb5SPatrick Delaunay 	}
687*9a138eb5SPatrick Delaunay 
688*9a138eb5SPatrick Delaunay 	mmio_write_32(usb_base_addr + OTG_DAINT, OTG_DAINT_IN_MASK | OTG_DAINT_OUT_MASK);
689*9a138eb5SPatrick Delaunay 
690*9a138eb5SPatrick Delaunay 	/* Clear interrupt masks */
691*9a138eb5SPatrick Delaunay 	mmio_write_32(usb_base_addr + OTG_DIEPMSK, 0U);
692*9a138eb5SPatrick Delaunay 	mmio_write_32(usb_base_addr + OTG_DOEPMSK, 0U);
693*9a138eb5SPatrick Delaunay 	mmio_write_32(usb_base_addr + OTG_DAINTMSK, 0U);
694*9a138eb5SPatrick Delaunay 
695*9a138eb5SPatrick Delaunay 	/* Flush the FIFO */
696*9a138eb5SPatrick Delaunay 	usb_dwc2_flush_rx_fifo(handle);
697*9a138eb5SPatrick Delaunay 	usb_dwc2_flush_tx_fifo(handle, EP_ALL);
698*9a138eb5SPatrick Delaunay 
699*9a138eb5SPatrick Delaunay 	/* Disconnect the USB device by disabling the pull-up/pull-down */
700*9a138eb5SPatrick Delaunay 	mmio_setbits_32((uintptr_t)handle + OTG_DCTL, OTG_DCTL_SDIS);
701*9a138eb5SPatrick Delaunay 
702*9a138eb5SPatrick Delaunay 	return USBD_OK;
703*9a138eb5SPatrick Delaunay }
704*9a138eb5SPatrick Delaunay 
705*9a138eb5SPatrick Delaunay /*
706*9a138eb5SPatrick Delaunay  * Stop the USB device mode.
707*9a138eb5SPatrick Delaunay  * handle: Selected device.
708*9a138eb5SPatrick Delaunay  * address: New device address to be assigned.
709*9a138eb5SPatrick Delaunay  *         This parameter can be a value from 0 to 255.
710*9a138eb5SPatrick Delaunay  * return: USB status.
711*9a138eb5SPatrick Delaunay  */
712*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_set_address(void *handle, uint8_t address)
713*9a138eb5SPatrick Delaunay {
714*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
715*9a138eb5SPatrick Delaunay 
716*9a138eb5SPatrick Delaunay 	mmio_clrsetbits_32(usb_base_addr + OTG_DCFG,
717*9a138eb5SPatrick Delaunay 			   OTG_DCFG_DAD,
718*9a138eb5SPatrick Delaunay 			   address << OTG_DCFG_DAD_SHIFT);
719*9a138eb5SPatrick Delaunay 
720*9a138eb5SPatrick Delaunay 	return USBD_OK;
721*9a138eb5SPatrick Delaunay }
722*9a138eb5SPatrick Delaunay 
723*9a138eb5SPatrick Delaunay /*
724*9a138eb5SPatrick Delaunay  * Check FIFO for the next packet to be loaded.
725*9a138eb5SPatrick Delaunay  * handle: Selected device.
726*9a138eb5SPatrick Delaunay  * epnum : Endpoint number.
727*9a138eb5SPatrick Delaunay  * xfer_len: Block length.
728*9a138eb5SPatrick Delaunay  * xfer_count: Number of blocks.
729*9a138eb5SPatrick Delaunay  * maxpacket: Max packet length.
730*9a138eb5SPatrick Delaunay  * xfer_buff: Buffer pointer.
731*9a138eb5SPatrick Delaunay  * return: USB status.
732*9a138eb5SPatrick Delaunay  */
733*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_write_empty_tx_fifo(void *handle,
734*9a138eb5SPatrick Delaunay 						    uint32_t epnum,
735*9a138eb5SPatrick Delaunay 						    uint32_t xfer_len,
736*9a138eb5SPatrick Delaunay 						    uint32_t *xfer_count,
737*9a138eb5SPatrick Delaunay 						    uint32_t maxpacket,
738*9a138eb5SPatrick Delaunay 						    uint8_t **xfer_buff)
739*9a138eb5SPatrick Delaunay {
740*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
741*9a138eb5SPatrick Delaunay 	uint32_t reg_offset;
742*9a138eb5SPatrick Delaunay 	int32_t len;
743*9a138eb5SPatrick Delaunay 	uint32_t len32b;
744*9a138eb5SPatrick Delaunay 	enum usb_status ret;
745*9a138eb5SPatrick Delaunay 
746*9a138eb5SPatrick Delaunay 	len = xfer_len - *xfer_count;
747*9a138eb5SPatrick Delaunay 
748*9a138eb5SPatrick Delaunay 	if ((len > 0) && ((uint32_t)len > maxpacket)) {
749*9a138eb5SPatrick Delaunay 		len = maxpacket;
750*9a138eb5SPatrick Delaunay 	}
751*9a138eb5SPatrick Delaunay 
752*9a138eb5SPatrick Delaunay 	len32b = (len + 3U) / 4U;
753*9a138eb5SPatrick Delaunay 
754*9a138eb5SPatrick Delaunay 	reg_offset = usb_base_addr + OTG_DIEP_BASE + (epnum * OTG_DIEP_SIZE);
755*9a138eb5SPatrick Delaunay 
756*9a138eb5SPatrick Delaunay 	while (((mmio_read_32(reg_offset + OTG_DTXFSTS) &
757*9a138eb5SPatrick Delaunay 		OTG_DTXFSTS_INEPTFSAV) > len32b) &&
758*9a138eb5SPatrick Delaunay 	       (*xfer_count < xfer_len) && (xfer_len != 0U)) {
759*9a138eb5SPatrick Delaunay 		/* Write the FIFO */
760*9a138eb5SPatrick Delaunay 		len = xfer_len - *xfer_count;
761*9a138eb5SPatrick Delaunay 
762*9a138eb5SPatrick Delaunay 		if ((len > 0) && ((uint32_t)len > maxpacket)) {
763*9a138eb5SPatrick Delaunay 			len = maxpacket;
764*9a138eb5SPatrick Delaunay 		}
765*9a138eb5SPatrick Delaunay 
766*9a138eb5SPatrick Delaunay 		len32b = (len + 3U) / 4U;
767*9a138eb5SPatrick Delaunay 
768*9a138eb5SPatrick Delaunay 		ret = usb_dwc2_write_packet(handle, *xfer_buff, epnum, len);
769*9a138eb5SPatrick Delaunay 		if (ret != USBD_OK) {
770*9a138eb5SPatrick Delaunay 			return ret;
771*9a138eb5SPatrick Delaunay 		}
772*9a138eb5SPatrick Delaunay 
773*9a138eb5SPatrick Delaunay 		*xfer_buff  += len;
774*9a138eb5SPatrick Delaunay 		*xfer_count += len;
775*9a138eb5SPatrick Delaunay 	}
776*9a138eb5SPatrick Delaunay 
777*9a138eb5SPatrick Delaunay 	if (len <= 0) {
778*9a138eb5SPatrick Delaunay 		mmio_clrbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(epnum));
779*9a138eb5SPatrick Delaunay 	}
780*9a138eb5SPatrick Delaunay 
781*9a138eb5SPatrick Delaunay 	return USBD_OK;
782*9a138eb5SPatrick Delaunay }
783*9a138eb5SPatrick Delaunay 
784*9a138eb5SPatrick Delaunay /*
785*9a138eb5SPatrick Delaunay  * Handle PCD interrupt request.
786*9a138eb5SPatrick Delaunay  * handle: PCD handle.
787*9a138eb5SPatrick Delaunay  * param: Pointer to information updated by the IT handling.
788*9a138eb5SPatrick Delaunay  * return: Action to do after IT handling.
789*9a138eb5SPatrick Delaunay  */
790*9a138eb5SPatrick Delaunay static enum usb_action usb_dwc2_it_handler(void *handle, uint32_t *param)
791*9a138eb5SPatrick Delaunay {
792*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
793*9a138eb5SPatrick Delaunay 	uint32_t ep_intr;
794*9a138eb5SPatrick Delaunay 	uint32_t epint;
795*9a138eb5SPatrick Delaunay 	uint32_t epnum;
796*9a138eb5SPatrick Delaunay 	uint32_t temp;
797*9a138eb5SPatrick Delaunay 	enum usb_status ret;
798*9a138eb5SPatrick Delaunay 
799*9a138eb5SPatrick Delaunay 	if (usb_dwc2_get_mode(handle) != USB_OTG_MODE_DEVICE) {
800*9a138eb5SPatrick Delaunay 		return USB_NOTHING;
801*9a138eb5SPatrick Delaunay 	}
802*9a138eb5SPatrick Delaunay 
803*9a138eb5SPatrick Delaunay 	/* Avoid spurious interrupt */
804*9a138eb5SPatrick Delaunay 	if (usb_dwc2_read_int(handle) == 0U) {
805*9a138eb5SPatrick Delaunay 		return USB_NOTHING;
806*9a138eb5SPatrick Delaunay 	}
807*9a138eb5SPatrick Delaunay 
808*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_MMIS) != 0U) {
809*9a138eb5SPatrick Delaunay 		/* Incorrect mode, acknowledge the interrupt */
810*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_MMIS);
811*9a138eb5SPatrick Delaunay 	}
812*9a138eb5SPatrick Delaunay 
813*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_OEPINT) != 0U) {
814*9a138eb5SPatrick Delaunay 		uint32_t reg_offset;
815*9a138eb5SPatrick Delaunay 
816*9a138eb5SPatrick Delaunay 		/* Read in the device interrupt bits */
817*9a138eb5SPatrick Delaunay 		ep_intr = usb_dwc2_all_out_ep_int(handle);
818*9a138eb5SPatrick Delaunay 		epnum = 0U;
819*9a138eb5SPatrick Delaunay 		while ((ep_intr & BIT(0)) != BIT(0)) {
820*9a138eb5SPatrick Delaunay 			epnum++;
821*9a138eb5SPatrick Delaunay 			ep_intr >>= 1;
822*9a138eb5SPatrick Delaunay 		}
823*9a138eb5SPatrick Delaunay 
824*9a138eb5SPatrick Delaunay 		reg_offset = usb_base_addr + OTG_DOEP_BASE + (epnum * OTG_DOEP_SIZE) + OTG_DOEPINT;
825*9a138eb5SPatrick Delaunay 
826*9a138eb5SPatrick Delaunay 		epint = usb_dwc2_out_ep_int(handle, epnum);
827*9a138eb5SPatrick Delaunay 
828*9a138eb5SPatrick Delaunay 		if ((epint & OTG_DOEPINT_XFRC) == OTG_DOEPINT_XFRC) {
829*9a138eb5SPatrick Delaunay 			mmio_write_32(reg_offset, OTG_DOEPINT_XFRC);
830*9a138eb5SPatrick Delaunay 			*param = epnum;
831*9a138eb5SPatrick Delaunay 
832*9a138eb5SPatrick Delaunay 			return USB_DATA_OUT;
833*9a138eb5SPatrick Delaunay 		}
834*9a138eb5SPatrick Delaunay 
835*9a138eb5SPatrick Delaunay 		if ((epint & OTG_DOEPINT_STUP) == OTG_DOEPINT_STUP) {
836*9a138eb5SPatrick Delaunay 			/* Inform  that a setup packet is available */
837*9a138eb5SPatrick Delaunay 			mmio_write_32(reg_offset, OTG_DOEPINT_STUP);
838*9a138eb5SPatrick Delaunay 
839*9a138eb5SPatrick Delaunay 			return USB_SETUP;
840*9a138eb5SPatrick Delaunay 		}
841*9a138eb5SPatrick Delaunay 
842*9a138eb5SPatrick Delaunay 		if ((epint & OTG_DOEPINT_OTEPDIS) == OTG_DOEPINT_OTEPDIS) {
843*9a138eb5SPatrick Delaunay 			mmio_write_32(reg_offset, OTG_DOEPINT_OTEPDIS);
844*9a138eb5SPatrick Delaunay 		}
845*9a138eb5SPatrick Delaunay 	}
846*9a138eb5SPatrick Delaunay 
847*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IEPINT) != 0U) {
848*9a138eb5SPatrick Delaunay 		uint32_t reg_offset;
849*9a138eb5SPatrick Delaunay 
850*9a138eb5SPatrick Delaunay 		/* Read in the device interrupt bits */
851*9a138eb5SPatrick Delaunay 		ep_intr = usb_dwc2_all_in_ep_int(handle);
852*9a138eb5SPatrick Delaunay 		epnum = 0U;
853*9a138eb5SPatrick Delaunay 		while ((ep_intr & BIT(0)) != BIT(0)) {
854*9a138eb5SPatrick Delaunay 			epnum++;
855*9a138eb5SPatrick Delaunay 			ep_intr >>= 1;
856*9a138eb5SPatrick Delaunay 		}
857*9a138eb5SPatrick Delaunay 
858*9a138eb5SPatrick Delaunay 		reg_offset = usb_base_addr + OTG_DIEP_BASE + (epnum * OTG_DIEP_SIZE) + OTG_DIEPINT;
859*9a138eb5SPatrick Delaunay 
860*9a138eb5SPatrick Delaunay 		epint = usb_dwc2_in_ep_int(handle, epnum);
861*9a138eb5SPatrick Delaunay 
862*9a138eb5SPatrick Delaunay 		if ((epint & OTG_DIEPINT_XFRC) == OTG_DIEPINT_XFRC) {
863*9a138eb5SPatrick Delaunay 			mmio_clrbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(epnum));
864*9a138eb5SPatrick Delaunay 			mmio_write_32(reg_offset, OTG_DIEPINT_XFRC);
865*9a138eb5SPatrick Delaunay 			*param = epnum;
866*9a138eb5SPatrick Delaunay 
867*9a138eb5SPatrick Delaunay 			return USB_DATA_IN;
868*9a138eb5SPatrick Delaunay 		}
869*9a138eb5SPatrick Delaunay 
870*9a138eb5SPatrick Delaunay 		if ((epint & OTG_DIEPINT_TOC) == OTG_DIEPINT_TOC) {
871*9a138eb5SPatrick Delaunay 			mmio_write_32(reg_offset, OTG_DIEPINT_TOC);
872*9a138eb5SPatrick Delaunay 		}
873*9a138eb5SPatrick Delaunay 
874*9a138eb5SPatrick Delaunay 		if ((epint & OTG_DIEPINT_ITTXFE) == OTG_DIEPINT_ITTXFE) {
875*9a138eb5SPatrick Delaunay 			mmio_write_32(reg_offset, OTG_DIEPINT_ITTXFE);
876*9a138eb5SPatrick Delaunay 		}
877*9a138eb5SPatrick Delaunay 
878*9a138eb5SPatrick Delaunay 		if ((epint & OTG_DIEPINT_INEPNE) == OTG_DIEPINT_INEPNE) {
879*9a138eb5SPatrick Delaunay 			mmio_write_32(reg_offset, OTG_DIEPINT_INEPNE);
880*9a138eb5SPatrick Delaunay 		}
881*9a138eb5SPatrick Delaunay 
882*9a138eb5SPatrick Delaunay 		if ((epint & OTG_DIEPINT_EPDISD) == OTG_DIEPINT_EPDISD) {
883*9a138eb5SPatrick Delaunay 			mmio_write_32(reg_offset, OTG_DIEPINT_EPDISD);
884*9a138eb5SPatrick Delaunay 		}
885*9a138eb5SPatrick Delaunay 
886*9a138eb5SPatrick Delaunay 		if ((epint & OTG_DIEPINT_TXFE) == OTG_DIEPINT_TXFE) {
887*9a138eb5SPatrick Delaunay 			*param = epnum;
888*9a138eb5SPatrick Delaunay 
889*9a138eb5SPatrick Delaunay 			return USB_WRITE_EMPTY;
890*9a138eb5SPatrick Delaunay 		}
891*9a138eb5SPatrick Delaunay 	}
892*9a138eb5SPatrick Delaunay 
893*9a138eb5SPatrick Delaunay 	/* Handle resume interrupt */
894*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_WKUPINT) != 0U) {
895*9a138eb5SPatrick Delaunay 		INFO("handle USB : Resume\n");
896*9a138eb5SPatrick Delaunay 
897*9a138eb5SPatrick Delaunay 		/* Clear the remote wake-up signaling */
898*9a138eb5SPatrick Delaunay 		mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_RWUSIG);
899*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_WKUPINT);
900*9a138eb5SPatrick Delaunay 
901*9a138eb5SPatrick Delaunay 		return USB_RESUME;
902*9a138eb5SPatrick Delaunay 	}
903*9a138eb5SPatrick Delaunay 
904*9a138eb5SPatrick Delaunay 	/* Handle suspend interrupt */
905*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_USBSUSP) != 0U) {
906*9a138eb5SPatrick Delaunay 		INFO("handle USB : Suspend int\n");
907*9a138eb5SPatrick Delaunay 
908*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_USBSUSP);
909*9a138eb5SPatrick Delaunay 
910*9a138eb5SPatrick Delaunay 		if ((mmio_read_32(usb_base_addr + OTG_DSTS) &
911*9a138eb5SPatrick Delaunay 		     OTG_DSTS_SUSPSTS) == OTG_DSTS_SUSPSTS) {
912*9a138eb5SPatrick Delaunay 			return USB_SUSPEND;
913*9a138eb5SPatrick Delaunay 		}
914*9a138eb5SPatrick Delaunay 	}
915*9a138eb5SPatrick Delaunay 
916*9a138eb5SPatrick Delaunay 	/* Handle LPM interrupt */
917*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_LPMINT) != 0U) {
918*9a138eb5SPatrick Delaunay 		INFO("handle USB : LPM int enter in suspend\n");
919*9a138eb5SPatrick Delaunay 
920*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_LPMINT);
921*9a138eb5SPatrick Delaunay 		*param = (mmio_read_32(usb_base_addr + OTG_GLPMCFG) &
922*9a138eb5SPatrick Delaunay 			  OTG_GLPMCFG_BESL) >> 2;
923*9a138eb5SPatrick Delaunay 
924*9a138eb5SPatrick Delaunay 		return USB_LPM;
925*9a138eb5SPatrick Delaunay 	}
926*9a138eb5SPatrick Delaunay 
927*9a138eb5SPatrick Delaunay 	/* Handle reset interrupt */
928*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_USBRST) != 0U) {
929*9a138eb5SPatrick Delaunay 		INFO("handle USB : Reset\n");
930*9a138eb5SPatrick Delaunay 
931*9a138eb5SPatrick Delaunay 		mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_RWUSIG);
932*9a138eb5SPatrick Delaunay 
933*9a138eb5SPatrick Delaunay 		usb_dwc2_flush_tx_fifo(handle, 0U);
934*9a138eb5SPatrick Delaunay 
935*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_DAINT, OTG_DAINT_IN_MASK | OTG_DAINT_OUT_MASK);
936*9a138eb5SPatrick Delaunay 		mmio_setbits_32(usb_base_addr + OTG_DAINTMSK, OTG_DAINT_EP0_IN | OTG_DAINT_EP0_OUT);
937*9a138eb5SPatrick Delaunay 
938*9a138eb5SPatrick Delaunay 		mmio_setbits_32(usb_base_addr + OTG_DOEPMSK, OTG_DOEPMSK_STUPM |
939*9a138eb5SPatrick Delaunay 							     OTG_DOEPMSK_XFRCM |
940*9a138eb5SPatrick Delaunay 							     OTG_DOEPMSK_EPDM);
941*9a138eb5SPatrick Delaunay 		mmio_setbits_32(usb_base_addr + OTG_DIEPMSK, OTG_DIEPMSK_TOM |
942*9a138eb5SPatrick Delaunay 							     OTG_DIEPMSK_XFRCM |
943*9a138eb5SPatrick Delaunay 							     OTG_DIEPMSK_EPDM);
944*9a138eb5SPatrick Delaunay 
945*9a138eb5SPatrick Delaunay 		/* Set default address to 0 */
946*9a138eb5SPatrick Delaunay 		mmio_clrbits_32(usb_base_addr + OTG_DCFG, OTG_DCFG_DAD);
947*9a138eb5SPatrick Delaunay 
948*9a138eb5SPatrick Delaunay 		/* Setup EP0 to receive SETUP packets */
949*9a138eb5SPatrick Delaunay 		ret = usb_dwc2_ep0_out_start(handle);
950*9a138eb5SPatrick Delaunay 		if (ret != USBD_OK) {
951*9a138eb5SPatrick Delaunay 			return ret;
952*9a138eb5SPatrick Delaunay 		}
953*9a138eb5SPatrick Delaunay 
954*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_USBRST);
955*9a138eb5SPatrick Delaunay 
956*9a138eb5SPatrick Delaunay 		return USB_RESET;
957*9a138eb5SPatrick Delaunay 	}
958*9a138eb5SPatrick Delaunay 
959*9a138eb5SPatrick Delaunay 	/* Handle enumeration done interrupt */
960*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_ENUMDNE) != 0U) {
961*9a138eb5SPatrick Delaunay 		ret = usb_dwc2_activate_setup(handle);
962*9a138eb5SPatrick Delaunay 		if (ret != USBD_OK) {
963*9a138eb5SPatrick Delaunay 			return ret;
964*9a138eb5SPatrick Delaunay 		}
965*9a138eb5SPatrick Delaunay 
966*9a138eb5SPatrick Delaunay 		mmio_clrbits_32(usb_base_addr + OTG_GUSBCFG, OTG_GUSBCFG_TRDT);
967*9a138eb5SPatrick Delaunay 
968*9a138eb5SPatrick Delaunay 		mmio_setbits_32(usb_base_addr + OTG_GUSBCFG,
969*9a138eb5SPatrick Delaunay 				(USBD_HS_TRDT_VALUE << OTG_GUSBCFG_TRDT_SHIFT) & OTG_GUSBCFG_TRDT);
970*9a138eb5SPatrick Delaunay 
971*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_ENUMDNE);
972*9a138eb5SPatrick Delaunay 
973*9a138eb5SPatrick Delaunay 		return USB_ENUM_DONE;
974*9a138eb5SPatrick Delaunay 	}
975*9a138eb5SPatrick Delaunay 
976*9a138eb5SPatrick Delaunay 	/* Handle RXQLevel interrupt */
977*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_RXFLVL) != 0U) {
978*9a138eb5SPatrick Delaunay 		mmio_clrbits_32(usb_base_addr + OTG_GINTMSK,
979*9a138eb5SPatrick Delaunay 				OTG_GINTSTS_RXFLVL);
980*9a138eb5SPatrick Delaunay 
981*9a138eb5SPatrick Delaunay 		temp = mmio_read_32(usb_base_addr + OTG_GRXSTSP);
982*9a138eb5SPatrick Delaunay 
983*9a138eb5SPatrick Delaunay 		*param = temp & OTG_GRXSTSP_EPNUM;
984*9a138eb5SPatrick Delaunay 		*param |= (temp & OTG_GRXSTSP_BCNT) << (USBD_OUT_COUNT_SHIFT -
985*9a138eb5SPatrick Delaunay 							OTG_GRXSTSP_BCNT_SHIFT);
986*9a138eb5SPatrick Delaunay 
987*9a138eb5SPatrick Delaunay 		if (((temp & OTG_GRXSTSP_PKTSTS) >> OTG_GRXSTSP_PKTSTS_SHIFT) == STS_DATA_UPDT) {
988*9a138eb5SPatrick Delaunay 			if ((temp & OTG_GRXSTSP_BCNT) != 0U) {
989*9a138eb5SPatrick Delaunay 				mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL);
990*9a138eb5SPatrick Delaunay 
991*9a138eb5SPatrick Delaunay 				return USB_READ_DATA_PACKET;
992*9a138eb5SPatrick Delaunay 			}
993*9a138eb5SPatrick Delaunay 		} else if (((temp & OTG_GRXSTSP_PKTSTS) >> OTG_GRXSTSP_PKTSTS_SHIFT) ==
994*9a138eb5SPatrick Delaunay 			    STS_SETUP_UPDT) {
995*9a138eb5SPatrick Delaunay 			mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL);
996*9a138eb5SPatrick Delaunay 
997*9a138eb5SPatrick Delaunay 			return USB_READ_SETUP_PACKET;
998*9a138eb5SPatrick Delaunay 		}
999*9a138eb5SPatrick Delaunay 
1000*9a138eb5SPatrick Delaunay 		mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL);
1001*9a138eb5SPatrick Delaunay 	}
1002*9a138eb5SPatrick Delaunay 
1003*9a138eb5SPatrick Delaunay 	/* Handle SOF interrupt */
1004*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_SOF) != 0U) {
1005*9a138eb5SPatrick Delaunay 		INFO("handle USB : SOF\n");
1006*9a138eb5SPatrick Delaunay 
1007*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_SOF);
1008*9a138eb5SPatrick Delaunay 
1009*9a138eb5SPatrick Delaunay 		return USB_SOF;
1010*9a138eb5SPatrick Delaunay 	}
1011*9a138eb5SPatrick Delaunay 
1012*9a138eb5SPatrick Delaunay 	/* Handle incomplete ISO IN interrupt */
1013*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IISOIXFR) != 0U) {
1014*9a138eb5SPatrick Delaunay 		INFO("handle USB : ISO IN\n");
1015*9a138eb5SPatrick Delaunay 
1016*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_GINTSTS,
1017*9a138eb5SPatrick Delaunay 			      OTG_GINTSTS_IISOIXFR);
1018*9a138eb5SPatrick Delaunay 	}
1019*9a138eb5SPatrick Delaunay 
1020*9a138eb5SPatrick Delaunay 	/* Handle incomplete ISO OUT interrupt */
1021*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IPXFR_INCOMPISOOUT) !=
1022*9a138eb5SPatrick Delaunay 	    0U) {
1023*9a138eb5SPatrick Delaunay 		INFO("handle USB : ISO OUT\n");
1024*9a138eb5SPatrick Delaunay 
1025*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_GINTSTS,
1026*9a138eb5SPatrick Delaunay 			      OTG_GINTSTS_IPXFR_INCOMPISOOUT);
1027*9a138eb5SPatrick Delaunay 	}
1028*9a138eb5SPatrick Delaunay 
1029*9a138eb5SPatrick Delaunay 	/* Handle connection event interrupt */
1030*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_SRQINT) != 0U) {
1031*9a138eb5SPatrick Delaunay 		INFO("handle USB : Connect\n");
1032*9a138eb5SPatrick Delaunay 
1033*9a138eb5SPatrick Delaunay 		mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_SRQINT);
1034*9a138eb5SPatrick Delaunay 	}
1035*9a138eb5SPatrick Delaunay 
1036*9a138eb5SPatrick Delaunay 	/* Handle disconnection event interrupt */
1037*9a138eb5SPatrick Delaunay 	if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_OTGINT) != 0U) {
1038*9a138eb5SPatrick Delaunay 		INFO("handle USB : Disconnect\n");
1039*9a138eb5SPatrick Delaunay 
1040*9a138eb5SPatrick Delaunay 		temp = mmio_read_32(usb_base_addr + OTG_GOTGINT);
1041*9a138eb5SPatrick Delaunay 
1042*9a138eb5SPatrick Delaunay 		if ((temp & OTG_GOTGINT_SEDET) == OTG_GOTGINT_SEDET) {
1043*9a138eb5SPatrick Delaunay 			return USB_DISCONNECT;
1044*9a138eb5SPatrick Delaunay 		}
1045*9a138eb5SPatrick Delaunay 	}
1046*9a138eb5SPatrick Delaunay 
1047*9a138eb5SPatrick Delaunay 	return USB_NOTHING;
1048*9a138eb5SPatrick Delaunay }
1049*9a138eb5SPatrick Delaunay 
1050*9a138eb5SPatrick Delaunay /*
1051*9a138eb5SPatrick Delaunay  * Start the usb device mode
1052*9a138eb5SPatrick Delaunay  * usb_core_handle: USB core driver handle.
1053*9a138eb5SPatrick Delaunay  * return  USB status.
1054*9a138eb5SPatrick Delaunay  */
1055*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_start_device(void *handle)
1056*9a138eb5SPatrick Delaunay {
1057*9a138eb5SPatrick Delaunay 	uintptr_t usb_base_addr = (uintptr_t)handle;
1058*9a138eb5SPatrick Delaunay 
1059*9a138eb5SPatrick Delaunay 	mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_SDIS);
1060*9a138eb5SPatrick Delaunay 	mmio_setbits_32(usb_base_addr + OTG_GAHBCFG, OTG_GAHBCFG_GINT);
1061*9a138eb5SPatrick Delaunay 
1062*9a138eb5SPatrick Delaunay 	return USBD_OK;
1063*9a138eb5SPatrick Delaunay }
1064*9a138eb5SPatrick Delaunay 
1065*9a138eb5SPatrick Delaunay static const struct usb_driver usb_dwc2driver = {
1066*9a138eb5SPatrick Delaunay 	.ep0_out_start = usb_dwc2_ep0_out_start,
1067*9a138eb5SPatrick Delaunay 	.ep_start_xfer = usb_dwc2_ep_start_xfer,
1068*9a138eb5SPatrick Delaunay 	.ep0_start_xfer = usb_dwc2_ep0_start_xfer,
1069*9a138eb5SPatrick Delaunay 	.write_packet = usb_dwc2_write_packet,
1070*9a138eb5SPatrick Delaunay 	.read_packet = usb_dwc2_read_packet,
1071*9a138eb5SPatrick Delaunay 	.ep_set_stall = usb_dwc2_ep_set_stall,
1072*9a138eb5SPatrick Delaunay 	.start_device = usb_dwc2_start_device,
1073*9a138eb5SPatrick Delaunay 	.stop_device = usb_dwc2_stop_device,
1074*9a138eb5SPatrick Delaunay 	.set_address = usb_dwc2_set_address,
1075*9a138eb5SPatrick Delaunay 	.write_empty_tx_fifo = usb_dwc2_write_empty_tx_fifo,
1076*9a138eb5SPatrick Delaunay 	.it_handler = usb_dwc2_it_handler
1077*9a138eb5SPatrick Delaunay };
1078*9a138eb5SPatrick Delaunay 
1079*9a138eb5SPatrick Delaunay /*
1080*9a138eb5SPatrick Delaunay  * Initialize USB DWC2 driver.
1081*9a138eb5SPatrick Delaunay  * usb_core_handle: USB core driver handle.
1082*9a138eb5SPatrick Delaunay  * pcd_handle: PCD handle.
1083*9a138eb5SPatrick Delaunay  * base_register: USB global register base address.
1084*9a138eb5SPatrick Delaunay  */
1085*9a138eb5SPatrick Delaunay void stm32mp1_usb_init_driver(struct usb_handle *usb_core_handle,
1086*9a138eb5SPatrick Delaunay 			      struct pcd_handle *pcd_handle,
1087*9a138eb5SPatrick Delaunay 			      void *base_register)
1088*9a138eb5SPatrick Delaunay {
1089*9a138eb5SPatrick Delaunay 	register_usb_driver(usb_core_handle, pcd_handle, &usb_dwc2driver,
1090*9a138eb5SPatrick Delaunay 			    base_register);
1091*9a138eb5SPatrick Delaunay }
1092