Просмотр исходного кода

moving esp32s2 to dwc2, abstract dwc2_set_turnaround()

hathach 4 лет назад
Родитель
Сommit
4ccf60954d

+ 1 - 1
examples/device/cdc_msc_freertos/src/CMakeLists.txt

@@ -27,5 +27,5 @@ target_sources(${COMPONENT_TARGET} PUBLIC
   "${TOP}/src/class/net/ncm_device.c"
   "${TOP}/src/class/usbtmc/usbtmc_device.c"
   "${TOP}/src/class/vendor/vendor_device.c"
-  "${TOP}/src/portable/espressif/esp32sx/dcd_esp32sx.c"
+  "${TOP}/src/portable/synopsys/dwc2/dcd_dwc2.c"
 )

+ 1 - 2
hw/bsp/gd32vf103/family.mk

@@ -28,8 +28,7 @@ CFLAGS += \
 	-mstrict-align \
 	-nostdlib -nostartfiles \
 	-DCFG_TUSB_MCU=OPT_MCU_GD32VF103 \
-	-DDOWNLOAD_MODE=DOWNLOAD_MODE_FLASHXIP \
-	-DGD32VF103 
+	-DDOWNLOAD_MODE=DOWNLOAD_MODE_FLASHXIP
 
 # mcu driver cause following warnings
 CFLAGS += -Wno-error=unused-parameter

+ 8 - 8
src/device/dcd_attr.h

@@ -36,13 +36,13 @@
 // - PORT_HIGHSPEED: mask to indicate which port support highspeed mode, bit0 for port0 and so on.
 
 //------------- NXP -------------//
-#if   TU_CHECK_MCU(LPC11UXX) || TU_CHECK_MCU(LPC13XX) || TU_CHECK_MCU(LPC15XX)
+#if   TU_CHECK_MCU(LPC11UXX, LPC13XX, LPC15XX)
   #define DCD_ATTR_ENDPOINT_MAX   5
 
-#elif TU_CHECK_MCU(LPC175X_6X) || TU_CHECK_MCU(LPC177X_8X) || TU_CHECK_MCU(LPC40XX)
+#elif TU_CHECK_MCU(LPC175X_6X, LPC177X_8X, LPC40XX)
   #define DCD_ATTR_ENDPOINT_MAX   16
 
-#elif TU_CHECK_MCU(LPC18XX) || TU_CHECK_MCU(LPC43XX)
+#elif TU_CHECK_MCU(LPC18XX, LPC43XX)
   // TODO USB0 has 6, USB1 has 4
   #define DCD_ATTR_ENDPOINT_MAX   6
 
@@ -60,7 +60,7 @@
 #elif TU_CHECK_MCU(MIMXRT10XX)
   #define DCD_ATTR_ENDPOINT_MAX   8
 
-#elif TU_CHECK_MCU(MKL25ZXX) || TU_CHECK_MCU(K32L2BXX)
+#elif TU_CHECK_MCU(MKL25ZXX, K32L2BXX)
   #define DCD_ATTR_ENDPOINT_MAX   16
 
 #elif TU_CHECK_MCU(MM32F327X)
@@ -72,8 +72,8 @@
   #define DCD_ATTR_ENDPOINT_MAX   9
 
 //------------- Microchip -------------//
-#elif TU_CHECK_MCU(SAMD21) || TU_CHECK_MCU(SAMD51) || TU_CHECK_MCU(SAME5X) || \
-      TU_CHECK_MCU(SAMD11) || TU_CHECK_MCU(SAML21) || TU_CHECK_MCU(SAML22)
+#elif TU_CHECK_MCU(SAMD21, SAMD51, SAME5X) || \
+      TU_CHECK_MCU(SAMD11, SAML21, SAML22)
   #define DCD_ATTR_ENDPOINT_MAX   8
 
 #elif TU_CHECK_MCU(SAMG)
@@ -119,7 +119,7 @@
   #define DCD_ATTR_ENDPOINT_MAX   9
   #define DCD_ATTR_DWC2_STM32
 
-#elif TU_CHECK_MCU(STM32L0) || TU_CHECK_MCU(STM32L1)
+#elif TU_CHECK_MCU(STM32L0, STM32L1)
   #define DCD_ATTR_ENDPOINT_MAX   8
 
 #elif TU_CHECK_MCU(STM32L4)
@@ -157,7 +157,7 @@
   #define DCD_ATTR_ENDPOINT_MAX   12
 
 //------------- Espressif -------------//
-#elif TU_CHECK_MCU(ESP32S2) || TU_CHECK_MCU(ESP32S3)
+#elif TU_CHECK_MCU(ESP32S2, ESP32S3)
   #define DCD_ATTR_ENDPOINT_MAX   6
 
 //------------- Dialog -------------//

+ 26 - 72
src/portable/synopsys/dwc2/dcd_dwc2.c

@@ -30,13 +30,16 @@
 #include "tusb_option.h"
 #include "device/dcd_attr.h"
 
-#if TUSB_OPT_DEVICE_ENABLED && (defined(DCD_ATTR_DWC2_STM32) || TU_CHECK_MCU(GD32VF103))
+#if TUSB_OPT_DEVICE_ENABLED && \
+    ( defined(DCD_ATTR_DWC2_STM32) || TU_CHECK_MCU(ESP32S2, ESP32S3, GD32VF103) )
 
 #include "device/dcd.h"
 #include "dwc2_type.h"
 
 #if defined(DCD_ATTR_DWC2_STM32)
   #include "dwc2_stm32.h"
+#elif TU_CHECK_MCU(ESP32S2, ESP32S3)
+  #include "dwc2_esp32.h"
 #elif TU_CHECK_MCU(GD32VF103)
   #include "dwc2_gd32.h"
 #else
@@ -72,7 +75,7 @@ typedef struct {
 
 typedef volatile uint32_t * usb_fifo_t;
 
-xfer_ctl_t xfer_status[EP_MAX][2];
+xfer_ctl_t xfer_status[DWC2_EP_MAX][2];
 #define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
 
 // EP0 transfers are limited to 1 packet - larger sizes has to be split
@@ -85,7 +88,7 @@ static bool _out_ep_closed;                       // Flag to check if RX FIFO si
 // Calculate the RX FIFO size according to recommendations from reference manual
 static inline uint16_t calc_rx_ff_size(uint16_t ep_size)
 {
-  return 15 + 2*(ep_size/4) + 2*EP_MAX;
+  return 15 + 2*(ep_size/4) + 2*DWC2_EP_MAX;
 }
 
 static void update_grxfsiz(uint8_t rhport)
@@ -96,7 +99,7 @@ static void update_grxfsiz(uint8_t rhport)
 
   // Determine largest EP size for RX FIFO
   uint16_t max_epsize = 0;
-  for (uint8_t epnum = 0; epnum < EP_MAX; epnum++)
+  for (uint8_t epnum = 0; epnum < DWC2_EP_MAX; epnum++)
   {
     max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size);
   }
@@ -122,7 +125,7 @@ static void bus_reset(uint8_t rhport)
   dev->DCFG &= ~DCFG_DAD_Msk;
 
   // 1. NAK for all OUT endpoints
-  for(uint8_t n = 0; n < EP_MAX; n++) {
+  for(uint8_t n = 0; n < DWC2_EP_MAX; n++) {
     out_ep[n].DOEPCTL |= DOEPCTL_SNAK;
   }
 
@@ -171,11 +174,11 @@ static void bus_reset(uint8_t rhport)
   //   - 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_MAX = 47  + 2 x EP_MAX
-  //   - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x EP_MAX = 271 + 2 x EP_MAX
+  //   - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x  16 + 2 x DWC2_EP_MAX = 47  + 2 x DWC2_EP_MAX
+  //   - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x DWC2_EP_MAX = 271 + 2 x DWC2_EP_MAX
   //
   //   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_MAX
+  //   of the overall picture yet. We will use the worst scenario: largest possible + DWC2_EP_MAX
   //
   //   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
@@ -186,7 +189,7 @@ static void bus_reset(uint8_t rhport)
   _allocated_fifo_words_tx = 16;
 
   // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
-  core->DIEPTXF0_HNPTXFSIZ = (16 << TX0FD_Pos) | (EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
+  core->DIEPTXF0_HNPTXFSIZ = (16 << TX0FD_Pos) | (DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
 
   // Fixed control EP0 size to 64 bytes
   in_ep[0].DIEPCTL &= ~(0x03 << DIEPCTL_MPSIZ_Pos);
@@ -197,47 +200,6 @@ static void bus_reset(uint8_t rhport)
   core->GINTMSK |= GINTMSK_OEPINT | GINTMSK_IEPINT;
 }
 
-// Set turn-around timeout according to link speed
-extern uint32_t SystemCoreClock;
-static void set_turnaround(dwc2_core_t * core, tusb_speed_t speed)
-{
-  core->GUSBCFG &= ~GUSBCFG_TRDT;
-
-  if ( speed == TUSB_SPEED_HIGH )
-  {
-    // Use fixed 0x09 for Highspeed
-    core->GUSBCFG |= (0x09 << GUSBCFG_TRDT_Pos);
-  }
-  else
-  {
-    // Turnaround timeout depends on the MCU clock
-    uint32_t turnaround;
-
-    if ( SystemCoreClock >= 32000000U )
-      turnaround = 0x6U;
-    else if ( SystemCoreClock >= 27500000U )
-      turnaround = 0x7U;
-    else if ( SystemCoreClock >= 24000000U )
-      turnaround = 0x8U;
-    else if ( SystemCoreClock >= 21800000U )
-      turnaround = 0x9U;
-    else if ( SystemCoreClock >= 20000000U )
-      turnaround = 0xAU;
-    else if ( SystemCoreClock >= 18500000U )
-      turnaround = 0xBU;
-    else if ( SystemCoreClock >= 17200000U )
-      turnaround = 0xCU;
-    else if ( SystemCoreClock >= 16000000U )
-      turnaround = 0xDU;
-    else if ( SystemCoreClock >= 15000000U )
-      turnaround = 0xEU;
-    else
-      turnaround = 0xFU;
-
-    // Fullspeed depends on MCU clocks, but we will use 0x06 for 32+ Mhz
-    core->GUSBCFG |= (turnaround << GUSBCFG_TRDT_Pos);
-  }
-}
 
 static tusb_speed_t get_speed(uint8_t rhport)
 {
@@ -368,6 +330,8 @@ void dcd_init (uint8_t rhport)
   // peripheral in each Reference Manual.
   dwc2_core_t * core = CORE_REG(rhport);
 
+  // check GSNPSID
+
   // No HNP/SRP (no OTG support), program timeout later.
   if ( rhport == 1 )
   {
@@ -422,7 +386,7 @@ void dcd_init (uint8_t rhport)
 
   // If USB host misbehaves during status portion of control xfer
   // (non zero-length packet), send STALL back and discard.
-  dev->DCFG |=  DCFG_NZLSOHSK;
+  dev->DCFG |= DCFG_NZLSOHSK;
 
   set_speed(rhport, TUD_OPT_HIGH_SPEED ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL);
 
@@ -457,16 +421,6 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
   dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
 }
 
-static void remote_wakeup_delay(void)
-{
-  // try to delay for 1 ms
-  uint32_t count = SystemCoreClock / 1000;
-  while ( count-- )
-  {
-    __NOP();
-  }
-}
-
 void dcd_remote_wakeup(uint8_t rhport)
 {
   (void) rhport;
@@ -482,7 +436,7 @@ void dcd_remote_wakeup(uint8_t rhport)
   core->GINTMSK |= GINTMSK_SOFM;
 
   // Per specs: remote wakeup signal bit must be clear within 1-15ms
-  remote_wakeup_delay();
+  dwc2_remote_wakeup_delay();
 
   dev->DCTL &= ~DCTL_RWUSIG;
 }
@@ -518,7 +472,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
   uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
   uint8_t const dir   = tu_edpt_dir(desc_edpt->bEndpointAddress);
 
-  TU_ASSERT(epnum < EP_MAX);
+  TU_ASSERT(epnum < DWC2_EP_MAX);
 
   xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
   xfer->max_size = tu_edpt_packet_size(desc_edpt);
@@ -534,7 +488,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
     // If size_rx needs to be extended check if possible and if so enlarge it
     if (core->GRXFSIZ < sz)
     {
-      TU_ASSERT(sz + _allocated_fifo_words_tx <= EP_FIFO_SIZE/4);
+      TU_ASSERT(sz + _allocated_fifo_words_tx <= DWC2_EP_FIFO_SIZE/4);
 
       // Enlarge RX FIFO
       core->GRXFSIZ = sz;
@@ -571,15 +525,15 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
     // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
 
     // Check if free space is available
-    TU_ASSERT(_allocated_fifo_words_tx + fifo_size + core->GRXFSIZ <= EP_FIFO_SIZE/4);
+    TU_ASSERT(_allocated_fifo_words_tx + fifo_size + core->GRXFSIZ <= DWC2_EP_FIFO_SIZE/4);
 
     _allocated_fifo_words_tx += fifo_size;
 
-    TU_LOG(2, "    Allocated %u bytes at offset %u", fifo_size*4, EP_FIFO_SIZE-_allocated_fifo_words_tx*4);
+    TU_LOG(2, "    Allocated %u bytes at offset %u", fifo_size*4, DWC2_EP_FIFO_SIZE-_allocated_fifo_words_tx*4);
 
     // DIEPTXF starts at FIFO #1.
     // Both TXFD and TXSA are in unit of 32-bit words.
-    core->DIEPTXF[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
+    core->DIEPTXF[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
 
     in_ep[epnum].DIEPCTL |= (1 << DIEPCTL_USBAEP_Pos) |
         (epnum << DIEPCTL_TXFNUM_Pos) |
@@ -606,7 +560,7 @@ void dcd_edpt_close_all (uint8_t rhport)
   // Disable non-control interrupt
   dev->DAINTMSK = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos);
 
-  for(uint8_t n = 1; n < EP_MAX; n++)
+  for(uint8_t n = 1; n < DWC2_EP_MAX; n++)
   {
     // disable OUT endpoint
     out_ep[n].DOEPCTL = 0;
@@ -756,7 +710,7 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
     uint16_t const fifo_size = (core->DIEPTXF[epnum - 1] & DIEPTXF_INEPTXFD_Msk) >> DIEPTXF_INEPTXFD_Pos;
     uint16_t const fifo_start = (core->DIEPTXF[epnum - 1] & DIEPTXF_INEPTXSA_Msk) >> DIEPTXF_INEPTXSA_Pos;
     // For now only the last opened endpoint can be closed without fuss.
-    TU_ASSERT(fifo_start == EP_FIFO_SIZE/4 - _allocated_fifo_words_tx,);
+    TU_ASSERT(fifo_start == DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx,);
     _allocated_fifo_words_tx -= fifo_size;
   }
   else
@@ -920,7 +874,7 @@ static void handle_rxflvl_ints(uint8_t rhport, dwc2_epout_t * out_ep) {
 static void handle_epout_ints(uint8_t rhport, dwc2_device_t * dev, dwc2_epout_t * out_ep) {
   // DAINT for a given EP clears when DOEPINTx is cleared.
   // OEPINT will be cleared when DAINT's out bits are cleared.
-  for(uint8_t n = 0; n < EP_MAX; n++) {
+  for(uint8_t n = 0; n < DWC2_EP_MAX; n++) {
     xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
 
     if(dev->DAINT & (1 << (DAINT_OEPINT_Pos + n))) {
@@ -949,7 +903,7 @@ static void handle_epout_ints(uint8_t rhport, dwc2_device_t * dev, dwc2_epout_t
 static void handle_epin_ints(uint8_t rhport, dwc2_device_t * dev, dwc2_epin_t * in_ep) {
   // DAINT for a given EP clears when DIEPINTx is cleared.
   // IEPINT will be cleared when DAINT's out bits are cleared.
-  for ( uint8_t n = 0; n < EP_MAX; n++ )
+  for ( uint8_t n = 0; n < DWC2_EP_MAX; n++ )
   {
     xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
 
@@ -1040,7 +994,7 @@ void dcd_int_handler(uint8_t rhport)
 
     tusb_speed_t const speed = get_speed(rhport);
 
-    set_turnaround(core, speed);
+    dwc2_set_turnaround(core, speed);
     dcd_event_bus_reset(rhport, speed, true);
   }
 

+ 82 - 0
src/portable/synopsys/dwc2/dwc2_esp32.h

@@ -0,0 +1,82 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+
+#ifndef _DWC2_ESP32_H_
+#define _DWC2_ESP32_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "esp_intr_alloc.h"
+#include "soc/periph_defs.h"
+//#include "soc/usb_periph.h"
+
+#define DWC2_REG_BASE       0x60080000UL
+#define DWC2_EP_MAX         5             // USB_OUT_EP_NUM
+#define DWC2_EP_FIFO_SIZE   1024
+
+// #define EP_FIFO_NUM 5
+
+static intr_handle_t usb_ih;
+
+static void dcd_int_handler_wrap(void* arg)
+{
+  (void) arg;
+  dcd_int_handler(0);
+}
+
+static inline void dcd_dwc2_int_enable (uint8_t rhport)
+{
+  (void) rhport;
+  esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, dcd_int_handler_wrap, NULL, &usb_ih);
+}
+
+static inline void dcd_dwc2_int_disable (uint8_t rhport)
+{
+  (void) rhport;
+  esp_intr_free(usb_ih);
+}
+
+static inline void dwc2_remote_wakeup_delay(void)
+{
+  vTaskDelay(pdMS_TO_TICKS(1));
+}
+
+static inline void dwc2_set_turnaround(dwc2_core_t * core, tusb_speed_t speed)
+{
+  (void) core;
+  (void) speed;
+
+  // keep the reset value
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DWC2_ESP32_H_ */

+ 31 - 6
src/portable/synopsys/dwc2/dwc2_gd32.h

@@ -28,14 +28,18 @@
 #ifndef DWC2_GD32_H_
 #define DWC2_GD32_H_
 
-// for remote wakeup delay
-#define __NOP()   __asm volatile ("nop")
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
 
 // These numbers are the same for the whole GD32VF103 family.
-#define DWC2_REG_BASE   0x50000000UL
-#define EP_MAX          4
-#define EP_FIFO_SIZE    1280
-#define RHPORT_IRQn     86
+#define DWC2_REG_BASE       0x50000000UL
+#define DWC2_EP_MAX         4
+#define DWC2_EP_FIFO_SIZE   1280
+#define RHPORT_IRQn         86
+
+extern uint32_t SystemCoreClock;
 
 // The GD32VF103 is a RISC-V MCU, which implements the ECLIC Core-Local
 // Interrupt Controller by Nuclei. It is nearly API compatible to the
@@ -66,4 +70,25 @@ static inline void dcd_dwc2_int_disable (uint8_t rhport)
   __eclic_disable_interrupt(RHPORT_IRQn);
 }
 
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_remote_wakeup_delay(void)
+{
+  // try to delay for 1 ms
+  uint32_t count = SystemCoreClock / 1000;
+  while ( count-- ) __asm volatile ("nop");
+}
+
+static inline void dwc2_set_turnaround(dwc2_core_t * core, tusb_speed_t speed)
+{
+  (void) core;
+  (void) speed;
+
+  // keep the reset value
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* DWC2_GD32_H_ */

+ 72 - 11
src/portable/synopsys/dwc2/dwc2_stm32.h

@@ -24,8 +24,12 @@
  * This file is part of the TinyUSB stack.
  */
 
-#ifndef _TUSB_DWC2_STM32_H_
-#define _TUSB_DWC2_STM32_H_
+#ifndef _DWC2_STM32_H_
+#define _DWC2_STM32_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
 
 // EP_MAX       : Max number of bi-directional endpoints including EP0
 // EP_FIFO_SIZE : Size of dedicated USB SRAM
@@ -71,19 +75,21 @@
 
 // On STM32 we associate Port0 to OTG_FS, and Port1 to OTG_HS
 #if TUD_OPT_RHPORT == 0
-  #define EP_MAX            EP_MAX_FS
-  #define EP_FIFO_SIZE      EP_FIFO_SIZE_FS
-  #define DWC2_REG_BASE     USB_OTG_FS_PERIPH_BASE
-  #define RHPORT_IRQn       OTG_FS_IRQn
+  #define DWC2_REG_BASE       USB_OTG_FS_PERIPH_BASE
+  #define DWC2_EP_MAX         EP_MAX_FS
+  #define DWC2_EP_FIFO_SIZE   EP_FIFO_SIZE_FS
+  #define RHPORT_IRQn         OTG_FS_IRQn
 
 #else
-  #define EP_MAX            EP_MAX_HS
-  #define EP_FIFO_SIZE      EP_FIFO_SIZE_HS
-  #define DWC2_REG_BASE     USB_OTG_HS_PERIPH_BASE
-  #define RHPORT_IRQn       OTG_HS_IRQn
+  #define DWC2_REG_BASE       USB_OTG_HS_PERIPH_BASE
+  #define DWC2_EP_MAX         EP_MAX_HS
+  #define DWC2_EP_FIFO_SIZE   EP_FIFO_SIZE_HS
+  #define RHPORT_IRQn         OTG_HS_IRQn
 
 #endif
 
+extern uint32_t SystemCoreClock;
+
 TU_ATTR_ALWAYS_INLINE
 static inline void dcd_dwc2_int_enable(uint8_t rhport)
 {
@@ -98,4 +104,59 @@ static inline void dcd_dwc2_int_disable (uint8_t rhport)
   NVIC_DisableIRQ(RHPORT_IRQn);
 }
 
-#endif /* DWC2_STM32_H_ */
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_remote_wakeup_delay(void)
+{
+  // try to delay for 1 ms
+  uint32_t count = SystemCoreClock / 1000;
+  while ( count-- ) __NOP();
+}
+
+// Set turn-around timeout according to link speed
+static inline void dwc2_set_turnaround(dwc2_core_t * core, tusb_speed_t speed)
+{
+  core->GUSBCFG &= ~GUSBCFG_TRDT;
+
+  if ( speed == TUSB_SPEED_HIGH )
+  {
+    // Use fixed 0x09 for Highspeed
+    core->GUSBCFG |= (0x09 << GUSBCFG_TRDT_Pos);
+  }
+  else
+  {
+    // Turnaround timeout depends on the MCU clock
+    uint32_t turnaround;
+
+    if ( SystemCoreClock >= 32000000U )
+      turnaround = 0x6U;
+    else if ( SystemCoreClock >= 27500000U )
+      turnaround = 0x7U;
+    else if ( SystemCoreClock >= 24000000U )
+      turnaround = 0x8U;
+    else if ( SystemCoreClock >= 21800000U )
+      turnaround = 0x9U;
+    else if ( SystemCoreClock >= 20000000U )
+      turnaround = 0xAU;
+    else if ( SystemCoreClock >= 18500000U )
+      turnaround = 0xBU;
+    else if ( SystemCoreClock >= 17200000U )
+      turnaround = 0xCU;
+    else if ( SystemCoreClock >= 16000000U )
+      turnaround = 0xDU;
+    else if ( SystemCoreClock >= 15000000U )
+      turnaround = 0xEU;
+    else
+      turnaround = 0xFU;
+
+    // Fullspeed depends on MCU clocks, but we will use 0x06 for 32+ Mhz
+    core->GUSBCFG |= (turnaround << GUSBCFG_TRDT_Pos);
+  }
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DWC2_STM32_H_ */

+ 1 - 1
src/tusb_option.h

@@ -131,7 +131,7 @@
 // Helper to check if configured MCU is one of listed
 // Apply _TU_CHECK_MCU with || as separator to list of input
 #define _TU_CHECK_MCU(_m)   (CFG_TUSB_MCU == OPT_MCU_##_m)
-#define TU_CHECK_MCU(...)   TU_ARGS_APPLY(_TU_CHECK_MCU, ||, __VA_ARGS__)
+#define TU_CHECK_MCU(...)   (TU_ARGS_APPLY(_TU_CHECK_MCU, ||, __VA_ARGS__))
 
 //--------------------------------------------------------------------+
 // Supported OS