Open FFBoard
Open source force feedback firmware
dcd_dwc2.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2019 William D. Jones
5 * Copyright (c) 2019 Ha Thach (tinyusb.org)
6 * Copyright (c) 2020 Jan Duempelmann
7 * Copyright (c) 2020 Reinhard Panhuber
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 *
27 * This file is part of the TinyUSB stack.
28 */
29
30#include "tusb_option.h"
31
32#if CFG_TUD_ENABLED && defined(TUP_USBIP_DWC2)
33
34// Debug level for DWC2
35#define DWC2_DEBUG 2
36
37#include "device/dcd.h"
38#include "dwc2_common.h"
39
40//--------------------------------------------------------------------+
41// MACRO TYPEDEF CONSTANT ENUM
42//--------------------------------------------------------------------+
43
44static CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2];
45
46typedef struct {
47 uint8_t* buffer;
48 tu_fifo_t* ff;
49 uint16_t total_len;
50 uint16_t max_size;
51 uint8_t interval;
53
54static xfer_ctl_t xfer_status[DWC2_EP_MAX][2];
55#define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir])
56
57// EP0 transfers are limited to 1 packet - larger sizes has to be split
58static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type
59static uint16_t _dfifo_top; // top free location in DFIFO in words
60
61// Number of IN endpoints active
63
64// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by
65static bool _sof_en;
66
67//--------------------------------------------------------------------
68// DMA
69//--------------------------------------------------------------------
70
71TU_ATTR_ALWAYS_INLINE static inline bool dma_device_enabled(const dwc2_regs_t* dwc2) {
72 (void) dwc2;
73 // Internal DMA only
74 return CFG_TUD_DWC2_DMA && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA;
75}
76
77static void dma_setup_prepare(uint8_t rhport) {
78 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
79
80 if (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a) {
81 if(dwc2->epout[0].doepctl & DOEPCTL_EPENA) {
82 return;
83 }
84 }
85
86 // Receive only 1 packet
87 dwc2->epout[0].doeptsiz = (1 << DOEPTSIZ_STUPCNT_Pos) | (1 << DOEPTSIZ_PKTCNT_Pos) | (8 << DOEPTSIZ_XFRSIZ_Pos);
88 dwc2->epout[0].doepdma = (uintptr_t)_setup_packet;
89 dwc2->epout[0].doepctl |= DOEPCTL_EPENA | DOEPCTL_USBAEP;
90}
91
92//--------------------------------------------------------------------+
93// Data FIFO
94//--------------------------------------------------------------------+
95
96
97/* Device Data FIFO scheme
98
99 The FIFO is split up into
100 - EPInfo: for storing DMA metadata, only required when use DMA. Maximum size is called
101 EP_LOC_CNT = ep_fifo_size - ghwcfg3.dfifo_depth. For value less than EP_LOC_CNT, gdfifocfg must be configured before
102 gahbcfg.dmaen is set
103 - Buffer mode: 1 word per endpoint direction
104 - Scatter/Gather DMA: 4 words per endpoint direction
105 - TX FIFO: one fifo for each IN endpoint. Size is dynamic depending on packet size, starting from top with EP0 IN.
106 - Shared RX FIFO: a shared fifo for all OUT endpoints. Typically, can hold up to 2 packets of the largest EP size.
107
108 We allocated TX FIFO from top to bottom (using top pointer), this to allow the RX FIFO to grow dynamically which is
109 possible since the free space is located between the RX and TX FIFOs.
110
111 ---------------- ep_fifo_size
112 | DxEPIDMAn |
113 |-------------|-- gdfifocfg.EPINFOBASE (max is ghwcfg3.dfifo_depth)
114 | IN FIFO 0 | control EP
115 |-------------|
116 | IN FIFO 1 |
117 |-------------|
118 | . . . . |
119 |-------------|
120 | IN FIFO n |
121 |-------------|
122 | FREE |
123 |-------------|-- GRXFSIZ (expandable)
124 | OUT FIFO |
125 | ( Shared ) |
126 --------------- 0
127
128 According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits):
129 - Each EP IN needs at least max packet size
130 - All EP OUT shared a unique OUT FIFO which uses (for Slave or Buffer DMA, Scatt/Gather DMA use different formula):
131 - 13 for setup packets + control words (up to 3 setup packets).
132 - 1 for global NAK (not required/used here).
133 - Largest-EPsize/4 + 1. ( FS: 64 bytes, HS: 512 bytes). Recommended is "2 x (Largest-EPsize/4 + 1)"
134 - 2 for each used OUT endpoint
135
136 Therefore GRXFSIZ = 13 + 1 + 2 x (Largest-EPsize/4 + 1) + 2 x EPOUTnum
137*/
138
139TU_ATTR_ALWAYS_INLINE static inline uint16_t calc_device_grxfsiz(uint16_t largest_ep_size, uint8_t ep_count) {
140 return 13 + 1 + 2 * ((largest_ep_size / 4) + 1) + 2 * ep_count;
141}
142
143static bool dfifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) {
144 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
145 const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
146 uint8_t const ep_count = dwc2_controller->ep_count;
147 uint8_t const epnum = tu_edpt_number(ep_addr);
148 uint8_t const dir = tu_edpt_dir(ep_addr);
149
150 TU_ASSERT(epnum < ep_count);
151
152 uint16_t fifo_size = tu_div_ceil(packet_size, 4);
153 if (dir == TUSB_DIR_OUT) {
154 // Calculate required size of RX FIFO
155 uint16_t const new_sz = calc_device_grxfsiz(4 * fifo_size, ep_count);
156
157 // If size_rx needs to be extended check if there is enough free space
158 if (dwc2->grxfsiz < new_sz) {
159 TU_ASSERT(new_sz <= _dfifo_top);
160 dwc2->grxfsiz = new_sz; // Enlarge RX FIFO
161 }
162 } else {
163 // Check IN endpoints concurrently active limit
164 if(_dwc2_controller->ep_in_count) {
165 TU_ASSERT(_allocated_ep_in_count < _dwc2_controller->ep_in_count);
167 }
168
169 // If The TXFELVL is configured as half empty, the fifo must be twice the max_size.
170 if ((dwc2->gahbcfg & GAHBCFG_TX_FIFO_EPMTY_LVL) == 0) {
171 fifo_size *= 2;
172 }
173
174 // Check if free space is available
175 TU_ASSERT(_dfifo_top >= fifo_size + dwc2->grxfsiz);
176 _dfifo_top -= fifo_size;
177 TU_LOG(DWC2_DEBUG, " TX FIFO %u: allocated %u words at offset %u\r\n", epnum, fifo_size, _dfifo_top);
178
179 // Both TXFD and TXSA are in unit of 32-bit words.
180 if (epnum == 0) {
181 dwc2->dieptxf0 = (fifo_size << DIEPTXF0_TX0FD_Pos) | _dfifo_top;
182 } else {
183 // DIEPTXF starts at FIFO #1.
184 dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | _dfifo_top;
185 }
186 }
187
188 return true;
189}
190
191static void dfifo_device_init(uint8_t rhport) {
192 const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
193 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
194 dwc2->grxfsiz = calc_device_grxfsiz(CFG_TUD_ENDPOINT0_SIZE, dwc2_controller->ep_count);
195
196 // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per endpoint direction
197 const bool is_dma = dma_device_enabled(dwc2);
198 _dfifo_top = dwc2_controller->ep_fifo_size/4;
199 if (is_dma) {
200 _dfifo_top -= 2 * dwc2_controller->ep_count;
201 }
202 dwc2->gdfifocfg = (_dfifo_top << GDFIFOCFG_EPINFOBASE_SHIFT) | _dfifo_top;
203
204 // Allocate FIFO for EP0 IN
205 dfifo_alloc(rhport, 0x80, CFG_TUD_ENDPOINT0_SIZE);
206}
207
208
209//--------------------------------------------------------------------
210// Endpoint
211//--------------------------------------------------------------------
212static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) {
213 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
214 uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
215 uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
216
217 xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
218 xfer->max_size = tu_edpt_packet_size(p_endpoint_desc);
219 xfer->interval = p_endpoint_desc->bInterval;
220
221 // USBAEP, EPTYP, SD0PID_SEVNFRM, MPSIZ are the same for IN and OUT endpoints.
222 uint32_t epctl = (1 << DOEPCTL_USBAEP_Pos) |
223 (p_endpoint_desc->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) |
224 (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) |
225 (xfer->max_size << DOEPCTL_MPSIZ_Pos);
226 if (dir == TUSB_DIR_IN) {
227 epctl |= (epnum << DIEPCTL_TXFNUM_Pos);
228 }
229
230 dwc2_dep_t* dep = &dwc2->ep[1 - dir][epnum];
231 dep->ctl = epctl;
232 dwc2->daintmsk |= TU_BIT(epnum + DAINT_SHIFT(dir));
233}
234
235static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
236 (void) rhport;
237
238 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
239 const uint8_t epnum = tu_edpt_number(ep_addr);
240 const uint8_t dir = tu_edpt_dir(ep_addr);
241 dwc2_dep_t* dep = &dwc2->ep[1 - dir][epnum];
242
243 if (dir == TUSB_DIR_IN) {
244 // Only disable currently enabled non-control endpoint
245 if ((epnum == 0) || !(dep->diepctl & DIEPCTL_EPENA)) {
246 dep->diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0);
247 } else {
248 // Stop transmitting packets and NAK IN xfers.
249 dep->diepctl |= DIEPCTL_SNAK;
250 while ((dep->diepint & DIEPINT_INEPNE) == 0) {}
251
252 // Disable the endpoint.
253 dep->diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0);
254 while ((dep->diepint & DIEPINT_EPDISD_Msk) == 0) {}
255
256 dep->diepint = DIEPINT_EPDISD;
257 }
258
259 // Flush the FIFO, and wait until we have confirmed it cleared.
260 dfifo_flush_tx(dwc2, epnum);
261 } else {
262 // Only disable currently enabled non-control endpoint
263 if ((epnum == 0) || !(dep->doepctl & DOEPCTL_EPENA)) {
264 dep->doepctl |= stall ? DOEPCTL_STALL : 0;
265 } else {
266 // Asserting GONAK is required to STALL an OUT endpoint.
267 // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt
268 // anyway, and it can't be cleared by user code. If this while loop never
269 // finishes, we have bigger problems than just the stack.
270 dwc2->dctl |= DCTL_SGONAK;
271 while ((dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0) {}
272
273 // Ditto here disable the endpoint.
274 dep->doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0);
275 while ((dep->doepint & DOEPINT_EPDISD_Msk) == 0) {}
276
277 dep->doepint = DOEPINT_EPDISD;
278
279 // Allow other OUT endpoints to keep receiving.
280 dwc2->dctl |= DCTL_CGONAK;
281 }
282 }
283}
284
285// Start of Bus Reset
286static void bus_reset(uint8_t rhport) {
287 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
288 uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
289
290 tu_memclr(xfer_status, sizeof(xfer_status));
291
292 _sof_en = false;
294
295 // 1. NAK for all OUT endpoints
296 for (uint8_t n = 0; n < ep_count; n++) {
297 dwc2->epout[n].doepctl |= DOEPCTL_SNAK;
298 }
299
300 // 2. Disable all IN endpoints
301 for (uint8_t n = 0; n < ep_count; n++) {
302 if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) {
303 dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS;
304 }
305 }
306
307 dfifo_flush_tx(dwc2, 0x10); // all tx fifo
308 dfifo_flush_rx(dwc2);
309
310 // 3. Set up interrupt mask for EP0
311 dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos);
312 dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM;
313 dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM;
314
315 // 4. Set up DFIFO
316 dfifo_device_init(rhport);
317
318 // 5. Reset device address
319 dwc2->dcfg &= ~DCFG_DAD_Msk;
320
321 // Fixed both control EP0 size to 64 bytes
322 dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos);
323 dwc2->epout[0].doepctl &= ~(0x03 << DOEPCTL_MPSIZ_Pos);
324
327
328 if(dma_device_enabled(dwc2)) {
329 dma_setup_prepare(rhport);
330 } else {
331 dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
332 }
333
334 dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT;
335}
336
337static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets,
338 uint16_t total_bytes) {
339 (void) rhport;
340
341 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
342 xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir);
343
344 // EP0 is limited to one packet each xfer
345 // We use multiple transaction of xfer->max_size length to get a whole transfer done
346 if (epnum == 0) {
347 total_bytes = tu_min16(ep0_pending[dir], xfer->max_size);
348 ep0_pending[dir] -= total_bytes;
349 }
350
351 // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here.
352 const uint8_t is_epout = 1 - dir;
353 dwc2_dep_t* dep = &dwc2->ep[is_epout][epnum];
354
355 if (dir == TUSB_DIR_IN) {
356 // A full IN transfer (multiple packets, possibly) triggers XFRC.
357 dep->dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) |
358 ((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk);
359
360 if(dma_device_enabled(dwc2)) {
361 dep->diepdma = (uintptr_t)xfer->buffer;
362
363 // For ISO endpoint set correct odd/even bit for next frame.
364 if ((dep->diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) {
365 // Take odd/even bit from frame counter.
366 uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos));
367 dep->diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk);
368 }
369
370 dep->diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK;
371 } else {
372 dep->diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK;
373
374 // For ISO endpoint set correct odd/even bit for next frame.
375 if ((dep->diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) {
376 // Take odd/even bit from frame counter.
377 uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos));
378 dep->diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk);
379 }
380 // Enable fifo empty interrupt only if there are something to put in the fifo.
381 if (total_bytes != 0) {
382 dwc2->diepempmsk |= (1 << epnum);
383 }
384 }
385 } else {
386 // A full OUT transfer (multiple packets, possibly) triggers XFRC.
387 dep->doeptsiz &= ~(DOEPTSIZ_PKTCNT_Msk | DOEPTSIZ_XFRSIZ);
388 dep->doeptsiz |= (num_packets << DOEPTSIZ_PKTCNT_Pos) |
389 ((total_bytes << DOEPTSIZ_XFRSIZ_Pos) & DOEPTSIZ_XFRSIZ_Msk);
390
391 if ((dep->doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 &&
392 XFER_CTL_BASE(epnum, dir)->interval == 1) {
393 // Take odd/even bit from frame counter.
394 uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos));
395 dep->doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk);
396 }
397
398 if(dma_device_enabled(dwc2)) {
399 dep->doepdma = (uintptr_t)xfer->buffer;
400 }
401
402 dep->doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK;
403 }
404}
405
406//--------------------------------------------------------------------
407// Controller API
408//--------------------------------------------------------------------
409bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
410 (void) rh_init;
411 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
412
413 // Core Initialization
414 const bool is_highspeed = dwc2_core_is_highspeed(dwc2, TUSB_ROLE_DEVICE);
415 TU_ASSERT(dwc2_core_init(rhport, is_highspeed));
416
417 if (dma_device_enabled(dwc2)) {
418 // DMA seems to be only settable after a core reset, and not possible to switch on-the-fly
419 dwc2->gahbcfg |= GAHBCFG_DMAEN | GAHBCFG_HBSTLEN_2;
420 } else {
421 dwc2->gintmsk |= GINTSTS_RXFLVL;
422 }
423
424 // Device Initialization
425 dcd_disconnect(rhport);
426
427 // Set device max speed
428 uint32_t dcfg = dwc2->dcfg & ~DCFG_DSPD_Msk;
429 if (is_highspeed) {
430 dcfg |= DCFG_DSPD_HS << DCFG_DSPD_Pos;
431
432 // XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required
433 // when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347)
435 dcfg |= DCFG_XCVRDLY;
436 }
437 }else {
438 dcfg |= DCFG_DSPD_FS << DCFG_DSPD_Pos;
439 }
440 dwc2->dcfg = dcfg;
441
442 // Force device mode
443 dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD;
444
445 // Clear A override, force B Valid
446 dwc2->gotgctl = (dwc2->gotgctl & ~GOTGCTL_AVALOEN) | GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL;
447
448 // If USB host misbehaves during status portion of control xfer (non zero-length packet), send STALL back and discard
449 dwc2->dcfg |= DCFG_NZLSOHSK;
450
451 // Enable required interrupts
452 dwc2->gintmsk |= GINTMSK_OTGINT | GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM;
453
454 // TX FIFO empty level for interrupt is complete empty
455 uint32_t gahbcfg = dwc2->gahbcfg;
456 gahbcfg |= GAHBCFG_TX_FIFO_EPMTY_LVL;
457 gahbcfg |= GAHBCFG_GINT; // Enable global interrupt
458 dwc2->gahbcfg = gahbcfg;
459
460 dcd_connect(rhport);
461 return true;
462}
463
464void dcd_int_enable(uint8_t rhport) {
465 dwc2_dcd_int_enable(rhport);
466}
467
468void dcd_int_disable(uint8_t rhport) {
469 dwc2_dcd_int_disable(rhport);
470}
471
472void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
473 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
474 dwc2->dcfg = (dwc2->dcfg & ~DCFG_DAD_Msk) | (dev_addr << DCFG_DAD_Pos);
475
476 // Response with status after changing device address
477 dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
478}
479
480void dcd_remote_wakeup(uint8_t rhport) {
481 (void) rhport;
482
483 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
484
485 // set remote wakeup
486 dwc2->dctl |= DCTL_RWUSIG;
487
488 // enable SOF to detect bus resume
489 dwc2->gintsts = GINTSTS_SOF;
490 dwc2->gintmsk |= GINTMSK_SOFM;
491
492 // Per specs: remote wakeup signal bit must be clear within 1-15ms
494
495 dwc2->dctl &= ~DCTL_RWUSIG;
496}
497
498void dcd_connect(uint8_t rhport) {
499 (void) rhport;
500 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
501
502#ifdef TUP_USBIP_DWC2_ESP32
503 usb_wrap_otg_conf_reg_t conf = USB_WRAP.otg_conf;
504 conf.pad_pull_override = 0;
505 conf.dp_pullup = 0;
506 conf.dp_pulldown = 0;
507 conf.dm_pullup = 0;
508 conf.dm_pulldown = 0;
509 USB_WRAP.otg_conf = conf;
510#endif
511
512 dwc2->dctl &= ~DCTL_SDIS;
513}
514
515void dcd_disconnect(uint8_t rhport) {
516 (void) rhport;
517 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
518
519#ifdef TUP_USBIP_DWC2_ESP32
520 usb_wrap_otg_conf_reg_t conf = USB_WRAP.otg_conf;
521 conf.pad_pull_override = 1;
522 conf.dp_pullup = 0;
523 conf.dp_pulldown = 1;
524 conf.dm_pullup = 0;
525 conf.dm_pulldown = 1;
526 USB_WRAP.otg_conf = conf;
527#endif
528
529 dwc2->dctl |= DCTL_SDIS;
530}
531
532// Be advised: audio, video and possibly other iso-ep classes use dcd_sof_enable() to enable/disable its corresponding ISR on purpose!
533void dcd_sof_enable(uint8_t rhport, bool en) {
534 (void) rhport;
535 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
536
537 _sof_en = en;
538
539 if (en) {
540 dwc2->gintsts = GINTSTS_SOF;
541 dwc2->gintmsk |= GINTMSK_SOFM;
542 } else {
543 dwc2->gintmsk &= ~GINTMSK_SOFM;
544 }
545}
546
547/*------------------------------------------------------------------*/
548/* DCD Endpoint port
549 *------------------------------------------------------------------*/
550
551bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
552 TU_ASSERT(dfifo_alloc(rhport, desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt)));
553 edpt_activate(rhport, desc_edpt);
554 return true;
555}
556
557// Close all non-control endpoints, cancel all pending transfers if any.
558void dcd_edpt_close_all(uint8_t rhport) {
559 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
560 uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
561
563
564 // Disable non-control interrupt
565 dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos);
566
567 for (uint8_t n = 1; n < ep_count; n++) {
568 for (uint8_t d = 0; d < 2; d++) {
569 dwc2_dep_t* dep = &dwc2->ep[d][n];
570 if (dep->ctl & EPCTL_EPENA) {
571 dep->ctl |= EPCTL_SNAK | EPCTL_EPDIS;
572 }
573 xfer_status[n][1-d].max_size = 0;
574 }
575 }
576
577 dfifo_flush_tx(dwc2, 0x10); // all tx fifo
578 dfifo_flush_rx(dwc2);
579
580 dfifo_device_init(rhport); // re-init dfifo
581}
582
583bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
584 TU_ASSERT(dfifo_alloc(rhport, ep_addr, largest_packet_size));
585 return true;
586}
587
588bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) {
589 // Disable EP to clear potential incomplete transfers
590 edpt_disable(rhport, p_endpoint_desc->bEndpointAddress, false);
591 edpt_activate(rhport, p_endpoint_desc);
592 return true;
593}
594
595bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
596 uint8_t const epnum = tu_edpt_number(ep_addr);
597 uint8_t const dir = tu_edpt_dir(ep_addr);
598
599 xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
600 xfer->buffer = buffer;
601 xfer->ff = NULL;
603
604 // EP0 can only handle one packet
605 if (epnum == 0) {
607
608 // Schedule the first transaction for EP0 transfer
609 edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]);
610 } else {
611 uint16_t num_packets = tu_div_ceil(total_bytes, xfer->max_size);
612 if (num_packets == 0) {
613 num_packets = 1; // zero length packet still count as 1
614 }
615
616 // Schedule packets to be sent within interrupt
617 edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes);
618 }
619
620 return true;
621}
622
623// The number of bytes has to be given explicitly to allow more flexible control of how many
624// bytes should be written and second to keep the return value free to give back a boolean
625// success message. If total_bytes is too big, the FIFO will copy only what is available
626// into the USB buffer!
627bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes) {
628 // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
629 TU_ASSERT(ff->item_size == 1);
630
631 uint8_t const epnum = tu_edpt_number(ep_addr);
632 uint8_t const dir = tu_edpt_dir(ep_addr);
633
634 xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
635 xfer->buffer = NULL;
636 xfer->ff = ff;
638
639 uint16_t num_packets = (total_bytes / xfer->max_size);
640 uint16_t const short_packet_size = total_bytes % xfer->max_size;
641
642 // Zero-size packet is special case.
643 if (short_packet_size > 0 || (total_bytes == 0)) {
644 num_packets++;
645 }
646
647 // Schedule packets to be sent within interrupt
648 edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes);
649
650 return true;
651}
652
653void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
654 edpt_disable(rhport, ep_addr, false);
655}
656
657void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
658 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
659 edpt_disable(rhport, ep_addr, true);
660 if((tu_edpt_number(ep_addr) == 0) && dma_device_enabled(dwc2)) {
661 dma_setup_prepare(rhport);
662 }
663}
664
665void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
666 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
667 uint8_t const epnum = tu_edpt_number(ep_addr);
668 uint8_t const dir = tu_edpt_dir(ep_addr);
669 dwc2_dep_t* dep = &dwc2->ep[1 - dir][epnum];
670
671 // Clear stall and reset data toggle
672 dep->ctl &= ~EPCTL_STALL;;
673 dep->ctl |= EPCTL_SD0PID_SEVNFRM;
674}
675
676//--------------------------------------------------------------------
677// Interrupt Handler
678//--------------------------------------------------------------------
679
680// Process shared receive FIFO, this interrupt is only used in Slave mode
681static void handle_rxflvl_irq(uint8_t rhport) {
682 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
683 const volatile uint32_t* rx_fifo = dwc2->fifo[0];
684
685 // Pop control word off FIFO
686 const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm;
687 const uint8_t epnum = grxstsp_bm.ep_ch_num;
688 const uint16_t byte_count = grxstsp_bm.byte_count;
689 dwc2_epout_t* epout = &dwc2->epout[epnum];
690
691 switch (grxstsp_bm.packet_status) {
692 // Global OUT NAK: do nothing
694 break;
695
697 // Setup packet received
698 // We can receive up to three setup packets in succession, but only the last one is valid.
699 _setup_packet[0] = (*rx_fifo);
700 _setup_packet[1] = (*rx_fifo);
701 break;
702
704 // Setup packet done:
705 // After popping this out, dwc2 asserts a DOEPINT_SETUP interrupt which is handled by handle_epout_irq()
706 epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
707 break;
708
709 case GRXSTS_PKTSTS_OUTRX: {
710 // Out packet received
711 xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
712
713 // Read packet off RxFIFO
714 if (xfer->ff) {
715 // Ring buffer
716 tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void*) (uintptr_t) rx_fifo, byte_count);
717 } else {
718 // Linear buffer
719 dfifo_read_packet(dwc2, xfer->buffer, byte_count);
720
721 // Increment pointer to xfer data
722 xfer->buffer += byte_count;
723 }
724
725 // short packet, minus remaining bytes (xfer_size)
726 if (byte_count < xfer->max_size) {
728 if (epnum == 0) {
731 }
732 }
733 break;
734 }
735
737 /* Out packet done
738 After this entry is popped from the receive FIFO, dwc2 asserts a Transfer Completed interrupt on
739 the specified OUT endpoint which will be handled by handle_epout_irq() */
740 break;
741
742 default:
743 TU_BREAKPOINT();
744 break;
745 }
746}
747
748static void handle_epout_irq(uint8_t rhport) {
749 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
750 uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
751
752 // DAINT for a given EP clears when DOEPINTx is cleared.
753 // OEPINT will be cleared when DAINT's out bits are cleared.
754 for (uint8_t epnum = 0; epnum < ep_count; epnum++) {
755 if (dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + epnum)) {
756 dwc2_epout_t* epout = &dwc2->epout[epnum];
757 const uint32_t doepint = epout->doepint;
758 TU_ASSERT((epout->doepint & DOEPINT_AHBERR) == 0, );
759
760 // Setup and/or STPKTRX/STSPHSRX (from 3.00a) can be set along with XFRC, and also set independently.
761 if (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a) {
762 if (doepint & DOEPINT_STSPHSRX) {
763 // Status phase received for control write: In token received from Host
764 epout->doepint = DOEPINT_STSPHSRX;
765 }
766
767 if (doepint & DOEPINT_STPKTRX) {
768 // New setup packet received, but wait for Setup done, since we can receive up to 3 setup consecutively
769 epout->doepint = DOEPINT_STPKTRX;
770 }
771 }
772
773 if (doepint & DOEPINT_SETUP) {
774 epout->doepint = DOEPINT_SETUP;
775
776 if(dma_device_enabled(dwc2)) {
777 dma_setup_prepare(rhport);
778 }
779
780 dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true);
781 }
782
783 // OUT XFER complete
784 if (doepint & DOEPINT_XFRC) {
785 epout->doepint = DOEPINT_XFRC;
786
787 // only handle data skip if it is setup or status related
788 // Normal OUT transfer complete
789 if (!(doepint & (DOEPINT_SETUP | DOEPINT_STPKTRX | DOEPINT_STSPHSRX))) {
790 xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
791
792 if(dma_device_enabled(dwc2)) {
793 if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) {
794 // EP0 can only handle one packet Schedule another packet to be received.
796 } else {
797 // Fix packet length
798 uint16_t remain = (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos;
799 xfer->total_len -= remain;
800 // this is ZLP, so prepare EP0 for next setup
801 if(epnum == 0 && xfer->total_len == 0) {
802 dma_setup_prepare(rhport);
803 }
804
806 }
807 } else {
808 // EP0 can only handle one packet
809 if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) {
810 // Schedule another packet to be received.
812 } else {
814 }
815 }
816 }
817 }
818 }
819 }
820}
821
822static void handle_epin_irq(uint8_t rhport) {
823 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
824 const uint8_t ep_count = _dwc2_controller[rhport].ep_count;
825
826 // DAINT for a given EP clears when DIEPINTx is cleared.
827 // IEPINT will be cleared when DAINT's out bits are cleared.
828 for (uint8_t n = 0; n < ep_count; n++) {
829 if (dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n)) {
830 // IN XFER complete (entire xfer).
831 xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
832 dwc2_epin_t* epin = &dwc2->epin[n];
833
834 if (epin->diepint & DIEPINT_XFRC) {
835 epin->diepint = DIEPINT_XFRC;
836
837 // EP0 can only handle one packet
838 if ((n == 0) && ep0_pending[TUSB_DIR_IN]) {
839 // Schedule another packet to be transmitted.
841 } else {
842 if((n == 0) && dma_device_enabled(dwc2)) {
843 dma_setup_prepare(rhport);
844 }
846 }
847 }
848
849 // XFER FIFO empty
850 if ((epin->diepint & DIEPINT_TXFE) && (dwc2->diepempmsk & (1 << n))) {
851 // diepint's TXFE bit is read-only, software cannot clear it.
852 // It will only be cleared by hardware when written bytes is more than
853 // - 64 bytes or
854 // - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL)
855 const uint16_t remain_packets = epin->dieptsiz_bm.packet_count;
856
857 // Process every single packet (only whole packets can be written to fifo)
858 for (uint16_t i = 0; i < remain_packets; i++) {
859 const uint16_t remain_bytes = (uint16_t) epin->dieptsiz_bm.xfer_size;
860
861 // Packet can not be larger than ep max size
862 const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size);
863
864 // It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current
865 // EP has to be checked if the buffer can take another WHOLE packet
866 if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) {
867 break;
868 }
869
870 // Push packet to Tx-FIFO
871 if (xfer->ff) {
872 volatile uint32_t* tx_fifo = dwc2->fifo[n];
873 tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*) (uintptr_t) tx_fifo, xact_bytes);
874 } else {
875 dfifo_write_packet(dwc2, n, xfer->buffer, xact_bytes);
876 xfer->buffer += xact_bytes;
877 }
878 }
879
880 // Turn off TXFE if all bytes are written.
881 if (epin->dieptsiz_bm.xfer_size == 0) {
882 dwc2->diepempmsk &= ~(1 << n);
883 }
884 }
885 }
886 }
887}
888
889/* Interrupt Hierarchy
890
891 DxEPINTn
892 |
893 DAINT.xEPn
894 |
895 GINTSTS: xEPInt
896
897 Note: when OTG_MULTI_PROC_INTRPT = 1, Device Each endpoint interrupt deachint/deachmsk/diepeachmsk/doepeachmsk
898 are combined to generate dedicated interrupt line for each endpoint.
899 */
900
901
902void dcd_int_handler(uint8_t rhport) {
903 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
904
905 uint32_t const int_mask = dwc2->gintmsk;
906 uint32_t const int_status = dwc2->gintsts & int_mask;
907
908 if (int_status & GINTSTS_USBRST) {
909 // USBRST is start of reset.
910 dwc2->gintsts = GINTSTS_USBRST;
911 bus_reset(rhport);
912 }
913
914 if (int_status & GINTSTS_ENUMDNE) {
915 // ENUMDNE is the end of reset where speed of the link is detected
916 dwc2->gintsts = GINTSTS_ENUMDNE;
917
918 tusb_speed_t speed;
919 switch ((dwc2->dsts & DSTS_ENUMSPD_Msk) >> DSTS_ENUMSPD_Pos) {
920 case DSTS_ENUMSPD_HS:
921 speed = TUSB_SPEED_HIGH;
922 break;
923
924 case DSTS_ENUMSPD_LS:
925 speed = TUSB_SPEED_LOW;
926 break;
927
928 case DSTS_ENUMSPD_FS_HSPHY:
929 case DSTS_ENUMSPD_FS:
930 default:
931 speed = TUSB_SPEED_FULL;
932 break;
933 }
934
935 // TODO must update GUSBCFG_TRDT according to link speed
936
937 dcd_event_bus_reset(rhport, speed, true);
938 }
939
940 if (int_status & GINTSTS_USBSUSP) {
941 dwc2->gintsts = GINTSTS_USBSUSP;
942 dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
943 }
944
945 if (int_status & GINTSTS_WKUINT) {
946 dwc2->gintsts = GINTSTS_WKUINT;
947 dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
948 }
949
950 // TODO check GINTSTS_DISCINT for disconnect detection
951 // if(int_status & GINTSTS_DISCINT)
952
953 if (int_status & GINTSTS_OTGINT) {
954 // OTG INT bit is read-only
955 uint32_t const otg_int = dwc2->gotgint;
956
957 if (otg_int & GOTGINT_SEDET) {
958 dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
959 }
960
961 dwc2->gotgint = otg_int;
962 }
963
964 if(int_status & GINTSTS_SOF) {
965 dwc2->gintsts = GINTSTS_SOF;
966 const uint32_t frame = (dwc2->dsts & DSTS_FNSOF) >> DSTS_FNSOF_Pos;
967
968 // Disable SOF interrupt if SOF was not explicitly enabled since SOF was used for remote wakeup detection
969 if (!_sof_en) {
970 dwc2->gintmsk &= ~GINTMSK_SOFM;
971 }
972
973 dcd_event_sof(rhport, frame, true);
974 }
975
976 // RxFIFO non-empty interrupt handling.
977 if (int_status & GINTSTS_RXFLVL) {
978 // RXFLVL bit is read-only
979 dwc2->gintmsk &= ~GINTMSK_RXFLVLM; // disable RXFLVL interrupt while reading
980
981 do {
982 handle_rxflvl_irq(rhport); // read all packets
983 } while(dwc2->gintsts & GINTSTS_RXFLVL);
984
985 dwc2->gintmsk |= GINTMSK_RXFLVLM;
986 }
987
988 // OUT endpoint interrupt handling.
989 if (int_status & GINTSTS_OEPINT) {
990 // OEPINT is read-only, clear using DOEPINTn
991 handle_epout_irq(rhport);
992 }
993
994 // IN endpoint interrupt handling.
995 if (int_status & GINTSTS_IEPINT) {
996 // IEPINT bit read-only, clear using DIEPINTn
997 handle_epin_irq(rhport);
998 }
999
1000 // // Check for Incomplete isochronous IN transfer
1001 // if(int_status & GINTSTS_IISOIXFR) {
1002 // printf(" IISOIXFR!\r\n");
1004 // }
1005}
1006
1007#if CFG_TUD_TEST_MODE
1008void dcd_enter_test_mode(uint8_t rhport, tusb_feature_test_mode_t test_selector) {
1009 dwc2_regs_t* dwc2 = DWC2_REG(rhport);
1010
1011 // Enable the test mode
1012 dwc2->dctl = (dwc2->dctl & ~DCTL_TCTL_Msk) | (((uint8_t) test_selector) << DCTL_TCTL_Pos);
1013}
1014#endif
1015
1016#endif
static TU_ATTR_ALWAYS_INLINE void dcd_event_bus_signal(uint8_t rhport, dcd_eventid_t eid, bool in_isr)
Definition: dcd.h:196
static TU_ATTR_ALWAYS_INLINE void dcd_event_xfer_complete(uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr)
Definition: dcd.h:222
static TU_ATTR_ALWAYS_INLINE void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_isr)
Definition: dcd.h:232
static TU_ATTR_ALWAYS_INLINE void dcd_event_setup_received(uint8_t rhport, uint8_t const *setup, bool in_isr)
Definition: dcd.h:213
static TU_ATTR_ALWAYS_INLINE void dcd_event_bus_reset(uint8_t rhport, tusb_speed_t speed, bool in_isr)
Definition: dcd.h:204
bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes)
Definition: dcd_dwc2.c:627
static void dma_setup_prepare(uint8_t rhport)
Definition: dcd_dwc2.c:77
static void handle_epin_irq(uint8_t rhport)
Definition: dcd_dwc2.c:822
static uint8_t _allocated_ep_in_count
Definition: dcd_dwc2.c:62
static void handle_rxflvl_irq(uint8_t rhport)
Definition: dcd_dwc2.c:681
static bool _sof_en
Definition: dcd_dwc2.c:65
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_dwc2.c:657
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_dwc2.c:653
void dcd_enter_test_mode(uint8_t rhport, tusb_feature_test_mode_t test_selector)
Definition: dcd_dwc2.c:1008
static void bus_reset(uint8_t rhport)
Definition: dcd_dwc2.c:286
void dcd_int_handler(uint8_t rhport)
Definition: dcd_dwc2.c:902
static uint16_t _dfifo_top
Definition: dcd_dwc2.c:59
static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall)
Definition: dcd_dwc2.c:235
void dcd_disconnect(uint8_t rhport)
Definition: dcd_dwc2.c:515
xfer_ctl_t
Definition: dcd_dwc2.c:52
static uint16_t ep0_pending[2]
Definition: dcd_dwc2.c:58
static TU_ATTR_ALWAYS_INLINE bool dma_device_enabled(const dwc2_regs_t *dwc2)
Definition: dcd_dwc2.c:71
void dcd_edpt_close_all(uint8_t rhport)
Definition: dcd_dwc2.c:558
static TU_ATTR_ALWAYS_INLINE uint16_t calc_device_grxfsiz(uint16_t largest_ep_size, uint8_t ep_count)
Definition: dcd_dwc2.c:139
void dcd_int_disable(uint8_t rhport)
Definition: dcd_dwc2.c:468
static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
Definition: dcd_dwc2.c:212
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_dwc2.c:665
static void handle_epout_irq(uint8_t rhport)
Definition: dcd_dwc2.c:748
void dcd_connect(uint8_t rhport)
Definition: dcd_dwc2.c:498
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
Definition: dcd_dwc2.c:551
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
Definition: dcd_dwc2.c:595
static bool dfifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size)
Definition: dcd_dwc2.c:143
bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
Definition: dcd_dwc2.c:588
static CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(4)
Definition: dcd_dwc2.c:44
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
Definition: dcd_dwc2.c:472
bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init)
Definition: dcd_dwc2.c:409
static xfer_ctl_t xfer_status[DWC2_EP_MAX][2]
Definition: dcd_dwc2.c:54
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size)
Definition: dcd_dwc2.c:583
static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, uint16_t total_bytes)
Definition: dcd_dwc2.c:337
void dcd_int_enable(uint8_t rhport)
Definition: dcd_dwc2.c:464
void dcd_remote_wakeup(uint8_t rhport)
Definition: dcd_dwc2.c:480
void dcd_sof_enable(uint8_t rhport, bool en)
Definition: dcd_dwc2.c:533
static void dfifo_device_init(uint8_t rhport)
Definition: dcd_dwc2.c:191
uint8_t _setup_packet[8]
xfer_td_t xfer[EP_CBI_COUNT+1][2]
Definition: dcd_nrf5x.c:119
uint16_t total_bytes
Definition: dcd_nuc505.c:113
uint8_t dev_addr
Definition: dcd_pic32mz.c:81
static void dwc2_remote_wakeup_delay(void)
Definition: dwc2_bcm.h:61
static TU_ATTR_ALWAYS_INLINE void dwc2_dcd_int_enable(uint8_t rhport)
Definition: dwc2_bcm.h:50
static TU_ATTR_ALWAYS_INLINE void dwc2_dcd_int_disable(uint8_t rhport)
Definition: dwc2_bcm.h:56
void dfifo_read_packet(dwc2_regs_t *dwc2, uint8_t *dst, uint16_t len)
Definition: dwc2_common.c:252
bool dwc2_core_is_highspeed(dwc2_regs_t *dwc2, tusb_role_t role)
Definition: dwc2_common.c:172
bool dwc2_core_init(uint8_t rhport, bool is_highspeed)
Definition: dwc2_common.c:197
void dfifo_write_packet(dwc2_regs_t *dwc2, uint8_t fifo_num, const uint8_t *src, uint16_t len)
Definition: dwc2_common.c:277
static TU_ATTR_ALWAYS_INLINE dwc2_regs_t * DWC2_REG(uint8_t rhport)
Definition: dwc2_common.h:67
static TU_ATTR_ALWAYS_INLINE void dfifo_flush_tx(dwc2_regs_t *dwc2, uint8_t fnum)
Definition: dwc2_common.h:82
static TU_ATTR_ALWAYS_INLINE void dfifo_flush_rx(dwc2_regs_t *dwc2)
Definition: dwc2_common.h:88
static const dwc2_controller_t _dwc2_controller[]
Definition: dwc2_esp32.h:57
@ GHWCFG2_HSPHY_ULPI
Definition: dwc2_type.h:112
@ GRXSTS_PKTSTS_GLOBALOUTNAK
Definition: dwc2_type.h:152
@ GRXSTS_PKTSTS_SETUPDONE
Definition: dwc2_type.h:155
@ GRXSTS_PKTSTS_SETUPRX
Definition: dwc2_type.h:156
@ GRXSTS_PKTSTS_OUTDONE
Definition: dwc2_type.h:154
@ GRXSTS_PKTSTS_OUTRX
Definition: dwc2_type.h:153
@ GHWCFG2_ARCH_INTERNAL_DMA
Definition: dwc2_type.h:106
uint8_t const * buffer
Definition: midi_device.h:100
AUDIO Channel Cluster Descriptor (4.1)
Definition: audio.h:647
uint32_t packet_count
Definition: dwc2_type.h:435
uint8_t bInterval
Definition: tusb_types.h:372
uint8_t bmAttributes
See: audio_clock_source_attribute_t.
Definition: audio.h:672
uint32_t byte_count
Definition: dwc2_type.h:294
uint32_t packet_status
Definition: dwc2_type.h:296
uint32_t xfer_size
Definition: dwc2_type.h:434
uint32_t arch
Definition: dwc2_type.h:305
uint32_t ep_ch_num
Definition: dwc2_type.h:293
uint8_t bEndpointAddress
Definition: video.h:306
uint32_t hs_phy_type
Definition: dwc2_type.h:307
volatile uint32_t doeptsiz
Definition: dwc2_type.h:522
volatile uint32_t dieptsiz
Definition: dwc2_type.h:521
volatile uint32_t diepctl
Definition: dwc2_type.h:510
volatile uint32_t doepint
Definition: dwc2_type.h:517
volatile uint32_t diepdma
Definition: dwc2_type.h:526
volatile uint32_t doepdma
Definition: dwc2_type.h:527
volatile uint32_t doepctl
Definition: dwc2_type.h:511
volatile uint32_t diepint
Definition: dwc2_type.h:516
volatile uint32_t ctl
Definition: dwc2_type.h:512
volatile dwc2_ep_tsize_t dieptsiz_bm
Definition: dwc2_type.h:486
volatile uint32_t dtxfsts
Definition: dwc2_type.h:489
volatile uint32_t diepctl
Definition: dwc2_type.h:480
volatile uint32_t diepint
Definition: dwc2_type.h:482
volatile uint32_t doeptsiz
Definition: dwc2_type.h:500
volatile uint32_t doepctl
Definition: dwc2_type.h:495
volatile dwc2_ep_tsize_t doeptsiz_bm
Definition: dwc2_type.h:501
volatile uint32_t doepint
Definition: dwc2_type.h:497
volatile uint32_t doepdma
Definition: dwc2_type.h:503
volatile uint32_t gahbcfg
Definition: dwc2_type.h:549
volatile uint32_t diepempmsk
Definition: dwc2_type.h:647
volatile uint32_t daintmsk
Definition: dwc2_type.h:641
volatile uint32_t gotgctl
Definition: dwc2_type.h:541
volatile uint32_t daint
Definition: dwc2_type.h:640
volatile uint32_t gotgint
Definition: dwc2_type.h:545
volatile uint32_t grxfsiz
Definition: dwc2_type.h:567
volatile uint32_t gusbcfg
Definition: dwc2_type.h:553
volatile uint32_t gsnpsid
Definition: dwc2_type.h:584
volatile uint32_t dieptxf0
Definition: dwc2_type.h:569
volatile dwc2_grxstsp_t grxstsp_bm
Definition: dwc2_type.h:565
volatile uint32_t diepmsk
Definition: dwc2_type.h:638
volatile dwc2_ghwcfg2_t ghwcfg2_bm
Definition: dwc2_type.h:588
dwc2_dep_t ep[2][16]
Definition: dwc2_type.h:659
volatile uint32_t dsts
Definition: dwc2_type.h:636
volatile uint32_t gintmsk
Definition: dwc2_type.h:561
volatile uint32_t doepmsk
Definition: dwc2_type.h:639
volatile uint32_t fifo[16][0x400]
Definition: dwc2_type.h:674
dwc2_epout_t epout[16]
Definition: dwc2_type.h:662
volatile uint32_t gintsts
Definition: dwc2_type.h:560
volatile uint32_t dcfg
Definition: dwc2_type.h:634
dwc2_epin_t epin[16]
Definition: dwc2_type.h:661
volatile uint32_t dctl
Definition: dwc2_type.h:635
volatile uint32_t gdfifocfg
Definition: dwc2_type.h:600
volatile uint32_t dieptxf[15]
Definition: dwc2_type.h:604
uint16_t max_size
Definition: dcd_esp32sx.c:71
uint16_t total_len
Definition: dcd_nrf5x.c:100
uint8_t * buffer
Definition: dcd_nrf5x.c:99
static TU_ATTR_ALWAYS_INLINE uint32_t tu_div_ceil(uint32_t v, uint32_t d)
Definition: tusb_common.h:179
static TU_ATTR_ALWAYS_INLINE uint16_t tu_min16(uint16_t x, uint16_t y)
Definition: tusb_common.h:155
uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t *f, const void *data, uint16_t n)
This function will write n elements into the array index specified by the write pointer and increment...
Definition: tusb_fifo.c:882
uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t *f, void *buffer, uint16_t n)
This function will read n elements from the array index specified by the read pointer and increment t...
Definition: tusb_fifo.c:753
@ TUSB_DIR_IN
Definition: tusb_types.h:67
@ TUSB_DIR_OUT
Definition: tusb_types.h:66
@ TUSB_DIR_IN_MASK
Definition: tusb_types.h:69
tusb_speed_t
defined base on EHCI specs value for Endpoint Speed
Definition: tusb_types.h:49
@ TUSB_SPEED_FULL
Definition: tusb_types.h:50
@ TUSB_SPEED_LOW
Definition: tusb_types.h:51
@ TUSB_SPEED_HIGH
Definition: tusb_types.h:52
static TU_ATTR_ALWAYS_INLINE uint8_t tu_edpt_number(uint8_t addr)
Definition: tusb_types.h:507
tusb_feature_test_mode_t
Definition: tusb_types.h:225
@ XFER_RESULT_SUCCESS
Definition: tusb_types.h:237
static TU_ATTR_ALWAYS_INLINE uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const *desc_ep)
Definition: tusb_types.h:515
@ TUSB_XFER_ISOCHRONOUS
Definition: tusb_types.h:60
TU_ATTR_PACKED_END TU_ATTR_BIT_FIELD_ORDER_END static TU_ATTR_ALWAYS_INLINE tusb_dir_t tu_edpt_dir(uint8_t addr)
Definition: tusb_types.h:502
static TU_ATTR_ALWAYS_INLINE uint8_t tu_edpt_addr(uint8_t num, uint8_t dir)
Definition: tusb_types.h:511