From cde722385c579fc388fcf78ddb57fad22a643ba5 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 5 Apr 2024 22:19:45 +0200 Subject: [PATCH 01/11] dwc2: add dma support. --- src/portable/synopsys/dwc2/dcd_dwc2.c | 154 +++++++++++++++++++++----- 1 file changed, 124 insertions(+), 30 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 692096fc82..2e679d1f3a 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -67,6 +67,11 @@ // Debug level for DWC2 #define DWC2_DEBUG 2 +// DMA switch +#ifndef DWC2_ENABLE_DMA +#define DWC2_ENABLE_DMA 1 +#endif + #ifndef dcache_clean #define dcache_clean(_addr, _size) #endif @@ -186,6 +191,32 @@ static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) { return true; } +static bool dma_supported(uint8_t rhport) +{ + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + // Internal DMA only + return (dwc2->ghwcfg2_bm.arch == 2) && DWC2_ENABLE_DMA; +} + +static void dma_stpkt_rx(uint8_t rhport) +{ + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + + if (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a) { + if(dwc2->epout[0].doepctl & DOEPCTL_EPENA) + return; + } + + // Receive only 1 packet + dwc2->epout[0].doeptsiz = 0; + dwc2->epout[0].doeptsiz |= (1 << DOEPTSIZ_STUPCNT_Pos); + dwc2->epout[0].doeptsiz |= 8; + dwc2->epout[0].doeptsiz |= (1 << DOEPTSIZ_PKTCNT_Pos); + dwc2->epout[0].doepdma = (uintptr_t)_setup_packet; + + dwc2->epout[0].doepctl |= DOEPCTL_EPENA | DOEPCTL_USBAEP; +} + static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); @@ -351,6 +382,11 @@ static void bus_reset(uint8_t rhport) { // Setup the control endpoint 0 _allocated_fifo_words_tx = 16; + // DMA needs extra space for processing, needs size confirmation + if(dma_supported(rhport)) { + _allocated_fifo_words_tx += 72; + } + // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx); @@ -361,6 +397,10 @@ static void bus_reset(uint8_t rhport) { dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); + if(dma_supported(rhport)) { + dma_stpkt_rx(rhport); + } + dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT; } @@ -369,11 +409,11 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c (void) rhport; dwc2_regs_t* dwc2 = DWC2_REG(rhport); + xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); // EP0 is limited to one packet each xfer // We use multiple transaction of xfer->max_size length to get a whole transfer done if (epnum == 0) { - xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); total_bytes = tu_min16(ep0_pending[dir], xfer->max_size); ep0_pending[dir] -= total_bytes; } @@ -386,17 +426,31 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c epin[epnum].dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) | ((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk); - epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; + if(dma_supported(rhport)) { + epin[epnum].diepdma = (uintptr_t)xfer->buffer; - // For ISO endpoint set correct odd/even bit for next frame. - if ((epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) { - // Take odd/even bit from frame counter. - uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); - epin[epnum].diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); - } - // Enable fifo empty interrupt only if there are something to put in the fifo. - if (total_bytes != 0) { - dwc2->diepempmsk |= (1 << epnum); + // For ISO endpoint set correct odd/even bit for next frame. + if ((epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) { + // Take odd/even bit from frame counter. + uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); + epin[epnum].diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); + } + + epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; + } else { + + epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; + + // For ISO endpoint set correct odd/even bit for next frame. + if ((epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) { + // Take odd/even bit from frame counter. + uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); + epin[epnum].diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); + } + // Enable fifo empty interrupt only if there are something to put in the fifo. + if (total_bytes != 0) { + dwc2->diepempmsk |= (1 << epnum); + } } } else { dwc2_epout_t* epout = dwc2->epout; @@ -406,13 +460,18 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c epout[epnum].doeptsiz |= (num_packets << DOEPTSIZ_PKTCNT_Pos) | ((total_bytes << DOEPTSIZ_XFRSIZ_Pos) & DOEPTSIZ_XFRSIZ_Msk); - epout[epnum].doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK; if ((epout[epnum].doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 && XFER_CTL_BASE(epnum, dir)->interval == 1) { // Take odd/even bit from frame counter. uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); epout[epnum].doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk); } + + if(dma_supported(rhport)) { + epout[epnum].doepdma = (uintptr_t)xfer->buffer; + } + + epout[epnum].doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK; } } @@ -619,6 +678,11 @@ void dcd_init(uint8_t rhport) { // Enable global interrupt dwc2->gahbcfg |= GAHBCFG_GINT; + if (dma_supported(rhport)) { + dwc2->gahbcfg |= GAHBCFG_DMAEN | GAHBCFG_HBSTLEN_2; + dwc2->gintmsk &=~GINTMSK_RXFLVLM; + } + // make sure we are in device mode // TU_ASSERT(!(dwc2->gintsts & GINTSTS_CMOD), ); @@ -728,6 +792,11 @@ void dcd_edpt_close_all(uint8_t rhport) { // reset allocated fifo IN _allocated_fifo_words_tx = 16; + // DMA needs extra space for processing, needs size confirmation + if(dma_supported(rhport)) { + _allocated_fifo_words_tx += 72; + } + fifo_flush_tx(dwc2, 0x10); // all tx fifo fifo_flush_rx(dwc2); } @@ -809,6 +878,9 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { edpt_disable(rhport, ep_addr, true); + if((tu_edpt_number(ep_addr) == 0) && dma_supported(rhport)) { + dma_stpkt_rx(rhport); + } } void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { @@ -991,32 +1063,51 @@ static void handle_epout_irq(uint8_t rhport) { uint32_t const doepint = epout->doepint; - // SETUP packet Setup Phase done. - if (doepint & DOEPINT_STUP) { - uint32_t clear_flag = DOEPINT_STUP; - - // STPKTRX is only available for version from 3_00a - if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { - clear_flag |= DOEPINT_STPKTRX; - } - - epout->doepint = clear_flag; - dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); - } - // OUT XFER complete if (epout->doepint & DOEPINT_XFRC) { epout->doepint = DOEPINT_XFRC; xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT); - // EP0 can only handle one packet - if ((n == 0) && ep0_pending[TUSB_DIR_OUT]) { - // Schedule another packet to be received. - edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + if (doepint & DOEPINT_STUP) { + // STPKTRX is only available for version from 3_00a + if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { + epout->doepint = DOEPINT_STPKTRX; + } + } else if (doepint & DOEPINT_OTEPSPR) { + epout->doepint = DOEPINT_OTEPSPR; } else { - dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); + // EP0 can only handle one packet + if ((n == 0) && ep0_pending[TUSB_DIR_OUT]) { + // Schedule another packet to be received. + edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + } else { + if(dma_supported(rhport)) { + // Fix packet length + uint16_t remain = (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; + xfer->total_len -= remain; + // this is ZLP, so prepare EP0 for next setup + if(n == 0 && xfer->total_len == 0) { + dma_stpkt_rx(rhport); + } + } + + dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); + } + } + } + + // SETUP packet Setup Phase done. + if (doepint & DOEPINT_STUP) { + epout->doepint = DOEPINT_STUP; + if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { + epout->doepint = DOEPINT_STPKTRX; + } + if(dma_supported(rhport) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { + dma_stpkt_rx(rhport); } + + dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); } } } @@ -1042,6 +1133,9 @@ static void handle_epin_irq(uint8_t rhport) { // Schedule another packet to be transmitted. edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); } else { + if((n == 0) && dma_supported(rhport)) { + dma_stpkt_rx(rhport); + } dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); } } From 394dc0686a5c26bd3375ce9aba12b82fa18ba42f Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Thu, 25 Apr 2024 22:09:59 +0200 Subject: [PATCH 02/11] Check IN ep count limit. --- src/portable/synopsys/dwc2/dcd_dwc2.c | 13 +++++++++++++ src/portable/synopsys/dwc2/dwc2_esp32.h | 5 +++-- src/portable/synopsys/dwc2/dwc2_type.h | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 2e679d1f3a..cdf6c2a68e 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -103,6 +103,9 @@ static uint16_t ep0_pending[2]; // Index determines direction as t // TX FIFO RAM allocation so far in words - RX FIFO size is readily available from dwc2->grxfsiz static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs) +// Number of IN endpoints active +static uint8_t _allocated_ep_in_count; + // SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by static bool _sof_en; @@ -170,6 +173,12 @@ static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) { dwc2->grxfsiz = sz; } } else { + // Check IN endpoints concurrently active limit + if(_dwc2_controller->ep_in_count) { + TU_ASSERT(_allocated_ep_in_count < _dwc2_controller->ep_in_count); + _allocated_ep_in_count++; + } + // Note if The TXFELVL is configured as half empty. In order // to be able to write a packet at that point, the fifo must be twice the max_size. if ((dwc2->gahbcfg & GAHBCFG_TXFELVL) == 0) { @@ -303,6 +312,8 @@ static void bus_reset(uint8_t rhport) { _sof_en = false; + _allocated_ep_in_count = 1; + // clear device address dwc2->dcfg &= ~DCFG_DAD_Msk; @@ -770,6 +781,8 @@ void dcd_edpt_close_all(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + _allocated_ep_in_count = 1; + // Disable non-control interrupt dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos); diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h index c50dd66b89..fc12d75512 100644 --- a/src/portable/synopsys/dwc2/dwc2_esp32.h +++ b/src/portable/synopsys/dwc2/dwc2_esp32.h @@ -37,11 +37,12 @@ //#include "soc/usb_periph.h" #define DWC2_REG_BASE 0x60080000UL -#define DWC2_EP_MAX 6 // USB_OUT_EP_NUM. TODO ESP32Sx only has 5 tx fifo (5 endpoint IN) +#define DWC2_EP_MAX 7 +#define DWC2_EP_IN_MAX 5 static const dwc2_controller_t _dwc2_controller[] = { - { .reg_base = DWC2_REG_BASE, .irqnum = 0, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1024 } + { .reg_base = DWC2_REG_BASE, .irqnum = 0, .ep_count = DWC2_EP_MAX, .ep_in_count = DWC2_EP_IN_MAX, .ep_fifo_size = 1024 } }; static intr_handle_t usb_ih; diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index c157712378..5db4535616 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -29,6 +29,7 @@ typedef struct uintptr_t reg_base; uint32_t irqnum; uint8_t ep_count; + uint8_t ep_in_count; uint32_t ep_fifo_size; }dwc2_controller_t; From 298f7f2d818d117785af9f79da79fbdb85120cd2 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Thu, 25 Apr 2024 22:11:49 +0200 Subject: [PATCH 03/11] Fix DMA FIFO reservation. --- src/portable/synopsys/dwc2/dcd_dwc2.c | 16 +++++++++------- src/portable/synopsys/dwc2/dwc2_bcm.h | 2 +- src/portable/synopsys/dwc2/dwc2_type.h | 6 +++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index cdf6c2a68e..1057ee9251 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -393,9 +393,10 @@ static void bus_reset(uint8_t rhport) { // Setup the control endpoint 0 _allocated_fifo_words_tx = 16; - // DMA needs extra space for processing, needs size confirmation + // DMA needs extra space for processing if(dma_supported(rhport)) { - _allocated_fifo_words_tx += 72; + uint16_t reserved = _dwc2_controller[rhport].ep_fifo_size / 4- dwc2->ghwcfg3_bm.total_fifo_size; + _allocated_fifo_words_tx += reserved; } // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) @@ -805,13 +806,14 @@ void dcd_edpt_close_all(uint8_t rhport) { // reset allocated fifo IN _allocated_fifo_words_tx = 16; - // DMA needs extra space for processing, needs size confirmation - if(dma_supported(rhport)) { - _allocated_fifo_words_tx += 72; - } - fifo_flush_tx(dwc2, 0x10); // all tx fifo fifo_flush_rx(dwc2); + + // DMA needs extra space for processing + if(dma_supported(rhport)) { + uint16_t reserved = _dwc2_controller[rhport].ep_fifo_size / 4- dwc2->ghwcfg3_bm.total_fifo_size; + _allocated_fifo_words_tx += reserved; + } } bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { diff --git a/src/portable/synopsys/dwc2/dwc2_bcm.h b/src/portable/synopsys/dwc2/dwc2_bcm.h index 732d96ae09..e5824606ad 100644 --- a/src/portable/synopsys/dwc2/dwc2_bcm.h +++ b/src/portable/synopsys/dwc2/dwc2_bcm.h @@ -39,7 +39,7 @@ static const dwc2_controller_t _dwc2_controller[] = { - { .reg_base = USB_OTG_GLOBAL_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 4096 } + { .reg_base = USB_OTG_GLOBAL_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 16384 } }; #define dcache_clean(_addr, _size) data_clean(_addr, _size) diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index 5db4535616..08c9b8b1b4 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -214,15 +214,15 @@ union { volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep) union { volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2 - dwc2_ghwcfg2_t ghwcfg2_bm; + volatile dwc2_ghwcfg2_t ghwcfg2_bm; }; union { volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3 - dwc2_ghwcfg3_t ghwcfg3_bm; + volatile dwc2_ghwcfg3_t ghwcfg3_bm; }; union { volatile uint32_t ghwcfg4; // 050 User Hardware Configuration4 - dwc2_ghwcfg4_t ghwcfg4_bm; + volatile dwc2_ghwcfg4_t ghwcfg4_bm; }; volatile uint32_t glpmcfg; // 054 Core LPM Configuration volatile uint32_t gpwrdn; // 058 Power Down From 87655682822690de87ade34ceca7c21ca65dd000 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Thu, 25 Apr 2024 22:39:19 +0200 Subject: [PATCH 04/11] Change DMA condition. --- src/class/audio/audio_device.c | 4 ++- src/portable/synopsys/dwc2/dcd_dwc2.c | 47 ++++++++++----------------- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 9ba38a20c2..b7af0259a1 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -65,8 +65,10 @@ //--------------------------------------------------------------------+ // Use ring buffer if it's available, some MCUs need extra RAM requirements +// For DWC2 enable ring buffer will disable DMA (if available) #ifndef TUD_AUDIO_PREFER_RING_BUFFER - #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX + #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX || \ + defined(TUP_USBIP_DWC2) #define TUD_AUDIO_PREFER_RING_BUFFER 0 #else #define TUD_AUDIO_PREFER_RING_BUFFER 1 diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 1057ee9251..c4b1956ce2 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -67,23 +67,6 @@ // Debug level for DWC2 #define DWC2_DEBUG 2 -// DMA switch -#ifndef DWC2_ENABLE_DMA -#define DWC2_ENABLE_DMA 1 -#endif - -#ifndef dcache_clean -#define dcache_clean(_addr, _size) -#endif - -#ifndef dcache_invalidate -#define dcache_invalidate(_addr, _size) -#endif - -#ifndef dcache_clean_invalidate -#define dcache_clean_invalidate(_addr, _size) -#endif - static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2]; typedef struct { @@ -200,11 +183,17 @@ static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) { return true; } -static bool dma_supported(uint8_t rhport) +static inline bool dma_enabled(uint8_t rhport) { + // DMA doesn't support fifo transfer +#ifdef TUD_AUDIO_PREFER_RING_BUFFER +#if TUD_AUDIO_PREFER_RING_BUFFER + return false; +#endif +#endif dwc2_regs_t* dwc2 = DWC2_REG(rhport); // Internal DMA only - return (dwc2->ghwcfg2_bm.arch == 2) && DWC2_ENABLE_DMA; + return (dwc2->ghwcfg2_bm.arch == 2); } static void dma_stpkt_rx(uint8_t rhport) @@ -394,7 +383,7 @@ static void bus_reset(uint8_t rhport) { _allocated_fifo_words_tx = 16; // DMA needs extra space for processing - if(dma_supported(rhport)) { + if(dma_enabled(rhport)) { uint16_t reserved = _dwc2_controller[rhport].ep_fifo_size / 4- dwc2->ghwcfg3_bm.total_fifo_size; _allocated_fifo_words_tx += reserved; } @@ -409,7 +398,7 @@ static void bus_reset(uint8_t rhport) { dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); - if(dma_supported(rhport)) { + if(dma_enabled(rhport)) { dma_stpkt_rx(rhport); } @@ -438,7 +427,7 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c epin[epnum].dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) | ((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk); - if(dma_supported(rhport)) { + if(dma_enabled(rhport)) { epin[epnum].diepdma = (uintptr_t)xfer->buffer; // For ISO endpoint set correct odd/even bit for next frame. @@ -479,7 +468,7 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c epout[epnum].doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk); } - if(dma_supported(rhport)) { + if(dma_enabled(rhport)) { epout[epnum].doepdma = (uintptr_t)xfer->buffer; } @@ -690,7 +679,7 @@ void dcd_init(uint8_t rhport) { // Enable global interrupt dwc2->gahbcfg |= GAHBCFG_GINT; - if (dma_supported(rhport)) { + if (dma_enabled(rhport)) { dwc2->gahbcfg |= GAHBCFG_DMAEN | GAHBCFG_HBSTLEN_2; dwc2->gintmsk &=~GINTMSK_RXFLVLM; } @@ -810,7 +799,7 @@ void dcd_edpt_close_all(uint8_t rhport) { fifo_flush_rx(dwc2); // DMA needs extra space for processing - if(dma_supported(rhport)) { + if(dma_enabled(rhport)) { uint16_t reserved = _dwc2_controller[rhport].ep_fifo_size / 4- dwc2->ghwcfg3_bm.total_fifo_size; _allocated_fifo_words_tx += reserved; } @@ -893,7 +882,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { edpt_disable(rhport, ep_addr, true); - if((tu_edpt_number(ep_addr) == 0) && dma_supported(rhport)) { + if((tu_edpt_number(ep_addr) == 0) && dma_enabled(rhport)) { dma_stpkt_rx(rhport); } } @@ -1097,7 +1086,7 @@ static void handle_epout_irq(uint8_t rhport) { // Schedule another packet to be received. edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); } else { - if(dma_supported(rhport)) { + if(dma_enabled(rhport)) { // Fix packet length uint16_t remain = (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; xfer->total_len -= remain; @@ -1118,7 +1107,7 @@ static void handle_epout_irq(uint8_t rhport) { if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { epout->doepint = DOEPINT_STPKTRX; } - if(dma_supported(rhport) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { + if(dma_enabled(rhport) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { dma_stpkt_rx(rhport); } @@ -1148,7 +1137,7 @@ static void handle_epin_irq(uint8_t rhport) { // Schedule another packet to be transmitted. edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); } else { - if((n == 0) && dma_supported(rhport)) { + if((n == 0) && dma_enabled(rhport)) { dma_stpkt_rx(rhport); } dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); From 02ec4866105eca3f95e7392e538caf97ebb902b4 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sun, 5 May 2024 22:01:09 +0200 Subject: [PATCH 05/11] Fix spurious EP0 completion. --- src/portable/synopsys/dwc2/dcd_dwc2.c | 30 +++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index c4b1956ce2..8c3a6ec610 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -1081,22 +1081,26 @@ static void handle_epout_irq(uint8_t rhport) { } else if (doepint & DOEPINT_OTEPSPR) { epout->doepint = DOEPINT_OTEPSPR; } else { - // EP0 can only handle one packet - if ((n == 0) && ep0_pending[TUSB_DIR_OUT]) { - // Schedule another packet to be received. - edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { + epout->doepint = DOEPINT_STPKTRX; } else { - if(dma_enabled(rhport)) { - // Fix packet length - uint16_t remain = (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; - xfer->total_len -= remain; - // this is ZLP, so prepare EP0 for next setup - if(n == 0 && xfer->total_len == 0) { - dma_stpkt_rx(rhport); + // EP0 can only handle one packet + if ((n == 0) && ep0_pending[TUSB_DIR_OUT]) { + // Schedule another packet to be received. + edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + } else { + if(dma_enabled(rhport)) { + // Fix packet length + uint16_t remain = (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; + xfer->total_len -= remain; + // this is ZLP, so prepare EP0 for next setup + if(n == 0 && xfer->total_len == 0) { + dma_stpkt_rx(rhport); + } } - } - dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); + } } } } From 6d4e2f6c16e239889195fcfbd81b4d27b6ff1979 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Thu, 27 Jun 2024 22:02:18 +0200 Subject: [PATCH 06/11] Fix GenID 3.10 issue on STM32L4. --- src/portable/synopsys/dwc2/dcd_dwc2.c | 66 ++++++++++++++------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index ffcb52f407..2871927be0 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -1032,21 +1032,7 @@ static void handle_rxflvl_irq(uint8_t rhport) { // XFRC complete is additionally generated when // - setup packet is received // - complete the data stage of control write is complete - if ((epnum == 0) && (bcnt == 0) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { - uint32_t doepint = epout->doepint; - - if (doepint & (DOEPINT_STPKTRX | DOEPINT_OTEPSPR)) { - // skip this "no-data" transfer complete event - // Note: STPKTRX will be clear later by setup received handler - uint32_t clear_flags = DOEPINT_XFRC; - - if (doepint & DOEPINT_OTEPSPR) clear_flags |= DOEPINT_OTEPSPR; - - epout->doepint = clear_flags; - - // TU_LOG(DWC2_DEBUG, " FIX extra transfer complete on setup/data compete\r\n"); - } - } + // It will be handled in handle_epout_irq() break; default: // Invalid @@ -1073,23 +1059,23 @@ static void handle_epout_irq(uint8_t rhport) { xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT); - if (doepint & DOEPINT_STUP) { - // STPKTRX is only available for version from 3_00a - if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { - epout->doepint = DOEPINT_STPKTRX; - } - } else if (doepint & DOEPINT_OTEPSPR) { - epout->doepint = DOEPINT_OTEPSPR; - } else { - if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { - epout->doepint = DOEPINT_STPKTRX; + if(dma_enabled(rhport)) { + if (doepint & DOEPINT_STUP) { + // STPKTRX is only available for version from 3_00a + if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) { + epout->doepint = DOEPINT_STPKTRX; + } + } else if (doepint & DOEPINT_OTEPSPR) { + epout->doepint = DOEPINT_OTEPSPR; } else { - // EP0 can only handle one packet - if ((n == 0) && ep0_pending[TUSB_DIR_OUT]) { - // Schedule another packet to be received. - edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) { + epout->doepint = DOEPINT_STPKTRX; } else { - if(dma_enabled(rhport)) { + // EP0 can only handle one packet + if ((n == 0) && ep0_pending[TUSB_DIR_OUT]) { + // Schedule another packet to be received. + edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + } else { // Fix packet length uint16_t remain = (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; xfer->total_len -= remain; @@ -1097,8 +1083,24 @@ static void handle_epout_irq(uint8_t rhport) { if(n == 0 && xfer->total_len == 0) { dma_stpkt_rx(rhport); } + + dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); } + } + } + } else { + if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid == DWC2_CORE_REV_3_10a)) { + epout->doepint = DOEPINT_STPKTRX; + } else { + if ((doepint & DOEPINT_OTEPSPR) && (dwc2->gsnpsid == DWC2_CORE_REV_3_10a)) { + epout->doepint = DOEPINT_OTEPSPR; + } + // EP0 can only handle one packet + if ((n == 0) && ep0_pending[TUSB_DIR_OUT]) { + // Schedule another packet to be received. + edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + } else { dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); } } @@ -1108,10 +1110,10 @@ static void handle_epout_irq(uint8_t rhport) { // SETUP packet Setup Phase done. if (doepint & DOEPINT_STUP) { epout->doepint = DOEPINT_STUP; - if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { + if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) { epout->doepint = DOEPINT_STPKTRX; } - if(dma_enabled(rhport) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) { + if(dma_enabled(rhport) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) { dma_stpkt_rx(rhport); } From 40b55170c87da109b3416ac80eaa55ca56eadc77 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Sep 2024 20:27:34 +0700 Subject: [PATCH 07/11] skip pico2 dual test, it seems not stable --- test/hil/hil_test.py | 1 + test/hil/rpi.json | 1 + 2 files changed, 2 insertions(+) diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index a569e76665..ec28328d47 100644 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -411,6 +411,7 @@ def test_board(board): for skip in board_tests['skip']: if skip in test_list: test_list.remove(skip) + print(f'{name:25} {skip:30} ... Skip') err_count = 0 for test in test_list: diff --git a/test/hil/rpi.json b/test/hil/rpi.json index 77919f3460..672e857fdf 100644 --- a/test/hil/rpi.json +++ b/test/hil/rpi.json @@ -59,6 +59,7 @@ "flasher_sn": "E6633861A3978538", "flasher_args": "-f interface/cmsis-dap.cfg -f target/rp2350.cfg -c \"adapter speed 5000\"", "tests": { + "skip": ["dual/host_info_to_device_cdc"], "dual_attached": [{"vid_pid": "1a86_55d4", "serial": "533D004242"}] } }, From 86b4608365e66ba250cf4fb52226b0ed02488cc1 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 24 Sep 2024 17:38:31 +0700 Subject: [PATCH 08/11] update dfifo allocation scheme to use top pointer, update document and explanation for EPInfo address and GDFIFO. some function rename update h743 linker to use SRAM1 since USB DMA cannot access DTCM ram update xmc4500 to use uuid for testing --- hw/bsp/stm32h7/linker/stm32h743xx_flash.ld | 35 +- hw/bsp/xmc4000/family.c | 6 + src/portable/synopsys/dwc2/dcd_dwc2.c | 361 ++++++++++----------- src/portable/synopsys/dwc2/dwc2_type.h | 14 +- 4 files changed, 206 insertions(+), 210 deletions(-) diff --git a/hw/bsp/stm32h7/linker/stm32h743xx_flash.ld b/hw/bsp/stm32h7/linker/stm32h743xx_flash.ld index 336afc01fa..ba18c8cd16 100644 --- a/hw/bsp/stm32h7/linker/stm32h743xx_flash.ld +++ b/hw/bsp/stm32h7/linker/stm32h743xx_flash.ld @@ -32,23 +32,24 @@ /* Entry Point */ ENTRY(Reset_Handler) -/* Highest address of the user mode stack */ -_estack = 0x20020000; /* end of RAM */ -/* Generate a link error if heap and stack don't fit into RAM */ -_Min_Heap_Size = 0x200; /* required amount of heap */ -_Min_Stack_Size = 0x400; /* required amount of stack */ - /* Specify the memory areas */ MEMORY { -DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K -RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K -RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K -RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K -ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K -FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K + DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K + RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K + RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K + RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K + ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K + } +/* Highest address of the user mode stack */ +_estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1); /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + /* Define output sections */ SECTIONS { @@ -127,7 +128,7 @@ SECTIONS . = ALIGN(4); _edata = .; /* define a global symbol at data end */ - } >DTCMRAM AT> FLASH + } >RAM_D1 AT> FLASH /* Uninitialized data section */ @@ -144,7 +145,9 @@ SECTIONS . = ALIGN(4); _ebss = .; /* define a global symbol at bss end */ __bss_end__ = _ebss; - } >DTCMRAM + } >RAM_D1 + + /* User_heap_stack section, used to check that there is enough RAM left */ ._user_heap_stack : @@ -155,9 +158,7 @@ SECTIONS . = . + _Min_Heap_Size; . = . + _Min_Stack_Size; . = ALIGN(8); - } >DTCMRAM - - + } >RAM_D1 /* Remove information from the standard libraries */ /DISCARD/ : diff --git a/hw/bsp/xmc4000/family.c b/hw/bsp/xmc4000/family.c index 88810de7a8..c776cb58a1 100644 --- a/hw/bsp/xmc4000/family.c +++ b/hw/bsp/xmc4000/family.c @@ -103,6 +103,12 @@ uint32_t board_button_read(void) { return BUTTON_STATE_ACTIVE == XMC_GPIO_GetInput(BUTTON_PIN); } +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + uint8_t const len = tu_min8(16, max_len); + memcpy(id, g_chipid, len); + return len; +} + int board_uart_read(uint8_t* buf, int len) { #ifdef UART_DEV for(int i=0;igrxfsiz -static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs) +static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type +static uint16_t _dfifo_top; // top free location in FIFO RAM // Number of IN endpoints active static uint8_t _allocated_ep_in_count; @@ -92,68 +90,125 @@ static uint8_t _allocated_ep_in_count; // SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by static bool _sof_en; -// Calculate the RX FIFO size according to minimum recommendations from reference manual -// RxFIFO = (5 * number of control endpoints + 8) + -// ((largest USB packet used / 4) + 1 for status information) + -// (2 * number of OUT endpoints) + 1 for Global NAK -// with number of control endpoints = 1 we have -// RxFIFO = 15 + (largest USB packet used / 4) + 2 * number of OUT endpoints -// we double the largest USB packet size to be able to hold up to 2 packets -static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) { - return 15 + 2 * (max_ep_size / 4) + 2 * ep_count; +//-------------------------------------------------------------------- +// DMA +//-------------------------------------------------------------------- + +TU_ATTR_ALWAYS_INLINE static inline bool dma_enabled(const dwc2_regs_t* dwc2) { + (void) dwc2; + // DMA doesn't support fifo transfer +#ifdef TUD_AUDIO_PREFER_RING_BUFFER +#if TUD_AUDIO_PREFER_RING_BUFFER + return false; +#endif +#endif + // Internal DMA only + return (dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA); + // return false; +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t dma_cal_epfifo_base(uint8_t rhport) { + // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per endpoint direction + const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport]; + return dwc2_controller->ep_fifo_size/4 - 2*dwc2_controller->ep_count; } -TU_ATTR_ALWAYS_INLINE static inline void fifo_flush_tx(dwc2_regs_t* dwc2, uint8_t epnum) { +static void dma_setup_prepare(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + + if (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a) { + if(dwc2->epout[0].doepctl & DOEPCTL_EPENA) { + return; + } + } + + // Receive only 1 packet + dwc2->epout[0].doeptsiz = (1 << DOEPTSIZ_STUPCNT_Pos) | (1 << DOEPTSIZ_PKTCNT_Pos) | (8 << DOEPTSIZ_XFRSIZ_Pos); + dwc2->epout[0].doepdma = (uintptr_t)_setup_packet; + dwc2->epout[0].doepctl |= DOEPCTL_EPENA | DOEPCTL_USBAEP; +} + +//--------------------------------------------------------------------+ +// Data FIFO +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline void dfifo_flush_tx(dwc2_regs_t* dwc2, uint8_t epnum) { // flush TX fifo and wait for it cleared dwc2->grstctl = GRSTCTL_TXFFLSH | (epnum << GRSTCTL_TXFNUM_Pos); while (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) {} } -TU_ATTR_ALWAYS_INLINE static inline void fifo_flush_rx(dwc2_regs_t* dwc2) { +TU_ATTR_ALWAYS_INLINE static inline void dfifo_flush_rx(dwc2_regs_t* dwc2) { // flush RX fifo and wait for it cleared dwc2->grstctl = GRSTCTL_RXFFLSH; while (dwc2->grstctl & GRSTCTL_RXFFLSH_Msk) {} } -static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) { +/* USB Data FIFO Layout + + The FIFO is split up into + - EPInfo: for storing DMA metadata, only required when use DMA. Maximum size is called + EP_LOC_CNT = ep_fifo_size - ghwcfg3.dfifo_depth. For value less than EP_LOC_CNT, gdfifocfg must be configured before + gahbcfg.dmaen is set + - Buffer mode: 1 word per endpoint direction + - Scatter/Gather DMA: 4 words per endpoint direction + - TX FIFO: one fifo for each IN endpoint. Size is dynamic depending on packet size, starting from top with EP0 IN. + - Shared RX FIFO: a shared fifo for all OUT endpoints. Typically, can hold up to 2 packets of the largest EP size. + + We allocated TX FIFO from top to bottom (using top pointer), this to allow the RX FIFO to grow dynamically which is + possible since the free space is located between the RX and TX FIFOs. + + ---------------- ep_fifo_size + | EPInfo | + | for DMA | + |-------------|-- gdfifocfg.EPINFOBASE (max is ghwcfg3.dfifo_depth) + | IN FIFO 0 | + | control | + |-------------| + | IN FIFO 1 | + |-------------| + | . . . . | + |-------------| + | IN FIFO n | + |-------------| + | FREE | + |-------------|-- GRXFSIZ (expandable) + | OUT FIFO | + | ( Shared ) | + --------------- 0 + + According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits): + - Each EP IN needs at least max packet size + - All EP OUT shared a unique OUT FIFO which uses (for Slave or Buffer DMA, Scatt/Gather DMA use different formula): + - 13 for setup packets + control words (up to 3 setup packets). + - 1 for global NAK (not required/used here). + - Largest-EPsize / 4 + 1. ( FS: 64 bytes, HS: 512 bytes). Recommended is "2 x (Largest-EPsize/4) + 1" + - 2 for each used OUT endpoint + + Therefore GRXFSIZ = 13 + 1 + 2 x (Largest-EPsize/4 + 1) + 2 x EPOUTnum +*/ + +TU_ATTR_ALWAYS_INLINE static inline uint16_t calc_grxfsiz(uint16_t largest_ep_size, uint8_t ep_count) { + return 13 + 1 + 2 * ((largest_ep_size / 4) + 1) + 2 * ep_count; +} + +static bool dfifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); - uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport]; + uint8_t const ep_count = dwc2_controller->ep_count; uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); TU_ASSERT(epnum < ep_count); uint16_t fifo_size = tu_div_ceil(packet_size, 4); - - // "USB Data FIFOs" section in reference manual - // Peripheral FIFO architecture - // - // --------------- 320 or 1024 ( 1280 or 4096 bytes ) - // | IN FIFO 0 | - // --------------- (320 or 1024) - 16 - // | IN FIFO 1 | - // --------------- (320 or 1024) - 16 - x - // | . . . . | - // --------------- (320 or 1024) - 16 - x - y - ... - z - // | IN FIFO MAX | - // --------------- - // | FREE | - // --------------- GRXFSIZ - // | OUT FIFO | - // | ( Shared ) | - // --------------- 0 - // - // In FIFO is allocated by following rules: - // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". if (dir == TUSB_DIR_OUT) { // Calculate required size of RX FIFO - uint16_t const sz = calc_grxfsiz(4 * fifo_size, ep_count); + uint16_t const new_sz = calc_grxfsiz(4 * fifo_size, ep_count); - // If size_rx needs to be extended check if possible and if so enlarge it - if (dwc2->grxfsiz < sz) { - TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size / 4); - - // Enlarge RX FIFO - dwc2->grxfsiz = sz; + // If size_rx needs to be extended check if there is enough free space + if (dwc2->grxfsiz < new_sz) { + TU_ASSERT(new_sz <= _dfifo_top); + dwc2->grxfsiz = new_sz; // Enlarge RX FIFO } } else { // Check IN endpoints concurrently active limit @@ -162,59 +217,48 @@ static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) { _allocated_ep_in_count++; } - // Note if The TXFELVL is configured as half empty. In order - // to be able to write a packet at that point, the fifo must be twice the max_size. + // If The TXFELVL is configured as half empty, the fifo must be twice the max_size. if ((dwc2->gahbcfg & GAHBCFG_TXFELVL) == 0) { fifo_size *= 2; } // Check if free space is available - TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size / 4); - _allocated_fifo_words_tx += fifo_size; - TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %" PRIu32, fifo_size * 4, - _dwc2_controller[rhport].ep_fifo_size - _allocated_fifo_words_tx * 4); + TU_ASSERT(_dfifo_top >= fifo_size + dwc2->grxfsiz); + _dfifo_top -= fifo_size; + TU_LOG(DWC2_DEBUG, " TX FIFO %u: allocated %u words at offset %u\r\n", epnum, fifo_size, _dfifo_top); - // DIEPTXF starts at FIFO #1. // Both TXFD and TXSA are in unit of 32-bit words. - dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | - (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx); + if (epnum == 0) { + dwc2->dieptxf0 = (fifo_size << DIEPTXF0_TX0FD_Pos) | _dfifo_top; + } else { + // DIEPTXF starts at FIFO #1. + dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | _dfifo_top; + } } return true; } -static inline bool dma_enabled(uint8_t rhport) -{ - // DMA doesn't support fifo transfer -#ifdef TUD_AUDIO_PREFER_RING_BUFFER -#if TUD_AUDIO_PREFER_RING_BUFFER - return false; -#endif -#endif - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - // Internal DMA only - return (dwc2->ghwcfg2_bm.arch == 2); -} - -static void dma_stpkt_rx(uint8_t rhport) -{ +static void dfifo_init(uint8_t rhport) { + const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport]; dwc2_regs_t* dwc2 = DWC2_REG(rhport); + dwc2->grxfsiz = calc_grxfsiz(CFG_TUD_ENDPOINT0_SIZE, dwc2_controller->ep_count); - if (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a) { - if(dwc2->epout[0].doepctl & DOEPCTL_EPENA) - return; + if(dma_enabled(dwc2)) { + // DMA use last DFIFO to store metadata + _dfifo_top = dma_cal_epfifo_base(rhport); + }else { + _dfifo_top = dwc2_controller->ep_fifo_size / 4; } - // Receive only 1 packet - dwc2->epout[0].doeptsiz = 0; - dwc2->epout[0].doeptsiz |= (1 << DOEPTSIZ_STUPCNT_Pos); - dwc2->epout[0].doeptsiz |= 8; - dwc2->epout[0].doeptsiz |= (1 << DOEPTSIZ_PKTCNT_Pos); - dwc2->epout[0].doepdma = (uintptr_t)_setup_packet; - - dwc2->epout[0].doepctl |= DOEPCTL_EPENA | DOEPCTL_USBAEP; + // Allocate FIFO for EP0 IN + dfifo_alloc(rhport, 0x80, CFG_TUD_ENDPOINT0_SIZE); } +//-------------------------------------------------------------------- +// Endpoint +//-------------------------------------------------------------------- + static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); @@ -235,7 +279,7 @@ static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoin dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum); } else { dwc2->epin[epnum].diepctl = dxepctl | (epnum << DIEPCTL_TXFNUM_Pos); - dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum)); + dwc2->daintmsk |= TU_BIT(DAINTMSK_IEPM_Pos + epnum); } } @@ -265,7 +309,7 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { } // Flush the FIFO, and wait until we have confirmed it cleared. - fifo_flush_tx(dwc2, epnum); + dfifo_flush_tx(dwc2, epnum); } else { dwc2_epout_t* epout = dwc2->epout; @@ -318,88 +362,27 @@ static void bus_reset(uint8_t rhport) { } } - fifo_flush_tx(dwc2, 0x10); // all tx fifo - fifo_flush_rx(dwc2); + dfifo_flush_tx(dwc2, 0x10); // all tx fifo + dfifo_flush_rx(dwc2); // 3. Set up interrupt mask dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos); dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM; dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM; - // "USB Data FIFOs" section in reference manual - // Peripheral FIFO architecture - // - // The FIFO is split up in a lower part where the RX FIFO is located and an upper part where the TX FIFOs start. - // We do this to allow the RX FIFO to grow dynamically which is possible since the free space is located - // between the RX and TX FIFOs. This is required by ISO OUT EPs which need a bigger FIFO than the standard - // configuration done below. - // - // Dynamically FIFO sizes are of interest only for ISO EPs since all others are usually not opened and closed. - // All EPs other than ISO are opened as soon as the driver starts up i.e. when the host sends a - // configure interface command. Hence, all IN EPs other the ISO will be located at the top. IN ISO EPs are usually - // opened when the host sends an additional command: setInterface. At this point in time - // the ISO EP will be located next to the free space and can change its size. In case more IN EPs change its size - // an additional memory - // - // --------------- 320 or 1024 ( 1280 or 4096 bytes ) - // | IN FIFO 0 | - // --------------- (320 or 1024) - 16 - // | IN FIFO 1 | - // --------------- (320 or 1024) - 16 - x - // | . . . . | - // --------------- (320 or 1024) - 16 - x - y - ... - z - // | IN FIFO MAX | - // --------------- - // | FREE | - // --------------- GRXFSIZ - // | OUT FIFO | - // | ( Shared ) | - // --------------- 0 - // - // According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits): - // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN - // - // - All EP OUT shared a unique OUT FIFO which uses - // - 13 for setup packets + control words (up to 3 setup packets). - // - 1 for global NAK (not required/used here). - // - Largest-EPsize / 4 + 1. ( FS: 64 bytes, HS: 512 bytes). Recommended is "2 x (Largest-EPsize/4) + 1" - // - 2 for each used OUT endpoint - // - // Therefore GRXFSIZ = 13 + 1 + 1 + 2 x (Largest-EPsize/4) + 2 x EPOUTnum - // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x ep_count = 47 + 2 x ep_count - // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x ep_count = 271 + 2 x ep_count - // - // NOTE: Largest-EPsize & EPOUTnum is actual used endpoints in configuration. Since DCD has no knowledge - // of the overall picture yet. We will use the worst scenario: largest possible + ep_count - // - // For Isochronous, largest EP size can be 1023/1024 for FS/HS respectively. In addition if multiple ISO - // are enabled at least "2 x (Largest-EPsize/4) + 1" are recommended. Maybe provide a macro for application to - // overwrite this. - - // EP0 out max is 64 - dwc2->grxfsiz = calc_grxfsiz(64, ep_count); - - // Setup the control endpoint 0 - _allocated_fifo_words_tx = 16; - - // DMA needs extra space for processing - if(dma_enabled(rhport)) { - uint16_t reserved = _dwc2_controller[rhport].ep_fifo_size / 4- dwc2->ghwcfg3_bm.total_fifo_size; - _allocated_fifo_words_tx += reserved; - } - - // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) - dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx); + dfifo_init(rhport); // Fixed control EP0 size to 64 bytes dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); + dwc2->epout[0].doepctl &= ~(0x03 << DOEPCTL_MPSIZ_Pos); + xfer_status[0][TUSB_DIR_OUT].max_size = 64; xfer_status[0][TUSB_DIR_IN].max_size = 64; - dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); - - if(dma_enabled(rhport)) { - dma_stpkt_rx(rhport); + if(dma_enabled(dwc2)) { + dma_setup_prepare(rhport); + } else { + dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); } dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT; @@ -427,7 +410,7 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c epin[epnum].dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) | ((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk); - if(dma_enabled(rhport)) { + if(dma_enabled(dwc2)) { epin[epnum].diepdma = (uintptr_t)xfer->buffer; // For ISO endpoint set correct odd/even bit for next frame. @@ -468,7 +451,7 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c epout[epnum].doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk); } - if(dma_enabled(rhport)) { + if(dma_enabled(dwc2)) { epout[epnum].doepdma = (uintptr_t)xfer->buffer; } @@ -599,7 +582,9 @@ static void phy_hs_init(dwc2_regs_t* dwc2) { // XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required // when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347) - if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) dcfg |= DCFG_XCVRDLY; + if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) { + dcfg |= DCFG_XCVRDLY; + } dwc2->dcfg = dcfg; } @@ -625,12 +610,9 @@ void dcd_init(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); // Check Synopsys ID register, failed if controller clock/power is not enabled - if (!check_dwc2(dwc2)) return; + TU_ASSERT(check_dwc2(dwc2), ); dcd_disconnect(rhport); - // max number of endpoints & total_fifo_size are: - // hw_cfg2->num_dev_ep, hw_cfg2->total_fifo_size - if (phy_hs_supported(dwc2)) { phy_hs_init(dwc2); // Highspeed } else { @@ -660,8 +642,8 @@ void dcd_init(uint8_t rhport) { // (non zero-length packet), send STALL back and discard. dwc2->dcfg |= DCFG_NZLSOHSK; - fifo_flush_tx(dwc2, 0x10); // all tx fifo - fifo_flush_rx(dwc2); + dfifo_flush_tx(dwc2, 0x10); // all tx fifo + dfifo_flush_rx(dwc2); // Clear all interrupts uint32_t int_mask = dwc2->gintsts; @@ -670,20 +652,24 @@ void dcd_init(uint8_t rhport) { dwc2->gotgint |= int_mask; // Required as part of core initialization. - dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_RXFLVLM | - GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM; + dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM; // Configure TX FIFO empty level for interrupt. Default is complete empty dwc2->gahbcfg |= GAHBCFG_TXFELVL; - // Enable global interrupt - dwc2->gahbcfg |= GAHBCFG_GINT; + if (dma_enabled(dwc2)) { + const uint16_t epinfo_base = dma_cal_epfifo_base(rhport); + dwc2->gdfifocfg = (epinfo_base << GDFIFOCFG_EPINFOBASE_SHIFT) | epinfo_base; - if (dma_enabled(rhport)) { + // DMA seems to be only settable after a core reset dwc2->gahbcfg |= GAHBCFG_DMAEN | GAHBCFG_HBSTLEN_2; - dwc2->gintmsk &=~GINTMSK_RXFLVLM; + }else { + dwc2->gintmsk |= GINTMSK_RXFLVLM; } + // Enable global interrupt + dwc2->gahbcfg |= GAHBCFG_GINT; + // make sure we are in device mode // TU_ASSERT(!(dwc2->gintsts & GINTSTS_CMOD), ); @@ -783,7 +769,7 @@ void dcd_sof_enable(uint8_t rhport, bool en) { *------------------------------------------------------------------*/ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { - TU_ASSERT(fifo_alloc(rhport, desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt))); + TU_ASSERT(dfifo_alloc(rhport, desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt))); edpt_activate(rhport, desc_edpt); return true; } @@ -812,32 +798,21 @@ void dcd_edpt_close_all(uint8_t rhport) { xfer_status[n][TUSB_DIR_IN].max_size = 0; } - // reset allocated fifo OUT - dwc2->grxfsiz = calc_grxfsiz(64, ep_count); - // reset allocated fifo IN - _allocated_fifo_words_tx = 16; - - fifo_flush_tx(dwc2, 0x10); // all tx fifo - fifo_flush_rx(dwc2); + dfifo_flush_tx(dwc2, 0x10); // all tx fifo + dfifo_flush_rx(dwc2); - // DMA needs extra space for processing - if(dma_enabled(rhport)) { - uint16_t reserved = _dwc2_controller[rhport].ep_fifo_size / 4- dwc2->ghwcfg3_bm.total_fifo_size; - _allocated_fifo_words_tx += reserved; - } + dfifo_init(rhport); // re-init dfifo } bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { - TU_ASSERT(fifo_alloc(rhport, ep_addr, largest_packet_size)); + TU_ASSERT(dfifo_alloc(rhport, ep_addr, largest_packet_size)); return true; } bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { // Disable EP to clear potential incomplete transfers edpt_disable(rhport, p_endpoint_desc->bEndpointAddress, false); - edpt_activate(rhport, p_endpoint_desc); - return true; } @@ -904,8 +879,8 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { edpt_disable(rhport, ep_addr, true); - if((tu_edpt_number(ep_addr) == 0) && dma_enabled(rhport)) { - dma_stpkt_rx(rhport); + if((tu_edpt_number(ep_addr) == 0) && dma_enabled(DWC2_REG(rhport))) { + dma_setup_prepare(rhport); } } @@ -1075,13 +1050,15 @@ static void handle_epout_irq(uint8_t rhport) { uint32_t const doepint = epout->doepint; + TU_ASSERT((epout->doepint & DOEPINT_AHBERR) == 0, ); + // OUT XFER complete if (epout->doepint & DOEPINT_XFRC) { epout->doepint = DOEPINT_XFRC; xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT); - if(dma_enabled(rhport)) { + if(dma_enabled(dwc2)) { if (doepint & DOEPINT_STUP) { // STPKTRX is only available for version from 3_00a if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) { @@ -1103,7 +1080,7 @@ static void handle_epout_irq(uint8_t rhport) { xfer->total_len -= remain; // this is ZLP, so prepare EP0 for next setup if(n == 0 && xfer->total_len == 0) { - dma_stpkt_rx(rhport); + dma_setup_prepare(rhport); } dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); @@ -1135,8 +1112,8 @@ static void handle_epout_irq(uint8_t rhport) { if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) { epout->doepint = DOEPINT_STPKTRX; } - if(dma_enabled(rhport) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) { - dma_stpkt_rx(rhport); + if(dma_enabled(dwc2) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) { + dma_setup_prepare(rhport); } dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); @@ -1165,8 +1142,8 @@ static void handle_epin_irq(uint8_t rhport) { // Schedule another packet to be transmitted. edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); } else { - if((n == 0) && dma_enabled(rhport)) { - dma_stpkt_rx(rhport); + if((n == 0) && dma_enabled(dwc2)) { + dma_setup_prepare(rhport); } dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); } diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index 244323b512..c21bf9e941 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -100,6 +100,12 @@ enum { FS_PHY_TYPE_ULPI, }; +enum { + GHWCFG2_ARCH_SLAVE_ONLY = 0, + GHWCFG2_ARCH_EXTERNAL_DMA, // 1 + GHWCFG2_ARCH_INTERNAL_DMA, // 2 +}; + typedef struct TU_ATTR_PACKED { uint32_t op_mode : 3; // 0: HNP and SRP | 1: SRP | 2: non-HNP, non-SRP @@ -134,7 +140,7 @@ typedef struct TU_ATTR_PACKED uint32_t otg_enable_hsic : 1; // 1: HSIC-capable with shared UTMI PHY interface | 0: non-HSIC uint32_t battery_charger_support : 1; // support battery charger uint32_t lpm_mode : 1; // LPC mode - uint32_t total_fifo_size : 16; // DFIFO depth value in terms of 32-bit words + uint32_t dfifo_depth : 16; // DFIFO depth - EP_LOC_CNT in terms of 32-bit words }dwc2_ghwcfg3_t; TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg3_t) == 4, "incorrect size"); @@ -1240,6 +1246,12 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); #define GLPMCFG_ENBESL_Msk (0x1UL << GLPMCFG_ENBESL_Pos) // 0x10000000 #define GLPMCFG_ENBESL GLPMCFG_ENBESL_Msk // Enable best effort service latency +// GDFIFOCFG +#define GDFIFOCFG_EPINFOBASE_MASK (0xffff << 16) +#define GDFIFOCFG_EPINFOBASE_SHIFT 16 +#define GDFIFOCFG_GDFIFOCFG_MASK (0xffff << 0) +#define GDFIFOCFG_GDFIFOCFG_SHIFT 0 + /******************** Bit definition for DIEPEACHMSK1 register ********************/ #define DIEPEACHMSK1_XFRCM_Pos (0U) #define DIEPEACHMSK1_XFRCM_Msk (0x1UL << DIEPEACHMSK1_XFRCM_Pos) // 0x00000001 From a1244381b3e68959f99bc0ba8057eea5ca35bac6 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 24 Sep 2024 17:55:15 +0700 Subject: [PATCH 09/11] add CFG_TUD_DWC2_DMA, make it compile time option --- src/common/tusb_mcu.h | 2 +- src/portable/synopsys/dwc2/dcd_dwc2.c | 9 +++---- src/tusb_option.h | 39 ++++++++++++++++----------- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 0a4462a0aa..6ead1ea0bb 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -524,7 +524,7 @@ #define TUP_DCD_EDPT_ISO_ALLOC #endif -#if defined(TUP_USBIP_DWC2) +#if defined(TUP_USBIP_DWC2) // && CFG_TUD_DWC2_DMA == 0 #define TUP_MEM_CONST_ADDR #endif diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 897f81a427..2c5e82778c 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -95,16 +95,13 @@ static bool _sof_en; //-------------------------------------------------------------------- TU_ATTR_ALWAYS_INLINE static inline bool dma_enabled(const dwc2_regs_t* dwc2) { + #if !CFG_TUD_DWC2_DMA (void) dwc2; - // DMA doesn't support fifo transfer -#ifdef TUD_AUDIO_PREFER_RING_BUFFER -#if TUD_AUDIO_PREFER_RING_BUFFER return false; -#endif -#endif + #else // Internal DMA only return (dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA); - // return false; + #endif } TU_ATTR_ALWAYS_INLINE static inline uint16_t dma_cal_epfifo_base(uint8_t rhport) { diff --git a/src/tusb_option.h b/src/tusb_option.h index fb0209023d..e61b3bb9e8 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -228,7 +228,7 @@ #define OPT_MODE_SPEED_MASK 0xff00 //--------------------------------------------------------------------+ -// Include tusb_config.h and tusb_mcu.h +// Include tusb_config.h //--------------------------------------------------------------------+ // Allow to use command line to change the config name/location @@ -238,6 +238,29 @@ #include "tusb_config.h" #endif +//--------------------------------------------------------------------+ +// USBIP +//--------------------------------------------------------------------+ + +// DWC2 controller: use DMA for data transfer +#ifndef CFG_TUD_DWC2_DMA + #define CFG_TUD_DWC2_DMA 1 +#endif + +// Enable PIO-USB software host controller +#ifndef CFG_TUH_RPI_PIO_USB + #define CFG_TUH_RPI_PIO_USB 0 +#endif + +#ifndef CFG_TUD_RPI_PIO_USB + #define CFG_TUD_RPI_PIO_USB 0 +#endif + +// MAX3421 Host controller option +#ifndef CFG_TUH_MAX3421 + #define CFG_TUH_MAX3421 0 +#endif + #include "common/tusb_mcu.h" //-------------------------------------------------------------------- @@ -548,20 +571,6 @@ #define CFG_TUH_API_EDPT_XFER 0 #endif -// Enable PIO-USB software host controller -#ifndef CFG_TUH_RPI_PIO_USB - #define CFG_TUH_RPI_PIO_USB 0 -#endif - -#ifndef CFG_TUD_RPI_PIO_USB - #define CFG_TUD_RPI_PIO_USB 0 -#endif - -// MAX3421 Host controller option -#ifndef CFG_TUH_MAX3421 - #define CFG_TUH_MAX3421 0 -#endif - //--------------------------------------------------------------------+ // TypeC Options (Default) //--------------------------------------------------------------------+ From 6a15e7875c6bc42247210fdcebdea1a4353c51ea Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 24 Sep 2024 18:01:09 +0700 Subject: [PATCH 10/11] more rename --- src/portable/synopsys/dwc2/dcd_dwc2.c | 106 +++++++++++++------------- src/tusb_option.h | 2 +- 2 files changed, 55 insertions(+), 53 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 2c5e82778c..eb5b145e88 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -252,6 +252,55 @@ static void dfifo_init(uint8_t rhport) { dfifo_alloc(rhport, 0x80, CFG_TUD_ENDPOINT0_SIZE); } +// Read a single data packet from receive FIFO +static void dfifo_read_packet(uint8_t rhport, uint8_t* dst, uint16_t len) { + (void) rhport; + + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + volatile const uint32_t* rx_fifo = dwc2->fifo[0]; + + // Reading full available 32 bit words from fifo + uint16_t full_words = len >> 2; + while (full_words--) { + tu_unaligned_write32(dst, *rx_fifo); + dst += 4; + } + + // Read the remaining 1-3 bytes from fifo + uint8_t const bytes_rem = len & 0x03; + if (bytes_rem != 0) { + uint32_t const tmp = *rx_fifo; + dst[0] = tu_u32_byte0(tmp); + if (bytes_rem > 1) dst[1] = tu_u32_byte1(tmp); + if (bytes_rem > 2) dst[2] = tu_u32_byte2(tmp); + } +} + +// Write a single data packet to EPIN FIFO +static void dfifo_write_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const* src, uint16_t len) { + (void) rhport; + + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num]; + + // Pushing full available 32 bit words to fifo + uint16_t full_words = len >> 2; + while (full_words--) { + *tx_fifo = tu_unaligned_read32(src); + src += 4; + } + + // Write the remaining 1-3 bytes into fifo + uint8_t const bytes_rem = len & 0x03; + if (bytes_rem) { + uint32_t tmp_word = src[0]; + if (bytes_rem > 1) tmp_word |= (src[1] << 8); + if (bytes_rem > 2) tmp_word |= (src[2] << 16); + + *tx_fifo = tmp_word; + } +} + //-------------------------------------------------------------------- // Endpoint //-------------------------------------------------------------------- @@ -899,56 +948,9 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { } } -/*------------------------------------------------------------------*/ - -// Read a single data packet from receive FIFO -static void read_fifo_packet(uint8_t rhport, uint8_t* dst, uint16_t len) { - (void) rhport; - - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - volatile const uint32_t* rx_fifo = dwc2->fifo[0]; - - // Reading full available 32 bit words from fifo - uint16_t full_words = len >> 2; - while (full_words--) { - tu_unaligned_write32(dst, *rx_fifo); - dst += 4; - } - - // Read the remaining 1-3 bytes from fifo - uint8_t const bytes_rem = len & 0x03; - if (bytes_rem != 0) { - uint32_t const tmp = *rx_fifo; - dst[0] = tu_u32_byte0(tmp); - if (bytes_rem > 1) dst[1] = tu_u32_byte1(tmp); - if (bytes_rem > 2) dst[2] = tu_u32_byte2(tmp); - } -} - -// Write a single data packet to EPIN FIFO -static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const* src, uint16_t len) { - (void) rhport; - - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num]; - - // Pushing full available 32 bit words to fifo - uint16_t full_words = len >> 2; - while (full_words--) { - *tx_fifo = tu_unaligned_read32(src); - src += 4; - } - - // Write the remaining 1-3 bytes into fifo - uint8_t const bytes_rem = len & 0x03; - if (bytes_rem) { - uint32_t tmp_word = src[0]; - if (bytes_rem > 1) tmp_word |= (src[1] << 8); - if (bytes_rem > 2) tmp_word |= (src[2] << 16); - - *tx_fifo = tmp_word; - } -} +//-------------------------------------------------------------------- +// Interrupt Handler +//-------------------------------------------------------------------- static void handle_rxflvl_irq(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); @@ -1002,7 +1004,7 @@ static void handle_rxflvl_irq(uint8_t rhport) { tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void*) (uintptr_t) rx_fifo, bcnt); } else { // Linear buffer - read_fifo_packet(rhport, xfer->buffer, bcnt); + dfifo_read_packet(rhport, xfer->buffer, bcnt); // Increment pointer to xfer data xfer->buffer += bcnt; @@ -1171,7 +1173,7 @@ static void handle_epin_irq(uint8_t rhport) { volatile uint32_t* tx_fifo = dwc2->fifo[n]; tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*) (uintptr_t) tx_fifo, packet_size); } else { - write_fifo_packet(rhport, n, xfer->buffer, packet_size); + dfifo_write_packet(rhport, n, xfer->buffer, packet_size); // Increment pointer to xfer data xfer->buffer += packet_size; diff --git a/src/tusb_option.h b/src/tusb_option.h index e61b3bb9e8..0d118eef9e 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -244,7 +244,7 @@ // DWC2 controller: use DMA for data transfer #ifndef CFG_TUD_DWC2_DMA - #define CFG_TUD_DWC2_DMA 1 + #define CFG_TUD_DWC2_DMA 0 #endif // Enable PIO-USB software host controller From e483c6a2ade2dbf2ec44d835134f62eab0cf9698 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 24 Sep 2024 21:30:16 +0200 Subject: [PATCH 11/11] Add a note about data cache. --- src/tusb_option.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tusb_option.h b/src/tusb_option.h index 0d118eef9e..17de9cd72b 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -243,6 +243,10 @@ //--------------------------------------------------------------------+ // DWC2 controller: use DMA for data transfer +// For processors with data cache enabled, USB endpoint buffer region +// (defined by CFG_TUSB_MEM_SECTION) must be declared as non-cacheable. +// For example, on Cortex-M7 the MPU region can be configured as normal +// non-cacheable, with RASR register value: TEX=1 C=0 B=0 S=0. #ifndef CFG_TUD_DWC2_DMA #define CFG_TUD_DWC2_DMA 0 #endif