xref: /rk3399_rockchip-uboot/drivers/usb/host/dwc2.c (revision 6e9e06260d4fa8873fdebddc2a11f9205674d189)
1*6e9e0626SOleksandr Tymoshenko /*
2*6e9e0626SOleksandr Tymoshenko  * Copyright (C) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
3*6e9e0626SOleksandr Tymoshenko  * Copyright (C) 2014 Marek Vasut <marex@denx.de>
4*6e9e0626SOleksandr Tymoshenko  *
5*6e9e0626SOleksandr Tymoshenko  * SPDX-License-Identifier:     GPL-2.0+
6*6e9e0626SOleksandr Tymoshenko  */
7*6e9e0626SOleksandr Tymoshenko 
8*6e9e0626SOleksandr Tymoshenko #include <common.h>
9*6e9e0626SOleksandr Tymoshenko #include <errno.h>
10*6e9e0626SOleksandr Tymoshenko #include <usb.h>
11*6e9e0626SOleksandr Tymoshenko #include <malloc.h>
12*6e9e0626SOleksandr Tymoshenko #include <usbroothubdes.h>
13*6e9e0626SOleksandr Tymoshenko #include <asm/io.h>
14*6e9e0626SOleksandr Tymoshenko 
15*6e9e0626SOleksandr Tymoshenko #include "dwc2.h"
16*6e9e0626SOleksandr Tymoshenko 
17*6e9e0626SOleksandr Tymoshenko /* Use only HC channel 0. */
18*6e9e0626SOleksandr Tymoshenko #define DWC2_HC_CHANNEL			0
19*6e9e0626SOleksandr Tymoshenko 
20*6e9e0626SOleksandr Tymoshenko #define DWC2_STATUS_BUF_SIZE		64
21*6e9e0626SOleksandr Tymoshenko #define DWC2_DATA_BUF_SIZE		(64 * 1024)
22*6e9e0626SOleksandr Tymoshenko 
23*6e9e0626SOleksandr Tymoshenko /* We need doubleword-aligned buffers for DMA transfers */
24*6e9e0626SOleksandr Tymoshenko DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer, DWC2_DATA_BUF_SIZE, 8);
25*6e9e0626SOleksandr Tymoshenko DEFINE_ALIGN_BUFFER(uint8_t, status_buffer, DWC2_STATUS_BUF_SIZE, 8);
26*6e9e0626SOleksandr Tymoshenko 
27*6e9e0626SOleksandr Tymoshenko #define MAX_DEVICE			16
28*6e9e0626SOleksandr Tymoshenko #define MAX_ENDPOINT			16
29*6e9e0626SOleksandr Tymoshenko static int bulk_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
30*6e9e0626SOleksandr Tymoshenko static int control_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
31*6e9e0626SOleksandr Tymoshenko 
32*6e9e0626SOleksandr Tymoshenko static int root_hub_devnum;
33*6e9e0626SOleksandr Tymoshenko 
34*6e9e0626SOleksandr Tymoshenko static struct dwc2_core_regs *regs =
35*6e9e0626SOleksandr Tymoshenko 	(struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR;
36*6e9e0626SOleksandr Tymoshenko 
37*6e9e0626SOleksandr Tymoshenko /*
38*6e9e0626SOleksandr Tymoshenko  * DWC2 IP interface
39*6e9e0626SOleksandr Tymoshenko  */
40*6e9e0626SOleksandr Tymoshenko static int wait_for_bit(void *reg, const uint32_t mask, bool set)
41*6e9e0626SOleksandr Tymoshenko {
42*6e9e0626SOleksandr Tymoshenko 	unsigned int timeout = 1000000;
43*6e9e0626SOleksandr Tymoshenko 	uint32_t val;
44*6e9e0626SOleksandr Tymoshenko 
45*6e9e0626SOleksandr Tymoshenko 	while (--timeout) {
46*6e9e0626SOleksandr Tymoshenko 		val = readl(reg);
47*6e9e0626SOleksandr Tymoshenko 		if (!set)
48*6e9e0626SOleksandr Tymoshenko 			val = ~val;
49*6e9e0626SOleksandr Tymoshenko 
50*6e9e0626SOleksandr Tymoshenko 		if ((val & mask) == mask)
51*6e9e0626SOleksandr Tymoshenko 			return 0;
52*6e9e0626SOleksandr Tymoshenko 
53*6e9e0626SOleksandr Tymoshenko 		udelay(1);
54*6e9e0626SOleksandr Tymoshenko 	}
55*6e9e0626SOleksandr Tymoshenko 
56*6e9e0626SOleksandr Tymoshenko 	debug("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n",
57*6e9e0626SOleksandr Tymoshenko 	      __func__, reg, mask, set);
58*6e9e0626SOleksandr Tymoshenko 
59*6e9e0626SOleksandr Tymoshenko 	return -ETIMEDOUT;
60*6e9e0626SOleksandr Tymoshenko }
61*6e9e0626SOleksandr Tymoshenko 
62*6e9e0626SOleksandr Tymoshenko /*
63*6e9e0626SOleksandr Tymoshenko  * Initializes the FSLSPClkSel field of the HCFG register
64*6e9e0626SOleksandr Tymoshenko  * depending on the PHY type.
65*6e9e0626SOleksandr Tymoshenko  */
66*6e9e0626SOleksandr Tymoshenko static void init_fslspclksel(struct dwc2_core_regs *regs)
67*6e9e0626SOleksandr Tymoshenko {
68*6e9e0626SOleksandr Tymoshenko 	uint32_t phyclk;
69*6e9e0626SOleksandr Tymoshenko 
70*6e9e0626SOleksandr Tymoshenko #if (CONFIG_DWC2_PHY_TYPE == DWC2_PHY_TYPE_FS)
71*6e9e0626SOleksandr Tymoshenko 	phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ;	/* Full speed PHY */
72*6e9e0626SOleksandr Tymoshenko #else
73*6e9e0626SOleksandr Tymoshenko 	/* High speed PHY running at full speed or high speed */
74*6e9e0626SOleksandr Tymoshenko 	phyclk = DWC2_HCFG_FSLSPCLKSEL_30_60_MHZ;
75*6e9e0626SOleksandr Tymoshenko #endif
76*6e9e0626SOleksandr Tymoshenko 
77*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_ULPI_FS_LS
78*6e9e0626SOleksandr Tymoshenko 	uint32_t hwcfg2 = readl(&regs->ghwcfg2);
79*6e9e0626SOleksandr Tymoshenko 	uint32_t hval = (ghwcfg2 & DWC2_HWCFG2_HS_PHY_TYPE_MASK) >>
80*6e9e0626SOleksandr Tymoshenko 			DWC2_HWCFG2_HS_PHY_TYPE_OFFSET;
81*6e9e0626SOleksandr Tymoshenko 	uint32_t fval = (ghwcfg2 & DWC2_HWCFG2_FS_PHY_TYPE_MASK) >>
82*6e9e0626SOleksandr Tymoshenko 			DWC2_HWCFG2_FS_PHY_TYPE_OFFSET;
83*6e9e0626SOleksandr Tymoshenko 
84*6e9e0626SOleksandr Tymoshenko 	if (hval == 2 && fval == 1)
85*6e9e0626SOleksandr Tymoshenko 		phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ;	/* Full speed PHY */
86*6e9e0626SOleksandr Tymoshenko #endif
87*6e9e0626SOleksandr Tymoshenko 
88*6e9e0626SOleksandr Tymoshenko 	clrsetbits_le32(&regs->host_regs.hcfg,
89*6e9e0626SOleksandr Tymoshenko 			DWC2_HCFG_FSLSPCLKSEL_MASK,
90*6e9e0626SOleksandr Tymoshenko 			phyclk << DWC2_HCFG_FSLSPCLKSEL_OFFSET);
91*6e9e0626SOleksandr Tymoshenko }
92*6e9e0626SOleksandr Tymoshenko 
93*6e9e0626SOleksandr Tymoshenko /*
94*6e9e0626SOleksandr Tymoshenko  * Flush a Tx FIFO.
95*6e9e0626SOleksandr Tymoshenko  *
96*6e9e0626SOleksandr Tymoshenko  * @param regs Programming view of DWC_otg controller.
97*6e9e0626SOleksandr Tymoshenko  * @param num Tx FIFO to flush.
98*6e9e0626SOleksandr Tymoshenko  */
99*6e9e0626SOleksandr Tymoshenko static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num)
100*6e9e0626SOleksandr Tymoshenko {
101*6e9e0626SOleksandr Tymoshenko 	int ret;
102*6e9e0626SOleksandr Tymoshenko 
103*6e9e0626SOleksandr Tymoshenko 	writel(DWC2_GRSTCTL_TXFFLSH | (num << DWC2_GRSTCTL_TXFNUM_OFFSET),
104*6e9e0626SOleksandr Tymoshenko 	       &regs->grstctl);
105*6e9e0626SOleksandr Tymoshenko 	ret = wait_for_bit(&regs->grstctl, DWC2_GRSTCTL_TXFFLSH, 0);
106*6e9e0626SOleksandr Tymoshenko 	if (ret)
107*6e9e0626SOleksandr Tymoshenko 		printf("%s: Timeout!\n", __func__);
108*6e9e0626SOleksandr Tymoshenko 
109*6e9e0626SOleksandr Tymoshenko 	/* Wait for 3 PHY Clocks */
110*6e9e0626SOleksandr Tymoshenko 	udelay(1);
111*6e9e0626SOleksandr Tymoshenko }
112*6e9e0626SOleksandr Tymoshenko 
113*6e9e0626SOleksandr Tymoshenko /*
114*6e9e0626SOleksandr Tymoshenko  * Flush Rx FIFO.
115*6e9e0626SOleksandr Tymoshenko  *
116*6e9e0626SOleksandr Tymoshenko  * @param regs Programming view of DWC_otg controller.
117*6e9e0626SOleksandr Tymoshenko  */
118*6e9e0626SOleksandr Tymoshenko static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs)
119*6e9e0626SOleksandr Tymoshenko {
120*6e9e0626SOleksandr Tymoshenko 	int ret;
121*6e9e0626SOleksandr Tymoshenko 
122*6e9e0626SOleksandr Tymoshenko 	writel(DWC2_GRSTCTL_RXFFLSH, &regs->grstctl);
123*6e9e0626SOleksandr Tymoshenko 	ret = wait_for_bit(&regs->grstctl, DWC2_GRSTCTL_RXFFLSH, 0);
124*6e9e0626SOleksandr Tymoshenko 	if (ret)
125*6e9e0626SOleksandr Tymoshenko 		printf("%s: Timeout!\n", __func__);
126*6e9e0626SOleksandr Tymoshenko 
127*6e9e0626SOleksandr Tymoshenko 	/* Wait for 3 PHY Clocks */
128*6e9e0626SOleksandr Tymoshenko 	udelay(1);
129*6e9e0626SOleksandr Tymoshenko }
130*6e9e0626SOleksandr Tymoshenko 
131*6e9e0626SOleksandr Tymoshenko /*
132*6e9e0626SOleksandr Tymoshenko  * Do core a soft reset of the core.  Be careful with this because it
133*6e9e0626SOleksandr Tymoshenko  * resets all the internal state machines of the core.
134*6e9e0626SOleksandr Tymoshenko  */
135*6e9e0626SOleksandr Tymoshenko static void dwc_otg_core_reset(struct dwc2_core_regs *regs)
136*6e9e0626SOleksandr Tymoshenko {
137*6e9e0626SOleksandr Tymoshenko 	int ret;
138*6e9e0626SOleksandr Tymoshenko 
139*6e9e0626SOleksandr Tymoshenko 	/* Wait for AHB master IDLE state. */
140*6e9e0626SOleksandr Tymoshenko 	ret = wait_for_bit(&regs->grstctl, DWC2_GRSTCTL_AHBIDLE, 1);
141*6e9e0626SOleksandr Tymoshenko 	if (ret)
142*6e9e0626SOleksandr Tymoshenko 		printf("%s: Timeout!\n", __func__);
143*6e9e0626SOleksandr Tymoshenko 
144*6e9e0626SOleksandr Tymoshenko 	/* Core Soft Reset */
145*6e9e0626SOleksandr Tymoshenko 	writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
146*6e9e0626SOleksandr Tymoshenko 	ret = wait_for_bit(&regs->grstctl, DWC2_GRSTCTL_CSFTRST, 0);
147*6e9e0626SOleksandr Tymoshenko 	if (ret)
148*6e9e0626SOleksandr Tymoshenko 		printf("%s: Timeout!\n", __func__);
149*6e9e0626SOleksandr Tymoshenko 
150*6e9e0626SOleksandr Tymoshenko 	/*
151*6e9e0626SOleksandr Tymoshenko 	 * Wait for core to come out of reset.
152*6e9e0626SOleksandr Tymoshenko 	 * NOTE: This long sleep is _very_ important, otherwise the core will
153*6e9e0626SOleksandr Tymoshenko 	 *       not stay in host mode after a connector ID change!
154*6e9e0626SOleksandr Tymoshenko 	 */
155*6e9e0626SOleksandr Tymoshenko 	mdelay(100);
156*6e9e0626SOleksandr Tymoshenko }
157*6e9e0626SOleksandr Tymoshenko 
158*6e9e0626SOleksandr Tymoshenko /*
159*6e9e0626SOleksandr Tymoshenko  * This function initializes the DWC_otg controller registers for
160*6e9e0626SOleksandr Tymoshenko  * host mode.
161*6e9e0626SOleksandr Tymoshenko  *
162*6e9e0626SOleksandr Tymoshenko  * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
163*6e9e0626SOleksandr Tymoshenko  * request queues. Host channels are reset to ensure that they are ready for
164*6e9e0626SOleksandr Tymoshenko  * performing transfers.
165*6e9e0626SOleksandr Tymoshenko  *
166*6e9e0626SOleksandr Tymoshenko  * @param regs Programming view of DWC_otg controller
167*6e9e0626SOleksandr Tymoshenko  *
168*6e9e0626SOleksandr Tymoshenko  */
169*6e9e0626SOleksandr Tymoshenko static void dwc_otg_core_host_init(struct dwc2_core_regs *regs)
170*6e9e0626SOleksandr Tymoshenko {
171*6e9e0626SOleksandr Tymoshenko 	uint32_t nptxfifosize = 0;
172*6e9e0626SOleksandr Tymoshenko 	uint32_t ptxfifosize = 0;
173*6e9e0626SOleksandr Tymoshenko 	uint32_t hprt0 = 0;
174*6e9e0626SOleksandr Tymoshenko 	int i, ret, num_channels;
175*6e9e0626SOleksandr Tymoshenko 
176*6e9e0626SOleksandr Tymoshenko 	/* Restart the Phy Clock */
177*6e9e0626SOleksandr Tymoshenko 	writel(0, &regs->pcgcctl);
178*6e9e0626SOleksandr Tymoshenko 
179*6e9e0626SOleksandr Tymoshenko 	/* Initialize Host Configuration Register */
180*6e9e0626SOleksandr Tymoshenko 	init_fslspclksel(regs);
181*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_DFLT_SPEED_FULL
182*6e9e0626SOleksandr Tymoshenko 	setbits_le32(&regs->host_regs.hcfg, DWC2_HCFG_FSLSSUPP);
183*6e9e0626SOleksandr Tymoshenko #endif
184*6e9e0626SOleksandr Tymoshenko 
185*6e9e0626SOleksandr Tymoshenko 	/* Configure data FIFO sizes */
186*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_ENABLE_DYNAMIC_FIFO
187*6e9e0626SOleksandr Tymoshenko 	if (readl(&regs->ghwcfg2) & DWC2_HWCFG2_DYNAMIC_FIFO) {
188*6e9e0626SOleksandr Tymoshenko 		/* Rx FIFO */
189*6e9e0626SOleksandr Tymoshenko 		writel(CONFIG_DWC2_HOST_RX_FIFO_SIZE, &regs->grxfsiz);
190*6e9e0626SOleksandr Tymoshenko 
191*6e9e0626SOleksandr Tymoshenko 		/* Non-periodic Tx FIFO */
192*6e9e0626SOleksandr Tymoshenko 		nptxfifosize |= CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE <<
193*6e9e0626SOleksandr Tymoshenko 				DWC2_FIFOSIZE_DEPTH_OFFSET;
194*6e9e0626SOleksandr Tymoshenko 		nptxfifosize |= CONFIG_DWC2_HOST_RX_FIFO_SIZE <<
195*6e9e0626SOleksandr Tymoshenko 				DWC2_FIFOSIZE_STARTADDR_OFFSET;
196*6e9e0626SOleksandr Tymoshenko 		writel(nptxfifosize, &regs->gnptxfsiz);
197*6e9e0626SOleksandr Tymoshenko 
198*6e9e0626SOleksandr Tymoshenko 		/* Periodic Tx FIFO */
199*6e9e0626SOleksandr Tymoshenko 		ptxfifosize |= CONFIG_DWC2_HOST_PERIO_TX_FIFO_SIZE <<
200*6e9e0626SOleksandr Tymoshenko 				DWC2_FIFOSIZE_DEPTH_OFFSET;
201*6e9e0626SOleksandr Tymoshenko 		ptxfifosize |= (CONFIG_DWC2_HOST_RX_FIFO_SIZE +
202*6e9e0626SOleksandr Tymoshenko 				CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE) <<
203*6e9e0626SOleksandr Tymoshenko 				DWC2_FIFOSIZE_STARTADDR_OFFSET;
204*6e9e0626SOleksandr Tymoshenko 		writel(ptxfifosize, &regs->hptxfsiz);
205*6e9e0626SOleksandr Tymoshenko 	}
206*6e9e0626SOleksandr Tymoshenko #endif
207*6e9e0626SOleksandr Tymoshenko 
208*6e9e0626SOleksandr Tymoshenko 	/* Clear Host Set HNP Enable in the OTG Control Register */
209*6e9e0626SOleksandr Tymoshenko 	clrbits_le32(&regs->gotgctl, DWC2_GOTGCTL_HSTSETHNPEN);
210*6e9e0626SOleksandr Tymoshenko 
211*6e9e0626SOleksandr Tymoshenko 	/* Make sure the FIFOs are flushed. */
212*6e9e0626SOleksandr Tymoshenko 	dwc_otg_flush_tx_fifo(regs, 0x10);	/* All Tx FIFOs */
213*6e9e0626SOleksandr Tymoshenko 	dwc_otg_flush_rx_fifo(regs);
214*6e9e0626SOleksandr Tymoshenko 
215*6e9e0626SOleksandr Tymoshenko 	/* Flush out any leftover queued requests. */
216*6e9e0626SOleksandr Tymoshenko 	num_channels = readl(&regs->ghwcfg2);
217*6e9e0626SOleksandr Tymoshenko 	num_channels &= DWC2_HWCFG2_NUM_HOST_CHAN_MASK;
218*6e9e0626SOleksandr Tymoshenko 	num_channels >>= DWC2_HWCFG2_NUM_HOST_CHAN_OFFSET;
219*6e9e0626SOleksandr Tymoshenko 	num_channels += 1;
220*6e9e0626SOleksandr Tymoshenko 
221*6e9e0626SOleksandr Tymoshenko 	for (i = 0; i < num_channels; i++)
222*6e9e0626SOleksandr Tymoshenko 		clrsetbits_le32(&regs->hc_regs[i].hcchar,
223*6e9e0626SOleksandr Tymoshenko 				DWC2_HCCHAR_CHEN | DWC2_HCCHAR_EPDIR,
224*6e9e0626SOleksandr Tymoshenko 				DWC2_HCCHAR_CHDIS);
225*6e9e0626SOleksandr Tymoshenko 
226*6e9e0626SOleksandr Tymoshenko 	/* Halt all channels to put them into a known state. */
227*6e9e0626SOleksandr Tymoshenko 	for (i = 0; i < num_channels; i++) {
228*6e9e0626SOleksandr Tymoshenko 		clrsetbits_le32(&regs->hc_regs[i].hcchar,
229*6e9e0626SOleksandr Tymoshenko 				DWC2_HCCHAR_EPDIR,
230*6e9e0626SOleksandr Tymoshenko 				DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS);
231*6e9e0626SOleksandr Tymoshenko 		ret = wait_for_bit(&regs->hc_regs[i].hcchar,
232*6e9e0626SOleksandr Tymoshenko 				   DWC2_HCCHAR_CHEN, 0);
233*6e9e0626SOleksandr Tymoshenko 		if (ret)
234*6e9e0626SOleksandr Tymoshenko 			printf("%s: Timeout!\n", __func__);
235*6e9e0626SOleksandr Tymoshenko 	}
236*6e9e0626SOleksandr Tymoshenko 
237*6e9e0626SOleksandr Tymoshenko 	/* Turn on the vbus power. */
238*6e9e0626SOleksandr Tymoshenko 	if (readl(&regs->gintsts) & DWC2_GINTSTS_CURMODE_HOST) {
239*6e9e0626SOleksandr Tymoshenko 		hprt0 = readl(&regs->hprt0);
240*6e9e0626SOleksandr Tymoshenko 		hprt0 &= ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET);
241*6e9e0626SOleksandr Tymoshenko 		hprt0 &= ~(DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG);
242*6e9e0626SOleksandr Tymoshenko 		if (!(hprt0 & DWC2_HPRT0_PRTPWR)) {
243*6e9e0626SOleksandr Tymoshenko 			hprt0 |= DWC2_HPRT0_PRTPWR;
244*6e9e0626SOleksandr Tymoshenko 			writel(hprt0, &regs->hprt0);
245*6e9e0626SOleksandr Tymoshenko 		}
246*6e9e0626SOleksandr Tymoshenko 	}
247*6e9e0626SOleksandr Tymoshenko }
248*6e9e0626SOleksandr Tymoshenko 
249*6e9e0626SOleksandr Tymoshenko /*
250*6e9e0626SOleksandr Tymoshenko  * This function initializes the DWC_otg controller registers and
251*6e9e0626SOleksandr Tymoshenko  * prepares the core for device mode or host mode operation.
252*6e9e0626SOleksandr Tymoshenko  *
253*6e9e0626SOleksandr Tymoshenko  * @param regs Programming view of the DWC_otg controller
254*6e9e0626SOleksandr Tymoshenko  */
255*6e9e0626SOleksandr Tymoshenko static void dwc_otg_core_init(struct dwc2_core_regs *regs)
256*6e9e0626SOleksandr Tymoshenko {
257*6e9e0626SOleksandr Tymoshenko 	uint32_t ahbcfg = 0;
258*6e9e0626SOleksandr Tymoshenko 	uint32_t usbcfg = 0;
259*6e9e0626SOleksandr Tymoshenko 	uint8_t brst_sz = CONFIG_DWC2_DMA_BURST_SIZE;
260*6e9e0626SOleksandr Tymoshenko 
261*6e9e0626SOleksandr Tymoshenko 	/* Common Initialization */
262*6e9e0626SOleksandr Tymoshenko 	usbcfg = readl(&regs->gusbcfg);
263*6e9e0626SOleksandr Tymoshenko 
264*6e9e0626SOleksandr Tymoshenko 	/* Program the ULPI External VBUS bit if needed */
265*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_PHY_ULPI_EXT_VBUS
266*6e9e0626SOleksandr Tymoshenko 	usbcfg |= DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV;
267*6e9e0626SOleksandr Tymoshenko #else
268*6e9e0626SOleksandr Tymoshenko 	usbcfg &= ~DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV;
269*6e9e0626SOleksandr Tymoshenko #endif
270*6e9e0626SOleksandr Tymoshenko 
271*6e9e0626SOleksandr Tymoshenko 	/* Set external TS Dline pulsing */
272*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_TS_DLINE
273*6e9e0626SOleksandr Tymoshenko 	usbcfg |= DWC2_GUSBCFG_TERM_SEL_DL_PULSE;
274*6e9e0626SOleksandr Tymoshenko #else
275*6e9e0626SOleksandr Tymoshenko 	usbcfg &= ~DWC2_GUSBCFG_TERM_SEL_DL_PULSE;
276*6e9e0626SOleksandr Tymoshenko #endif
277*6e9e0626SOleksandr Tymoshenko 	writel(usbcfg, &regs->gusbcfg);
278*6e9e0626SOleksandr Tymoshenko 
279*6e9e0626SOleksandr Tymoshenko 	/* Reset the Controller */
280*6e9e0626SOleksandr Tymoshenko 	dwc_otg_core_reset(regs);
281*6e9e0626SOleksandr Tymoshenko 
282*6e9e0626SOleksandr Tymoshenko 	/*
283*6e9e0626SOleksandr Tymoshenko 	 * This programming sequence needs to happen in FS mode before
284*6e9e0626SOleksandr Tymoshenko 	 * any other programming occurs
285*6e9e0626SOleksandr Tymoshenko 	 */
286*6e9e0626SOleksandr Tymoshenko #if defined(CONFIG_DWC2_DFLT_SPEED_FULL) && \
287*6e9e0626SOleksandr Tymoshenko 	(CONFIG_DWC2_PHY_TYPE == DWC2_PHY_TYPE_FS)
288*6e9e0626SOleksandr Tymoshenko 	/* If FS mode with FS PHY */
289*6e9e0626SOleksandr Tymoshenko 	setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_PHYSEL);
290*6e9e0626SOleksandr Tymoshenko 
291*6e9e0626SOleksandr Tymoshenko 	/* Reset after a PHY select */
292*6e9e0626SOleksandr Tymoshenko 	dwc_otg_core_reset(regs);
293*6e9e0626SOleksandr Tymoshenko 
294*6e9e0626SOleksandr Tymoshenko 	/*
295*6e9e0626SOleksandr Tymoshenko 	 * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS.
296*6e9e0626SOleksandr Tymoshenko 	 * Also do this on HNP Dev/Host mode switches (done in dev_init
297*6e9e0626SOleksandr Tymoshenko 	 * and host_init).
298*6e9e0626SOleksandr Tymoshenko 	 */
299*6e9e0626SOleksandr Tymoshenko 	if (readl(&regs->gintsts) & DWC2_GINTSTS_CURMODE_HOST)
300*6e9e0626SOleksandr Tymoshenko 		init_fslspclksel(regs);
301*6e9e0626SOleksandr Tymoshenko 
302*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_I2C_ENABLE
303*6e9e0626SOleksandr Tymoshenko 	/* Program GUSBCFG.OtgUtmifsSel to I2C */
304*6e9e0626SOleksandr Tymoshenko 	setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_OTGUTMIFSSEL);
305*6e9e0626SOleksandr Tymoshenko 
306*6e9e0626SOleksandr Tymoshenko 	/* Program GI2CCTL.I2CEn */
307*6e9e0626SOleksandr Tymoshenko 	clrsetbits_le32(&regs->gi2cctl, DWC2_GI2CCTL_I2CEN |
308*6e9e0626SOleksandr Tymoshenko 			DWC2_GI2CCTL_I2CDEVADDR_MASK,
309*6e9e0626SOleksandr Tymoshenko 			1 << DWC2_GI2CCTL_I2CDEVADDR_OFFSET);
310*6e9e0626SOleksandr Tymoshenko 	setbits_le32(&regs->gi2cctl, DWC2_GI2CCTL_I2CEN);
311*6e9e0626SOleksandr Tymoshenko #endif
312*6e9e0626SOleksandr Tymoshenko 
313*6e9e0626SOleksandr Tymoshenko #else
314*6e9e0626SOleksandr Tymoshenko 	/* High speed PHY. */
315*6e9e0626SOleksandr Tymoshenko 
316*6e9e0626SOleksandr Tymoshenko 	/*
317*6e9e0626SOleksandr Tymoshenko 	 * HS PHY parameters. These parameters are preserved during
318*6e9e0626SOleksandr Tymoshenko 	 * soft reset so only program the first time. Do a soft reset
319*6e9e0626SOleksandr Tymoshenko 	 * immediately after setting phyif.
320*6e9e0626SOleksandr Tymoshenko 	 */
321*6e9e0626SOleksandr Tymoshenko 	usbcfg &= ~(DWC2_GUSBCFG_ULPI_UTMI_SEL | DWC2_GUSBCFG_PHYIF);
322*6e9e0626SOleksandr Tymoshenko 	usbcfg |= CONFIG_DWC2_PHY_TYPE << DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET;
323*6e9e0626SOleksandr Tymoshenko 
324*6e9e0626SOleksandr Tymoshenko 	if (usbcfg & DWC2_GUSBCFG_ULPI_UTMI_SEL) {	/* ULPI interface */
325*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_PHY_ULPI_DDR
326*6e9e0626SOleksandr Tymoshenko 		usbcfg |= DWC2_GUSBCFG_DDRSEL;
327*6e9e0626SOleksandr Tymoshenko #else
328*6e9e0626SOleksandr Tymoshenko 		usbcfg &= ~DWC2_GUSBCFG_DDRSEL;
329*6e9e0626SOleksandr Tymoshenko #endif
330*6e9e0626SOleksandr Tymoshenko 	} else {	/* UTMI+ interface */
331*6e9e0626SOleksandr Tymoshenko #if (CONFIG_DWC2_UTMI_PHY_WIDTH == 16)
332*6e9e0626SOleksandr Tymoshenko 		usbcfg |= DWC2_GUSBCFG_PHYIF;
333*6e9e0626SOleksandr Tymoshenko #endif
334*6e9e0626SOleksandr Tymoshenko 	}
335*6e9e0626SOleksandr Tymoshenko 
336*6e9e0626SOleksandr Tymoshenko 	writel(usbcfg, &regs->gusbcfg);
337*6e9e0626SOleksandr Tymoshenko 
338*6e9e0626SOleksandr Tymoshenko 	/* Reset after setting the PHY parameters */
339*6e9e0626SOleksandr Tymoshenko 	dwc_otg_core_reset(regs);
340*6e9e0626SOleksandr Tymoshenko #endif
341*6e9e0626SOleksandr Tymoshenko 
342*6e9e0626SOleksandr Tymoshenko 	usbcfg = readl(&regs->gusbcfg);
343*6e9e0626SOleksandr Tymoshenko 	usbcfg &= ~(DWC2_GUSBCFG_ULPI_FSLS | DWC2_GUSBCFG_ULPI_CLK_SUS_M);
344*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_ULPI_FS_LS
345*6e9e0626SOleksandr Tymoshenko 	uint32_t hwcfg2 = readl(&regs->ghwcfg2);
346*6e9e0626SOleksandr Tymoshenko 	uint32_t hval = (ghwcfg2 & DWC2_HWCFG2_HS_PHY_TYPE_MASK) >>
347*6e9e0626SOleksandr Tymoshenko 			DWC2_HWCFG2_HS_PHY_TYPE_OFFSET;
348*6e9e0626SOleksandr Tymoshenko 	uint32_t fval = (ghwcfg2 & DWC2_HWCFG2_FS_PHY_TYPE_MASK) >>
349*6e9e0626SOleksandr Tymoshenko 			DWC2_HWCFG2_FS_PHY_TYPE_OFFSET;
350*6e9e0626SOleksandr Tymoshenko 	if (hval == 2 && fval == 1) {
351*6e9e0626SOleksandr Tymoshenko 		usbcfg |= DWC2_GUSBCFG_ULPI_FSLS;
352*6e9e0626SOleksandr Tymoshenko 		usbcfg |= DWC2_GUSBCFG_ULPI_CLK_SUS_M;
353*6e9e0626SOleksandr Tymoshenko 	}
354*6e9e0626SOleksandr Tymoshenko #endif
355*6e9e0626SOleksandr Tymoshenko 	writel(usbcfg, &regs->gusbcfg);
356*6e9e0626SOleksandr Tymoshenko 
357*6e9e0626SOleksandr Tymoshenko 	/* Program the GAHBCFG Register. */
358*6e9e0626SOleksandr Tymoshenko 	switch (readl(&regs->ghwcfg2) & DWC2_HWCFG2_ARCHITECTURE_MASK) {
359*6e9e0626SOleksandr Tymoshenko 	case DWC2_HWCFG2_ARCHITECTURE_SLAVE_ONLY:
360*6e9e0626SOleksandr Tymoshenko 		break;
361*6e9e0626SOleksandr Tymoshenko 	case DWC2_HWCFG2_ARCHITECTURE_EXT_DMA:
362*6e9e0626SOleksandr Tymoshenko 		while (brst_sz > 1) {
363*6e9e0626SOleksandr Tymoshenko 			ahbcfg |= ahbcfg + (1 << DWC2_GAHBCFG_HBURSTLEN_OFFSET);
364*6e9e0626SOleksandr Tymoshenko 			ahbcfg &= DWC2_GAHBCFG_HBURSTLEN_MASK;
365*6e9e0626SOleksandr Tymoshenko 			brst_sz >>= 1;
366*6e9e0626SOleksandr Tymoshenko 		}
367*6e9e0626SOleksandr Tymoshenko 
368*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_DMA_ENABLE
369*6e9e0626SOleksandr Tymoshenko 		ahbcfg |= DWC2_GAHBCFG_DMAENABLE;
370*6e9e0626SOleksandr Tymoshenko #endif
371*6e9e0626SOleksandr Tymoshenko 		break;
372*6e9e0626SOleksandr Tymoshenko 
373*6e9e0626SOleksandr Tymoshenko 	case DWC2_HWCFG2_ARCHITECTURE_INT_DMA:
374*6e9e0626SOleksandr Tymoshenko 		ahbcfg |= DWC2_GAHBCFG_HBURSTLEN_INCR4;
375*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_DMA_ENABLE
376*6e9e0626SOleksandr Tymoshenko 		ahbcfg |= DWC2_GAHBCFG_DMAENABLE;
377*6e9e0626SOleksandr Tymoshenko #endif
378*6e9e0626SOleksandr Tymoshenko 		break;
379*6e9e0626SOleksandr Tymoshenko 	}
380*6e9e0626SOleksandr Tymoshenko 
381*6e9e0626SOleksandr Tymoshenko 	writel(ahbcfg, &regs->gahbcfg);
382*6e9e0626SOleksandr Tymoshenko 
383*6e9e0626SOleksandr Tymoshenko 	/* Program the GUSBCFG register for HNP/SRP. */
384*6e9e0626SOleksandr Tymoshenko 	setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_HNPCAP | DWC2_GUSBCFG_SRPCAP);
385*6e9e0626SOleksandr Tymoshenko 
386*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_IC_USB_CAP
387*6e9e0626SOleksandr Tymoshenko 	setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_IC_USB_CAP);
388*6e9e0626SOleksandr Tymoshenko #endif
389*6e9e0626SOleksandr Tymoshenko }
390*6e9e0626SOleksandr Tymoshenko 
391*6e9e0626SOleksandr Tymoshenko /*
392*6e9e0626SOleksandr Tymoshenko  * Prepares a host channel for transferring packets to/from a specific
393*6e9e0626SOleksandr Tymoshenko  * endpoint. The HCCHARn register is set up with the characteristics specified
394*6e9e0626SOleksandr Tymoshenko  * in _hc. Host channel interrupts that may need to be serviced while this
395*6e9e0626SOleksandr Tymoshenko  * transfer is in progress are enabled.
396*6e9e0626SOleksandr Tymoshenko  *
397*6e9e0626SOleksandr Tymoshenko  * @param regs Programming view of DWC_otg controller
398*6e9e0626SOleksandr Tymoshenko  * @param hc Information needed to initialize the host channel
399*6e9e0626SOleksandr Tymoshenko  */
400*6e9e0626SOleksandr Tymoshenko static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num,
401*6e9e0626SOleksandr Tymoshenko 		uint8_t dev_addr, uint8_t ep_num, uint8_t ep_is_in,
402*6e9e0626SOleksandr Tymoshenko 		uint8_t ep_type, uint16_t max_packet)
403*6e9e0626SOleksandr Tymoshenko {
404*6e9e0626SOleksandr Tymoshenko 	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[hc_num];
405*6e9e0626SOleksandr Tymoshenko 	const uint32_t hcchar = (dev_addr << DWC2_HCCHAR_DEVADDR_OFFSET) |
406*6e9e0626SOleksandr Tymoshenko 				(ep_num << DWC2_HCCHAR_EPNUM_OFFSET) |
407*6e9e0626SOleksandr Tymoshenko 				(ep_is_in << DWC2_HCCHAR_EPDIR_OFFSET) |
408*6e9e0626SOleksandr Tymoshenko 				(ep_type << DWC2_HCCHAR_EPTYPE_OFFSET) |
409*6e9e0626SOleksandr Tymoshenko 				(max_packet << DWC2_HCCHAR_MPS_OFFSET);
410*6e9e0626SOleksandr Tymoshenko 
411*6e9e0626SOleksandr Tymoshenko 	/* Clear old interrupt conditions for this host channel. */
412*6e9e0626SOleksandr Tymoshenko 	writel(0x3fff, &hc_regs->hcint);
413*6e9e0626SOleksandr Tymoshenko 
414*6e9e0626SOleksandr Tymoshenko 	/*
415*6e9e0626SOleksandr Tymoshenko 	 * Program the HCCHARn register with the endpoint characteristics
416*6e9e0626SOleksandr Tymoshenko 	 * for the current transfer.
417*6e9e0626SOleksandr Tymoshenko 	 */
418*6e9e0626SOleksandr Tymoshenko 	writel(hcchar, &hc_regs->hcchar);
419*6e9e0626SOleksandr Tymoshenko 
420*6e9e0626SOleksandr Tymoshenko 	/* Program the HCSPLIT register for SPLITs */
421*6e9e0626SOleksandr Tymoshenko 	writel(0, &hc_regs->hcsplt);
422*6e9e0626SOleksandr Tymoshenko }
423*6e9e0626SOleksandr Tymoshenko 
424*6e9e0626SOleksandr Tymoshenko /*
425*6e9e0626SOleksandr Tymoshenko  * DWC2 to USB API interface
426*6e9e0626SOleksandr Tymoshenko  */
427*6e9e0626SOleksandr Tymoshenko /* Direction: In ; Request: Status */
428*6e9e0626SOleksandr Tymoshenko static int dwc_otg_submit_rh_msg_in_status(struct usb_device *dev, void *buffer,
429*6e9e0626SOleksandr Tymoshenko 					   int txlen, struct devrequest *cmd)
430*6e9e0626SOleksandr Tymoshenko {
431*6e9e0626SOleksandr Tymoshenko 	uint32_t hprt0 = 0;
432*6e9e0626SOleksandr Tymoshenko 	uint32_t port_status = 0;
433*6e9e0626SOleksandr Tymoshenko 	uint32_t port_change = 0;
434*6e9e0626SOleksandr Tymoshenko 	int len = 0;
435*6e9e0626SOleksandr Tymoshenko 	int stat = 0;
436*6e9e0626SOleksandr Tymoshenko 
437*6e9e0626SOleksandr Tymoshenko 	switch (cmd->requesttype & ~USB_DIR_IN) {
438*6e9e0626SOleksandr Tymoshenko 	case 0:
439*6e9e0626SOleksandr Tymoshenko 		*(uint16_t *)buffer = cpu_to_le16(1);
440*6e9e0626SOleksandr Tymoshenko 		len = 2;
441*6e9e0626SOleksandr Tymoshenko 		break;
442*6e9e0626SOleksandr Tymoshenko 	case USB_RECIP_INTERFACE:
443*6e9e0626SOleksandr Tymoshenko 	case USB_RECIP_ENDPOINT:
444*6e9e0626SOleksandr Tymoshenko 		*(uint16_t *)buffer = cpu_to_le16(0);
445*6e9e0626SOleksandr Tymoshenko 		len = 2;
446*6e9e0626SOleksandr Tymoshenko 		break;
447*6e9e0626SOleksandr Tymoshenko 	case USB_TYPE_CLASS:
448*6e9e0626SOleksandr Tymoshenko 		*(uint32_t *)buffer = cpu_to_le32(0);
449*6e9e0626SOleksandr Tymoshenko 		len = 4;
450*6e9e0626SOleksandr Tymoshenko 		break;
451*6e9e0626SOleksandr Tymoshenko 	case USB_RECIP_OTHER | USB_TYPE_CLASS:
452*6e9e0626SOleksandr Tymoshenko 		hprt0 = readl(&regs->hprt0);
453*6e9e0626SOleksandr Tymoshenko 		if (hprt0 & DWC2_HPRT0_PRTCONNSTS)
454*6e9e0626SOleksandr Tymoshenko 			port_status |= USB_PORT_STAT_CONNECTION;
455*6e9e0626SOleksandr Tymoshenko 		if (hprt0 & DWC2_HPRT0_PRTENA)
456*6e9e0626SOleksandr Tymoshenko 			port_status |= USB_PORT_STAT_ENABLE;
457*6e9e0626SOleksandr Tymoshenko 		if (hprt0 & DWC2_HPRT0_PRTSUSP)
458*6e9e0626SOleksandr Tymoshenko 			port_status |= USB_PORT_STAT_SUSPEND;
459*6e9e0626SOleksandr Tymoshenko 		if (hprt0 & DWC2_HPRT0_PRTOVRCURRACT)
460*6e9e0626SOleksandr Tymoshenko 			port_status |= USB_PORT_STAT_OVERCURRENT;
461*6e9e0626SOleksandr Tymoshenko 		if (hprt0 & DWC2_HPRT0_PRTRST)
462*6e9e0626SOleksandr Tymoshenko 			port_status |= USB_PORT_STAT_RESET;
463*6e9e0626SOleksandr Tymoshenko 		if (hprt0 & DWC2_HPRT0_PRTPWR)
464*6e9e0626SOleksandr Tymoshenko 			port_status |= USB_PORT_STAT_POWER;
465*6e9e0626SOleksandr Tymoshenko 
466*6e9e0626SOleksandr Tymoshenko 		port_status |= USB_PORT_STAT_HIGH_SPEED;
467*6e9e0626SOleksandr Tymoshenko 
468*6e9e0626SOleksandr Tymoshenko 		if (hprt0 & DWC2_HPRT0_PRTENCHNG)
469*6e9e0626SOleksandr Tymoshenko 			port_change |= USB_PORT_STAT_C_ENABLE;
470*6e9e0626SOleksandr Tymoshenko 		if (hprt0 & DWC2_HPRT0_PRTCONNDET)
471*6e9e0626SOleksandr Tymoshenko 			port_change |= USB_PORT_STAT_C_CONNECTION;
472*6e9e0626SOleksandr Tymoshenko 		if (hprt0 & DWC2_HPRT0_PRTOVRCURRCHNG)
473*6e9e0626SOleksandr Tymoshenko 			port_change |= USB_PORT_STAT_C_OVERCURRENT;
474*6e9e0626SOleksandr Tymoshenko 
475*6e9e0626SOleksandr Tymoshenko 		*(uint32_t *)buffer = cpu_to_le32(port_status |
476*6e9e0626SOleksandr Tymoshenko 					(port_change << 16));
477*6e9e0626SOleksandr Tymoshenko 		len = 4;
478*6e9e0626SOleksandr Tymoshenko 		break;
479*6e9e0626SOleksandr Tymoshenko 	default:
480*6e9e0626SOleksandr Tymoshenko 		puts("unsupported root hub command\n");
481*6e9e0626SOleksandr Tymoshenko 		stat = USB_ST_STALLED;
482*6e9e0626SOleksandr Tymoshenko 	}
483*6e9e0626SOleksandr Tymoshenko 
484*6e9e0626SOleksandr Tymoshenko 	dev->act_len = min(len, txlen);
485*6e9e0626SOleksandr Tymoshenko 	dev->status = stat;
486*6e9e0626SOleksandr Tymoshenko 
487*6e9e0626SOleksandr Tymoshenko 	return stat;
488*6e9e0626SOleksandr Tymoshenko }
489*6e9e0626SOleksandr Tymoshenko 
490*6e9e0626SOleksandr Tymoshenko /* Direction: In ; Request: Descriptor */
491*6e9e0626SOleksandr Tymoshenko static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev,
492*6e9e0626SOleksandr Tymoshenko 					       void *buffer, int txlen,
493*6e9e0626SOleksandr Tymoshenko 					       struct devrequest *cmd)
494*6e9e0626SOleksandr Tymoshenko {
495*6e9e0626SOleksandr Tymoshenko 	unsigned char data[32];
496*6e9e0626SOleksandr Tymoshenko 	uint32_t dsc;
497*6e9e0626SOleksandr Tymoshenko 	int len = 0;
498*6e9e0626SOleksandr Tymoshenko 	int stat = 0;
499*6e9e0626SOleksandr Tymoshenko 	uint16_t wValue = cpu_to_le16(cmd->value);
500*6e9e0626SOleksandr Tymoshenko 	uint16_t wLength = cpu_to_le16(cmd->length);
501*6e9e0626SOleksandr Tymoshenko 
502*6e9e0626SOleksandr Tymoshenko 	switch (cmd->requesttype & ~USB_DIR_IN) {
503*6e9e0626SOleksandr Tymoshenko 	case 0:
504*6e9e0626SOleksandr Tymoshenko 		switch (wValue & 0xff00) {
505*6e9e0626SOleksandr Tymoshenko 		case 0x0100:	/* device descriptor */
506*6e9e0626SOleksandr Tymoshenko 			len = min3(txlen, sizeof(root_hub_dev_des), wLength);
507*6e9e0626SOleksandr Tymoshenko 			memcpy(buffer, root_hub_dev_des, len);
508*6e9e0626SOleksandr Tymoshenko 			break;
509*6e9e0626SOleksandr Tymoshenko 		case 0x0200:	/* configuration descriptor */
510*6e9e0626SOleksandr Tymoshenko 			len = min3(txlen, sizeof(root_hub_config_des), wLength);
511*6e9e0626SOleksandr Tymoshenko 			memcpy(buffer, root_hub_config_des, len);
512*6e9e0626SOleksandr Tymoshenko 			break;
513*6e9e0626SOleksandr Tymoshenko 		case 0x0300:	/* string descriptors */
514*6e9e0626SOleksandr Tymoshenko 			switch (wValue & 0xff) {
515*6e9e0626SOleksandr Tymoshenko 			case 0x00:
516*6e9e0626SOleksandr Tymoshenko 				len = min3(txlen, sizeof(root_hub_str_index0),
517*6e9e0626SOleksandr Tymoshenko 					   wLength);
518*6e9e0626SOleksandr Tymoshenko 				memcpy(buffer, root_hub_str_index0, len);
519*6e9e0626SOleksandr Tymoshenko 				break;
520*6e9e0626SOleksandr Tymoshenko 			case 0x01:
521*6e9e0626SOleksandr Tymoshenko 				len = min3(txlen, sizeof(root_hub_str_index1),
522*6e9e0626SOleksandr Tymoshenko 					   wLength);
523*6e9e0626SOleksandr Tymoshenko 				memcpy(buffer, root_hub_str_index1, len);
524*6e9e0626SOleksandr Tymoshenko 				break;
525*6e9e0626SOleksandr Tymoshenko 			}
526*6e9e0626SOleksandr Tymoshenko 			break;
527*6e9e0626SOleksandr Tymoshenko 		default:
528*6e9e0626SOleksandr Tymoshenko 			stat = USB_ST_STALLED;
529*6e9e0626SOleksandr Tymoshenko 		}
530*6e9e0626SOleksandr Tymoshenko 		break;
531*6e9e0626SOleksandr Tymoshenko 
532*6e9e0626SOleksandr Tymoshenko 	case USB_TYPE_CLASS:
533*6e9e0626SOleksandr Tymoshenko 		/* Root port config, set 1 port and nothing else. */
534*6e9e0626SOleksandr Tymoshenko 		dsc = 0x00000001;
535*6e9e0626SOleksandr Tymoshenko 
536*6e9e0626SOleksandr Tymoshenko 		data[0] = 9;		/* min length; */
537*6e9e0626SOleksandr Tymoshenko 		data[1] = 0x29;
538*6e9e0626SOleksandr Tymoshenko 		data[2] = dsc & RH_A_NDP;
539*6e9e0626SOleksandr Tymoshenko 		data[3] = 0;
540*6e9e0626SOleksandr Tymoshenko 		if (dsc & RH_A_PSM)
541*6e9e0626SOleksandr Tymoshenko 			data[3] |= 0x1;
542*6e9e0626SOleksandr Tymoshenko 		if (dsc & RH_A_NOCP)
543*6e9e0626SOleksandr Tymoshenko 			data[3] |= 0x10;
544*6e9e0626SOleksandr Tymoshenko 		else if (dsc & RH_A_OCPM)
545*6e9e0626SOleksandr Tymoshenko 			data[3] |= 0x8;
546*6e9e0626SOleksandr Tymoshenko 
547*6e9e0626SOleksandr Tymoshenko 		/* corresponds to data[4-7] */
548*6e9e0626SOleksandr Tymoshenko 		data[5] = (dsc & RH_A_POTPGT) >> 24;
549*6e9e0626SOleksandr Tymoshenko 		data[7] = dsc & RH_B_DR;
550*6e9e0626SOleksandr Tymoshenko 		if (data[2] < 7) {
551*6e9e0626SOleksandr Tymoshenko 			data[8] = 0xff;
552*6e9e0626SOleksandr Tymoshenko 		} else {
553*6e9e0626SOleksandr Tymoshenko 			data[0] += 2;
554*6e9e0626SOleksandr Tymoshenko 			data[8] = (dsc & RH_B_DR) >> 8;
555*6e9e0626SOleksandr Tymoshenko 			data[9] = 0xff;
556*6e9e0626SOleksandr Tymoshenko 			data[10] = data[9];
557*6e9e0626SOleksandr Tymoshenko 		}
558*6e9e0626SOleksandr Tymoshenko 
559*6e9e0626SOleksandr Tymoshenko 		len = min3(txlen, data[0], wLength);
560*6e9e0626SOleksandr Tymoshenko 		memcpy(buffer, data, len);
561*6e9e0626SOleksandr Tymoshenko 		break;
562*6e9e0626SOleksandr Tymoshenko 	default:
563*6e9e0626SOleksandr Tymoshenko 		puts("unsupported root hub command\n");
564*6e9e0626SOleksandr Tymoshenko 		stat = USB_ST_STALLED;
565*6e9e0626SOleksandr Tymoshenko 	}
566*6e9e0626SOleksandr Tymoshenko 
567*6e9e0626SOleksandr Tymoshenko 	dev->act_len = min(len, txlen);
568*6e9e0626SOleksandr Tymoshenko 	dev->status = stat;
569*6e9e0626SOleksandr Tymoshenko 
570*6e9e0626SOleksandr Tymoshenko 	return stat;
571*6e9e0626SOleksandr Tymoshenko }
572*6e9e0626SOleksandr Tymoshenko 
573*6e9e0626SOleksandr Tymoshenko /* Direction: In ; Request: Configuration */
574*6e9e0626SOleksandr Tymoshenko static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev,
575*6e9e0626SOleksandr Tymoshenko 						  void *buffer, int txlen,
576*6e9e0626SOleksandr Tymoshenko 						  struct devrequest *cmd)
577*6e9e0626SOleksandr Tymoshenko {
578*6e9e0626SOleksandr Tymoshenko 	int len = 0;
579*6e9e0626SOleksandr Tymoshenko 	int stat = 0;
580*6e9e0626SOleksandr Tymoshenko 
581*6e9e0626SOleksandr Tymoshenko 	switch (cmd->requesttype & ~USB_DIR_IN) {
582*6e9e0626SOleksandr Tymoshenko 	case 0:
583*6e9e0626SOleksandr Tymoshenko 		*(uint8_t *)buffer = 0x01;
584*6e9e0626SOleksandr Tymoshenko 		len = 1;
585*6e9e0626SOleksandr Tymoshenko 		break;
586*6e9e0626SOleksandr Tymoshenko 	default:
587*6e9e0626SOleksandr Tymoshenko 		puts("unsupported root hub command\n");
588*6e9e0626SOleksandr Tymoshenko 		stat = USB_ST_STALLED;
589*6e9e0626SOleksandr Tymoshenko 	}
590*6e9e0626SOleksandr Tymoshenko 
591*6e9e0626SOleksandr Tymoshenko 	dev->act_len = min(len, txlen);
592*6e9e0626SOleksandr Tymoshenko 	dev->status = stat;
593*6e9e0626SOleksandr Tymoshenko 
594*6e9e0626SOleksandr Tymoshenko 	return stat;
595*6e9e0626SOleksandr Tymoshenko }
596*6e9e0626SOleksandr Tymoshenko 
597*6e9e0626SOleksandr Tymoshenko /* Direction: In */
598*6e9e0626SOleksandr Tymoshenko static int dwc_otg_submit_rh_msg_in(struct usb_device *dev,
599*6e9e0626SOleksandr Tymoshenko 				 void *buffer, int txlen,
600*6e9e0626SOleksandr Tymoshenko 				 struct devrequest *cmd)
601*6e9e0626SOleksandr Tymoshenko {
602*6e9e0626SOleksandr Tymoshenko 	switch (cmd->request) {
603*6e9e0626SOleksandr Tymoshenko 	case USB_REQ_GET_STATUS:
604*6e9e0626SOleksandr Tymoshenko 		return dwc_otg_submit_rh_msg_in_status(dev, buffer,
605*6e9e0626SOleksandr Tymoshenko 						       txlen, cmd);
606*6e9e0626SOleksandr Tymoshenko 	case USB_REQ_GET_DESCRIPTOR:
607*6e9e0626SOleksandr Tymoshenko 		return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer,
608*6e9e0626SOleksandr Tymoshenko 							   txlen, cmd);
609*6e9e0626SOleksandr Tymoshenko 	case USB_REQ_GET_CONFIGURATION:
610*6e9e0626SOleksandr Tymoshenko 		return dwc_otg_submit_rh_msg_in_configuration(dev, buffer,
611*6e9e0626SOleksandr Tymoshenko 							      txlen, cmd);
612*6e9e0626SOleksandr Tymoshenko 	default:
613*6e9e0626SOleksandr Tymoshenko 		puts("unsupported root hub command\n");
614*6e9e0626SOleksandr Tymoshenko 		return USB_ST_STALLED;
615*6e9e0626SOleksandr Tymoshenko 	}
616*6e9e0626SOleksandr Tymoshenko }
617*6e9e0626SOleksandr Tymoshenko 
618*6e9e0626SOleksandr Tymoshenko /* Direction: Out */
619*6e9e0626SOleksandr Tymoshenko static int dwc_otg_submit_rh_msg_out(struct usb_device *dev,
620*6e9e0626SOleksandr Tymoshenko 				 void *buffer, int txlen,
621*6e9e0626SOleksandr Tymoshenko 				 struct devrequest *cmd)
622*6e9e0626SOleksandr Tymoshenko {
623*6e9e0626SOleksandr Tymoshenko 	int len = 0;
624*6e9e0626SOleksandr Tymoshenko 	int stat = 0;
625*6e9e0626SOleksandr Tymoshenko 	uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8);
626*6e9e0626SOleksandr Tymoshenko 	uint16_t wValue = cpu_to_le16(cmd->value);
627*6e9e0626SOleksandr Tymoshenko 
628*6e9e0626SOleksandr Tymoshenko 	switch (bmrtype_breq & ~USB_DIR_IN) {
629*6e9e0626SOleksandr Tymoshenko 	case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_ENDPOINT:
630*6e9e0626SOleksandr Tymoshenko 	case (USB_REQ_CLEAR_FEATURE << 8) | USB_TYPE_CLASS:
631*6e9e0626SOleksandr Tymoshenko 		break;
632*6e9e0626SOleksandr Tymoshenko 
633*6e9e0626SOleksandr Tymoshenko 	case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
634*6e9e0626SOleksandr Tymoshenko 		switch (wValue) {
635*6e9e0626SOleksandr Tymoshenko 		case USB_PORT_FEAT_C_CONNECTION:
636*6e9e0626SOleksandr Tymoshenko 			setbits_le32(&regs->hprt0, DWC2_HPRT0_PRTCONNDET);
637*6e9e0626SOleksandr Tymoshenko 			break;
638*6e9e0626SOleksandr Tymoshenko 		}
639*6e9e0626SOleksandr Tymoshenko 		break;
640*6e9e0626SOleksandr Tymoshenko 
641*6e9e0626SOleksandr Tymoshenko 	case (USB_REQ_SET_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
642*6e9e0626SOleksandr Tymoshenko 		switch (wValue) {
643*6e9e0626SOleksandr Tymoshenko 		case USB_PORT_FEAT_SUSPEND:
644*6e9e0626SOleksandr Tymoshenko 			break;
645*6e9e0626SOleksandr Tymoshenko 
646*6e9e0626SOleksandr Tymoshenko 		case USB_PORT_FEAT_RESET:
647*6e9e0626SOleksandr Tymoshenko 			clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
648*6e9e0626SOleksandr Tymoshenko 					DWC2_HPRT0_PRTCONNDET |
649*6e9e0626SOleksandr Tymoshenko 					DWC2_HPRT0_PRTENCHNG |
650*6e9e0626SOleksandr Tymoshenko 					DWC2_HPRT0_PRTOVRCURRCHNG,
651*6e9e0626SOleksandr Tymoshenko 					DWC2_HPRT0_PRTRST);
652*6e9e0626SOleksandr Tymoshenko 			mdelay(50);
653*6e9e0626SOleksandr Tymoshenko 			clrbits_le32(&regs->hprt0, DWC2_HPRT0_PRTRST);
654*6e9e0626SOleksandr Tymoshenko 			break;
655*6e9e0626SOleksandr Tymoshenko 
656*6e9e0626SOleksandr Tymoshenko 		case USB_PORT_FEAT_POWER:
657*6e9e0626SOleksandr Tymoshenko 			clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
658*6e9e0626SOleksandr Tymoshenko 					DWC2_HPRT0_PRTCONNDET |
659*6e9e0626SOleksandr Tymoshenko 					DWC2_HPRT0_PRTENCHNG |
660*6e9e0626SOleksandr Tymoshenko 					DWC2_HPRT0_PRTOVRCURRCHNG,
661*6e9e0626SOleksandr Tymoshenko 					DWC2_HPRT0_PRTRST);
662*6e9e0626SOleksandr Tymoshenko 			break;
663*6e9e0626SOleksandr Tymoshenko 
664*6e9e0626SOleksandr Tymoshenko 		case USB_PORT_FEAT_ENABLE:
665*6e9e0626SOleksandr Tymoshenko 			break;
666*6e9e0626SOleksandr Tymoshenko 		}
667*6e9e0626SOleksandr Tymoshenko 		break;
668*6e9e0626SOleksandr Tymoshenko 	case (USB_REQ_SET_ADDRESS << 8):
669*6e9e0626SOleksandr Tymoshenko 		root_hub_devnum = wValue;
670*6e9e0626SOleksandr Tymoshenko 		break;
671*6e9e0626SOleksandr Tymoshenko 	case (USB_REQ_SET_CONFIGURATION << 8):
672*6e9e0626SOleksandr Tymoshenko 		break;
673*6e9e0626SOleksandr Tymoshenko 	default:
674*6e9e0626SOleksandr Tymoshenko 		puts("unsupported root hub command\n");
675*6e9e0626SOleksandr Tymoshenko 		stat = USB_ST_STALLED;
676*6e9e0626SOleksandr Tymoshenko 	}
677*6e9e0626SOleksandr Tymoshenko 
678*6e9e0626SOleksandr Tymoshenko 	len = min(len, txlen);
679*6e9e0626SOleksandr Tymoshenko 
680*6e9e0626SOleksandr Tymoshenko 	dev->act_len = len;
681*6e9e0626SOleksandr Tymoshenko 	dev->status = stat;
682*6e9e0626SOleksandr Tymoshenko 
683*6e9e0626SOleksandr Tymoshenko 	return stat;
684*6e9e0626SOleksandr Tymoshenko }
685*6e9e0626SOleksandr Tymoshenko 
686*6e9e0626SOleksandr Tymoshenko static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
687*6e9e0626SOleksandr Tymoshenko 				 void *buffer, int txlen,
688*6e9e0626SOleksandr Tymoshenko 				 struct devrequest *cmd)
689*6e9e0626SOleksandr Tymoshenko {
690*6e9e0626SOleksandr Tymoshenko 	int stat = 0;
691*6e9e0626SOleksandr Tymoshenko 
692*6e9e0626SOleksandr Tymoshenko 	if (usb_pipeint(pipe)) {
693*6e9e0626SOleksandr Tymoshenko 		puts("Root-Hub submit IRQ: NOT implemented\n");
694*6e9e0626SOleksandr Tymoshenko 		return 0;
695*6e9e0626SOleksandr Tymoshenko 	}
696*6e9e0626SOleksandr Tymoshenko 
697*6e9e0626SOleksandr Tymoshenko 	if (cmd->requesttype & USB_DIR_IN)
698*6e9e0626SOleksandr Tymoshenko 		stat = dwc_otg_submit_rh_msg_in(dev, buffer, txlen, cmd);
699*6e9e0626SOleksandr Tymoshenko 	else
700*6e9e0626SOleksandr Tymoshenko 		stat = dwc_otg_submit_rh_msg_out(dev, buffer, txlen, cmd);
701*6e9e0626SOleksandr Tymoshenko 
702*6e9e0626SOleksandr Tymoshenko 	mdelay(1);
703*6e9e0626SOleksandr Tymoshenko 
704*6e9e0626SOleksandr Tymoshenko 	return stat;
705*6e9e0626SOleksandr Tymoshenko }
706*6e9e0626SOleksandr Tymoshenko 
707*6e9e0626SOleksandr Tymoshenko /* U-Boot USB transmission interface */
708*6e9e0626SOleksandr Tymoshenko int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
709*6e9e0626SOleksandr Tymoshenko 		    int len)
710*6e9e0626SOleksandr Tymoshenko {
711*6e9e0626SOleksandr Tymoshenko 	int devnum = usb_pipedevice(pipe);
712*6e9e0626SOleksandr Tymoshenko 	int ep = usb_pipeendpoint(pipe);
713*6e9e0626SOleksandr Tymoshenko 	int max = usb_maxpacket(dev, pipe);
714*6e9e0626SOleksandr Tymoshenko 	int done = 0;
715*6e9e0626SOleksandr Tymoshenko 	uint32_t hctsiz, sub, tmp;
716*6e9e0626SOleksandr Tymoshenko 	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
717*6e9e0626SOleksandr Tymoshenko 	uint32_t hcint;
718*6e9e0626SOleksandr Tymoshenko 	uint32_t xfer_len;
719*6e9e0626SOleksandr Tymoshenko 	uint32_t num_packets;
720*6e9e0626SOleksandr Tymoshenko 	int stop_transfer = 0;
721*6e9e0626SOleksandr Tymoshenko 	unsigned int timeout = 1000000;
722*6e9e0626SOleksandr Tymoshenko 
723*6e9e0626SOleksandr Tymoshenko 	if (devnum == root_hub_devnum) {
724*6e9e0626SOleksandr Tymoshenko 		dev->status = 0;
725*6e9e0626SOleksandr Tymoshenko 		return -EINVAL;
726*6e9e0626SOleksandr Tymoshenko 	}
727*6e9e0626SOleksandr Tymoshenko 
728*6e9e0626SOleksandr Tymoshenko 	if (len > DWC2_DATA_BUF_SIZE) {
729*6e9e0626SOleksandr Tymoshenko 		printf("%s: %d is more then available buffer size (%d)\n",
730*6e9e0626SOleksandr Tymoshenko 		       __func__, len, DWC2_DATA_BUF_SIZE);
731*6e9e0626SOleksandr Tymoshenko 		dev->status = 0;
732*6e9e0626SOleksandr Tymoshenko 		dev->act_len = 0;
733*6e9e0626SOleksandr Tymoshenko 		return -EINVAL;
734*6e9e0626SOleksandr Tymoshenko 	}
735*6e9e0626SOleksandr Tymoshenko 
736*6e9e0626SOleksandr Tymoshenko 	while ((done < len) && !stop_transfer) {
737*6e9e0626SOleksandr Tymoshenko 		/* Initialize channel */
738*6e9e0626SOleksandr Tymoshenko 		dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, devnum, ep,
739*6e9e0626SOleksandr Tymoshenko 				usb_pipein(pipe), DWC2_HCCHAR_EPTYPE_BULK, max);
740*6e9e0626SOleksandr Tymoshenko 
741*6e9e0626SOleksandr Tymoshenko 		xfer_len = len - done;
742*6e9e0626SOleksandr Tymoshenko 		/* Make sure that xfer_len is a multiple of max packet size. */
743*6e9e0626SOleksandr Tymoshenko 		if (xfer_len > CONFIG_DWC2_MAX_TRANSFER_SIZE)
744*6e9e0626SOleksandr Tymoshenko 			xfer_len = CONFIG_DWC2_MAX_TRANSFER_SIZE - max + 1;
745*6e9e0626SOleksandr Tymoshenko 
746*6e9e0626SOleksandr Tymoshenko 		if (xfer_len > 0) {
747*6e9e0626SOleksandr Tymoshenko 			num_packets = (xfer_len + max - 1) / max;
748*6e9e0626SOleksandr Tymoshenko 			if (num_packets > CONFIG_DWC2_MAX_PACKET_COUNT) {
749*6e9e0626SOleksandr Tymoshenko 				num_packets = CONFIG_DWC2_MAX_PACKET_COUNT;
750*6e9e0626SOleksandr Tymoshenko 				xfer_len = num_packets * max;
751*6e9e0626SOleksandr Tymoshenko 			}
752*6e9e0626SOleksandr Tymoshenko 		} else {
753*6e9e0626SOleksandr Tymoshenko 			num_packets = 1;
754*6e9e0626SOleksandr Tymoshenko 		}
755*6e9e0626SOleksandr Tymoshenko 
756*6e9e0626SOleksandr Tymoshenko 		if (usb_pipein(pipe))
757*6e9e0626SOleksandr Tymoshenko 			xfer_len = num_packets * max;
758*6e9e0626SOleksandr Tymoshenko 
759*6e9e0626SOleksandr Tymoshenko 		writel((xfer_len << DWC2_HCTSIZ_XFERSIZE_OFFSET) |
760*6e9e0626SOleksandr Tymoshenko 		       (num_packets << DWC2_HCTSIZ_PKTCNT_OFFSET) |
761*6e9e0626SOleksandr Tymoshenko 		       (bulk_data_toggle[devnum][ep] <<
762*6e9e0626SOleksandr Tymoshenko 				DWC2_HCTSIZ_PID_OFFSET),
763*6e9e0626SOleksandr Tymoshenko 		       &hc_regs->hctsiz);
764*6e9e0626SOleksandr Tymoshenko 
765*6e9e0626SOleksandr Tymoshenko 		memcpy(aligned_buffer, (char *)buffer + done, len - done);
766*6e9e0626SOleksandr Tymoshenko 		writel((uint32_t)aligned_buffer, &hc_regs->hcdma);
767*6e9e0626SOleksandr Tymoshenko 
768*6e9e0626SOleksandr Tymoshenko 		/* Set host channel enable after all other setup is complete. */
769*6e9e0626SOleksandr Tymoshenko 		clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
770*6e9e0626SOleksandr Tymoshenko 				DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS,
771*6e9e0626SOleksandr Tymoshenko 				(1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
772*6e9e0626SOleksandr Tymoshenko 				DWC2_HCCHAR_CHEN);
773*6e9e0626SOleksandr Tymoshenko 
774*6e9e0626SOleksandr Tymoshenko 		while (1) {
775*6e9e0626SOleksandr Tymoshenko 			hcint = readl(&hc_regs->hcint);
776*6e9e0626SOleksandr Tymoshenko 
777*6e9e0626SOleksandr Tymoshenko 			if (!(hcint & DWC2_HCINT_CHHLTD))
778*6e9e0626SOleksandr Tymoshenko 				continue;
779*6e9e0626SOleksandr Tymoshenko 
780*6e9e0626SOleksandr Tymoshenko 			if (hcint & DWC2_HCINT_XFERCOMP) {
781*6e9e0626SOleksandr Tymoshenko 				hctsiz = readl(&hc_regs->hctsiz);
782*6e9e0626SOleksandr Tymoshenko 				done += xfer_len;
783*6e9e0626SOleksandr Tymoshenko 
784*6e9e0626SOleksandr Tymoshenko 				sub = hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK;
785*6e9e0626SOleksandr Tymoshenko 				sub >>= DWC2_HCTSIZ_XFERSIZE_OFFSET;
786*6e9e0626SOleksandr Tymoshenko 
787*6e9e0626SOleksandr Tymoshenko 				if (usb_pipein(pipe)) {
788*6e9e0626SOleksandr Tymoshenko 					done -= sub;
789*6e9e0626SOleksandr Tymoshenko 					if (hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK)
790*6e9e0626SOleksandr Tymoshenko 						stop_transfer = 1;
791*6e9e0626SOleksandr Tymoshenko 				}
792*6e9e0626SOleksandr Tymoshenko 
793*6e9e0626SOleksandr Tymoshenko 				tmp = hctsiz & DWC2_HCTSIZ_PID_MASK;
794*6e9e0626SOleksandr Tymoshenko 				tmp >>= DWC2_HCTSIZ_PID_OFFSET;
795*6e9e0626SOleksandr Tymoshenko 				if (tmp == DWC2_HC_PID_DATA1) {
796*6e9e0626SOleksandr Tymoshenko 					bulk_data_toggle[devnum][ep] =
797*6e9e0626SOleksandr Tymoshenko 						DWC2_HC_PID_DATA1;
798*6e9e0626SOleksandr Tymoshenko 				} else {
799*6e9e0626SOleksandr Tymoshenko 					bulk_data_toggle[devnum][ep] =
800*6e9e0626SOleksandr Tymoshenko 						DWC2_HC_PID_DATA0;
801*6e9e0626SOleksandr Tymoshenko 				}
802*6e9e0626SOleksandr Tymoshenko 				break;
803*6e9e0626SOleksandr Tymoshenko 			}
804*6e9e0626SOleksandr Tymoshenko 
805*6e9e0626SOleksandr Tymoshenko 			if (hcint & DWC2_HCINT_STALL) {
806*6e9e0626SOleksandr Tymoshenko 				puts("DWC OTG: Channel halted\n");
807*6e9e0626SOleksandr Tymoshenko 				bulk_data_toggle[devnum][ep] =
808*6e9e0626SOleksandr Tymoshenko 					DWC2_HC_PID_DATA0;
809*6e9e0626SOleksandr Tymoshenko 
810*6e9e0626SOleksandr Tymoshenko 				stop_transfer = 1;
811*6e9e0626SOleksandr Tymoshenko 				break;
812*6e9e0626SOleksandr Tymoshenko 			}
813*6e9e0626SOleksandr Tymoshenko 
814*6e9e0626SOleksandr Tymoshenko 			if (!--timeout) {
815*6e9e0626SOleksandr Tymoshenko 				printf("%s: Timeout!\n", __func__);
816*6e9e0626SOleksandr Tymoshenko 				break;
817*6e9e0626SOleksandr Tymoshenko 			}
818*6e9e0626SOleksandr Tymoshenko 		}
819*6e9e0626SOleksandr Tymoshenko 	}
820*6e9e0626SOleksandr Tymoshenko 
821*6e9e0626SOleksandr Tymoshenko 	if (done && usb_pipein(pipe))
822*6e9e0626SOleksandr Tymoshenko 		memcpy(buffer, aligned_buffer, done);
823*6e9e0626SOleksandr Tymoshenko 
824*6e9e0626SOleksandr Tymoshenko 	writel(0, &hc_regs->hcintmsk);
825*6e9e0626SOleksandr Tymoshenko 	writel(0xFFFFFFFF, &hc_regs->hcint);
826*6e9e0626SOleksandr Tymoshenko 
827*6e9e0626SOleksandr Tymoshenko 	dev->status = 0;
828*6e9e0626SOleksandr Tymoshenko 	dev->act_len = done;
829*6e9e0626SOleksandr Tymoshenko 
830*6e9e0626SOleksandr Tymoshenko 	return 0;
831*6e9e0626SOleksandr Tymoshenko }
832*6e9e0626SOleksandr Tymoshenko 
833*6e9e0626SOleksandr Tymoshenko int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
834*6e9e0626SOleksandr Tymoshenko 		       int len, struct devrequest *setup)
835*6e9e0626SOleksandr Tymoshenko {
836*6e9e0626SOleksandr Tymoshenko 	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
837*6e9e0626SOleksandr Tymoshenko 	int done = 0;
838*6e9e0626SOleksandr Tymoshenko 	int devnum = usb_pipedevice(pipe);
839*6e9e0626SOleksandr Tymoshenko 	int ep = usb_pipeendpoint(pipe);
840*6e9e0626SOleksandr Tymoshenko 	int max = usb_maxpacket(dev, pipe);
841*6e9e0626SOleksandr Tymoshenko 	uint32_t hctsiz = 0, sub, tmp, ret;
842*6e9e0626SOleksandr Tymoshenko 	uint32_t hcint;
843*6e9e0626SOleksandr Tymoshenko 	const uint32_t hcint_comp_hlt_ack = DWC2_HCINT_XFERCOMP |
844*6e9e0626SOleksandr Tymoshenko 		DWC2_HCINT_CHHLTD | DWC2_HCINT_ACK;
845*6e9e0626SOleksandr Tymoshenko 	unsigned int timeout = 1000000;
846*6e9e0626SOleksandr Tymoshenko 
847*6e9e0626SOleksandr Tymoshenko 	/* For CONTROL endpoint pid should start with DATA1 */
848*6e9e0626SOleksandr Tymoshenko 	int status_direction;
849*6e9e0626SOleksandr Tymoshenko 
850*6e9e0626SOleksandr Tymoshenko 	if (devnum == root_hub_devnum) {
851*6e9e0626SOleksandr Tymoshenko 		dev->status = 0;
852*6e9e0626SOleksandr Tymoshenko 		dev->speed = USB_SPEED_HIGH;
853*6e9e0626SOleksandr Tymoshenko 		return dwc_otg_submit_rh_msg(dev, pipe, buffer, len, setup);
854*6e9e0626SOleksandr Tymoshenko 	}
855*6e9e0626SOleksandr Tymoshenko 
856*6e9e0626SOleksandr Tymoshenko 	if (len > DWC2_DATA_BUF_SIZE) {
857*6e9e0626SOleksandr Tymoshenko 		printf("%s: %d is more then available buffer size(%d)\n",
858*6e9e0626SOleksandr Tymoshenko 		       __func__, len, DWC2_DATA_BUF_SIZE);
859*6e9e0626SOleksandr Tymoshenko 		dev->status = 0;
860*6e9e0626SOleksandr Tymoshenko 		dev->act_len = 0;
861*6e9e0626SOleksandr Tymoshenko 		return -EINVAL;
862*6e9e0626SOleksandr Tymoshenko 	}
863*6e9e0626SOleksandr Tymoshenko 
864*6e9e0626SOleksandr Tymoshenko 	/* Initialize channel, OUT for setup buffer */
865*6e9e0626SOleksandr Tymoshenko 	dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, devnum, ep, 0,
866*6e9e0626SOleksandr Tymoshenko 			DWC2_HCCHAR_EPTYPE_CONTROL, max);
867*6e9e0626SOleksandr Tymoshenko 
868*6e9e0626SOleksandr Tymoshenko 	/* SETUP stage  */
869*6e9e0626SOleksandr Tymoshenko 	writel((8 << DWC2_HCTSIZ_XFERSIZE_OFFSET) |
870*6e9e0626SOleksandr Tymoshenko 	       (1 << DWC2_HCTSIZ_PKTCNT_OFFSET) |
871*6e9e0626SOleksandr Tymoshenko 	       (DWC2_HC_PID_SETUP << DWC2_HCTSIZ_PID_OFFSET),
872*6e9e0626SOleksandr Tymoshenko 	       &hc_regs->hctsiz);
873*6e9e0626SOleksandr Tymoshenko 
874*6e9e0626SOleksandr Tymoshenko 	writel((uint32_t)setup, &hc_regs->hcdma);
875*6e9e0626SOleksandr Tymoshenko 
876*6e9e0626SOleksandr Tymoshenko 	/* Set host channel enable after all other setup is complete. */
877*6e9e0626SOleksandr Tymoshenko 	clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
878*6e9e0626SOleksandr Tymoshenko 			DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS,
879*6e9e0626SOleksandr Tymoshenko 			(1 << DWC2_HCCHAR_MULTICNT_OFFSET) | DWC2_HCCHAR_CHEN);
880*6e9e0626SOleksandr Tymoshenko 
881*6e9e0626SOleksandr Tymoshenko 	ret = wait_for_bit(&hc_regs->hcint, DWC2_HCINT_CHHLTD, 1);
882*6e9e0626SOleksandr Tymoshenko 	if (ret)
883*6e9e0626SOleksandr Tymoshenko 		printf("%s: Timeout!\n", __func__);
884*6e9e0626SOleksandr Tymoshenko 
885*6e9e0626SOleksandr Tymoshenko 	hcint = readl(&hc_regs->hcint);
886*6e9e0626SOleksandr Tymoshenko 
887*6e9e0626SOleksandr Tymoshenko 	if (!(hcint & DWC2_HCINT_CHHLTD) || !(hcint & DWC2_HCINT_XFERCOMP)) {
888*6e9e0626SOleksandr Tymoshenko 		printf("%s: Error (HCINT=%08x)\n", __func__, hcint);
889*6e9e0626SOleksandr Tymoshenko 		dev->status = 0;
890*6e9e0626SOleksandr Tymoshenko 		dev->act_len = 0;
891*6e9e0626SOleksandr Tymoshenko 		return -EINVAL;
892*6e9e0626SOleksandr Tymoshenko 	}
893*6e9e0626SOleksandr Tymoshenko 
894*6e9e0626SOleksandr Tymoshenko 	/* Clear interrupts */
895*6e9e0626SOleksandr Tymoshenko 	writel(0, &hc_regs->hcintmsk);
896*6e9e0626SOleksandr Tymoshenko 	writel(0xFFFFFFFF, &hc_regs->hcint);
897*6e9e0626SOleksandr Tymoshenko 
898*6e9e0626SOleksandr Tymoshenko 	if (buffer) {
899*6e9e0626SOleksandr Tymoshenko 		/* DATA stage */
900*6e9e0626SOleksandr Tymoshenko 		dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, devnum, ep,
901*6e9e0626SOleksandr Tymoshenko 				usb_pipein(pipe),
902*6e9e0626SOleksandr Tymoshenko 				DWC2_HCCHAR_EPTYPE_CONTROL, max);
903*6e9e0626SOleksandr Tymoshenko 
904*6e9e0626SOleksandr Tymoshenko 		/* TODO: check if len < 64 */
905*6e9e0626SOleksandr Tymoshenko 		control_data_toggle[devnum][ep] = DWC2_HC_PID_DATA1;
906*6e9e0626SOleksandr Tymoshenko 		writel((len << DWC2_HCTSIZ_XFERSIZE_OFFSET) |
907*6e9e0626SOleksandr Tymoshenko 		       (1 << DWC2_HCTSIZ_PKTCNT_OFFSET) |
908*6e9e0626SOleksandr Tymoshenko 		       (control_data_toggle[devnum][ep] <<
909*6e9e0626SOleksandr Tymoshenko 				DWC2_HCTSIZ_PID_OFFSET),
910*6e9e0626SOleksandr Tymoshenko 		       &hc_regs->hctsiz);
911*6e9e0626SOleksandr Tymoshenko 
912*6e9e0626SOleksandr Tymoshenko 		writel((uint32_t)buffer, &hc_regs->hcdma);
913*6e9e0626SOleksandr Tymoshenko 
914*6e9e0626SOleksandr Tymoshenko 		/* Set host channel enable after all other setup is complete */
915*6e9e0626SOleksandr Tymoshenko 		clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
916*6e9e0626SOleksandr Tymoshenko 				DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS,
917*6e9e0626SOleksandr Tymoshenko 				(1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
918*6e9e0626SOleksandr Tymoshenko 				DWC2_HCCHAR_CHEN);
919*6e9e0626SOleksandr Tymoshenko 
920*6e9e0626SOleksandr Tymoshenko 		while (1) {
921*6e9e0626SOleksandr Tymoshenko 			hcint = readl(&hc_regs->hcint);
922*6e9e0626SOleksandr Tymoshenko 			if (!(hcint & DWC2_HCINT_CHHLTD))
923*6e9e0626SOleksandr Tymoshenko 				continue;
924*6e9e0626SOleksandr Tymoshenko 
925*6e9e0626SOleksandr Tymoshenko 			if (hcint & DWC2_HCINT_XFERCOMP) {
926*6e9e0626SOleksandr Tymoshenko 				hctsiz = readl(&hc_regs->hctsiz);
927*6e9e0626SOleksandr Tymoshenko 				done = len;
928*6e9e0626SOleksandr Tymoshenko 
929*6e9e0626SOleksandr Tymoshenko 				sub = hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK;
930*6e9e0626SOleksandr Tymoshenko 				sub >>= DWC2_HCTSIZ_XFERSIZE_OFFSET;
931*6e9e0626SOleksandr Tymoshenko 
932*6e9e0626SOleksandr Tymoshenko 				if (usb_pipein(pipe))
933*6e9e0626SOleksandr Tymoshenko 					done -= sub;
934*6e9e0626SOleksandr Tymoshenko 			}
935*6e9e0626SOleksandr Tymoshenko 
936*6e9e0626SOleksandr Tymoshenko 			if (hcint & DWC2_HCINT_ACK) {
937*6e9e0626SOleksandr Tymoshenko 				tmp = hctsiz & DWC2_HCTSIZ_PID_MASK;
938*6e9e0626SOleksandr Tymoshenko 				tmp >>= DWC2_HCTSIZ_PID_OFFSET;
939*6e9e0626SOleksandr Tymoshenko 				if (tmp == DWC2_HC_PID_DATA0) {
940*6e9e0626SOleksandr Tymoshenko 					control_data_toggle[devnum][ep] =
941*6e9e0626SOleksandr Tymoshenko 						DWC2_HC_PID_DATA0;
942*6e9e0626SOleksandr Tymoshenko 				} else {
943*6e9e0626SOleksandr Tymoshenko 					control_data_toggle[devnum][ep] =
944*6e9e0626SOleksandr Tymoshenko 						DWC2_HC_PID_DATA1;
945*6e9e0626SOleksandr Tymoshenko 				}
946*6e9e0626SOleksandr Tymoshenko 			}
947*6e9e0626SOleksandr Tymoshenko 
948*6e9e0626SOleksandr Tymoshenko 			if (hcint != hcint_comp_hlt_ack) {
949*6e9e0626SOleksandr Tymoshenko 				printf("%s: Error (HCINT=%08x)\n",
950*6e9e0626SOleksandr Tymoshenko 				       __func__, hcint);
951*6e9e0626SOleksandr Tymoshenko 				goto out;
952*6e9e0626SOleksandr Tymoshenko 			}
953*6e9e0626SOleksandr Tymoshenko 
954*6e9e0626SOleksandr Tymoshenko 			if (!--timeout) {
955*6e9e0626SOleksandr Tymoshenko 				printf("%s: Timeout!\n", __func__);
956*6e9e0626SOleksandr Tymoshenko 				goto out;
957*6e9e0626SOleksandr Tymoshenko 			}
958*6e9e0626SOleksandr Tymoshenko 
959*6e9e0626SOleksandr Tymoshenko 			break;
960*6e9e0626SOleksandr Tymoshenko 		}
961*6e9e0626SOleksandr Tymoshenko 	} /* End of DATA stage */
962*6e9e0626SOleksandr Tymoshenko 
963*6e9e0626SOleksandr Tymoshenko 	/* STATUS stage */
964*6e9e0626SOleksandr Tymoshenko 	if ((len == 0) || usb_pipeout(pipe))
965*6e9e0626SOleksandr Tymoshenko 		status_direction = 1;
966*6e9e0626SOleksandr Tymoshenko 	else
967*6e9e0626SOleksandr Tymoshenko 		status_direction = 0;
968*6e9e0626SOleksandr Tymoshenko 
969*6e9e0626SOleksandr Tymoshenko 	dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, devnum, ep,
970*6e9e0626SOleksandr Tymoshenko 			status_direction, DWC2_HCCHAR_EPTYPE_CONTROL, max);
971*6e9e0626SOleksandr Tymoshenko 
972*6e9e0626SOleksandr Tymoshenko 	writel((1 << DWC2_HCTSIZ_PKTCNT_OFFSET) |
973*6e9e0626SOleksandr Tymoshenko 	       (DWC2_HC_PID_DATA1 << DWC2_HCTSIZ_PID_OFFSET),
974*6e9e0626SOleksandr Tymoshenko 	       &hc_regs->hctsiz);
975*6e9e0626SOleksandr Tymoshenko 
976*6e9e0626SOleksandr Tymoshenko 	writel((uint32_t)status_buffer, &hc_regs->hcdma);
977*6e9e0626SOleksandr Tymoshenko 
978*6e9e0626SOleksandr Tymoshenko 	/* Set host channel enable after all other setup is complete. */
979*6e9e0626SOleksandr Tymoshenko 	clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
980*6e9e0626SOleksandr Tymoshenko 			DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS,
981*6e9e0626SOleksandr Tymoshenko 			(1 << DWC2_HCCHAR_MULTICNT_OFFSET) | DWC2_HCCHAR_CHEN);
982*6e9e0626SOleksandr Tymoshenko 
983*6e9e0626SOleksandr Tymoshenko 	while (1) {
984*6e9e0626SOleksandr Tymoshenko 		hcint = readl(&hc_regs->hcint);
985*6e9e0626SOleksandr Tymoshenko 		if (hcint & DWC2_HCINT_CHHLTD)
986*6e9e0626SOleksandr Tymoshenko 			break;
987*6e9e0626SOleksandr Tymoshenko 	}
988*6e9e0626SOleksandr Tymoshenko 
989*6e9e0626SOleksandr Tymoshenko 	if (hcint != hcint_comp_hlt_ack)
990*6e9e0626SOleksandr Tymoshenko 		printf("%s: Error (HCINT=%08x)\n", __func__, hcint);
991*6e9e0626SOleksandr Tymoshenko 
992*6e9e0626SOleksandr Tymoshenko out:
993*6e9e0626SOleksandr Tymoshenko 	dev->act_len = done;
994*6e9e0626SOleksandr Tymoshenko 	dev->status = 0;
995*6e9e0626SOleksandr Tymoshenko 
996*6e9e0626SOleksandr Tymoshenko 	return done;
997*6e9e0626SOleksandr Tymoshenko }
998*6e9e0626SOleksandr Tymoshenko 
999*6e9e0626SOleksandr Tymoshenko int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
1000*6e9e0626SOleksandr Tymoshenko 		   int len, int interval)
1001*6e9e0626SOleksandr Tymoshenko {
1002*6e9e0626SOleksandr Tymoshenko 	printf("dev = %p pipe = %#lx buf = %p size = %d int = %d\n",
1003*6e9e0626SOleksandr Tymoshenko 	       dev, pipe, buffer, len, interval);
1004*6e9e0626SOleksandr Tymoshenko 	return -ENOSYS;
1005*6e9e0626SOleksandr Tymoshenko }
1006*6e9e0626SOleksandr Tymoshenko 
1007*6e9e0626SOleksandr Tymoshenko /* U-Boot USB control interface */
1008*6e9e0626SOleksandr Tymoshenko int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
1009*6e9e0626SOleksandr Tymoshenko {
1010*6e9e0626SOleksandr Tymoshenko 	uint32_t snpsid;
1011*6e9e0626SOleksandr Tymoshenko 	int i, j;
1012*6e9e0626SOleksandr Tymoshenko 
1013*6e9e0626SOleksandr Tymoshenko 	root_hub_devnum = 0;
1014*6e9e0626SOleksandr Tymoshenko 
1015*6e9e0626SOleksandr Tymoshenko 	snpsid = readl(&regs->gsnpsid);
1016*6e9e0626SOleksandr Tymoshenko 	printf("Core Release: %x.%03x\n", snpsid >> 12 & 0xf, snpsid & 0xfff);
1017*6e9e0626SOleksandr Tymoshenko 
1018*6e9e0626SOleksandr Tymoshenko 	if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx) {
1019*6e9e0626SOleksandr Tymoshenko 		printf("SNPSID invalid (not DWC2 OTG device): %08x\n", snpsid);
1020*6e9e0626SOleksandr Tymoshenko 		return -ENODEV;
1021*6e9e0626SOleksandr Tymoshenko 	}
1022*6e9e0626SOleksandr Tymoshenko 
1023*6e9e0626SOleksandr Tymoshenko 	dwc_otg_core_init(regs);
1024*6e9e0626SOleksandr Tymoshenko 	dwc_otg_core_host_init(regs);
1025*6e9e0626SOleksandr Tymoshenko 
1026*6e9e0626SOleksandr Tymoshenko 	clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
1027*6e9e0626SOleksandr Tymoshenko 			DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
1028*6e9e0626SOleksandr Tymoshenko 			DWC2_HPRT0_PRTOVRCURRCHNG,
1029*6e9e0626SOleksandr Tymoshenko 			DWC2_HPRT0_PRTRST);
1030*6e9e0626SOleksandr Tymoshenko 	mdelay(50);
1031*6e9e0626SOleksandr Tymoshenko 	clrbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET |
1032*6e9e0626SOleksandr Tymoshenko 		     DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG |
1033*6e9e0626SOleksandr Tymoshenko 		     DWC2_HPRT0_PRTRST);
1034*6e9e0626SOleksandr Tymoshenko 
1035*6e9e0626SOleksandr Tymoshenko 	for (i = 0; i < MAX_DEVICE; i++) {
1036*6e9e0626SOleksandr Tymoshenko 		for (j = 0; j < MAX_ENDPOINT; j++) {
1037*6e9e0626SOleksandr Tymoshenko 			control_data_toggle[i][j] = DWC2_HC_PID_DATA1;
1038*6e9e0626SOleksandr Tymoshenko 			bulk_data_toggle[i][j] = DWC2_HC_PID_DATA0;
1039*6e9e0626SOleksandr Tymoshenko 		}
1040*6e9e0626SOleksandr Tymoshenko 	}
1041*6e9e0626SOleksandr Tymoshenko 
1042*6e9e0626SOleksandr Tymoshenko 	return 0;
1043*6e9e0626SOleksandr Tymoshenko }
1044*6e9e0626SOleksandr Tymoshenko 
1045*6e9e0626SOleksandr Tymoshenko int usb_lowlevel_stop(int index)
1046*6e9e0626SOleksandr Tymoshenko {
1047*6e9e0626SOleksandr Tymoshenko 	/* Put everything in reset. */
1048*6e9e0626SOleksandr Tymoshenko 	clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
1049*6e9e0626SOleksandr Tymoshenko 			DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
1050*6e9e0626SOleksandr Tymoshenko 			DWC2_HPRT0_PRTOVRCURRCHNG,
1051*6e9e0626SOleksandr Tymoshenko 			DWC2_HPRT0_PRTRST);
1052*6e9e0626SOleksandr Tymoshenko 	return 0;
1053*6e9e0626SOleksandr Tymoshenko }
1054