blob: cbf21d31dd926ccef983637814c87926c605aa24 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +05302/**
3 * core.c - DesignWare USB3 DRD Controller Core file
4 *
Kishon Vijay Abraham Id1e431a2015-02-23 18:39:52 +05305 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +05306 *
7 * Authors: Felipe Balbi <balbi@ti.com>,
8 * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
9 *
Kishon Vijay Abraham Id1e431a2015-02-23 18:39:52 +053010 * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/core.c) and ported
11 * to uboot.
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +053012 *
Kishon Vijay Abraham Id1e431a2015-02-23 18:39:52 +053013 * commit cd72f890d2 : usb: dwc3: core: enable phy suspend quirk on non-FPGA
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +053014 */
15
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +053016#include <common.h>
Simon Glass63334482019-11-14 12:57:39 -070017#include <cpu_func.h>
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +053018#include <malloc.h>
Kishon Vijay Abraham Ibfbf05d2015-02-23 18:40:04 +053019#include <dwc3-uboot.h>
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +053020#include <asm/dma-mapping.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070021#include <dm/devres.h>
22#include <linux/err.h>
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +053023#include <linux/ioport.h>
Mugunthan V N121f93c2018-05-18 13:10:27 +020024#include <dm.h>
Jean-Jacques Hiblot3de978a2018-11-29 10:52:45 +010025#include <generic-phy.h>
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +053026#include <linux/usb/ch9.h>
27#include <linux/usb/gadget.h>
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +053028
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +053029#include "core.h"
30#include "gadget.h"
31#include "io.h"
32
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +053033#include "linux-compat.h"
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +053034
Kishon Vijay Abraham Idc5c6532015-02-23 18:40:05 +053035static LIST_HEAD(dwc3_list);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +053036/* -------------------------------------------------------------------------- */
37
Joonyoung Shimbf35c602015-03-03 17:32:09 +010038static void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +053039{
40 u32 reg;
41
42 reg = dwc3_readl(dwc->regs, DWC3_GCTL);
43 reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
44 reg |= DWC3_GCTL_PRTCAPDIR(mode);
45 dwc3_writel(dwc->regs, DWC3_GCTL, reg);
46}
47
48/**
49 * dwc3_core_soft_reset - Issues core soft reset and PHY reset
50 * @dwc: pointer to our context structure
51 */
52static int dwc3_core_soft_reset(struct dwc3 *dwc)
53{
54 u32 reg;
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +053055
56 /* Before Resetting PHY, put Core in Reset */
57 reg = dwc3_readl(dwc->regs, DWC3_GCTL);
58 reg |= DWC3_GCTL_CORESOFTRESET;
59 dwc3_writel(dwc->regs, DWC3_GCTL, reg);
60
61 /* Assert USB3 PHY reset */
62 reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
63 reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
64 dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
65
66 /* Assert USB2 PHY reset */
67 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
68 reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
69 dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
70
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +053071 mdelay(100);
72
73 /* Clear USB3 PHY reset */
74 reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
75 reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
76 dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
77
78 /* Clear USB2 PHY reset */
79 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
80 reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
81 dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
82
83 mdelay(100);
84
85 /* After PHYs are stable we can take Core out of reset state */
86 reg = dwc3_readl(dwc->regs, DWC3_GCTL);
87 reg &= ~DWC3_GCTL_CORESOFTRESET;
88 dwc3_writel(dwc->regs, DWC3_GCTL, reg);
89
90 return 0;
91}
92
93/**
94 * dwc3_free_one_event_buffer - Frees one event buffer
95 * @dwc: Pointer to our controller context structure
96 * @evt: Pointer to event buffer to be freed
97 */
98static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
99 struct dwc3_event_buffer *evt)
100{
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530101 dma_free_coherent(evt->buf);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530102}
103
104/**
105 * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
106 * @dwc: Pointer to our controller context structure
107 * @length: size of the event buffer
108 *
109 * Returns a pointer to the allocated event buffer structure on success
110 * otherwise ERR_PTR(errno).
111 */
112static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
113 unsigned length)
114{
115 struct dwc3_event_buffer *evt;
116
Mugunthan V N121f93c2018-05-18 13:10:27 +0200117 evt = devm_kzalloc((struct udevice *)dwc->dev, sizeof(*evt),
118 GFP_KERNEL);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530119 if (!evt)
120 return ERR_PTR(-ENOMEM);
121
122 evt->dwc = dwc;
123 evt->length = length;
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530124 evt->buf = dma_alloc_coherent(length,
125 (unsigned long *)&evt->dma);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530126 if (!evt->buf)
127 return ERR_PTR(-ENOMEM);
128
Philipp Tomsich8e17c162017-04-06 16:58:53 +0200129 dwc3_flush_cache((uintptr_t)evt->buf, evt->length);
130
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530131 return evt;
132}
133
134/**
135 * dwc3_free_event_buffers - frees all allocated event buffers
136 * @dwc: Pointer to our controller context structure
137 */
138static void dwc3_free_event_buffers(struct dwc3 *dwc)
139{
140 struct dwc3_event_buffer *evt;
141 int i;
142
143 for (i = 0; i < dwc->num_event_buffers; i++) {
144 evt = dwc->ev_buffs[i];
145 if (evt)
146 dwc3_free_one_event_buffer(dwc, evt);
147 }
148}
149
150/**
151 * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
152 * @dwc: pointer to our controller context structure
153 * @length: size of event buffer
154 *
155 * Returns 0 on success otherwise negative errno. In the error case, dwc
156 * may contain some buffers allocated but not all which were requested.
157 */
158static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
159{
160 int num;
161 int i;
162
163 num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
164 dwc->num_event_buffers = num;
165
Kishon Vijay Abraham Ic7bdfe32015-02-23 18:40:13 +0530166 dwc->ev_buffs = memalign(CONFIG_SYS_CACHELINE_SIZE,
167 sizeof(*dwc->ev_buffs) * num);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530168 if (!dwc->ev_buffs)
169 return -ENOMEM;
170
171 for (i = 0; i < num; i++) {
172 struct dwc3_event_buffer *evt;
173
174 evt = dwc3_alloc_one_event_buffer(dwc, length);
175 if (IS_ERR(evt)) {
176 dev_err(dwc->dev, "can't allocate event buffer\n");
177 return PTR_ERR(evt);
178 }
179 dwc->ev_buffs[i] = evt;
180 }
181
182 return 0;
183}
184
185/**
186 * dwc3_event_buffers_setup - setup our allocated event buffers
187 * @dwc: pointer to our controller context structure
188 *
189 * Returns 0 on success otherwise negative errno.
190 */
191static int dwc3_event_buffers_setup(struct dwc3 *dwc)
192{
193 struct dwc3_event_buffer *evt;
194 int n;
195
196 for (n = 0; n < dwc->num_event_buffers; n++) {
197 evt = dwc->ev_buffs[n];
198 dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
199 evt->buf, (unsigned long long) evt->dma,
200 evt->length);
201
202 evt->lpos = 0;
203
204 dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
205 lower_32_bits(evt->dma));
206 dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
207 upper_32_bits(evt->dma));
208 dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
209 DWC3_GEVNTSIZ_SIZE(evt->length));
210 dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
211 }
212
213 return 0;
214}
215
216static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
217{
218 struct dwc3_event_buffer *evt;
219 int n;
220
221 for (n = 0; n < dwc->num_event_buffers; n++) {
222 evt = dwc->ev_buffs[n];
223
224 evt->lpos = 0;
225
226 dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
227 dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
228 dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
229 | DWC3_GEVNTSIZ_SIZE(0));
230 dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
231 }
232}
233
234static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
235{
236 if (!dwc->has_hibernation)
237 return 0;
238
239 if (!dwc->nr_scratch)
240 return 0;
241
242 dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
243 DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
244 if (!dwc->scratchbuf)
245 return -ENOMEM;
246
247 return 0;
248}
249
250static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
251{
252 dma_addr_t scratch_addr;
253 u32 param;
254 int ret;
255
256 if (!dwc->has_hibernation)
257 return 0;
258
259 if (!dwc->nr_scratch)
260 return 0;
261
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530262 scratch_addr = dma_map_single(dwc->scratchbuf,
263 dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
264 DMA_BIDIRECTIONAL);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530265 if (dma_mapping_error(dwc->dev, scratch_addr)) {
266 dev_err(dwc->dev, "failed to map scratch buffer\n");
267 ret = -EFAULT;
268 goto err0;
269 }
270
271 dwc->scratch_addr = scratch_addr;
272
273 param = lower_32_bits(scratch_addr);
274
275 ret = dwc3_send_gadget_generic_command(dwc,
276 DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
277 if (ret < 0)
278 goto err1;
279
280 param = upper_32_bits(scratch_addr);
281
282 ret = dwc3_send_gadget_generic_command(dwc,
283 DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
284 if (ret < 0)
285 goto err1;
286
287 return 0;
288
289err1:
Michal Simek698cd6f2015-10-30 16:24:06 +0100290 dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch *
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530291 DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530292
293err0:
294 return ret;
295}
296
297static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
298{
299 if (!dwc->has_hibernation)
300 return;
301
302 if (!dwc->nr_scratch)
303 return;
304
Michal Simek698cd6f2015-10-30 16:24:06 +0100305 dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch *
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530306 DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530307 kfree(dwc->scratchbuf);
308}
309
310static void dwc3_core_num_eps(struct dwc3 *dwc)
311{
312 struct dwc3_hwparams *parms = &dwc->hwparams;
313
314 dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
315 dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
316
317 dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
318 dwc->num_in_eps, dwc->num_out_eps);
319}
320
321static void dwc3_cache_hwparams(struct dwc3 *dwc)
322{
323 struct dwc3_hwparams *parms = &dwc->hwparams;
324
325 parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
326 parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
327 parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
328 parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
329 parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
330 parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
331 parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
332 parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
333 parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
334}
335
336/**
337 * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
338 * @dwc: Pointer to our controller context structure
339 */
340static void dwc3_phy_setup(struct dwc3 *dwc)
341{
342 u32 reg;
343
344 reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
345
346 /*
347 * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
348 * to '0' during coreConsultant configuration. So default value
349 * will be '0' when the core is reset. Application needs to set it
350 * to '1' after the core initialization is completed.
351 */
352 if (dwc->revision > DWC3_REVISION_194A)
353 reg |= DWC3_GUSB3PIPECTL_SUSPHY;
354
355 if (dwc->u2ss_inp3_quirk)
356 reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
357
358 if (dwc->req_p1p2p3_quirk)
359 reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
360
361 if (dwc->del_p1p2p3_quirk)
362 reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
363
364 if (dwc->del_phy_power_chg_quirk)
365 reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
366
367 if (dwc->lfps_filter_quirk)
368 reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
369
370 if (dwc->rx_detect_poll_quirk)
371 reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
372
373 if (dwc->tx_de_emphasis_quirk)
374 reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
375
376 if (dwc->dis_u3_susphy_quirk)
377 reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
378
379 dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
380
381 mdelay(100);
382
383 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
384
385 /*
386 * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
387 * '0' during coreConsultant configuration. So default value will
388 * be '0' when the core is reset. Application needs to set it to
389 * '1' after the core initialization is completed.
390 */
391 if (dwc->revision > DWC3_REVISION_194A)
392 reg |= DWC3_GUSB2PHYCFG_SUSPHY;
393
394 if (dwc->dis_u2_susphy_quirk)
395 reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
396
397 dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
398
399 mdelay(100);
400}
401
402/**
403 * dwc3_core_init - Low-level initialization of DWC3 Core
404 * @dwc: Pointer to our controller context structure
405 *
406 * Returns 0 on success otherwise negative errno.
407 */
408static int dwc3_core_init(struct dwc3 *dwc)
409{
410 unsigned long timeout;
411 u32 hwparams4 = dwc->hwparams.hwparams4;
412 u32 reg;
413 int ret;
414
415 reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
416 /* This should read as U3 followed by revision number */
417 if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
418 dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
419 ret = -ENODEV;
420 goto err0;
421 }
422 dwc->revision = reg;
423
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530424 /* Handle USB2.0-only core configuration */
425 if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
426 DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
427 if (dwc->maximum_speed == USB_SPEED_SUPER)
428 dwc->maximum_speed = USB_SPEED_HIGH;
429 }
430
431 /* issue device SoftReset too */
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530432 timeout = 5000;
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530433 dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530434 while (timeout--) {
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530435 reg = dwc3_readl(dwc->regs, DWC3_DCTL);
436 if (!(reg & DWC3_DCTL_CSFTRST))
437 break;
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530438 };
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530439
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530440 if (!timeout) {
441 dev_err(dwc->dev, "Reset Timed Out\n");
442 ret = -ETIMEDOUT;
443 goto err0;
444 }
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530445
T Karthik Reddy7bb245a2019-05-01 10:14:49 +0530446 dwc3_phy_setup(dwc);
447
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530448 ret = dwc3_core_soft_reset(dwc);
449 if (ret)
450 goto err0;
451
452 reg = dwc3_readl(dwc->regs, DWC3_GCTL);
453 reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
454
455 switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
456 case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
457 /**
458 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
459 * issue which would cause xHCI compliance tests to fail.
460 *
461 * Because of that we cannot enable clock gating on such
462 * configurations.
463 *
464 * Refers to:
465 *
466 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
467 * SOF/ITP Mode Used
468 */
469 if ((dwc->dr_mode == USB_DR_MODE_HOST ||
470 dwc->dr_mode == USB_DR_MODE_OTG) &&
471 (dwc->revision >= DWC3_REVISION_210A &&
472 dwc->revision <= DWC3_REVISION_250A))
473 reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
474 else
475 reg &= ~DWC3_GCTL_DSBLCLKGTNG;
476 break;
477 case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
478 /* enable hibernation here */
479 dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
480
481 /*
482 * REVISIT Enabling this bit so that host-mode hibernation
483 * will work. Device-mode hibernation is not yet implemented.
484 */
485 reg |= DWC3_GCTL_GBLHIBERNATIONEN;
486 break;
487 default:
488 dev_dbg(dwc->dev, "No power optimization available\n");
489 }
490
491 /* check if current dwc3 is on simulation board */
492 if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
493 dev_dbg(dwc->dev, "it is on FPGA board\n");
494 dwc->is_fpga = true;
495 }
496
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530497 if(dwc->disable_scramble_quirk && !dwc->is_fpga)
498 WARN(true,
499 "disable_scramble cannot be used on non-FPGA builds\n");
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530500
501 if (dwc->disable_scramble_quirk && dwc->is_fpga)
502 reg |= DWC3_GCTL_DISSCRAMBLE;
503 else
504 reg &= ~DWC3_GCTL_DISSCRAMBLE;
505
506 if (dwc->u2exit_lfps_quirk)
507 reg |= DWC3_GCTL_U2EXIT_LFPS;
508
509 /*
510 * WORKAROUND: DWC3 revisions <1.90a have a bug
511 * where the device can fail to connect at SuperSpeed
512 * and falls back to high-speed mode which causes
513 * the device to enter a Connect/Disconnect loop
514 */
515 if (dwc->revision < DWC3_REVISION_190A)
516 reg |= DWC3_GCTL_U2RSTECN;
517
518 dwc3_core_num_eps(dwc);
519
520 dwc3_writel(dwc->regs, DWC3_GCTL, reg);
521
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530522 ret = dwc3_alloc_scratch_buffers(dwc);
523 if (ret)
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530524 goto err0;
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530525
526 ret = dwc3_setup_scratch_buffers(dwc);
527 if (ret)
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530528 goto err1;
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530529
530 return 0;
531
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530532err1:
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530533 dwc3_free_scratch_buffers(dwc);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530534
535err0:
536 return ret;
537}
538
539static void dwc3_core_exit(struct dwc3 *dwc)
540{
541 dwc3_free_scratch_buffers(dwc);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530542}
543
544static int dwc3_core_init_mode(struct dwc3 *dwc)
545{
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530546 int ret;
547
548 switch (dwc->dr_mode) {
549 case USB_DR_MODE_PERIPHERAL:
550 dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
551 ret = dwc3_gadget_init(dwc);
552 if (ret) {
553 dev_err(dev, "failed to initialize gadget\n");
554 return ret;
555 }
556 break;
557 case USB_DR_MODE_HOST:
558 dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
559 ret = dwc3_host_init(dwc);
560 if (ret) {
561 dev_err(dev, "failed to initialize host\n");
562 return ret;
563 }
564 break;
565 case USB_DR_MODE_OTG:
566 dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
567 ret = dwc3_host_init(dwc);
568 if (ret) {
569 dev_err(dev, "failed to initialize host\n");
570 return ret;
571 }
572
573 ret = dwc3_gadget_init(dwc);
574 if (ret) {
575 dev_err(dev, "failed to initialize gadget\n");
576 return ret;
577 }
578 break;
579 default:
580 dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
581 return -EINVAL;
582 }
583
584 return 0;
585}
586
Jean-Jacques Hiblot73a1b8b2019-09-11 11:33:45 +0200587static void dwc3_gadget_run(struct dwc3 *dwc)
588{
589 dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_RUN_STOP);
590 mdelay(100);
591}
592
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530593static void dwc3_core_exit_mode(struct dwc3 *dwc)
594{
595 switch (dwc->dr_mode) {
596 case USB_DR_MODE_PERIPHERAL:
597 dwc3_gadget_exit(dwc);
598 break;
599 case USB_DR_MODE_HOST:
600 dwc3_host_exit(dwc);
601 break;
602 case USB_DR_MODE_OTG:
603 dwc3_host_exit(dwc);
604 dwc3_gadget_exit(dwc);
605 break;
606 default:
607 /* do nothing */
608 break;
609 }
Jean-Jacques Hiblot73a1b8b2019-09-11 11:33:45 +0200610
611 /*
612 * switch back to peripheral mode
613 * This enables the phy to enter idle and then, if enabled, suspend.
614 */
615 dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
616 dwc3_gadget_run(dwc);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530617}
618
Jagan Teki106c71f2019-11-19 13:56:20 +0530619static void dwc3_uboot_hsphy_mode(struct dwc3_device *dwc3_dev,
620 struct dwc3 *dwc)
621{
622 enum usb_phy_interface hsphy_mode = dwc3_dev->hsphy_mode;
623 u32 reg;
624
625 /* Set dwc3 usb2 phy config */
626 reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
Jagan Teki106c71f2019-11-19 13:56:20 +0530627
628 switch (hsphy_mode) {
629 case USBPHY_INTERFACE_MODE_UTMI:
Jagan Teki5abcf942019-12-18 13:00:02 +0530630 reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
631 DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
632 reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
633 DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT);
Jagan Teki106c71f2019-11-19 13:56:20 +0530634 break;
635 case USBPHY_INTERFACE_MODE_UTMIW:
Jagan Teki5abcf942019-12-18 13:00:02 +0530636 reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
637 DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
638 reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) |
639 DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
Jagan Teki106c71f2019-11-19 13:56:20 +0530640 break;
641 default:
642 break;
643 }
644
645 dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
646}
647
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530648#define DWC3_ALIGN_MASK (16 - 1)
649
Kishon Vijay Abraham Ibfbf05d2015-02-23 18:40:04 +0530650/**
651 * dwc3_uboot_init - dwc3 core uboot initialization code
652 * @dwc3_dev: struct dwc3_device containing initialization data
653 *
654 * Entry point for dwc3 driver (equivalent to dwc3_probe in linux
655 * kernel driver). Pointer to dwc3_device should be passed containing
656 * base address and other initialization data. Returns '0' on success and
657 * a negative value on failure.
658 *
659 * Generally called from board_usb_init() implemented in board file.
660 */
661int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530662{
Kishon Vijay Abraham Idc5c6532015-02-23 18:40:05 +0530663 struct dwc3 *dwc;
Felipe Balbi424305f2015-10-01 14:22:18 -0500664 struct device *dev = NULL;
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530665 u8 lpm_nyet_threshold;
666 u8 tx_de_emphasis;
667 u8 hird_threshold;
668
669 int ret;
670
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530671 void *mem;
672
Mugunthan V N121f93c2018-05-18 13:10:27 +0200673 mem = devm_kzalloc((struct udevice *)dev,
674 sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530675 if (!mem)
676 return -ENOMEM;
677
678 dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
679 dwc->mem = mem;
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530680
Michal Simek698cd6f2015-10-30 16:24:06 +0100681 dwc->regs = (void *)(uintptr_t)(dwc3_dev->base +
682 DWC3_GLOBALS_REGS_START);
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530683
684 /* default to highest possible threshold */
685 lpm_nyet_threshold = 0xff;
686
687 /* default to -3.5dB de-emphasis */
688 tx_de_emphasis = 1;
689
690 /*
691 * default to assert utmi_sleep_n and use maximum allowed HIRD
692 * threshold value of 0b1100
693 */
694 hird_threshold = 12;
695
Kishon Vijay Abraham Ibfbf05d2015-02-23 18:40:04 +0530696 dwc->maximum_speed = dwc3_dev->maximum_speed;
697 dwc->has_lpm_erratum = dwc3_dev->has_lpm_erratum;
698 if (dwc3_dev->lpm_nyet_threshold)
699 lpm_nyet_threshold = dwc3_dev->lpm_nyet_threshold;
700 dwc->is_utmi_l1_suspend = dwc3_dev->is_utmi_l1_suspend;
701 if (dwc3_dev->hird_threshold)
702 hird_threshold = dwc3_dev->hird_threshold;
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530703
Kishon Vijay Abraham Ibfbf05d2015-02-23 18:40:04 +0530704 dwc->needs_fifo_resize = dwc3_dev->tx_fifo_resize;
705 dwc->dr_mode = dwc3_dev->dr_mode;
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530706
Kishon Vijay Abraham Ibfbf05d2015-02-23 18:40:04 +0530707 dwc->disable_scramble_quirk = dwc3_dev->disable_scramble_quirk;
708 dwc->u2exit_lfps_quirk = dwc3_dev->u2exit_lfps_quirk;
709 dwc->u2ss_inp3_quirk = dwc3_dev->u2ss_inp3_quirk;
710 dwc->req_p1p2p3_quirk = dwc3_dev->req_p1p2p3_quirk;
711 dwc->del_p1p2p3_quirk = dwc3_dev->del_p1p2p3_quirk;
712 dwc->del_phy_power_chg_quirk = dwc3_dev->del_phy_power_chg_quirk;
713 dwc->lfps_filter_quirk = dwc3_dev->lfps_filter_quirk;
714 dwc->rx_detect_poll_quirk = dwc3_dev->rx_detect_poll_quirk;
715 dwc->dis_u3_susphy_quirk = dwc3_dev->dis_u3_susphy_quirk;
716 dwc->dis_u2_susphy_quirk = dwc3_dev->dis_u2_susphy_quirk;
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530717
Kishon Vijay Abraham Ibfbf05d2015-02-23 18:40:04 +0530718 dwc->tx_de_emphasis_quirk = dwc3_dev->tx_de_emphasis_quirk;
719 if (dwc3_dev->tx_de_emphasis)
720 tx_de_emphasis = dwc3_dev->tx_de_emphasis;
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530721
722 /* default to superspeed if no maximum_speed passed */
723 if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
724 dwc->maximum_speed = USB_SPEED_SUPER;
725
726 dwc->lpm_nyet_threshold = lpm_nyet_threshold;
727 dwc->tx_de_emphasis = tx_de_emphasis;
728
729 dwc->hird_threshold = hird_threshold
730 | (dwc->is_utmi_l1_suspend << 4);
731
Kishon Vijay Abraham Idc5c6532015-02-23 18:40:05 +0530732 dwc->index = dwc3_dev->index;
733
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530734 dwc3_cache_hwparams(dwc);
735
736 ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
737 if (ret) {
738 dev_err(dwc->dev, "failed to allocate event buffers\n");
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530739 return -ENOMEM;
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530740 }
741
Jean-Jacques Hiblot731a2a32019-09-11 11:33:53 +0200742 if (!IS_ENABLED(CONFIG_USB_DWC3_GADGET))
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530743 dwc->dr_mode = USB_DR_MODE_HOST;
Jean-Jacques Hiblot731a2a32019-09-11 11:33:53 +0200744 else if (!IS_ENABLED(CONFIG_USB_HOST))
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530745 dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
746
747 if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
748 dwc->dr_mode = USB_DR_MODE_OTG;
749
750 ret = dwc3_core_init(dwc);
751 if (ret) {
752 dev_err(dev, "failed to initialize core\n");
753 goto err0;
754 }
755
Jagan Teki106c71f2019-11-19 13:56:20 +0530756 dwc3_uboot_hsphy_mode(dwc3_dev, dwc);
757
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530758 ret = dwc3_event_buffers_setup(dwc);
759 if (ret) {
760 dev_err(dwc->dev, "failed to setup event buffers\n");
Kishon Vijay Abraham I99030d72015-02-23 18:40:02 +0530761 goto err1;
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530762 }
763
764 ret = dwc3_core_init_mode(dwc);
765 if (ret)
766 goto err2;
767
Kishon Vijay Abraham Idc5c6532015-02-23 18:40:05 +0530768 list_add_tail(&dwc->list, &dwc3_list);
769
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530770 return 0;
771
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530772err2:
773 dwc3_event_buffers_cleanup(dwc);
774
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530775err1:
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530776 dwc3_core_exit(dwc);
777
778err0:
779 dwc3_free_event_buffers(dwc);
780
781 return ret;
782}
783
Kishon Vijay Abraham Ibfbf05d2015-02-23 18:40:04 +0530784/**
785 * dwc3_uboot_exit - dwc3 core uboot cleanup code
786 * @index: index of this controller
787 *
788 * Performs cleanup of memory allocated in dwc3_uboot_init and other misc
Kishon Vijay Abraham Idc5c6532015-02-23 18:40:05 +0530789 * cleanups (equivalent to dwc3_remove in linux). index of _this_ controller
790 * should be passed and should match with the index passed in
791 * dwc3_device during init.
Kishon Vijay Abraham Ibfbf05d2015-02-23 18:40:04 +0530792 *
793 * Generally called from board file.
794 */
Kishon Vijay Abraham Idc5c6532015-02-23 18:40:05 +0530795void dwc3_uboot_exit(int index)
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530796{
Kishon Vijay Abraham Idc5c6532015-02-23 18:40:05 +0530797 struct dwc3 *dwc;
798
799 list_for_each_entry(dwc, &dwc3_list, list) {
800 if (dwc->index != index)
801 continue;
802
803 dwc3_core_exit_mode(dwc);
804 dwc3_event_buffers_cleanup(dwc);
805 dwc3_free_event_buffers(dwc);
806 dwc3_core_exit(dwc);
807 list_del(&dwc->list);
808 kfree(dwc->mem);
809 break;
810 }
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530811}
812
Kishon Vijay Abraham I1cee7b12015-02-23 18:40:06 +0530813/**
814 * dwc3_uboot_handle_interrupt - handle dwc3 core interrupt
815 * @index: index of this controller
816 *
817 * Invokes dwc3 gadget interrupts.
818 *
819 * Generally called from board file.
820 */
821void dwc3_uboot_handle_interrupt(int index)
822{
823 struct dwc3 *dwc = NULL;
824
825 list_for_each_entry(dwc, &dwc3_list, list) {
826 if (dwc->index != index)
827 continue;
828
829 dwc3_gadget_uboot_handle_interrupt(dwc);
830 break;
831 }
832}
833
Kishon Vijay Abraham I1530fe32015-02-23 18:39:50 +0530834MODULE_ALIAS("platform:dwc3");
835MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
836MODULE_LICENSE("GPL v2");
837MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
Mugunthan V N5f7ff712018-05-18 13:15:04 +0200838
Jean-Jacques Hiblot3de978a2018-11-29 10:52:45 +0100839#if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB)
840int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys)
841{
842 int i, ret, count;
843 struct phy *usb_phys;
844
845 /* Return if no phy declared */
846 if (!dev_read_prop(dev, "phys", NULL))
847 return 0;
848 count = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
849 if (count <= 0)
850 return count;
851
852 usb_phys = devm_kcalloc(dev, count, sizeof(struct phy),
853 GFP_KERNEL);
854 if (!usb_phys)
855 return -ENOMEM;
856
857 for (i = 0; i < count; i++) {
858 ret = generic_phy_get_by_index(dev, i, &usb_phys[i]);
859 if (ret && ret != -ENOENT) {
860 pr_err("Failed to get USB PHY%d for %s\n",
861 i, dev->name);
862 return ret;
863 }
864 }
865
866 for (i = 0; i < count; i++) {
867 ret = generic_phy_init(&usb_phys[i]);
868 if (ret) {
869 pr_err("Can't init USB PHY%d for %s\n",
870 i, dev->name);
871 goto phys_init_err;
872 }
873 }
874
875 for (i = 0; i < count; i++) {
876 ret = generic_phy_power_on(&usb_phys[i]);
877 if (ret) {
878 pr_err("Can't power USB PHY%d for %s\n",
879 i, dev->name);
880 goto phys_poweron_err;
881 }
882 }
883
884 *array = usb_phys;
885 *num_phys = count;
886 return 0;
887
888phys_poweron_err:
889 for (i = count - 1; i >= 0; i--)
890 generic_phy_power_off(&usb_phys[i]);
891
892 for (i = 0; i < count; i++)
893 generic_phy_exit(&usb_phys[i]);
894
895 return ret;
896
897phys_init_err:
898 for (; i >= 0; i--)
899 generic_phy_exit(&usb_phys[i]);
900
901 return ret;
902}
903
904int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys)
905{
906 int i, ret;
907
908 for (i = 0; i < num_phys; i++) {
909 if (!generic_phy_valid(&usb_phys[i]))
910 continue;
911
912 ret = generic_phy_power_off(&usb_phys[i]);
913 ret |= generic_phy_exit(&usb_phys[i]);
914 if (ret) {
915 pr_err("Can't shutdown USB PHY%d for %s\n",
916 i, dev->name);
917 }
918 }
919
920 return 0;
921}
922#endif
923
Jean-Jacques Hiblot175cd7c2019-09-11 11:33:50 +0200924#if CONFIG_IS_ENABLED(DM_USB)
Jean-Jacques Hiblotce868d02019-09-11 11:33:52 +0200925void dwc3_of_parse(struct dwc3 *dwc)
926{
927 const u8 *tmp;
928 struct udevice *dev = dwc->dev;
929 u8 lpm_nyet_threshold;
930 u8 tx_de_emphasis;
931 u8 hird_threshold;
932
933 /* default to highest possible threshold */
934 lpm_nyet_threshold = 0xff;
935
936 /* default to -3.5dB de-emphasis */
937 tx_de_emphasis = 1;
938
939 /*
940 * default to assert utmi_sleep_n and use maximum allowed HIRD
941 * threshold value of 0b1100
942 */
943 hird_threshold = 12;
944
945 dwc->has_lpm_erratum = dev_read_bool(dev,
946 "snps,has-lpm-erratum");
947 tmp = dev_read_u8_array_ptr(dev, "snps,lpm-nyet-threshold", 1);
948 if (tmp)
949 lpm_nyet_threshold = *tmp;
950
951 dwc->is_utmi_l1_suspend = dev_read_bool(dev,
952 "snps,is-utmi-l1-suspend");
953 tmp = dev_read_u8_array_ptr(dev, "snps,hird-threshold", 1);
954 if (tmp)
955 hird_threshold = *tmp;
956
957 dwc->disable_scramble_quirk = dev_read_bool(dev,
958 "snps,disable_scramble_quirk");
959 dwc->u2exit_lfps_quirk = dev_read_bool(dev,
960 "snps,u2exit_lfps_quirk");
961 dwc->u2ss_inp3_quirk = dev_read_bool(dev,
962 "snps,u2ss_inp3_quirk");
963 dwc->req_p1p2p3_quirk = dev_read_bool(dev,
964 "snps,req_p1p2p3_quirk");
965 dwc->del_p1p2p3_quirk = dev_read_bool(dev,
966 "snps,del_p1p2p3_quirk");
967 dwc->del_phy_power_chg_quirk = dev_read_bool(dev,
968 "snps,del_phy_power_chg_quirk");
969 dwc->lfps_filter_quirk = dev_read_bool(dev,
970 "snps,lfps_filter_quirk");
971 dwc->rx_detect_poll_quirk = dev_read_bool(dev,
972 "snps,rx_detect_poll_quirk");
973 dwc->dis_u3_susphy_quirk = dev_read_bool(dev,
974 "snps,dis_u3_susphy_quirk");
975 dwc->dis_u2_susphy_quirk = dev_read_bool(dev,
976 "snps,dis_u2_susphy_quirk");
977 dwc->tx_de_emphasis_quirk = dev_read_bool(dev,
978 "snps,tx_de_emphasis_quirk");
979 tmp = dev_read_u8_array_ptr(dev, "snps,tx_de_emphasis", 1);
980 if (tmp)
981 tx_de_emphasis = *tmp;
982
983 dwc->lpm_nyet_threshold = lpm_nyet_threshold;
984 dwc->tx_de_emphasis = tx_de_emphasis;
985
986 dwc->hird_threshold = hird_threshold
987 | (dwc->is_utmi_l1_suspend << 4);
988}
989
Mugunthan V N5f7ff712018-05-18 13:15:04 +0200990int dwc3_init(struct dwc3 *dwc)
991{
992 int ret;
993
994 dwc3_cache_hwparams(dwc);
995
996 ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
997 if (ret) {
998 dev_err(dwc->dev, "failed to allocate event buffers\n");
999 return -ENOMEM;
1000 }
1001
1002 ret = dwc3_core_init(dwc);
1003 if (ret) {
1004 dev_err(dev, "failed to initialize core\n");
1005 goto core_fail;
1006 }
1007
1008 ret = dwc3_event_buffers_setup(dwc);
1009 if (ret) {
1010 dev_err(dwc->dev, "failed to setup event buffers\n");
1011 goto event_fail;
1012 }
1013
1014 ret = dwc3_core_init_mode(dwc);
1015 if (ret)
1016 goto mode_fail;
1017
1018 return 0;
1019
1020mode_fail:
1021 dwc3_event_buffers_cleanup(dwc);
1022
1023event_fail:
1024 dwc3_core_exit(dwc);
1025
1026core_fail:
1027 dwc3_free_event_buffers(dwc);
1028
1029 return ret;
1030}
1031
1032void dwc3_remove(struct dwc3 *dwc)
1033{
1034 dwc3_core_exit_mode(dwc);
1035 dwc3_event_buffers_cleanup(dwc);
1036 dwc3_free_event_buffers(dwc);
1037 dwc3_core_exit(dwc);
1038 kfree(dwc->mem);
1039}
Mugunthan V N5f7ff712018-05-18 13:15:04 +02001040#endif