xref: /OK3568_Linux_fs/u-boot/drivers/usb/host/dwc2.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
3*4882a593Smuzhiyun  * Copyright (C) 2014 Marek Vasut <marex@denx.de>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:     GPL-2.0+
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <dm.h>
10*4882a593Smuzhiyun #include <errno.h>
11*4882a593Smuzhiyun #include <usb.h>
12*4882a593Smuzhiyun #include <malloc.h>
13*4882a593Smuzhiyun #include <memalign.h>
14*4882a593Smuzhiyun #include <phys2bus.h>
15*4882a593Smuzhiyun #include <usbroothubdes.h>
16*4882a593Smuzhiyun #include <wait_bit.h>
17*4882a593Smuzhiyun #include <asm/io.h>
18*4882a593Smuzhiyun #include <power/regulator.h>
19*4882a593Smuzhiyun #include <reset.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include "dwc2.h"
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* Use only HC channel 0. */
26*4882a593Smuzhiyun #define DWC2_HC_CHANNEL			0
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define DWC2_STATUS_BUF_SIZE		64
29*4882a593Smuzhiyun #define DWC2_DATA_BUF_SIZE		(CONFIG_USB_DWC2_BUFFER_SIZE * 1024)
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define MAX_DEVICE			16
32*4882a593Smuzhiyun #define MAX_ENDPOINT			16
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun struct dwc2_priv {
35*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(DM_USB)
36*4882a593Smuzhiyun 	uint8_t aligned_buffer[DWC2_DATA_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
37*4882a593Smuzhiyun 	uint8_t status_buffer[DWC2_STATUS_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
38*4882a593Smuzhiyun #ifdef CONFIG_DM_REGULATOR
39*4882a593Smuzhiyun 	struct udevice *vbus_supply;
40*4882a593Smuzhiyun #endif
41*4882a593Smuzhiyun #else
42*4882a593Smuzhiyun 	uint8_t *aligned_buffer;
43*4882a593Smuzhiyun 	uint8_t *status_buffer;
44*4882a593Smuzhiyun #endif
45*4882a593Smuzhiyun 	u8 in_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
46*4882a593Smuzhiyun 	u8 out_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
47*4882a593Smuzhiyun 	struct dwc2_core_regs *regs;
48*4882a593Smuzhiyun 	int root_hub_devnum;
49*4882a593Smuzhiyun 	bool ext_vbus;
50*4882a593Smuzhiyun 	/*
51*4882a593Smuzhiyun 	 * The hnp/srp capability must be disabled if the platform
52*4882a593Smuzhiyun 	 * does't support hnp/srp. Otherwise the force mode can't work.
53*4882a593Smuzhiyun 	 */
54*4882a593Smuzhiyun 	bool hnp_srp_disable;
55*4882a593Smuzhiyun 	bool oc_disable;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	struct reset_ctl_bulk	resets;
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #if !CONFIG_IS_ENABLED(DM_USB)
61*4882a593Smuzhiyun /* We need cacheline-aligned buffers for DMA transfers and dcache support */
62*4882a593Smuzhiyun DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer_addr, DWC2_DATA_BUF_SIZE,
63*4882a593Smuzhiyun 		ARCH_DMA_MINALIGN);
64*4882a593Smuzhiyun DEFINE_ALIGN_BUFFER(uint8_t, status_buffer_addr, DWC2_STATUS_BUF_SIZE,
65*4882a593Smuzhiyun 		ARCH_DMA_MINALIGN);
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun static struct dwc2_priv local;
68*4882a593Smuzhiyun #endif
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /*
71*4882a593Smuzhiyun  * DWC2 IP interface
72*4882a593Smuzhiyun  */
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun /*
75*4882a593Smuzhiyun  * Initializes the FSLSPClkSel field of the HCFG register
76*4882a593Smuzhiyun  * depending on the PHY type.
77*4882a593Smuzhiyun  */
init_fslspclksel(struct dwc2_core_regs * regs)78*4882a593Smuzhiyun static void init_fslspclksel(struct dwc2_core_regs *regs)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	uint32_t phyclk;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun #if (CONFIG_DWC2_PHY_TYPE == DWC2_PHY_TYPE_FS)
83*4882a593Smuzhiyun 	phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ;	/* Full speed PHY */
84*4882a593Smuzhiyun #else
85*4882a593Smuzhiyun 	/* High speed PHY running at full speed or high speed */
86*4882a593Smuzhiyun 	phyclk = DWC2_HCFG_FSLSPCLKSEL_30_60_MHZ;
87*4882a593Smuzhiyun #endif
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun #ifdef CONFIG_DWC2_ULPI_FS_LS
90*4882a593Smuzhiyun 	uint32_t hwcfg2 = readl(&regs->ghwcfg2);
91*4882a593Smuzhiyun 	uint32_t hval = (ghwcfg2 & DWC2_HWCFG2_HS_PHY_TYPE_MASK) >>
92*4882a593Smuzhiyun 			DWC2_HWCFG2_HS_PHY_TYPE_OFFSET;
93*4882a593Smuzhiyun 	uint32_t fval = (ghwcfg2 & DWC2_HWCFG2_FS_PHY_TYPE_MASK) >>
94*4882a593Smuzhiyun 			DWC2_HWCFG2_FS_PHY_TYPE_OFFSET;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	if (hval == 2 && fval == 1)
97*4882a593Smuzhiyun 		phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ;	/* Full speed PHY */
98*4882a593Smuzhiyun #endif
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	clrsetbits_le32(&regs->host_regs.hcfg,
101*4882a593Smuzhiyun 			DWC2_HCFG_FSLSPCLKSEL_MASK,
102*4882a593Smuzhiyun 			phyclk << DWC2_HCFG_FSLSPCLKSEL_OFFSET);
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun /*
106*4882a593Smuzhiyun  * Flush a Tx FIFO.
107*4882a593Smuzhiyun  *
108*4882a593Smuzhiyun  * @param regs Programming view of DWC_otg controller.
109*4882a593Smuzhiyun  * @param num Tx FIFO to flush.
110*4882a593Smuzhiyun  */
dwc_otg_flush_tx_fifo(struct dwc2_core_regs * regs,const int num)111*4882a593Smuzhiyun static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	int ret;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	writel(DWC2_GRSTCTL_TXFFLSH | (num << DWC2_GRSTCTL_TXFNUM_OFFSET),
116*4882a593Smuzhiyun 	       &regs->grstctl);
117*4882a593Smuzhiyun 	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_TXFFLSH,
118*4882a593Smuzhiyun 				false, 1000, false);
119*4882a593Smuzhiyun 	if (ret)
120*4882a593Smuzhiyun 		dev_info(dev, "%s: Timeout!\n", __func__);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	/* Wait for 3 PHY Clocks */
123*4882a593Smuzhiyun 	udelay(1);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun /*
127*4882a593Smuzhiyun  * Flush Rx FIFO.
128*4882a593Smuzhiyun  *
129*4882a593Smuzhiyun  * @param regs Programming view of DWC_otg controller.
130*4882a593Smuzhiyun  */
dwc_otg_flush_rx_fifo(struct dwc2_core_regs * regs)131*4882a593Smuzhiyun static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	int ret;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	writel(DWC2_GRSTCTL_RXFFLSH, &regs->grstctl);
136*4882a593Smuzhiyun 	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_RXFFLSH,
137*4882a593Smuzhiyun 				false, 1000, false);
138*4882a593Smuzhiyun 	if (ret)
139*4882a593Smuzhiyun 		dev_info(dev, "%s: Timeout!\n", __func__);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	/* Wait for 3 PHY Clocks */
142*4882a593Smuzhiyun 	udelay(1);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun /*
146*4882a593Smuzhiyun  * Do core a soft reset of the core.  Be careful with this because it
147*4882a593Smuzhiyun  * resets all the internal state machines of the core.
148*4882a593Smuzhiyun  */
dwc_otg_core_reset(struct dwc2_core_regs * regs)149*4882a593Smuzhiyun static void dwc_otg_core_reset(struct dwc2_core_regs *regs)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	int ret;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	/* Wait for AHB master IDLE state. */
154*4882a593Smuzhiyun 	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_AHBIDLE,
155*4882a593Smuzhiyun 				true, 1000, false);
156*4882a593Smuzhiyun 	if (ret)
157*4882a593Smuzhiyun 		dev_info(dev, "%s: Timeout!\n", __func__);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	/* Core Soft Reset */
160*4882a593Smuzhiyun 	writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
161*4882a593Smuzhiyun 	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
162*4882a593Smuzhiyun 				false, 1000, false);
163*4882a593Smuzhiyun 	if (ret)
164*4882a593Smuzhiyun 		dev_info(dev, "%s: Timeout!\n", __func__);
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	/*
167*4882a593Smuzhiyun 	 * Wait for core to come out of reset.
168*4882a593Smuzhiyun 	 * NOTE: This long sleep is _very_ important, otherwise the core will
169*4882a593Smuzhiyun 	 *       not stay in host mode after a connector ID change!
170*4882a593Smuzhiyun 	 */
171*4882a593Smuzhiyun 	mdelay(100);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(DM_USB) && defined(CONFIG_DM_REGULATOR)
dwc_vbus_supply_init(struct udevice * dev)175*4882a593Smuzhiyun static int dwc_vbus_supply_init(struct udevice *dev)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	struct dwc2_priv *priv = dev_get_priv(dev);
178*4882a593Smuzhiyun 	int ret;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	ret = device_get_supply_regulator(dev, "vbus-supply",
181*4882a593Smuzhiyun 					  &priv->vbus_supply);
182*4882a593Smuzhiyun 	if (ret) {
183*4882a593Smuzhiyun 		debug("%s: No vbus supply\n", dev->name);
184*4882a593Smuzhiyun 		return 0;
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	ret = regulator_set_enable(priv->vbus_supply, true);
188*4882a593Smuzhiyun 	if (ret) {
189*4882a593Smuzhiyun 		dev_err(dev, "Error enabling vbus supply\n");
190*4882a593Smuzhiyun 		return ret;
191*4882a593Smuzhiyun 	}
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	return 0;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
dwc_vbus_supply_exit(struct udevice * dev)196*4882a593Smuzhiyun static int dwc_vbus_supply_exit(struct udevice *dev)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	struct dwc2_priv *priv = dev_get_priv(dev);
199*4882a593Smuzhiyun 	int ret;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	if (priv->vbus_supply) {
202*4882a593Smuzhiyun 		ret = regulator_set_enable(priv->vbus_supply, false);
203*4882a593Smuzhiyun 		if (ret) {
204*4882a593Smuzhiyun 			dev_err(dev, "Error disabling vbus supply\n");
205*4882a593Smuzhiyun 			return ret;
206*4882a593Smuzhiyun 		}
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	return 0;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun #else
dwc_vbus_supply_init(struct udevice * dev)212*4882a593Smuzhiyun static int dwc_vbus_supply_init(struct udevice *dev)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	return 0;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(DM_USB)
dwc_vbus_supply_exit(struct udevice * dev)218*4882a593Smuzhiyun static int dwc_vbus_supply_exit(struct udevice *dev)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	return 0;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun #endif
223*4882a593Smuzhiyun #endif
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun /*
226*4882a593Smuzhiyun  * This function initializes the DWC_otg controller registers for
227*4882a593Smuzhiyun  * host mode.
228*4882a593Smuzhiyun  *
229*4882a593Smuzhiyun  * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
230*4882a593Smuzhiyun  * request queues. Host channels are reset to ensure that they are ready for
231*4882a593Smuzhiyun  * performing transfers.
232*4882a593Smuzhiyun  *
233*4882a593Smuzhiyun  * @param dev USB Device (NULL if driver model is not being used)
234*4882a593Smuzhiyun  * @param regs Programming view of DWC_otg controller
235*4882a593Smuzhiyun  *
236*4882a593Smuzhiyun  */
dwc_otg_core_host_init(struct udevice * dev,struct dwc2_core_regs * regs)237*4882a593Smuzhiyun static void dwc_otg_core_host_init(struct udevice *dev,
238*4882a593Smuzhiyun 				   struct dwc2_core_regs *regs)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	uint32_t nptxfifosize = 0;
241*4882a593Smuzhiyun 	uint32_t ptxfifosize = 0;
242*4882a593Smuzhiyun 	uint32_t hprt0 = 0;
243*4882a593Smuzhiyun 	int i, ret, num_channels;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	/* Restart the Phy Clock */
246*4882a593Smuzhiyun 	writel(0, &regs->pcgcctl);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	/* Initialize Host Configuration Register */
249*4882a593Smuzhiyun 	init_fslspclksel(regs);
250*4882a593Smuzhiyun #ifdef CONFIG_DWC2_DFLT_SPEED_FULL
251*4882a593Smuzhiyun 	setbits_le32(&regs->host_regs.hcfg, DWC2_HCFG_FSLSSUPP);
252*4882a593Smuzhiyun #endif
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/* Configure data FIFO sizes */
255*4882a593Smuzhiyun #ifdef CONFIG_DWC2_ENABLE_DYNAMIC_FIFO
256*4882a593Smuzhiyun 	if (readl(&regs->ghwcfg2) & DWC2_HWCFG2_DYNAMIC_FIFO) {
257*4882a593Smuzhiyun 		/* Rx FIFO */
258*4882a593Smuzhiyun 		writel(CONFIG_DWC2_HOST_RX_FIFO_SIZE, &regs->grxfsiz);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 		/* Non-periodic Tx FIFO */
261*4882a593Smuzhiyun 		nptxfifosize |= CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE <<
262*4882a593Smuzhiyun 				DWC2_FIFOSIZE_DEPTH_OFFSET;
263*4882a593Smuzhiyun 		nptxfifosize |= CONFIG_DWC2_HOST_RX_FIFO_SIZE <<
264*4882a593Smuzhiyun 				DWC2_FIFOSIZE_STARTADDR_OFFSET;
265*4882a593Smuzhiyun 		writel(nptxfifosize, &regs->gnptxfsiz);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 		/* Periodic Tx FIFO */
268*4882a593Smuzhiyun 		ptxfifosize |= CONFIG_DWC2_HOST_PERIO_TX_FIFO_SIZE <<
269*4882a593Smuzhiyun 				DWC2_FIFOSIZE_DEPTH_OFFSET;
270*4882a593Smuzhiyun 		ptxfifosize |= (CONFIG_DWC2_HOST_RX_FIFO_SIZE +
271*4882a593Smuzhiyun 				CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE) <<
272*4882a593Smuzhiyun 				DWC2_FIFOSIZE_STARTADDR_OFFSET;
273*4882a593Smuzhiyun 		writel(ptxfifosize, &regs->hptxfsiz);
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun #endif
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	/* Clear Host Set HNP Enable in the OTG Control Register */
278*4882a593Smuzhiyun 	clrbits_le32(&regs->gotgctl, DWC2_GOTGCTL_HSTSETHNPEN);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	/* Make sure the FIFOs are flushed. */
281*4882a593Smuzhiyun 	dwc_otg_flush_tx_fifo(regs, 0x10);	/* All Tx FIFOs */
282*4882a593Smuzhiyun 	dwc_otg_flush_rx_fifo(regs);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	/* Flush out any leftover queued requests. */
285*4882a593Smuzhiyun 	num_channels = readl(&regs->ghwcfg2);
286*4882a593Smuzhiyun 	num_channels &= DWC2_HWCFG2_NUM_HOST_CHAN_MASK;
287*4882a593Smuzhiyun 	num_channels >>= DWC2_HWCFG2_NUM_HOST_CHAN_OFFSET;
288*4882a593Smuzhiyun 	num_channels += 1;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	for (i = 0; i < num_channels; i++)
291*4882a593Smuzhiyun 		clrsetbits_le32(&regs->hc_regs[i].hcchar,
292*4882a593Smuzhiyun 				DWC2_HCCHAR_CHEN | DWC2_HCCHAR_EPDIR,
293*4882a593Smuzhiyun 				DWC2_HCCHAR_CHDIS);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	/* Halt all channels to put them into a known state. */
296*4882a593Smuzhiyun 	for (i = 0; i < num_channels; i++) {
297*4882a593Smuzhiyun 		clrsetbits_le32(&regs->hc_regs[i].hcchar,
298*4882a593Smuzhiyun 				DWC2_HCCHAR_EPDIR,
299*4882a593Smuzhiyun 				DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS);
300*4882a593Smuzhiyun 		ret = wait_for_bit_le32(&regs->hc_regs[i].hcchar,
301*4882a593Smuzhiyun 					DWC2_HCCHAR_CHEN, false, 1000, false);
302*4882a593Smuzhiyun 		if (ret)
303*4882a593Smuzhiyun 			dev_info("%s: Timeout!\n", __func__);
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	/* Turn on the vbus power. */
307*4882a593Smuzhiyun 	if (readl(&regs->gintsts) & DWC2_GINTSTS_CURMODE_HOST) {
308*4882a593Smuzhiyun 		hprt0 = readl(&regs->hprt0);
309*4882a593Smuzhiyun 		hprt0 &= ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET);
310*4882a593Smuzhiyun 		hprt0 &= ~(DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG);
311*4882a593Smuzhiyun 		if (!(hprt0 & DWC2_HPRT0_PRTPWR)) {
312*4882a593Smuzhiyun 			hprt0 |= DWC2_HPRT0_PRTPWR;
313*4882a593Smuzhiyun 			writel(hprt0, &regs->hprt0);
314*4882a593Smuzhiyun 		}
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	if (dev)
318*4882a593Smuzhiyun 		dwc_vbus_supply_init(dev);
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun /*
322*4882a593Smuzhiyun  * This function initializes the DWC_otg controller registers and
323*4882a593Smuzhiyun  * prepares the core for device mode or host mode operation.
324*4882a593Smuzhiyun  *
325*4882a593Smuzhiyun  * @param regs Programming view of the DWC_otg controller
326*4882a593Smuzhiyun  */
dwc_otg_core_init(struct dwc2_priv * priv)327*4882a593Smuzhiyun static void dwc_otg_core_init(struct dwc2_priv *priv)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun 	struct dwc2_core_regs *regs = priv->regs;
330*4882a593Smuzhiyun 	uint32_t ahbcfg = 0;
331*4882a593Smuzhiyun 	uint32_t usbcfg = 0;
332*4882a593Smuzhiyun 	uint8_t brst_sz = CONFIG_DWC2_DMA_BURST_SIZE;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	/* Common Initialization */
335*4882a593Smuzhiyun 	usbcfg = readl(&regs->gusbcfg);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	/* Program the ULPI External VBUS bit if needed */
338*4882a593Smuzhiyun 	if (priv->ext_vbus) {
339*4882a593Smuzhiyun 		usbcfg |= DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV;
340*4882a593Smuzhiyun 		if (!priv->oc_disable) {
341*4882a593Smuzhiyun 			usbcfg |= DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR |
342*4882a593Smuzhiyun 				  DWC2_GUSBCFG_INDICATOR_PASSTHROUGH;
343*4882a593Smuzhiyun 		}
344*4882a593Smuzhiyun 	} else {
345*4882a593Smuzhiyun 		usbcfg &= ~DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV;
346*4882a593Smuzhiyun 	}
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	/* Set external TS Dline pulsing */
349*4882a593Smuzhiyun #ifdef CONFIG_DWC2_TS_DLINE
350*4882a593Smuzhiyun 	usbcfg |= DWC2_GUSBCFG_TERM_SEL_DL_PULSE;
351*4882a593Smuzhiyun #else
352*4882a593Smuzhiyun 	usbcfg &= ~DWC2_GUSBCFG_TERM_SEL_DL_PULSE;
353*4882a593Smuzhiyun #endif
354*4882a593Smuzhiyun 	writel(usbcfg, &regs->gusbcfg);
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	/* Reset the Controller */
357*4882a593Smuzhiyun 	dwc_otg_core_reset(regs);
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	/*
360*4882a593Smuzhiyun 	 * This programming sequence needs to happen in FS mode before
361*4882a593Smuzhiyun 	 * any other programming occurs
362*4882a593Smuzhiyun 	 */
363*4882a593Smuzhiyun #if defined(CONFIG_DWC2_DFLT_SPEED_FULL) && \
364*4882a593Smuzhiyun 	(CONFIG_DWC2_PHY_TYPE == DWC2_PHY_TYPE_FS)
365*4882a593Smuzhiyun 	/* If FS mode with FS PHY */
366*4882a593Smuzhiyun 	setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_PHYSEL);
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	/* Reset after a PHY select */
369*4882a593Smuzhiyun 	dwc_otg_core_reset(regs);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	/*
372*4882a593Smuzhiyun 	 * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS.
373*4882a593Smuzhiyun 	 * Also do this on HNP Dev/Host mode switches (done in dev_init
374*4882a593Smuzhiyun 	 * and host_init).
375*4882a593Smuzhiyun 	 */
376*4882a593Smuzhiyun 	if (readl(&regs->gintsts) & DWC2_GINTSTS_CURMODE_HOST)
377*4882a593Smuzhiyun 		init_fslspclksel(regs);
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun #ifdef CONFIG_DWC2_I2C_ENABLE
380*4882a593Smuzhiyun 	/* Program GUSBCFG.OtgUtmifsSel to I2C */
381*4882a593Smuzhiyun 	setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_OTGUTMIFSSEL);
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	/* Program GI2CCTL.I2CEn */
384*4882a593Smuzhiyun 	clrsetbits_le32(&regs->gi2cctl, DWC2_GI2CCTL_I2CEN |
385*4882a593Smuzhiyun 			DWC2_GI2CCTL_I2CDEVADDR_MASK,
386*4882a593Smuzhiyun 			1 << DWC2_GI2CCTL_I2CDEVADDR_OFFSET);
387*4882a593Smuzhiyun 	setbits_le32(&regs->gi2cctl, DWC2_GI2CCTL_I2CEN);
388*4882a593Smuzhiyun #endif
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun #else
391*4882a593Smuzhiyun 	/* High speed PHY. */
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	/*
394*4882a593Smuzhiyun 	 * HS PHY parameters. These parameters are preserved during
395*4882a593Smuzhiyun 	 * soft reset so only program the first time. Do a soft reset
396*4882a593Smuzhiyun 	 * immediately after setting phyif.
397*4882a593Smuzhiyun 	 */
398*4882a593Smuzhiyun 	usbcfg &= ~(DWC2_GUSBCFG_ULPI_UTMI_SEL | DWC2_GUSBCFG_PHYIF);
399*4882a593Smuzhiyun 	usbcfg |= CONFIG_DWC2_PHY_TYPE << DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	if (usbcfg & DWC2_GUSBCFG_ULPI_UTMI_SEL) {	/* ULPI interface */
402*4882a593Smuzhiyun #ifdef CONFIG_DWC2_PHY_ULPI_DDR
403*4882a593Smuzhiyun 		usbcfg |= DWC2_GUSBCFG_DDRSEL;
404*4882a593Smuzhiyun #else
405*4882a593Smuzhiyun 		usbcfg &= ~DWC2_GUSBCFG_DDRSEL;
406*4882a593Smuzhiyun #endif
407*4882a593Smuzhiyun 	} else {	/* UTMI+ interface */
408*4882a593Smuzhiyun #if (CONFIG_DWC2_UTMI_WIDTH == 16)
409*4882a593Smuzhiyun 		usbcfg |= DWC2_GUSBCFG_PHYIF;
410*4882a593Smuzhiyun #endif
411*4882a593Smuzhiyun 	}
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	writel(usbcfg, &regs->gusbcfg);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	/* Reset after setting the PHY parameters */
416*4882a593Smuzhiyun 	dwc_otg_core_reset(regs);
417*4882a593Smuzhiyun #endif
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	usbcfg = readl(&regs->gusbcfg);
420*4882a593Smuzhiyun 	usbcfg &= ~(DWC2_GUSBCFG_ULPI_FSLS | DWC2_GUSBCFG_ULPI_CLK_SUS_M);
421*4882a593Smuzhiyun #ifdef CONFIG_DWC2_ULPI_FS_LS
422*4882a593Smuzhiyun 	uint32_t hwcfg2 = readl(&regs->ghwcfg2);
423*4882a593Smuzhiyun 	uint32_t hval = (ghwcfg2 & DWC2_HWCFG2_HS_PHY_TYPE_MASK) >>
424*4882a593Smuzhiyun 			DWC2_HWCFG2_HS_PHY_TYPE_OFFSET;
425*4882a593Smuzhiyun 	uint32_t fval = (ghwcfg2 & DWC2_HWCFG2_FS_PHY_TYPE_MASK) >>
426*4882a593Smuzhiyun 			DWC2_HWCFG2_FS_PHY_TYPE_OFFSET;
427*4882a593Smuzhiyun 	if (hval == 2 && fval == 1) {
428*4882a593Smuzhiyun 		usbcfg |= DWC2_GUSBCFG_ULPI_FSLS;
429*4882a593Smuzhiyun 		usbcfg |= DWC2_GUSBCFG_ULPI_CLK_SUS_M;
430*4882a593Smuzhiyun 	}
431*4882a593Smuzhiyun #endif
432*4882a593Smuzhiyun 	if (priv->hnp_srp_disable)
433*4882a593Smuzhiyun 		usbcfg |= DWC2_GUSBCFG_FORCEHOSTMODE;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	writel(usbcfg, &regs->gusbcfg);
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	/* Program the GAHBCFG Register. */
438*4882a593Smuzhiyun 	switch (readl(&regs->ghwcfg2) & DWC2_HWCFG2_ARCHITECTURE_MASK) {
439*4882a593Smuzhiyun 	case DWC2_HWCFG2_ARCHITECTURE_SLAVE_ONLY:
440*4882a593Smuzhiyun 		break;
441*4882a593Smuzhiyun 	case DWC2_HWCFG2_ARCHITECTURE_EXT_DMA:
442*4882a593Smuzhiyun 		while (brst_sz > 1) {
443*4882a593Smuzhiyun 			ahbcfg |= ahbcfg + (1 << DWC2_GAHBCFG_HBURSTLEN_OFFSET);
444*4882a593Smuzhiyun 			ahbcfg &= DWC2_GAHBCFG_HBURSTLEN_MASK;
445*4882a593Smuzhiyun 			brst_sz >>= 1;
446*4882a593Smuzhiyun 		}
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun #ifdef CONFIG_DWC2_DMA_ENABLE
449*4882a593Smuzhiyun 		ahbcfg |= DWC2_GAHBCFG_DMAENABLE;
450*4882a593Smuzhiyun #endif
451*4882a593Smuzhiyun 		break;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	case DWC2_HWCFG2_ARCHITECTURE_INT_DMA:
454*4882a593Smuzhiyun 		ahbcfg |= DWC2_GAHBCFG_HBURSTLEN_INCR4;
455*4882a593Smuzhiyun #ifdef CONFIG_DWC2_DMA_ENABLE
456*4882a593Smuzhiyun 		ahbcfg |= DWC2_GAHBCFG_DMAENABLE;
457*4882a593Smuzhiyun #endif
458*4882a593Smuzhiyun 		break;
459*4882a593Smuzhiyun 	}
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	writel(ahbcfg, &regs->gahbcfg);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	/* Program the capabilities in GUSBCFG Register */
464*4882a593Smuzhiyun 	usbcfg = 0;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	if (!priv->hnp_srp_disable)
467*4882a593Smuzhiyun 		usbcfg |= DWC2_GUSBCFG_HNPCAP | DWC2_GUSBCFG_SRPCAP;
468*4882a593Smuzhiyun #ifdef CONFIG_DWC2_IC_USB_CAP
469*4882a593Smuzhiyun 	usbcfg |= DWC2_GUSBCFG_IC_USB_CAP;
470*4882a593Smuzhiyun #endif
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	setbits_le32(&regs->gusbcfg, usbcfg);
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun /*
476*4882a593Smuzhiyun  * Prepares a host channel for transferring packets to/from a specific
477*4882a593Smuzhiyun  * endpoint. The HCCHARn register is set up with the characteristics specified
478*4882a593Smuzhiyun  * in _hc. Host channel interrupts that may need to be serviced while this
479*4882a593Smuzhiyun  * transfer is in progress are enabled.
480*4882a593Smuzhiyun  *
481*4882a593Smuzhiyun  * @param regs Programming view of DWC_otg controller
482*4882a593Smuzhiyun  * @param hc Information needed to initialize the host channel
483*4882a593Smuzhiyun  */
dwc_otg_hc_init(struct dwc2_core_regs * regs,uint8_t hc_num,struct usb_device * dev,uint8_t dev_addr,uint8_t ep_num,uint8_t ep_is_in,uint8_t ep_type,uint16_t max_packet)484*4882a593Smuzhiyun static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num,
485*4882a593Smuzhiyun 		struct usb_device *dev, uint8_t dev_addr, uint8_t ep_num,
486*4882a593Smuzhiyun 		uint8_t ep_is_in, uint8_t ep_type, uint16_t max_packet)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun 	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[hc_num];
489*4882a593Smuzhiyun 	uint32_t hcchar = (dev_addr << DWC2_HCCHAR_DEVADDR_OFFSET) |
490*4882a593Smuzhiyun 			  (ep_num << DWC2_HCCHAR_EPNUM_OFFSET) |
491*4882a593Smuzhiyun 			  (ep_is_in << DWC2_HCCHAR_EPDIR_OFFSET) |
492*4882a593Smuzhiyun 			  (ep_type << DWC2_HCCHAR_EPTYPE_OFFSET) |
493*4882a593Smuzhiyun 			  (max_packet << DWC2_HCCHAR_MPS_OFFSET);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	if (dev->speed == USB_SPEED_LOW)
496*4882a593Smuzhiyun 		hcchar |= DWC2_HCCHAR_LSPDDEV;
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	/*
499*4882a593Smuzhiyun 	 * Program the HCCHARn register with the endpoint characteristics
500*4882a593Smuzhiyun 	 * for the current transfer.
501*4882a593Smuzhiyun 	 */
502*4882a593Smuzhiyun 	writel(hcchar, &hc_regs->hcchar);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	/* Program the HCSPLIT register, default to no SPLIT */
505*4882a593Smuzhiyun 	writel(0, &hc_regs->hcsplt);
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun 
dwc_otg_hc_init_split(struct dwc2_hc_regs * hc_regs,uint8_t hub_devnum,uint8_t hub_port)508*4882a593Smuzhiyun static void dwc_otg_hc_init_split(struct dwc2_hc_regs *hc_regs,
509*4882a593Smuzhiyun 				  uint8_t hub_devnum, uint8_t hub_port)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	uint32_t hcsplt = 0;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	hcsplt = DWC2_HCSPLT_SPLTENA;
514*4882a593Smuzhiyun 	hcsplt |= hub_devnum << DWC2_HCSPLT_HUBADDR_OFFSET;
515*4882a593Smuzhiyun 	hcsplt |= hub_port << DWC2_HCSPLT_PRTADDR_OFFSET;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	/* Program the HCSPLIT register for SPLITs */
518*4882a593Smuzhiyun 	writel(hcsplt, &hc_regs->hcsplt);
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun /*
522*4882a593Smuzhiyun  * DWC2 to USB API interface
523*4882a593Smuzhiyun  */
524*4882a593Smuzhiyun /* Direction: In ; Request: Status */
dwc_otg_submit_rh_msg_in_status(struct dwc2_core_regs * regs,struct usb_device * dev,void * buffer,int txlen,struct devrequest * cmd)525*4882a593Smuzhiyun static int dwc_otg_submit_rh_msg_in_status(struct dwc2_core_regs *regs,
526*4882a593Smuzhiyun 					   struct usb_device *dev, void *buffer,
527*4882a593Smuzhiyun 					   int txlen, struct devrequest *cmd)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun 	uint32_t hprt0 = 0;
530*4882a593Smuzhiyun 	uint32_t port_status = 0;
531*4882a593Smuzhiyun 	uint32_t port_change = 0;
532*4882a593Smuzhiyun 	int len = 0;
533*4882a593Smuzhiyun 	int stat = 0;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	switch (cmd->requesttype & ~USB_DIR_IN) {
536*4882a593Smuzhiyun 	case 0:
537*4882a593Smuzhiyun 		*(uint16_t *)buffer = cpu_to_le16(1);
538*4882a593Smuzhiyun 		len = 2;
539*4882a593Smuzhiyun 		break;
540*4882a593Smuzhiyun 	case USB_RECIP_INTERFACE:
541*4882a593Smuzhiyun 	case USB_RECIP_ENDPOINT:
542*4882a593Smuzhiyun 		*(uint16_t *)buffer = cpu_to_le16(0);
543*4882a593Smuzhiyun 		len = 2;
544*4882a593Smuzhiyun 		break;
545*4882a593Smuzhiyun 	case USB_TYPE_CLASS:
546*4882a593Smuzhiyun 		*(uint32_t *)buffer = cpu_to_le32(0);
547*4882a593Smuzhiyun 		len = 4;
548*4882a593Smuzhiyun 		break;
549*4882a593Smuzhiyun 	case USB_RECIP_OTHER | USB_TYPE_CLASS:
550*4882a593Smuzhiyun 		hprt0 = readl(&regs->hprt0);
551*4882a593Smuzhiyun 		if (hprt0 & DWC2_HPRT0_PRTCONNSTS)
552*4882a593Smuzhiyun 			port_status |= USB_PORT_STAT_CONNECTION;
553*4882a593Smuzhiyun 		if (hprt0 & DWC2_HPRT0_PRTENA)
554*4882a593Smuzhiyun 			port_status |= USB_PORT_STAT_ENABLE;
555*4882a593Smuzhiyun 		if (hprt0 & DWC2_HPRT0_PRTSUSP)
556*4882a593Smuzhiyun 			port_status |= USB_PORT_STAT_SUSPEND;
557*4882a593Smuzhiyun 		if (hprt0 & DWC2_HPRT0_PRTOVRCURRACT)
558*4882a593Smuzhiyun 			port_status |= USB_PORT_STAT_OVERCURRENT;
559*4882a593Smuzhiyun 		if (hprt0 & DWC2_HPRT0_PRTRST)
560*4882a593Smuzhiyun 			port_status |= USB_PORT_STAT_RESET;
561*4882a593Smuzhiyun 		if (hprt0 & DWC2_HPRT0_PRTPWR)
562*4882a593Smuzhiyun 			port_status |= USB_PORT_STAT_POWER;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 		if ((hprt0 & DWC2_HPRT0_PRTSPD_MASK) == DWC2_HPRT0_PRTSPD_LOW)
565*4882a593Smuzhiyun 			port_status |= USB_PORT_STAT_LOW_SPEED;
566*4882a593Smuzhiyun 		else if ((hprt0 & DWC2_HPRT0_PRTSPD_MASK) ==
567*4882a593Smuzhiyun 			 DWC2_HPRT0_PRTSPD_HIGH)
568*4882a593Smuzhiyun 			port_status |= USB_PORT_STAT_HIGH_SPEED;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 		if (hprt0 & DWC2_HPRT0_PRTENCHNG)
571*4882a593Smuzhiyun 			port_change |= USB_PORT_STAT_C_ENABLE;
572*4882a593Smuzhiyun 		if (hprt0 & DWC2_HPRT0_PRTCONNDET)
573*4882a593Smuzhiyun 			port_change |= USB_PORT_STAT_C_CONNECTION;
574*4882a593Smuzhiyun 		if (hprt0 & DWC2_HPRT0_PRTOVRCURRCHNG)
575*4882a593Smuzhiyun 			port_change |= USB_PORT_STAT_C_OVERCURRENT;
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 		*(uint32_t *)buffer = cpu_to_le32(port_status |
578*4882a593Smuzhiyun 					(port_change << 16));
579*4882a593Smuzhiyun 		len = 4;
580*4882a593Smuzhiyun 		break;
581*4882a593Smuzhiyun 	default:
582*4882a593Smuzhiyun 		puts("unsupported root hub command\n");
583*4882a593Smuzhiyun 		stat = USB_ST_STALLED;
584*4882a593Smuzhiyun 	}
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	dev->act_len = min(len, txlen);
587*4882a593Smuzhiyun 	dev->status = stat;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	return stat;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun /* Direction: In ; Request: Descriptor */
dwc_otg_submit_rh_msg_in_descriptor(struct usb_device * dev,void * buffer,int txlen,struct devrequest * cmd)593*4882a593Smuzhiyun static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev,
594*4882a593Smuzhiyun 					       void *buffer, int txlen,
595*4882a593Smuzhiyun 					       struct devrequest *cmd)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun 	unsigned char data[32];
598*4882a593Smuzhiyun 	uint32_t dsc;
599*4882a593Smuzhiyun 	int len = 0;
600*4882a593Smuzhiyun 	int stat = 0;
601*4882a593Smuzhiyun 	uint16_t wValue = cpu_to_le16(cmd->value);
602*4882a593Smuzhiyun 	uint16_t wLength = cpu_to_le16(cmd->length);
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	switch (cmd->requesttype & ~USB_DIR_IN) {
605*4882a593Smuzhiyun 	case 0:
606*4882a593Smuzhiyun 		switch (wValue & 0xff00) {
607*4882a593Smuzhiyun 		case 0x0100:	/* device descriptor */
608*4882a593Smuzhiyun 			len = min3(txlen, (int)sizeof(root_hub_dev_des), (int)wLength);
609*4882a593Smuzhiyun 			memcpy(buffer, root_hub_dev_des, len);
610*4882a593Smuzhiyun 			break;
611*4882a593Smuzhiyun 		case 0x0200:	/* configuration descriptor */
612*4882a593Smuzhiyun 			len = min3(txlen, (int)sizeof(root_hub_config_des), (int)wLength);
613*4882a593Smuzhiyun 			memcpy(buffer, root_hub_config_des, len);
614*4882a593Smuzhiyun 			break;
615*4882a593Smuzhiyun 		case 0x0300:	/* string descriptors */
616*4882a593Smuzhiyun 			switch (wValue & 0xff) {
617*4882a593Smuzhiyun 			case 0x00:
618*4882a593Smuzhiyun 				len = min3(txlen, (int)sizeof(root_hub_str_index0),
619*4882a593Smuzhiyun 					   (int)wLength);
620*4882a593Smuzhiyun 				memcpy(buffer, root_hub_str_index0, len);
621*4882a593Smuzhiyun 				break;
622*4882a593Smuzhiyun 			case 0x01:
623*4882a593Smuzhiyun 				len = min3(txlen, (int)sizeof(root_hub_str_index1),
624*4882a593Smuzhiyun 					   (int)wLength);
625*4882a593Smuzhiyun 				memcpy(buffer, root_hub_str_index1, len);
626*4882a593Smuzhiyun 				break;
627*4882a593Smuzhiyun 			}
628*4882a593Smuzhiyun 			break;
629*4882a593Smuzhiyun 		default:
630*4882a593Smuzhiyun 			stat = USB_ST_STALLED;
631*4882a593Smuzhiyun 		}
632*4882a593Smuzhiyun 		break;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	case USB_TYPE_CLASS:
635*4882a593Smuzhiyun 		/* Root port config, set 1 port and nothing else. */
636*4882a593Smuzhiyun 		dsc = 0x00000001;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 		data[0] = 9;		/* min length; */
639*4882a593Smuzhiyun 		data[1] = 0x29;
640*4882a593Smuzhiyun 		data[2] = dsc & RH_A_NDP;
641*4882a593Smuzhiyun 		data[3] = 0;
642*4882a593Smuzhiyun 		if (dsc & RH_A_PSM)
643*4882a593Smuzhiyun 			data[3] |= 0x1;
644*4882a593Smuzhiyun 		if (dsc & RH_A_NOCP)
645*4882a593Smuzhiyun 			data[3] |= 0x10;
646*4882a593Smuzhiyun 		else if (dsc & RH_A_OCPM)
647*4882a593Smuzhiyun 			data[3] |= 0x8;
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 		/* corresponds to data[4-7] */
650*4882a593Smuzhiyun 		data[5] = (dsc & RH_A_POTPGT) >> 24;
651*4882a593Smuzhiyun 		data[7] = dsc & RH_B_DR;
652*4882a593Smuzhiyun 		if (data[2] < 7) {
653*4882a593Smuzhiyun 			data[8] = 0xff;
654*4882a593Smuzhiyun 		} else {
655*4882a593Smuzhiyun 			data[0] += 2;
656*4882a593Smuzhiyun 			data[8] = (dsc & RH_B_DR) >> 8;
657*4882a593Smuzhiyun 			data[9] = 0xff;
658*4882a593Smuzhiyun 			data[10] = data[9];
659*4882a593Smuzhiyun 		}
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 		len = min3(txlen, (int)data[0], (int)wLength);
662*4882a593Smuzhiyun 		memcpy(buffer, data, len);
663*4882a593Smuzhiyun 		break;
664*4882a593Smuzhiyun 	default:
665*4882a593Smuzhiyun 		puts("unsupported root hub command\n");
666*4882a593Smuzhiyun 		stat = USB_ST_STALLED;
667*4882a593Smuzhiyun 	}
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	dev->act_len = min(len, txlen);
670*4882a593Smuzhiyun 	dev->status = stat;
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	return stat;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun /* Direction: In ; Request: Configuration */
dwc_otg_submit_rh_msg_in_configuration(struct usb_device * dev,void * buffer,int txlen,struct devrequest * cmd)676*4882a593Smuzhiyun static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev,
677*4882a593Smuzhiyun 						  void *buffer, int txlen,
678*4882a593Smuzhiyun 						  struct devrequest *cmd)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	int len = 0;
681*4882a593Smuzhiyun 	int stat = 0;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	switch (cmd->requesttype & ~USB_DIR_IN) {
684*4882a593Smuzhiyun 	case 0:
685*4882a593Smuzhiyun 		*(uint8_t *)buffer = 0x01;
686*4882a593Smuzhiyun 		len = 1;
687*4882a593Smuzhiyun 		break;
688*4882a593Smuzhiyun 	default:
689*4882a593Smuzhiyun 		puts("unsupported root hub command\n");
690*4882a593Smuzhiyun 		stat = USB_ST_STALLED;
691*4882a593Smuzhiyun 	}
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	dev->act_len = min(len, txlen);
694*4882a593Smuzhiyun 	dev->status = stat;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	return stat;
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun /* Direction: In */
dwc_otg_submit_rh_msg_in(struct dwc2_priv * priv,struct usb_device * dev,void * buffer,int txlen,struct devrequest * cmd)700*4882a593Smuzhiyun static int dwc_otg_submit_rh_msg_in(struct dwc2_priv *priv,
701*4882a593Smuzhiyun 				    struct usb_device *dev, void *buffer,
702*4882a593Smuzhiyun 				    int txlen, struct devrequest *cmd)
703*4882a593Smuzhiyun {
704*4882a593Smuzhiyun 	switch (cmd->request) {
705*4882a593Smuzhiyun 	case USB_REQ_GET_STATUS:
706*4882a593Smuzhiyun 		return dwc_otg_submit_rh_msg_in_status(priv->regs, dev, buffer,
707*4882a593Smuzhiyun 						       txlen, cmd);
708*4882a593Smuzhiyun 	case USB_REQ_GET_DESCRIPTOR:
709*4882a593Smuzhiyun 		return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer,
710*4882a593Smuzhiyun 							   txlen, cmd);
711*4882a593Smuzhiyun 	case USB_REQ_GET_CONFIGURATION:
712*4882a593Smuzhiyun 		return dwc_otg_submit_rh_msg_in_configuration(dev, buffer,
713*4882a593Smuzhiyun 							      txlen, cmd);
714*4882a593Smuzhiyun 	default:
715*4882a593Smuzhiyun 		puts("unsupported root hub command\n");
716*4882a593Smuzhiyun 		return USB_ST_STALLED;
717*4882a593Smuzhiyun 	}
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun /* Direction: Out */
dwc_otg_submit_rh_msg_out(struct dwc2_priv * priv,struct usb_device * dev,void * buffer,int txlen,struct devrequest * cmd)721*4882a593Smuzhiyun static int dwc_otg_submit_rh_msg_out(struct dwc2_priv *priv,
722*4882a593Smuzhiyun 				     struct usb_device *dev,
723*4882a593Smuzhiyun 				     void *buffer, int txlen,
724*4882a593Smuzhiyun 				     struct devrequest *cmd)
725*4882a593Smuzhiyun {
726*4882a593Smuzhiyun 	struct dwc2_core_regs *regs = priv->regs;
727*4882a593Smuzhiyun 	int len = 0;
728*4882a593Smuzhiyun 	int stat = 0;
729*4882a593Smuzhiyun 	uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8);
730*4882a593Smuzhiyun 	uint16_t wValue = cpu_to_le16(cmd->value);
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	switch (bmrtype_breq & ~USB_DIR_IN) {
733*4882a593Smuzhiyun 	case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_ENDPOINT:
734*4882a593Smuzhiyun 	case (USB_REQ_CLEAR_FEATURE << 8) | USB_TYPE_CLASS:
735*4882a593Smuzhiyun 		break;
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 	case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
738*4882a593Smuzhiyun 		switch (wValue) {
739*4882a593Smuzhiyun 		case USB_PORT_FEAT_C_CONNECTION:
740*4882a593Smuzhiyun 			setbits_le32(&regs->hprt0, DWC2_HPRT0_PRTCONNDET);
741*4882a593Smuzhiyun 			break;
742*4882a593Smuzhiyun 		}
743*4882a593Smuzhiyun 		break;
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun 	case (USB_REQ_SET_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
746*4882a593Smuzhiyun 		switch (wValue) {
747*4882a593Smuzhiyun 		case USB_PORT_FEAT_SUSPEND:
748*4882a593Smuzhiyun 			break;
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 		case USB_PORT_FEAT_RESET:
751*4882a593Smuzhiyun 			clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
752*4882a593Smuzhiyun 					DWC2_HPRT0_PRTCONNDET |
753*4882a593Smuzhiyun 					DWC2_HPRT0_PRTENCHNG |
754*4882a593Smuzhiyun 					DWC2_HPRT0_PRTOVRCURRCHNG,
755*4882a593Smuzhiyun 					DWC2_HPRT0_PRTRST);
756*4882a593Smuzhiyun 			mdelay(50);
757*4882a593Smuzhiyun 			clrbits_le32(&regs->hprt0, DWC2_HPRT0_PRTRST);
758*4882a593Smuzhiyun 			break;
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 		case USB_PORT_FEAT_POWER:
761*4882a593Smuzhiyun 			clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
762*4882a593Smuzhiyun 					DWC2_HPRT0_PRTCONNDET |
763*4882a593Smuzhiyun 					DWC2_HPRT0_PRTENCHNG |
764*4882a593Smuzhiyun 					DWC2_HPRT0_PRTOVRCURRCHNG,
765*4882a593Smuzhiyun 					DWC2_HPRT0_PRTRST);
766*4882a593Smuzhiyun 			break;
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 		case USB_PORT_FEAT_ENABLE:
769*4882a593Smuzhiyun 			break;
770*4882a593Smuzhiyun 		}
771*4882a593Smuzhiyun 		break;
772*4882a593Smuzhiyun 	case (USB_REQ_SET_ADDRESS << 8):
773*4882a593Smuzhiyun 		priv->root_hub_devnum = wValue;
774*4882a593Smuzhiyun 		break;
775*4882a593Smuzhiyun 	case (USB_REQ_SET_CONFIGURATION << 8):
776*4882a593Smuzhiyun 		break;
777*4882a593Smuzhiyun 	default:
778*4882a593Smuzhiyun 		puts("unsupported root hub command\n");
779*4882a593Smuzhiyun 		stat = USB_ST_STALLED;
780*4882a593Smuzhiyun 	}
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	len = min(len, txlen);
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	dev->act_len = len;
785*4882a593Smuzhiyun 	dev->status = stat;
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	return stat;
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun 
dwc_otg_submit_rh_msg(struct dwc2_priv * priv,struct usb_device * dev,unsigned long pipe,void * buffer,int txlen,struct devrequest * cmd)790*4882a593Smuzhiyun static int dwc_otg_submit_rh_msg(struct dwc2_priv *priv, struct usb_device *dev,
791*4882a593Smuzhiyun 				 unsigned long pipe, void *buffer, int txlen,
792*4882a593Smuzhiyun 				 struct devrequest *cmd)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun 	int stat = 0;
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 	if (usb_pipeint(pipe)) {
797*4882a593Smuzhiyun 		puts("Root-Hub submit IRQ: NOT implemented\n");
798*4882a593Smuzhiyun 		return 0;
799*4882a593Smuzhiyun 	}
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	if (cmd->requesttype & USB_DIR_IN)
802*4882a593Smuzhiyun 		stat = dwc_otg_submit_rh_msg_in(priv, dev, buffer, txlen, cmd);
803*4882a593Smuzhiyun 	else
804*4882a593Smuzhiyun 		stat = dwc_otg_submit_rh_msg_out(priv, dev, buffer, txlen, cmd);
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	mdelay(1);
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 	return stat;
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun 
wait_for_chhltd(struct dwc2_hc_regs * hc_regs,uint32_t * sub,u8 * toggle)811*4882a593Smuzhiyun int wait_for_chhltd(struct dwc2_hc_regs *hc_regs, uint32_t *sub, u8 *toggle)
812*4882a593Smuzhiyun {
813*4882a593Smuzhiyun 	int ret;
814*4882a593Smuzhiyun 	uint32_t hcint, hctsiz;
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 	ret = wait_for_bit_le32(&hc_regs->hcint, DWC2_HCINT_CHHLTD, true,
817*4882a593Smuzhiyun 				2000, false);
818*4882a593Smuzhiyun 	if (ret)
819*4882a593Smuzhiyun 		return ret;
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	hcint = readl(&hc_regs->hcint);
822*4882a593Smuzhiyun 	hctsiz = readl(&hc_regs->hctsiz);
823*4882a593Smuzhiyun 	*sub = (hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK) >>
824*4882a593Smuzhiyun 		DWC2_HCTSIZ_XFERSIZE_OFFSET;
825*4882a593Smuzhiyun 	*toggle = (hctsiz & DWC2_HCTSIZ_PID_MASK) >> DWC2_HCTSIZ_PID_OFFSET;
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	debug("%s: HCINT=%08x sub=%u toggle=%d\n", __func__, hcint, *sub,
828*4882a593Smuzhiyun 	      *toggle);
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	if (hcint & DWC2_HCINT_XFERCOMP)
831*4882a593Smuzhiyun 		return 0;
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	if (hcint & (DWC2_HCINT_NAK | DWC2_HCINT_FRMOVRUN))
834*4882a593Smuzhiyun 		return -EAGAIN;
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 	debug("%s: Error (HCINT=%08x)\n", __func__, hcint);
837*4882a593Smuzhiyun 	return -EINVAL;
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun static int dwc2_eptype[] = {
841*4882a593Smuzhiyun 	DWC2_HCCHAR_EPTYPE_ISOC,
842*4882a593Smuzhiyun 	DWC2_HCCHAR_EPTYPE_INTR,
843*4882a593Smuzhiyun 	DWC2_HCCHAR_EPTYPE_CONTROL,
844*4882a593Smuzhiyun 	DWC2_HCCHAR_EPTYPE_BULK,
845*4882a593Smuzhiyun };
846*4882a593Smuzhiyun 
transfer_chunk(struct dwc2_hc_regs * hc_regs,void * aligned_buffer,u8 * pid,int in,void * buffer,int num_packets,int xfer_len,int * actual_len,int odd_frame)847*4882a593Smuzhiyun static int transfer_chunk(struct dwc2_hc_regs *hc_regs, void *aligned_buffer,
848*4882a593Smuzhiyun 			  u8 *pid, int in, void *buffer, int num_packets,
849*4882a593Smuzhiyun 			  int xfer_len, int *actual_len, int odd_frame)
850*4882a593Smuzhiyun {
851*4882a593Smuzhiyun 	int ret = 0;
852*4882a593Smuzhiyun 	uint32_t sub;
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 	debug("%s: chunk: pid %d xfer_len %u pkts %u\n", __func__,
855*4882a593Smuzhiyun 	      *pid, xfer_len, num_packets);
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	writel((xfer_len << DWC2_HCTSIZ_XFERSIZE_OFFSET) |
858*4882a593Smuzhiyun 	       (num_packets << DWC2_HCTSIZ_PKTCNT_OFFSET) |
859*4882a593Smuzhiyun 	       (*pid << DWC2_HCTSIZ_PID_OFFSET),
860*4882a593Smuzhiyun 	       &hc_regs->hctsiz);
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun 	if (xfer_len) {
863*4882a593Smuzhiyun 		if (in) {
864*4882a593Smuzhiyun 			invalidate_dcache_range(
865*4882a593Smuzhiyun 					(uintptr_t)aligned_buffer,
866*4882a593Smuzhiyun 					(uintptr_t)aligned_buffer +
867*4882a593Smuzhiyun 					roundup(xfer_len, ARCH_DMA_MINALIGN));
868*4882a593Smuzhiyun 		} else {
869*4882a593Smuzhiyun 			memcpy(aligned_buffer, buffer, xfer_len);
870*4882a593Smuzhiyun 			flush_dcache_range(
871*4882a593Smuzhiyun 					(uintptr_t)aligned_buffer,
872*4882a593Smuzhiyun 					(uintptr_t)aligned_buffer +
873*4882a593Smuzhiyun 					roundup(xfer_len, ARCH_DMA_MINALIGN));
874*4882a593Smuzhiyun 		}
875*4882a593Smuzhiyun 	}
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun 	writel(phys_to_bus((unsigned long)aligned_buffer), &hc_regs->hcdma);
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun 	/* Clear old interrupt conditions for this host channel. */
880*4882a593Smuzhiyun 	writel(0x3fff, &hc_regs->hcint);
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 	/* Set host channel enable after all other setup is complete. */
883*4882a593Smuzhiyun 	clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
884*4882a593Smuzhiyun 			DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS |
885*4882a593Smuzhiyun 			DWC2_HCCHAR_ODDFRM,
886*4882a593Smuzhiyun 			(1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
887*4882a593Smuzhiyun 			(odd_frame << DWC2_HCCHAR_ODDFRM_OFFSET) |
888*4882a593Smuzhiyun 			DWC2_HCCHAR_CHEN);
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 	ret = wait_for_chhltd(hc_regs, &sub, pid);
891*4882a593Smuzhiyun 	if (ret < 0)
892*4882a593Smuzhiyun 		return ret;
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 	if (in) {
895*4882a593Smuzhiyun 		xfer_len -= sub;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 		invalidate_dcache_range((unsigned long)aligned_buffer,
898*4882a593Smuzhiyun 					(unsigned long)aligned_buffer +
899*4882a593Smuzhiyun 					roundup(xfer_len, ARCH_DMA_MINALIGN));
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 		memcpy(buffer, aligned_buffer, xfer_len);
902*4882a593Smuzhiyun 	}
903*4882a593Smuzhiyun 	*actual_len = xfer_len;
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	return ret;
906*4882a593Smuzhiyun }
907*4882a593Smuzhiyun 
chunk_msg(struct dwc2_priv * priv,struct usb_device * dev,unsigned long pipe,u8 * pid,int in,void * buffer,int len)908*4882a593Smuzhiyun int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev,
909*4882a593Smuzhiyun 	      unsigned long pipe, u8 *pid, int in, void *buffer, int len)
910*4882a593Smuzhiyun {
911*4882a593Smuzhiyun 	struct dwc2_core_regs *regs = priv->regs;
912*4882a593Smuzhiyun 	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
913*4882a593Smuzhiyun 	struct dwc2_host_regs *host_regs = &regs->host_regs;
914*4882a593Smuzhiyun 	int devnum = usb_pipedevice(pipe);
915*4882a593Smuzhiyun 	int ep = usb_pipeendpoint(pipe);
916*4882a593Smuzhiyun 	int max = usb_maxpacket(dev, pipe);
917*4882a593Smuzhiyun 	int eptype = dwc2_eptype[usb_pipetype(pipe)];
918*4882a593Smuzhiyun 	int done = 0;
919*4882a593Smuzhiyun 	int ret = 0;
920*4882a593Smuzhiyun 	int do_split = 0;
921*4882a593Smuzhiyun 	int complete_split = 0;
922*4882a593Smuzhiyun 	uint32_t xfer_len;
923*4882a593Smuzhiyun 	uint32_t num_packets;
924*4882a593Smuzhiyun 	int stop_transfer = 0;
925*4882a593Smuzhiyun 	uint32_t max_xfer_len;
926*4882a593Smuzhiyun 	int ssplit_frame_num = 0;
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 	debug("%s: msg: pipe %lx pid %d in %d len %d\n", __func__, pipe, *pid,
929*4882a593Smuzhiyun 	      in, len);
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	max_xfer_len = CONFIG_DWC2_MAX_PACKET_COUNT * max;
932*4882a593Smuzhiyun 	if (max_xfer_len > CONFIG_DWC2_MAX_TRANSFER_SIZE)
933*4882a593Smuzhiyun 		max_xfer_len = CONFIG_DWC2_MAX_TRANSFER_SIZE;
934*4882a593Smuzhiyun 	if (max_xfer_len > DWC2_DATA_BUF_SIZE)
935*4882a593Smuzhiyun 		max_xfer_len = DWC2_DATA_BUF_SIZE;
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	/* Make sure that max_xfer_len is a multiple of max packet size. */
938*4882a593Smuzhiyun 	num_packets = max_xfer_len / max;
939*4882a593Smuzhiyun 	max_xfer_len = num_packets * max;
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	/* Initialize channel */
942*4882a593Smuzhiyun 	dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, dev, devnum, ep, in,
943*4882a593Smuzhiyun 			eptype, max);
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun 	/* Check if the target is a FS/LS device behind a HS hub */
946*4882a593Smuzhiyun 	if (dev->speed != USB_SPEED_HIGH) {
947*4882a593Smuzhiyun 		uint8_t hub_addr;
948*4882a593Smuzhiyun 		uint8_t hub_port;
949*4882a593Smuzhiyun 		uint32_t hprt0 = readl(&regs->hprt0);
950*4882a593Smuzhiyun 		if ((hprt0 & DWC2_HPRT0_PRTSPD_MASK) ==
951*4882a593Smuzhiyun 		     DWC2_HPRT0_PRTSPD_HIGH) {
952*4882a593Smuzhiyun 			usb_find_usb2_hub_address_port(dev, &hub_addr,
953*4882a593Smuzhiyun 						       &hub_port);
954*4882a593Smuzhiyun 			dwc_otg_hc_init_split(hc_regs, hub_addr, hub_port);
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun 			do_split = 1;
957*4882a593Smuzhiyun 			num_packets = 1;
958*4882a593Smuzhiyun 			max_xfer_len = max;
959*4882a593Smuzhiyun 		}
960*4882a593Smuzhiyun 	}
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun 	do {
963*4882a593Smuzhiyun 		int actual_len = 0;
964*4882a593Smuzhiyun 		uint32_t hcint;
965*4882a593Smuzhiyun 		int odd_frame = 0;
966*4882a593Smuzhiyun 		xfer_len = len - done;
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun 		if (xfer_len > max_xfer_len)
969*4882a593Smuzhiyun 			xfer_len = max_xfer_len;
970*4882a593Smuzhiyun 		else if (xfer_len > max)
971*4882a593Smuzhiyun 			num_packets = (xfer_len + max - 1) / max;
972*4882a593Smuzhiyun 		else
973*4882a593Smuzhiyun 			num_packets = 1;
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun 		if (complete_split)
976*4882a593Smuzhiyun 			setbits_le32(&hc_regs->hcsplt, DWC2_HCSPLT_COMPSPLT);
977*4882a593Smuzhiyun 		else if (do_split)
978*4882a593Smuzhiyun 			clrbits_le32(&hc_regs->hcsplt, DWC2_HCSPLT_COMPSPLT);
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 		if (eptype == DWC2_HCCHAR_EPTYPE_INTR) {
981*4882a593Smuzhiyun 			int uframe_num = readl(&host_regs->hfnum);
982*4882a593Smuzhiyun 			if (!(uframe_num & 0x1))
983*4882a593Smuzhiyun 				odd_frame = 1;
984*4882a593Smuzhiyun 		}
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 		ret = transfer_chunk(hc_regs, priv->aligned_buffer, pid,
987*4882a593Smuzhiyun 				     in, (char *)buffer + done, num_packets,
988*4882a593Smuzhiyun 				     xfer_len, &actual_len, odd_frame);
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 		hcint = readl(&hc_regs->hcint);
991*4882a593Smuzhiyun 		if (complete_split) {
992*4882a593Smuzhiyun 			stop_transfer = 0;
993*4882a593Smuzhiyun 			if (hcint & DWC2_HCINT_NYET) {
994*4882a593Smuzhiyun 				ret = 0;
995*4882a593Smuzhiyun 				int frame_num = DWC2_HFNUM_MAX_FRNUM &
996*4882a593Smuzhiyun 						readl(&host_regs->hfnum);
997*4882a593Smuzhiyun 				if (((frame_num - ssplit_frame_num) &
998*4882a593Smuzhiyun 				    DWC2_HFNUM_MAX_FRNUM) > 4)
999*4882a593Smuzhiyun 					ret = -EAGAIN;
1000*4882a593Smuzhiyun 			} else
1001*4882a593Smuzhiyun 				complete_split = 0;
1002*4882a593Smuzhiyun 		} else if (do_split) {
1003*4882a593Smuzhiyun 			if (hcint & DWC2_HCINT_ACK) {
1004*4882a593Smuzhiyun 				ssplit_frame_num = DWC2_HFNUM_MAX_FRNUM &
1005*4882a593Smuzhiyun 						   readl(&host_regs->hfnum);
1006*4882a593Smuzhiyun 				ret = 0;
1007*4882a593Smuzhiyun 				complete_split = 1;
1008*4882a593Smuzhiyun 			}
1009*4882a593Smuzhiyun 		}
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 		if (ret)
1012*4882a593Smuzhiyun 			break;
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 		if (actual_len < xfer_len)
1015*4882a593Smuzhiyun 			stop_transfer = 1;
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 		done += actual_len;
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun 	/* Transactions are done when when either all data is transferred or
1020*4882a593Smuzhiyun 	 * there is a short transfer. In case of a SPLIT make sure the CSPLIT
1021*4882a593Smuzhiyun 	 * is executed.
1022*4882a593Smuzhiyun 	 */
1023*4882a593Smuzhiyun 	} while (((done < len) && !stop_transfer) || complete_split);
1024*4882a593Smuzhiyun 
1025*4882a593Smuzhiyun 	writel(0, &hc_regs->hcintmsk);
1026*4882a593Smuzhiyun 	writel(0xFFFFFFFF, &hc_regs->hcint);
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	dev->status = 0;
1029*4882a593Smuzhiyun 	dev->act_len = done;
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	return ret;
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun /* U-Boot USB transmission interface */
_submit_bulk_msg(struct dwc2_priv * priv,struct usb_device * dev,unsigned long pipe,void * buffer,int len)1035*4882a593Smuzhiyun int _submit_bulk_msg(struct dwc2_priv *priv, struct usb_device *dev,
1036*4882a593Smuzhiyun 		     unsigned long pipe, void *buffer, int len)
1037*4882a593Smuzhiyun {
1038*4882a593Smuzhiyun 	int devnum = usb_pipedevice(pipe);
1039*4882a593Smuzhiyun 	int ep = usb_pipeendpoint(pipe);
1040*4882a593Smuzhiyun 	u8* pid;
1041*4882a593Smuzhiyun 
1042*4882a593Smuzhiyun 	if ((devnum >= MAX_DEVICE) || (devnum == priv->root_hub_devnum)) {
1043*4882a593Smuzhiyun 		dev->status = 0;
1044*4882a593Smuzhiyun 		return -EINVAL;
1045*4882a593Smuzhiyun 	}
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun 	if (usb_pipein(pipe))
1048*4882a593Smuzhiyun 		pid = &priv->in_data_toggle[devnum][ep];
1049*4882a593Smuzhiyun 	else
1050*4882a593Smuzhiyun 		pid = &priv->out_data_toggle[devnum][ep];
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun 	return chunk_msg(priv, dev, pipe, pid, usb_pipein(pipe), buffer, len);
1053*4882a593Smuzhiyun }
1054*4882a593Smuzhiyun 
_submit_control_msg(struct dwc2_priv * priv,struct usb_device * dev,unsigned long pipe,void * buffer,int len,struct devrequest * setup)1055*4882a593Smuzhiyun static int _submit_control_msg(struct dwc2_priv *priv, struct usb_device *dev,
1056*4882a593Smuzhiyun 			       unsigned long pipe, void *buffer, int len,
1057*4882a593Smuzhiyun 			       struct devrequest *setup)
1058*4882a593Smuzhiyun {
1059*4882a593Smuzhiyun 	int devnum = usb_pipedevice(pipe);
1060*4882a593Smuzhiyun 	int ret, act_len;
1061*4882a593Smuzhiyun 	u8 pid;
1062*4882a593Smuzhiyun 	/* For CONTROL endpoint pid should start with DATA1 */
1063*4882a593Smuzhiyun 	int status_direction;
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun 	if (devnum == priv->root_hub_devnum) {
1066*4882a593Smuzhiyun 		dev->status = 0;
1067*4882a593Smuzhiyun 		dev->speed = USB_SPEED_HIGH;
1068*4882a593Smuzhiyun 		return dwc_otg_submit_rh_msg(priv, dev, pipe, buffer, len,
1069*4882a593Smuzhiyun 					     setup);
1070*4882a593Smuzhiyun 	}
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun 	/* SETUP stage */
1073*4882a593Smuzhiyun 	pid = DWC2_HC_PID_SETUP;
1074*4882a593Smuzhiyun 	do {
1075*4882a593Smuzhiyun 		ret = chunk_msg(priv, dev, pipe, &pid, 0, setup, 8);
1076*4882a593Smuzhiyun 	} while (ret == -EAGAIN);
1077*4882a593Smuzhiyun 	if (ret)
1078*4882a593Smuzhiyun 		return ret;
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun 	/* DATA stage */
1081*4882a593Smuzhiyun 	act_len = 0;
1082*4882a593Smuzhiyun 	if (buffer) {
1083*4882a593Smuzhiyun 		pid = DWC2_HC_PID_DATA1;
1084*4882a593Smuzhiyun 		do {
1085*4882a593Smuzhiyun 			ret = chunk_msg(priv, dev, pipe, &pid, usb_pipein(pipe),
1086*4882a593Smuzhiyun 					buffer, len);
1087*4882a593Smuzhiyun 			act_len += dev->act_len;
1088*4882a593Smuzhiyun 			buffer += dev->act_len;
1089*4882a593Smuzhiyun 			len -= dev->act_len;
1090*4882a593Smuzhiyun 		} while (ret == -EAGAIN);
1091*4882a593Smuzhiyun 		if (ret)
1092*4882a593Smuzhiyun 			return ret;
1093*4882a593Smuzhiyun 		status_direction = usb_pipeout(pipe);
1094*4882a593Smuzhiyun 	} else {
1095*4882a593Smuzhiyun 		/* No-data CONTROL always ends with an IN transaction */
1096*4882a593Smuzhiyun 		status_direction = 1;
1097*4882a593Smuzhiyun 	}
1098*4882a593Smuzhiyun 
1099*4882a593Smuzhiyun 	/* STATUS stage */
1100*4882a593Smuzhiyun 	pid = DWC2_HC_PID_DATA1;
1101*4882a593Smuzhiyun 	do {
1102*4882a593Smuzhiyun 		ret = chunk_msg(priv, dev, pipe, &pid, status_direction,
1103*4882a593Smuzhiyun 				priv->status_buffer, 0);
1104*4882a593Smuzhiyun 	} while (ret == -EAGAIN);
1105*4882a593Smuzhiyun 	if (ret)
1106*4882a593Smuzhiyun 		return ret;
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	dev->act_len = act_len;
1109*4882a593Smuzhiyun 
1110*4882a593Smuzhiyun 	return 0;
1111*4882a593Smuzhiyun }
1112*4882a593Smuzhiyun 
_submit_int_msg(struct dwc2_priv * priv,struct usb_device * dev,unsigned long pipe,void * buffer,int len,int interval,bool nonblock)1113*4882a593Smuzhiyun int _submit_int_msg(struct dwc2_priv *priv, struct usb_device *dev,
1114*4882a593Smuzhiyun 		    unsigned long pipe, void *buffer, int len, int interval,
1115*4882a593Smuzhiyun 		    bool nonblock)
1116*4882a593Smuzhiyun {
1117*4882a593Smuzhiyun 	unsigned long timeout;
1118*4882a593Smuzhiyun 	int ret;
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun 	/* FIXME: what is interval? */
1121*4882a593Smuzhiyun 
1122*4882a593Smuzhiyun 	timeout = get_timer(0) + USB_TIMEOUT_MS(pipe);
1123*4882a593Smuzhiyun 	for (;;) {
1124*4882a593Smuzhiyun 		if (get_timer(0) > timeout) {
1125*4882a593Smuzhiyun 			dev_err(dev, "Timeout poll on interrupt endpoint\n");
1126*4882a593Smuzhiyun 			return -ETIMEDOUT;
1127*4882a593Smuzhiyun 		}
1128*4882a593Smuzhiyun 		ret = _submit_bulk_msg(priv, dev, pipe, buffer, len);
1129*4882a593Smuzhiyun 		if ((ret != -EAGAIN) || nonblock)
1130*4882a593Smuzhiyun 			return ret;
1131*4882a593Smuzhiyun 	}
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun 
dwc2_reset(struct udevice * dev)1134*4882a593Smuzhiyun static int dwc2_reset(struct udevice *dev)
1135*4882a593Smuzhiyun {
1136*4882a593Smuzhiyun 	int ret;
1137*4882a593Smuzhiyun 	struct dwc2_priv *priv = dev_get_priv(dev);
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 	ret = reset_get_bulk(dev, &priv->resets);
1140*4882a593Smuzhiyun 	if (ret) {
1141*4882a593Smuzhiyun 		dev_warn(dev, "Can't get reset: %d\n", ret);
1142*4882a593Smuzhiyun 		/* Return 0 if error due to !CONFIG_DM_RESET and reset
1143*4882a593Smuzhiyun 		 * DT property is not present.
1144*4882a593Smuzhiyun 		 */
1145*4882a593Smuzhiyun 		if (ret == -ENOENT || ret == -ENOTSUPP)
1146*4882a593Smuzhiyun 			return 0;
1147*4882a593Smuzhiyun 		else
1148*4882a593Smuzhiyun 			return ret;
1149*4882a593Smuzhiyun 	}
1150*4882a593Smuzhiyun 
1151*4882a593Smuzhiyun 	ret = reset_deassert_bulk(&priv->resets);
1152*4882a593Smuzhiyun 	if (ret) {
1153*4882a593Smuzhiyun 		reset_release_bulk(&priv->resets);
1154*4882a593Smuzhiyun 		dev_err(dev, "Failed to reset: %d\n", ret);
1155*4882a593Smuzhiyun 		return ret;
1156*4882a593Smuzhiyun 	}
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 	return 0;
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun 
dwc2_init_common(struct udevice * dev,struct dwc2_priv * priv)1161*4882a593Smuzhiyun static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
1162*4882a593Smuzhiyun {
1163*4882a593Smuzhiyun 	struct dwc2_core_regs *regs = priv->regs;
1164*4882a593Smuzhiyun 	uint32_t snpsid;
1165*4882a593Smuzhiyun 	int i, j;
1166*4882a593Smuzhiyun 	int ret;
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 	ret = dwc2_reset(dev);
1169*4882a593Smuzhiyun 	if (ret)
1170*4882a593Smuzhiyun 		return ret;
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun 	snpsid = readl(&regs->gsnpsid);
1173*4882a593Smuzhiyun 	dev_info(dev, "Core Release: %x.%03x\n",
1174*4882a593Smuzhiyun 		 snpsid >> 12 & 0xf, snpsid & 0xfff);
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 	if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx &&
1177*4882a593Smuzhiyun 	    (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) {
1178*4882a593Smuzhiyun 		dev_info(dev, "SNPSID invalid (not DWC2 OTG device): %08x\n",
1179*4882a593Smuzhiyun 			 snpsid);
1180*4882a593Smuzhiyun 		return -ENODEV;
1181*4882a593Smuzhiyun 	}
1182*4882a593Smuzhiyun 
1183*4882a593Smuzhiyun #ifdef CONFIG_DWC2_PHY_ULPI_EXT_VBUS
1184*4882a593Smuzhiyun 	priv->ext_vbus = 1;
1185*4882a593Smuzhiyun #else
1186*4882a593Smuzhiyun 	priv->ext_vbus = 0;
1187*4882a593Smuzhiyun #endif
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun 	dwc_otg_core_init(priv);
1190*4882a593Smuzhiyun 	dwc_otg_core_host_init(dev, regs);
1191*4882a593Smuzhiyun 
1192*4882a593Smuzhiyun 	clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
1193*4882a593Smuzhiyun 			DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
1194*4882a593Smuzhiyun 			DWC2_HPRT0_PRTOVRCURRCHNG,
1195*4882a593Smuzhiyun 			DWC2_HPRT0_PRTRST);
1196*4882a593Smuzhiyun 	mdelay(50);
1197*4882a593Smuzhiyun 	clrbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET |
1198*4882a593Smuzhiyun 		     DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG |
1199*4882a593Smuzhiyun 		     DWC2_HPRT0_PRTRST);
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun 	for (i = 0; i < MAX_DEVICE; i++) {
1202*4882a593Smuzhiyun 		for (j = 0; j < MAX_ENDPOINT; j++) {
1203*4882a593Smuzhiyun 			priv->in_data_toggle[i][j] = DWC2_HC_PID_DATA0;
1204*4882a593Smuzhiyun 			priv->out_data_toggle[i][j] = DWC2_HC_PID_DATA0;
1205*4882a593Smuzhiyun 		}
1206*4882a593Smuzhiyun 	}
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	/*
1209*4882a593Smuzhiyun 	 * Add a 1 second delay here. This gives the host controller
1210*4882a593Smuzhiyun 	 * a bit time before the comminucation with the USB devices
1211*4882a593Smuzhiyun 	 * is started (the bus is scanned) and  fixes the USB detection
1212*4882a593Smuzhiyun 	 * problems with some problematic USB keys.
1213*4882a593Smuzhiyun 	 */
1214*4882a593Smuzhiyun 	if (readl(&regs->gintsts) & DWC2_GINTSTS_CURMODE_HOST)
1215*4882a593Smuzhiyun 		mdelay(1000);
1216*4882a593Smuzhiyun 
1217*4882a593Smuzhiyun 	return 0;
1218*4882a593Smuzhiyun }
1219*4882a593Smuzhiyun 
dwc2_uninit_common(struct dwc2_core_regs * regs)1220*4882a593Smuzhiyun static void dwc2_uninit_common(struct dwc2_core_regs *regs)
1221*4882a593Smuzhiyun {
1222*4882a593Smuzhiyun 	/* Put everything in reset. */
1223*4882a593Smuzhiyun 	clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
1224*4882a593Smuzhiyun 			DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
1225*4882a593Smuzhiyun 			DWC2_HPRT0_PRTOVRCURRCHNG,
1226*4882a593Smuzhiyun 			DWC2_HPRT0_PRTRST);
1227*4882a593Smuzhiyun }
1228*4882a593Smuzhiyun 
1229*4882a593Smuzhiyun #if !CONFIG_IS_ENABLED(DM_USB)
submit_control_msg(struct usb_device * dev,unsigned long pipe,void * buffer,int len,struct devrequest * setup)1230*4882a593Smuzhiyun int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
1231*4882a593Smuzhiyun 		       int len, struct devrequest *setup)
1232*4882a593Smuzhiyun {
1233*4882a593Smuzhiyun 	return _submit_control_msg(&local, dev, pipe, buffer, len, setup);
1234*4882a593Smuzhiyun }
1235*4882a593Smuzhiyun 
submit_bulk_msg(struct usb_device * dev,unsigned long pipe,void * buffer,int len)1236*4882a593Smuzhiyun int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
1237*4882a593Smuzhiyun 		    int len)
1238*4882a593Smuzhiyun {
1239*4882a593Smuzhiyun 	return _submit_bulk_msg(&local, dev, pipe, buffer, len);
1240*4882a593Smuzhiyun }
1241*4882a593Smuzhiyun 
submit_int_msg(struct usb_device * dev,unsigned long pipe,void * buffer,int len,int interval,bool nonblock)1242*4882a593Smuzhiyun int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
1243*4882a593Smuzhiyun 		   int len, int interval, bool nonblock)
1244*4882a593Smuzhiyun {
1245*4882a593Smuzhiyun 	return _submit_int_msg(&local, dev, pipe, buffer, len, interval,
1246*4882a593Smuzhiyun 			       nonblock);
1247*4882a593Smuzhiyun }
1248*4882a593Smuzhiyun 
1249*4882a593Smuzhiyun /* U-Boot USB control interface */
usb_lowlevel_init(int index,enum usb_init_type init,void ** controller)1250*4882a593Smuzhiyun int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
1251*4882a593Smuzhiyun {
1252*4882a593Smuzhiyun 	struct dwc2_priv *priv = &local;
1253*4882a593Smuzhiyun 
1254*4882a593Smuzhiyun 	memset(priv, '\0', sizeof(*priv));
1255*4882a593Smuzhiyun 	priv->root_hub_devnum = 0;
1256*4882a593Smuzhiyun 	priv->regs = (struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR;
1257*4882a593Smuzhiyun 	priv->aligned_buffer = aligned_buffer_addr;
1258*4882a593Smuzhiyun 	priv->status_buffer = status_buffer_addr;
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun 	/* board-dependant init */
1261*4882a593Smuzhiyun 	if (board_usb_init(index, USB_INIT_HOST))
1262*4882a593Smuzhiyun 		return -1;
1263*4882a593Smuzhiyun 
1264*4882a593Smuzhiyun 	return dwc2_init_common(NULL, priv);
1265*4882a593Smuzhiyun }
1266*4882a593Smuzhiyun 
usb_lowlevel_stop(int index)1267*4882a593Smuzhiyun int usb_lowlevel_stop(int index)
1268*4882a593Smuzhiyun {
1269*4882a593Smuzhiyun 	dwc2_uninit_common(local.regs);
1270*4882a593Smuzhiyun 
1271*4882a593Smuzhiyun 	return 0;
1272*4882a593Smuzhiyun }
1273*4882a593Smuzhiyun #endif
1274*4882a593Smuzhiyun 
1275*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(DM_USB)
dwc2_submit_control_msg(struct udevice * dev,struct usb_device * udev,unsigned long pipe,void * buffer,int length,struct devrequest * setup)1276*4882a593Smuzhiyun static int dwc2_submit_control_msg(struct udevice *dev, struct usb_device *udev,
1277*4882a593Smuzhiyun 				   unsigned long pipe, void *buffer, int length,
1278*4882a593Smuzhiyun 				   struct devrequest *setup)
1279*4882a593Smuzhiyun {
1280*4882a593Smuzhiyun 	struct dwc2_priv *priv = dev_get_priv(dev);
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun 	debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__,
1283*4882a593Smuzhiyun 	      dev->name, udev, udev->dev->name, udev->portnr);
1284*4882a593Smuzhiyun 
1285*4882a593Smuzhiyun 	return _submit_control_msg(priv, udev, pipe, buffer, length, setup);
1286*4882a593Smuzhiyun }
1287*4882a593Smuzhiyun 
dwc2_submit_bulk_msg(struct udevice * dev,struct usb_device * udev,unsigned long pipe,void * buffer,int length)1288*4882a593Smuzhiyun static int dwc2_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
1289*4882a593Smuzhiyun 				unsigned long pipe, void *buffer, int length)
1290*4882a593Smuzhiyun {
1291*4882a593Smuzhiyun 	struct dwc2_priv *priv = dev_get_priv(dev);
1292*4882a593Smuzhiyun 
1293*4882a593Smuzhiyun 	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 	return _submit_bulk_msg(priv, udev, pipe, buffer, length);
1296*4882a593Smuzhiyun }
1297*4882a593Smuzhiyun 
dwc2_submit_int_msg(struct udevice * dev,struct usb_device * udev,unsigned long pipe,void * buffer,int length,int interval,bool nonblock)1298*4882a593Smuzhiyun static int dwc2_submit_int_msg(struct udevice *dev, struct usb_device *udev,
1299*4882a593Smuzhiyun 			       unsigned long pipe, void *buffer, int length,
1300*4882a593Smuzhiyun 			       int interval, bool nonblock)
1301*4882a593Smuzhiyun {
1302*4882a593Smuzhiyun 	struct dwc2_priv *priv = dev_get_priv(dev);
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	return _submit_int_msg(priv, udev, pipe, buffer, length, interval,
1307*4882a593Smuzhiyun 			       nonblock);
1308*4882a593Smuzhiyun }
1309*4882a593Smuzhiyun 
dwc2_usb_ofdata_to_platdata(struct udevice * dev)1310*4882a593Smuzhiyun static int dwc2_usb_ofdata_to_platdata(struct udevice *dev)
1311*4882a593Smuzhiyun {
1312*4882a593Smuzhiyun 	struct dwc2_priv *priv = dev_get_priv(dev);
1313*4882a593Smuzhiyun 	fdt_addr_t addr;
1314*4882a593Smuzhiyun 
1315*4882a593Smuzhiyun 	addr = dev_read_addr(dev);
1316*4882a593Smuzhiyun 	if (addr == FDT_ADDR_T_NONE)
1317*4882a593Smuzhiyun 		return -EINVAL;
1318*4882a593Smuzhiyun 	priv->regs = (struct dwc2_core_regs *)addr;
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun 	priv->oc_disable = dev_read_bool(dev, "disable-over-current");
1321*4882a593Smuzhiyun 	priv->hnp_srp_disable = dev_read_bool(dev, "hnp-srp-disable");
1322*4882a593Smuzhiyun 
1323*4882a593Smuzhiyun 	return 0;
1324*4882a593Smuzhiyun }
1325*4882a593Smuzhiyun 
dwc2_usb_probe(struct udevice * dev)1326*4882a593Smuzhiyun static int dwc2_usb_probe(struct udevice *dev)
1327*4882a593Smuzhiyun {
1328*4882a593Smuzhiyun 	struct dwc2_priv *priv = dev_get_priv(dev);
1329*4882a593Smuzhiyun 	struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev);
1330*4882a593Smuzhiyun 
1331*4882a593Smuzhiyun 	bus_priv->desc_before_addr = true;
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun #ifdef CONFIG_ARCH_ROCKCHIP
1334*4882a593Smuzhiyun 	priv->hnp_srp_disable = true;
1335*4882a593Smuzhiyun #endif
1336*4882a593Smuzhiyun 
1337*4882a593Smuzhiyun 	return dwc2_init_common(dev, priv);
1338*4882a593Smuzhiyun }
1339*4882a593Smuzhiyun 
dwc2_usb_remove(struct udevice * dev)1340*4882a593Smuzhiyun static int dwc2_usb_remove(struct udevice *dev)
1341*4882a593Smuzhiyun {
1342*4882a593Smuzhiyun 	struct dwc2_priv *priv = dev_get_priv(dev);
1343*4882a593Smuzhiyun 	int ret;
1344*4882a593Smuzhiyun 
1345*4882a593Smuzhiyun 	ret = dwc_vbus_supply_exit(dev);
1346*4882a593Smuzhiyun 	if (ret)
1347*4882a593Smuzhiyun 		return ret;
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 	dwc2_uninit_common(priv->regs);
1350*4882a593Smuzhiyun 
1351*4882a593Smuzhiyun 	reset_release_bulk(&priv->resets);
1352*4882a593Smuzhiyun 
1353*4882a593Smuzhiyun 	return 0;
1354*4882a593Smuzhiyun }
1355*4882a593Smuzhiyun 
1356*4882a593Smuzhiyun struct dm_usb_ops dwc2_usb_ops = {
1357*4882a593Smuzhiyun 	.control = dwc2_submit_control_msg,
1358*4882a593Smuzhiyun 	.bulk = dwc2_submit_bulk_msg,
1359*4882a593Smuzhiyun 	.interrupt = dwc2_submit_int_msg,
1360*4882a593Smuzhiyun };
1361*4882a593Smuzhiyun 
1362*4882a593Smuzhiyun static const struct udevice_id dwc2_usb_ids[] = {
1363*4882a593Smuzhiyun 	{ .compatible = "brcm,bcm2835-usb" },
1364*4882a593Smuzhiyun 	{ .compatible = "brcm,bcm2708-usb" },
1365*4882a593Smuzhiyun 	{ .compatible = "snps,dwc2" },
1366*4882a593Smuzhiyun 	{ }
1367*4882a593Smuzhiyun };
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun U_BOOT_DRIVER(usb_dwc2) = {
1370*4882a593Smuzhiyun 	.name	= "dwc2_usb",
1371*4882a593Smuzhiyun 	.id	= UCLASS_USB,
1372*4882a593Smuzhiyun 	.of_match = dwc2_usb_ids,
1373*4882a593Smuzhiyun 	.ofdata_to_platdata = dwc2_usb_ofdata_to_platdata,
1374*4882a593Smuzhiyun 	.probe	= dwc2_usb_probe,
1375*4882a593Smuzhiyun 	.remove = dwc2_usb_remove,
1376*4882a593Smuzhiyun 	.ops	= &dwc2_usb_ops,
1377*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct dwc2_priv),
1378*4882a593Smuzhiyun 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
1379*4882a593Smuzhiyun };
1380*4882a593Smuzhiyun #endif
1381