Skip to content

Commit a0e3e5c

Browse files
authored
Update dcd_dwc2.c
1 parent a668c5d commit a0e3e5c

File tree

1 file changed

+92
-54
lines changed

1 file changed

+92
-54
lines changed

components/arduino_tinyusb/src/dcd_dwc2.c

Lines changed: 92 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131

3232
#if CFG_TUD_ENABLED && defined(TUP_USBIP_DWC2)
3333

34+
#if !CFG_TUD_DWC2_SLAVE_ENABLE && !CFG_TUH_DWC2_DMA_ENABLE
35+
#error DWC2 require either CFG_TUD_DWC2_SLAVE_ENABLE or CFG_TUH_DWC2_DMA_ENABLE to be enabled
36+
#endif
37+
3438
// Debug level for DWC2
3539
#define DWC2_DEBUG 2
3640

@@ -46,9 +50,6 @@
4650
//--------------------------------------------------------------------+
4751
// MACRO TYPEDEF CONSTANT ENUM
4852
//--------------------------------------------------------------------+
49-
50-
static CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2];
51-
5253
typedef struct {
5354
uint8_t* buffer;
5455
tu_fifo_t* ff;
@@ -60,19 +61,46 @@ typedef struct {
6061
static xfer_ctl_t xfer_status[DWC2_EP_MAX][2];
6162
#define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir])
6263

63-
// EP0 transfers are limited to 1 packet - larger sizes has to be split
64-
static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type
65-
static uint16_t _dfifo_top; // top free location in DFIFO in words
64+
typedef struct {
65+
// EP0 transfers are limited to 1 packet - larger sizes has to be split
66+
uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type
67+
uint16_t dfifo_top; // top free location in DFIFO in words
68+
69+
// Number of IN endpoints active
70+
uint8_t allocated_epin_count;
71+
72+
// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by
73+
bool sof_en;
74+
} dcd_data_t;
6675

67-
// Number of IN endpoints active
68-
static uint8_t _allocated_ep_in_count;
76+
static dcd_data_t _dcd_data;
6977

70-
// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by
71-
static bool _sof_en;
78+
CFG_TUD_MEM_SECTION static struct {
79+
TUD_EPBUF_DEF(setup_packet, 8);
80+
} _dcd_usbbuf;
7281

7382
//--------------------------------------------------------------------
7483
// DMA
7584
//--------------------------------------------------------------------
85+
#if CFG_TUD_MEM_DCACHE_ENABLE
86+
void dcd_dcache_clean(const void* addr, uint32_t data_size) {
87+
if (addr && data_size) {
88+
dwc2_dcache_clean(addr, data_size);
89+
}
90+
}
91+
92+
void dcd_dcache_invalidate(const void* addr, uint32_t data_size) {
93+
if (addr && data_size) {
94+
dwc2_dcache_invalidate(addr, data_size);
95+
}
96+
}
97+
98+
void dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
99+
if (addr && data_size) {
100+
dwc2_dcache_clean_invalidate(addr, data_size);
101+
}
102+
}
103+
#endif
76104

77105
TU_ATTR_ALWAYS_INLINE static inline bool dma_device_enabled(const dwc2_regs_t* dwc2) {
78106
(void) dwc2;
@@ -91,7 +119,7 @@ static void dma_setup_prepare(uint8_t rhport) {
91119

92120
// Receive only 1 packet
93121
dwc2->epout[0].doeptsiz = (1 << DOEPTSIZ_STUPCNT_Pos) | (1 << DOEPTSIZ_PKTCNT_Pos) | (8 << DOEPTSIZ_XFRSIZ_Pos);
94-
dwc2->epout[0].doepdma = (uintptr_t)_setup_packet;
122+
dwc2->epout[0].doepdma = (uintptr_t) _dcd_usbbuf.setup_packet;
95123
dwc2->epout[0].doepctl |= DOEPCTL_EPENA | DOEPCTL_USBAEP;
96124
}
97125

@@ -149,27 +177,27 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t calc_device_grxfsiz(uint16_t larges
149177
static bool dfifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) {
150178
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
151179
const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
152-
uint8_t const ep_count = dwc2_controller->ep_count;
153-
uint8_t const epnum = tu_edpt_number(ep_addr);
154-
uint8_t const dir = tu_edpt_dir(ep_addr);
180+
const uint8_t ep_count = dwc2_controller->ep_count;
181+
const uint8_t epnum = tu_edpt_number(ep_addr);
182+
const uint8_t dir = tu_edpt_dir(ep_addr);
155183

156184
TU_ASSERT(epnum < ep_count);
157185

158186
uint16_t fifo_size = tu_div_ceil(packet_size, 4);
159187
if (dir == TUSB_DIR_OUT) {
160188
// Calculate required size of RX FIFO
161-
uint16_t const new_sz = calc_device_grxfsiz(4 * fifo_size, ep_count);
189+
const uint16_t new_sz = calc_device_grxfsiz(4 * fifo_size, ep_count);
162190

163191
// If size_rx needs to be extended check if there is enough free space
164192
if (dwc2->grxfsiz < new_sz) {
165-
TU_ASSERT(new_sz <= _dfifo_top);
193+
TU_ASSERT(new_sz <= _dcd_data.dfifo_top);
166194
dwc2->grxfsiz = new_sz; // Enlarge RX FIFO
167195
}
168196
} else {
169197
// Check IN endpoints concurrently active limit
170198
if(_dwc2_controller->ep_in_count) {
171-
TU_ASSERT(_allocated_ep_in_count < _dwc2_controller->ep_in_count);
172-
_allocated_ep_in_count++;
199+
TU_ASSERT(_dcd_data.allocated_epin_count < _dwc2_controller->ep_in_count);
200+
_dcd_data.allocated_epin_count++;
173201
}
174202

175203
// If The TXFELVL is configured as half empty, the fifo must be twice the max_size.
@@ -178,16 +206,16 @@ static bool dfifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) {
178206
}
179207

180208
// Check if free space is available
181-
TU_ASSERT(_dfifo_top >= fifo_size + dwc2->grxfsiz);
182-
_dfifo_top -= fifo_size;
183-
TU_LOG(DWC2_DEBUG, " TX FIFO %u: allocated %u words at offset %u\r\n", epnum, fifo_size, _dfifo_top);
209+
TU_ASSERT(_dcd_data.dfifo_top >= fifo_size + dwc2->grxfsiz);
210+
_dcd_data.dfifo_top -= fifo_size;
211+
// TU_LOG(DWC2_DEBUG, " TX FIFO %u: allocated %u words at offset %u\r\n", epnum, fifo_size, dfifo_top);
184212

185213
// Both TXFD and TXSA are in unit of 32-bit words.
186214
if (epnum == 0) {
187-
dwc2->dieptxf0 = (fifo_size << DIEPTXF0_TX0FD_Pos) | _dfifo_top;
215+
dwc2->dieptxf0 = (fifo_size << DIEPTXF0_TX0FD_Pos) | _dcd_data.dfifo_top;
188216
} else {
189217
// DIEPTXF starts at FIFO #1.
190-
dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | _dfifo_top;
218+
dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | _dcd_data.dfifo_top;
191219
}
192220
}
193221

@@ -201,11 +229,11 @@ static void dfifo_device_init(uint8_t rhport) {
201229

202230
// Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per endpoint direction
203231
const bool is_dma = dma_device_enabled(dwc2);
204-
_dfifo_top = dwc2_controller->ep_fifo_size/4;
232+
_dcd_data.dfifo_top = dwc2_controller->ep_fifo_size/4;
205233
if (is_dma) {
206-
_dfifo_top -= 2 * dwc2_controller->ep_count;
234+
_dcd_data.dfifo_top -= 2 * dwc2_controller->ep_count;
207235
}
208-
dwc2->gdfifocfg = (_dfifo_top << GDFIFOCFG_EPINFOBASE_SHIFT) | _dfifo_top;
236+
dwc2->gdfifocfg = (_dcd_data.dfifo_top << GDFIFOCFG_EPINFOBASE_SHIFT) | _dcd_data.dfifo_top;
209237

210238
// Allocate FIFO for EP0 IN
211239
dfifo_alloc(rhport, 0x80, CFG_TUD_ENDPOINT0_SIZE);
@@ -225,8 +253,8 @@ static uint8_t get_free_fifo(void) {
225253
return 0;
226254
}
227255
#endif
228-
229-
static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) {
256+
257+
static void edpt_activate(uint8_t rhport, const tusb_desc_endpoint_t* p_endpoint_desc) {
230258
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
231259
const uint8_t epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
232260
const uint8_t dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
@@ -328,8 +356,8 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
328356

329357
// EP0 is limited to one packet per xfer
330358
if (epnum == 0) {
331-
total_bytes = tu_min16(ep0_pending[dir], xfer->max_size);
332-
ep0_pending[dir] -= total_bytes;
359+
total_bytes = tu_min16(_dcd_data.ep0_pending[dir], xfer->max_size);
360+
_dcd_data.ep0_pending[dir] -= total_bytes;
333361
num_packets = 1;
334362
} else {
335363
total_bytes = xfer->total_len;
@@ -370,14 +398,18 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
370398

371399
const bool is_dma = dma_device_enabled(dwc2);
372400
if(is_dma) {
401+
if (dir == TUSB_DIR_IN && total_bytes != 0) {
402+
dcd_dcache_clean(xfer->buffer, total_bytes);
403+
}
373404
dep->diepdma = (uintptr_t) xfer->buffer;
374-
}
375-
376-
dep->diepctl = depctl.value; // enable endpoint
405+
dep->diepctl = depctl.value; // enable endpoint
406+
} else {
407+
dep->diepctl = depctl.value; // enable endpoint
377408

378-
// Slave: enable tx fifo empty interrupt only if there is data. Note must after depctl enable
379-
if (!is_dma && dir == TUSB_DIR_IN && total_bytes != 0) {
380-
dwc2->diepempmsk |= (1 << epnum);
409+
// Enable tx fifo empty interrupt only if there is data. Note must after depctl enable
410+
if (dir == TUSB_DIR_IN && total_bytes != 0) {
411+
dwc2->diepempmsk |= (1 << epnum);
412+
}
381413
}
382414
}
383415

@@ -388,6 +420,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
388420
(void) rh_init;
389421
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
390422

423+
tu_memclr(&_dcd_data, sizeof(_dcd_data));
424+
391425
// Core Initialization
392426
const bool is_highspeed = dwc2_core_is_highspeed(dwc2, TUSB_ROLE_DEVICE);
393427
const bool is_dma = dma_device_enabled(dwc2);
@@ -505,7 +539,7 @@ void dcd_sof_enable(uint8_t rhport, bool en) {
505539
(void) rhport;
506540
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
507541

508-
_sof_en = en;
542+
_dcd_data.sof_en = en;
509543

510544
if (en) {
511545
dwc2->gintsts = GINTSTS_SOF;
@@ -530,7 +564,7 @@ void dcd_edpt_close_all(uint8_t rhport) {
530564
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
531565
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
532566

533-
_allocated_ep_in_count = 1;
567+
_dcd_data.allocated_epin_count = 1;
534568

535569
// Disable non-control interrupt
536570
dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos);
@@ -578,7 +612,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
578612

579613
// EP0 can only handle one packet
580614
if (epnum == 0) {
581-
ep0_pending[dir] = total_bytes;
615+
_dcd_data.ep0_pending[dir] = total_bytes;
582616
}
583617

584618
// Schedule packets to be sent within interrupt
@@ -644,8 +678,8 @@ static void handle_bus_reset(uint8_t rhport) {
644678

645679
tu_memclr(xfer_status, sizeof(xfer_status));
646680

647-
_sof_en = false;
648-
_allocated_ep_in_count = 1;
681+
_dcd_data.sof_en = false;
682+
_dcd_data.allocated_epin_count = 1;
649683

650684
// 1. NAK for all OUT endpoints
651685
for (uint8_t n = 0; n < ep_count; n++) {
@@ -746,12 +780,14 @@ static void handle_rxflvl_irq(uint8_t rhport) {
746780
// Global OUT NAK: do nothing
747781
break;
748782

749-
case GRXSTS_PKTSTS_SETUP_RX:
783+
case GRXSTS_PKTSTS_SETUP_RX: {
750784
// Setup packet received
785+
uint32_t* setup = (uint32_t*)(uintptr_t) _dcd_usbbuf.setup_packet;
751786
// We can receive up to three setup packets in succession, but only the last one is valid.
752-
_setup_packet[0] = (*rx_fifo);
753-
_setup_packet[1] = (*rx_fifo);
787+
setup[0] = (*rx_fifo);
788+
setup[1] = (*rx_fifo);
754789
break;
790+
}
755791

756792
case GRXSTS_PKTSTS_SETUP_DONE:
757793
// Setup packet done:
@@ -777,8 +813,8 @@ static void handle_rxflvl_irq(uint8_t rhport) {
777813
if (byte_count < xfer->max_size) {
778814
xfer->total_len -= epout->tsiz_bm.xfer_size;
779815
if (epnum == 0) {
780-
xfer->total_len -= ep0_pending[TUSB_DIR_OUT];
781-
ep0_pending[TUSB_DIR_OUT] = 0;
816+
xfer->total_len -= _dcd_data.ep0_pending[TUSB_DIR_OUT];
817+
_dcd_data.ep0_pending[TUSB_DIR_OUT] = 0;
782818
}
783819
}
784820
}
@@ -797,7 +833,7 @@ static void handle_rxflvl_irq(uint8_t rhport) {
797833

798834
static void handle_epout_slave(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepint_bm) {
799835
if (doepint_bm.setup_phase_done) {
800-
dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true);
836+
dcd_event_setup_received(rhport, _dcd_usbbuf.setup_packet, true);
801837
return;
802838
}
803839

@@ -809,7 +845,7 @@ static void handle_epout_slave(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doe
809845
if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) {
810846
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
811847

812-
if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) {
848+
if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_OUT]) {
813849
// EP0 can only handle one packet, Schedule another packet to be received.
814850
edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT);
815851
} else {
@@ -825,7 +861,7 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep
825861
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
826862

827863
if (diepint_bm.xfer_complete) {
828-
if ((epnum == 0) && ep0_pending[TUSB_DIR_IN]) {
864+
if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_IN]) {
829865
// EP0 can only handle one packet. Schedule another packet to be transmitted.
830866
edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN);
831867
} else {
@@ -873,7 +909,8 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi
873909

874910
if (doepint_bm.setup_phase_done) {
875911
dma_setup_prepare(rhport);
876-
dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true);
912+
dcd_dcache_invalidate(_dcd_usbbuf.setup_packet, 8);
913+
dcd_event_setup_received(rhport, _dcd_usbbuf.setup_packet, true);
877914
return;
878915
}
879916

@@ -882,7 +919,7 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi
882919
// only handle data skip if it is setup or status related
883920
// Normal OUT transfer complete
884921
if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) {
885-
if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) {
922+
if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_OUT]) {
886923
// EP0 can only handle one packet Schedule another packet to be received.
887924
edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT);
888925
} else {
@@ -899,6 +936,7 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi
899936
dma_setup_prepare(rhport);
900937
}
901938

939+
dcd_dcache_invalidate(xfer->buffer, xfer->total_len);
902940
dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true);
903941
}
904942
}
@@ -909,7 +947,7 @@ static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepin
909947
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
910948

911949
if (diepint_bm.xfer_complete) {
912-
if ((epnum == 0) && ep0_pending[TUSB_DIR_IN]) {
950+
if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_IN]) {
913951
// EP0 can only handle one packet. Schedule another packet to be transmitted.
914952
edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN);
915953
} else {
@@ -1016,7 +1054,7 @@ void dcd_int_handler(uint8_t rhport) {
10161054

10171055
if (gintsts & GINTSTS_OTGINT) {
10181056
// OTG INT bit is read-only
1019-
uint32_t const otg_int = dwc2->gotgint;
1057+
const uint32_t otg_int = dwc2->gotgint;
10201058

10211059
if (otg_int & GOTGINT_SEDET) {
10221060
dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
@@ -1033,7 +1071,7 @@ void dcd_int_handler(uint8_t rhport) {
10331071
const uint32_t frame = (dwc2->dsts & DSTS_FNSOF) >> DSTS_FNSOF_Pos;
10341072

10351073
// Disable SOF interrupt if SOF was not explicitly enabled since SOF was used for remote wakeup detection
1036-
if (!_sof_en) {
1074+
if (!_dcd_data.sof_en) {
10371075
dwc2->gintmsk &= ~GINTMSK_SOFM;
10381076
}
10391077

0 commit comments

Comments
 (0)