From cc979da5163d0d407e27d90411a6d4b1a0092779 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 2 Jun 2026 22:38:57 +0200 Subject: dcd/dwc2: fix back-to-back SETUP reception in DMA mode Signed-off-by: HiFiPhile --- src/portable/synopsys/dwc2/dcd_dwc2.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index c90429a15..e6d7dc08e 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -73,9 +73,8 @@ typedef struct { static dcd_data_t _dcd_data; -CFG_TUD_MEM_SECTION static union { - TUD_EPBUF_DEF(setup_buffer, 8); - tusb_control_request_t setup_packet; +CFG_TUD_MEM_SECTION static struct { + TUD_EPBUF_DEF(setup_buffer, 24); } _dcd_usbbuf; static tud_configure_dwc2_t _tud_cfg = CFG_TUD_CONFIGURE_DWC2_DEFAULT; @@ -137,8 +136,8 @@ static void dma_setup_prepare(uint8_t rhport) { } } - // Receive only 1 packet - dwc2->epout[0].doeptsiz = (1 << DOEPTSIZ_STUPCNT_Pos) | (1 << DOEPTSIZ_PKTCNT_Pos) | (8 << DOEPTSIZ_XFRSIZ_Pos); + // Receive back-to-back setup packets + dwc2->epout[0].doeptsiz = (3 << DOEPTSIZ_STUPCNT_Pos); dwc2->epout[0].doepdma = (uintptr_t) _dcd_usbbuf.setup_buffer; dwc2->epout[0].doepctl |= DOEPCTL_EPENA | DOEPCTL_USBAEP; } @@ -1003,15 +1002,19 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi if (doepint_bm.setup_phase_done) { // Cleanup previous pending EP0 IN transfer if any - dwc2_dep_t* epin0 = &DWC2_REG(rhport)->epin[0]; + dwc2_dep_t* epin0 = &dwc2->epin[0]; + dwc2_dep_t* epout0 = &dwc2->epout[0]; if (edpt_is_enabled(epin0)) { edpt_disable(rhport, 0x80, false); } - dcd_dcache_invalidate(_dcd_usbbuf.setup_buffer, 8); - dcd_event_setup_received(rhport, _dcd_usbbuf.setup_buffer, true); + + dcd_dcache_invalidate(_dcd_usbbuf.setup_buffer, sizeof(_dcd_usbbuf.setup_buffer)); + + tusb_control_request_t *setup_packet = (tusb_control_request_t *) (epout0->doepdma - 8); + dcd_event_setup_received(rhport, (uint8_t*)setup_packet, true); // Prepare EP0 for next setup if this setup has no data stage - if (_dcd_usbbuf.setup_packet.wLength == 0) { + if (setup_packet->wLength == 0) { dma_setup_prepare(rhport); } return; -- cgit v1.3.1 From b5e080732e67a52afefa6966ca33474c91a53d0c Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 4 Jun 2026 17:55:44 +0700 Subject: Update setup buffer size definition based on DMA configuration --- src/portable/synopsys/dwc2/dcd_dwc2.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index c7899a354..ee52ef1e7 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -73,8 +73,15 @@ typedef struct { static dcd_data_t _dcd_data; +// DMA receives up to 3 back-to-back SETUP packets (3 x 8 bytes), Slave mode only needs 1 packet (8 bytes) +#if CFG_TUD_DWC2_DMA_ENABLE + #define DWC2_SETUP_BUFFER_SIZE 24 +#else + #define DWC2_SETUP_BUFFER_SIZE 8 +#endif + CFG_TUD_MEM_SECTION static struct { - TUD_EPBUF_DEF(setup_buffer, 24); + TUD_EPBUF_DEF(setup_buffer, DWC2_SETUP_BUFFER_SIZE); } _dcd_usbbuf; static tud_configure_dwc2_t _tud_cfg = CFG_TUD_CONFIGURE_DWC2_DEFAULT; -- cgit v1.3.1 From a900ea93db686cacde5e595dc09fdfeaa334d556 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 4 Jun 2026 20:46:49 +0700 Subject: dwc2: cleanup setup_packet pointer cast (review feedback) Cast DOEPDMA0 through uintptr_t and use sizeof(tusb_control_request_t) instead of the magic constant 8, matching project convention. Add a reference to Programming Guide v4.20a 9.1.2.1 for the DOEPDMAn-8 rule. Addresses Copilot review comment; no functional change. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/portable/synopsys/dwc2/dcd_dwc2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index ee52ef1e7..e1a2f6cf2 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -1031,7 +1031,9 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi dcd_dcache_invalidate(_dcd_usbbuf.setup_buffer, sizeof(_dcd_usbbuf.setup_buffer)); - tusb_control_request_t *setup_packet = (tusb_control_request_t *) (epout0->doepdma - 8); + // DOEPDMA0 has advanced past the last received SETUP packet; back up one packet to the latest valid one + // (Programming Guide v4.20a section 9.1.2.1: "DOEPDMAn-8 provides the pointer to the last valid SETUP data") + tusb_control_request_t *setup_packet = (tusb_control_request_t *) (uintptr_t) (epout0->doepdma - sizeof(tusb_control_request_t)); dcd_event_setup_received(rhport, (uint8_t*)setup_packet, true); // Prepare EP0 for next setup if this setup has no data stage -- cgit v1.3.1