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(®s->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(®s->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 ®s->grstctl);
117*4882a593Smuzhiyun ret = wait_for_bit_le32(®s->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, ®s->grstctl);
136*4882a593Smuzhiyun ret = wait_for_bit_le32(®s->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(®s->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, ®s->grstctl);
161*4882a593Smuzhiyun ret = wait_for_bit_le32(®s->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, ®s->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(®s->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(®s->ghwcfg2) & DWC2_HWCFG2_DYNAMIC_FIFO) {
257*4882a593Smuzhiyun /* Rx FIFO */
258*4882a593Smuzhiyun writel(CONFIG_DWC2_HOST_RX_FIFO_SIZE, ®s->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, ®s->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, ®s->hptxfsiz);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun #endif
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun /* Clear Host Set HNP Enable in the OTG Control Register */
278*4882a593Smuzhiyun clrbits_le32(®s->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(®s->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(®s->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(®s->hc_regs[i].hcchar,
298*4882a593Smuzhiyun DWC2_HCCHAR_EPDIR,
299*4882a593Smuzhiyun DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS);
300*4882a593Smuzhiyun ret = wait_for_bit_le32(®s->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(®s->gintsts) & DWC2_GINTSTS_CURMODE_HOST) {
308*4882a593Smuzhiyun hprt0 = readl(®s->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, ®s->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(®s->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, ®s->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(®s->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(®s->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(®s->gusbcfg, DWC2_GUSBCFG_OTGUTMIFSSEL);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun /* Program GI2CCTL.I2CEn */
384*4882a593Smuzhiyun clrsetbits_le32(®s->gi2cctl, DWC2_GI2CCTL_I2CEN |
385*4882a593Smuzhiyun DWC2_GI2CCTL_I2CDEVADDR_MASK,
386*4882a593Smuzhiyun 1 << DWC2_GI2CCTL_I2CDEVADDR_OFFSET);
387*4882a593Smuzhiyun setbits_le32(®s->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, ®s->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(®s->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(®s->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, ®s->gusbcfg);
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /* Program the GAHBCFG Register. */
438*4882a593Smuzhiyun switch (readl(®s->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, ®s->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(®s->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 = ®s->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(®s->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(®s->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(®s->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(®s->hprt0, DWC2_HPRT0_PRTRST);
758*4882a593Smuzhiyun break;
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun case USB_PORT_FEAT_POWER:
761*4882a593Smuzhiyun clrsetbits_le32(®s->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 = ®s->hc_regs[DWC2_HC_CHANNEL];
913*4882a593Smuzhiyun struct dwc2_host_regs *host_regs = ®s->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(®s->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(®s->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(®s->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(®s->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(®s->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(®s->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