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
4650//--------------------------------------------------------------------+
4751// MACRO TYPEDEF CONSTANT ENUM
4852//--------------------------------------------------------------------+
49-
50- static CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED (4 ) uint32_t _setup_packet [2 ];
51-
5253typedef struct {
5354 uint8_t * buffer ;
5455 tu_fifo_t * ff ;
@@ -60,19 +61,46 @@ typedef struct {
6061static 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
77105TU_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
149177static 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
798834static 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