diff --git a/components/arduino_tinyusb/CMakeLists.txt b/components/arduino_tinyusb/CMakeLists.txt index 242b0ef17..0d1fe9fb7 100755 --- a/components/arduino_tinyusb/CMakeLists.txt +++ b/components/arduino_tinyusb/CMakeLists.txt @@ -24,8 +24,6 @@ if(CONFIG_TINYUSB_ENABLED) endif() set(srcs - # espressif: - #"${COMPONENT_DIR}/src/dcd_dwc2.c" # tusb: "${COMPONENT_DIR}/tinyusb/src/portable/synopsys/dwc2/dcd_dwc2.c" "${COMPONENT_DIR}/tinyusb/src/portable/synopsys/dwc2/dwc2_common.c" diff --git a/components/arduino_tinyusb/patches/dcd_dwc2.patch b/components/arduino_tinyusb/patches/dcd_dwc2.patch deleted file mode 100644 index 2521a38e5..000000000 --- a/components/arduino_tinyusb/patches/dcd_dwc2.patch +++ /dev/null @@ -1,84 +0,0 @@ ---- a/components/arduino_tinyusb/src/dcd_dwc2.c 2024-10-02 12:17:40.000000000 +0300 -+++ b/components/arduino_tinyusb/src/dcd_dwc2.c 2024-10-02 12:19:48.000000000 +0300 -@@ -243,6 +243,17 @@ - //-------------------------------------------------------------------- - // Endpoint - //-------------------------------------------------------------------- -+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) -+// Keep count of how many FIFOs are in use -+static uint8_t _allocated_fifos = 1; //FIFO0 is always in use -+ -+// Will either return an unused FIFO number, or 0 if all are used. -+static uint8_t get_free_fifo(void) { -+ if (_allocated_fifos < 5) return _allocated_fifos++; -+ return 0; -+} -+#endif -+ - static void edpt_activate(uint8_t rhport, const tusb_desc_endpoint_t* p_endpoint_desc) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - const uint8_t epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); -@@ -266,7 +277,18 @@ - depctl.set_data0_iso_even = 1; - } - if (dir == TUSB_DIR_IN) { -- depctl.tx_fifo_num = epnum; -+ //depctl.tx_fifo_num = epnum; -+ uint8_t fifo_num = epnum; -+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) -+ // Special Case for EP5, which is used by CDC but not actually called by the driver -+ // we can give it a fake FIFO -+ if (epnum == 5) { -+ fifo_num = epnum; -+ } else { -+ fifo_num = get_free_fifo(); -+ } -+#endif -+ depctl.tx_fifo_num = fifo_num; - } - - dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum]; -@@ -557,6 +579,10 @@ - } - } - -+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) -+ _allocated_fifos = 1; -+#endif -+ - dfifo_flush_tx(dwc2, 0x10); // all tx fifo - dfifo_flush_rx(dwc2); - -@@ -997,6 +1023,9 @@ - if (gintsts & GINTSTS_USBRST) { - // USBRST is start of reset. - dwc2->gintsts = GINTSTS_USBRST; -+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) -+ _allocated_fifos = 1; -+#endif - - usbd_spin_lock(true); - handle_bus_reset(rhport); -@@ -1008,7 +1037,11 @@ - - if (gintsts & GINTSTS_USBSUSP) { - dwc2->gintsts = GINTSTS_USBSUSP; -- dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); -+ //dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); -+ dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); -+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) -+ _allocated_fifos = 1; -+#endif - } - - if (gintsts & GINTSTS_WKUINT) { -@@ -1025,6 +1058,9 @@ - - if (otg_int & GOTGINT_SEDET) { - dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); -+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) -+ _allocated_fifos = 1; -+#endif - } - - dwc2->gotgint = otg_int; diff --git a/components/arduino_tinyusb/src/dcd_dwc2.c b/components/arduino_tinyusb/src/dcd_dwc2.c deleted file mode 100644 index b6c3b1b22..000000000 --- a/components/arduino_tinyusb/src/dcd_dwc2.c +++ /dev/null @@ -1,1141 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 William D. Jones - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2020 Jan Duempelmann - * Copyright (c) 2020 Reinhard Panhuber - * - * 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. - */ - -#include "tusb_option.h" - -#if CFG_TUD_ENABLED && defined(TUP_USBIP_DWC2) - -#if !(CFG_TUD_DWC2_SLAVE_ENABLE || CFG_TUD_DWC2_DMA_ENABLE) -#error DWC2 require either CFG_TUD_DWC2_SLAVE_ENABLE or CFG_TUD_DWC2_DMA_ENABLE to be enabled -#endif - -// Debug level for DWC2 -#define DWC2_DEBUG 2 - -#include "device/dcd.h" -#include "device/usbd_pvt.h" -#include "dwc2_common.h" - -//--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM -//--------------------------------------------------------------------+ -typedef struct { - uint8_t* buffer; - tu_fifo_t* ff; - uint16_t total_len; - uint16_t max_size; - uint8_t interval; -} xfer_ctl_t; - -// This variable is modified from ISR context, so it must be protected by critical section -static xfer_ctl_t xfer_status[DWC2_EP_MAX][2]; -#define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir]) - -typedef struct { - // EP0 transfers are limited to 1 packet - larger sizes has to be split - uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type - uint16_t dfifo_top; // top free location in DFIFO in words - - // Number of IN endpoints active - uint8_t allocated_epin_count; - - // SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by - bool sof_en; -} dcd_data_t; - -static dcd_data_t _dcd_data; - -CFG_TUD_MEM_SECTION static struct { - TUD_EPBUF_DEF(setup_packet, 8); -} _dcd_usbbuf; - -TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_ep_count(const dwc2_regs_t* dwc2) { - #if TU_CHECK_MCU(OPT_MCU_GD32VF103) - return DWC2_EP_MAX; - #else - const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; - return ghwcfg2.num_dev_ep + 1; - #endif -} - - -//-------------------------------------------------------------------- -// DMA -//-------------------------------------------------------------------- -#if CFG_TUD_MEM_DCACHE_ENABLE -bool dcd_dcache_clean(const void* addr, uint32_t data_size) { - TU_VERIFY(addr && data_size); - return dwc2_dcache_clean(addr, data_size); -} - -bool dcd_dcache_invalidate(const void* addr, uint32_t data_size) { - TU_VERIFY(addr && data_size); - return dwc2_dcache_invalidate(addr, data_size); -} - -bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) { - TU_VERIFY(addr && data_size); - return dwc2_dcache_clean_invalidate(addr, data_size); -} -#endif - -TU_ATTR_ALWAYS_INLINE static inline bool dma_device_enabled(const dwc2_regs_t* dwc2) { - (void) dwc2; - // Internal DMA only - const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; - return CFG_TUD_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA; -} - -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) _dcd_usbbuf.setup_packet; - dwc2->epout[0].doepctl |= DOEPCTL_EPENA | DOEPCTL_USBAEP; -} - -//--------------------------------------------------------------------+ -// Data FIFO -//--------------------------------------------------------------------+ - - -/* Device Data FIFO scheme - - 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 - | DxEPIDMAn | - |-------------|-- gdfifocfg.EPINFOBASE (max is ghwcfg3.dfifo_depth) - | IN FIFO 0 | control EP - |-------------| - | 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_device_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); - const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport]; - const uint8_t ep_count = dwc2_controller->ep_count; - const uint8_t epnum = tu_edpt_number(ep_addr); - const uint8_t dir = tu_edpt_dir(ep_addr); - - TU_ASSERT(epnum < ep_count); - - uint16_t fifo_size = tu_div_ceil(packet_size, 4); - if (dir == TUSB_DIR_OUT) { - // Calculate required size of RX FIFO - const uint16_t new_sz = calc_device_grxfsiz(4 * fifo_size, ep_count); - - // If size_rx needs to be extended check if there is enough free space - if (dwc2->grxfsiz < new_sz) { - TU_ASSERT(new_sz <= _dcd_data.dfifo_top); - dwc2->grxfsiz = new_sz; // Enlarge RX FIFO - } - } else { - // Check IN endpoints concurrently active limit - if(dwc2_controller->ep_in_count) { - TU_ASSERT(_dcd_data.allocated_epin_count < dwc2_controller->ep_in_count); - _dcd_data.allocated_epin_count++; - } - - // If The TXFELVL is configured as half empty, the fifo must be twice the max_size. - if ((dwc2->gahbcfg & GAHBCFG_TX_FIFO_EPMTY_LVL) == 0) { - fifo_size *= 2; - } - - // Check if free space is available - TU_ASSERT(_dcd_data.dfifo_top >= fifo_size + dwc2->grxfsiz); - _dcd_data.dfifo_top -= fifo_size; - // TU_LOG(DWC2_DEBUG, " TX FIFO %u: allocated %u words at offset %u\r\n", epnum, fifo_size, dfifo_top); - - // Both TXFD and TXSA are in unit of 32-bit words. - if (epnum == 0) { - dwc2->dieptxf0 = (fifo_size << DIEPTXF0_TX0FD_Pos) | _dcd_data.dfifo_top; - } else { - // DIEPTXF starts at FIFO #1. - dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | _dcd_data.dfifo_top; - } - } - - return true; -} - -static void dfifo_device_init(uint8_t rhport) { - const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport]; - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - dwc2->grxfsiz = calc_device_grxfsiz(CFG_TUD_ENDPOINT0_SIZE, dwc2_controller->ep_count); - - // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per endpoint direction - const bool is_dma = dma_device_enabled(dwc2); - _dcd_data.dfifo_top = dwc2_controller->ep_fifo_size/4; - if (is_dma) { - _dcd_data.dfifo_top -= 2 * dwc2_controller->ep_count; - } - dwc2->gdfifocfg = (_dcd_data.dfifo_top << GDFIFOCFG_EPINFOBASE_SHIFT) | _dcd_data.dfifo_top; - - // Allocate FIFO for EP0 IN - dfifo_alloc(rhport, 0x80, CFG_TUD_ENDPOINT0_SIZE); -} - - -//-------------------------------------------------------------------- -// Endpoint -//-------------------------------------------------------------------- -#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) -// Keep count of how many FIFOs are in use -static uint8_t _allocated_fifos = 1; //FIFO0 is always in use - -// Will either return an unused FIFO number, or 0 if all are used. -static uint8_t get_free_fifo(void) { - if (_allocated_fifos < 5) return _allocated_fifos++; - return 0; -} -#endif - -static void edpt_activate(uint8_t rhport, const tusb_desc_endpoint_t* p_endpoint_desc) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - const uint8_t epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); - const uint8_t dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); - - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); - xfer->max_size = tu_edpt_packet_size(p_endpoint_desc); - xfer->interval = p_endpoint_desc->bInterval; - - // Endpoint control - dwc2_depctl_t depctl = {.value = 0}; - depctl.mps = xfer->max_size; - depctl.active = 1; - depctl.type = p_endpoint_desc->bmAttributes.xfer; - if (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) { - depctl.set_data0_iso_even = 1; - } - if (dir == TUSB_DIR_IN) { - //depctl.tx_fifo_num = epnum; - uint8_t fifo_num = epnum; -#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) - // Special Case for EP5, which is used by CDC but not actually called by the driver - // we can give it a fake FIFO - if (epnum == 5) { - fifo_num = epnum; - } else { - fifo_num = get_free_fifo(); - } -#endif - depctl.tx_fifo_num = fifo_num; - } - - dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum]; - dep->ctl = depctl.value; - dwc2->daintmsk |= TU_BIT(epnum + DAINT_SHIFT(dir)); -} - -static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { - (void) rhport; - - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - const uint8_t epnum = tu_edpt_number(ep_addr); - const uint8_t dir = tu_edpt_dir(ep_addr); - dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum]; - - if (dir == TUSB_DIR_IN) { - // Only disable currently enabled non-control endpoint - if ((epnum == 0) || !(dep->diepctl & DIEPCTL_EPENA)) { - dep->diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0); - } else { - // Stop transmitting packets and NAK IN xfers. - dep->diepctl |= DIEPCTL_SNAK; - while ((dep->diepint & DIEPINT_INEPNE) == 0) {} - - // Disable the endpoint. - dep->diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0); - while ((dep->diepint & DIEPINT_EPDISD_Msk) == 0) {} - - dep->diepint = DIEPINT_EPDISD; - } - - // Flush the FIFO, and wait until we have confirmed it cleared. - dfifo_flush_tx(dwc2, epnum); - } else { - // Only disable currently enabled non-control endpoint - if ((epnum == 0) || !(dep->doepctl & DOEPCTL_EPENA)) { - dep->doepctl |= stall ? DOEPCTL_STALL : 0; - } else { - // Asserting GONAK is required to STALL an OUT endpoint. - // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt - // anyway, and it can't be cleared by user code. If this while loop never - // finishes, we have bigger problems than just the stack. - dwc2->dctl |= DCTL_SGONAK; - while ((dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0) {} - - // Ditto here disable the endpoint. - dep->doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0); - while ((dep->doepint & DOEPINT_EPDISD_Msk) == 0) {} - - dep->doepint = DOEPINT_EPDISD; - - // Allow other OUT endpoints to keep receiving. - dwc2->dctl |= DCTL_CGONAK; - } - } -} - -// Since this function returns void, it is not possible to return a boolean success message -// We must make sure that this function is not called when the EP is disabled -// Must be called from critical section -static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uint8_t dir) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); - dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum]; - - uint16_t num_packets; - uint16_t total_bytes; - - // EP0 is limited to one packet per xfer - if (epnum == 0) { - total_bytes = tu_min16(_dcd_data.ep0_pending[dir], xfer->max_size); - _dcd_data.ep0_pending[dir] -= total_bytes; - num_packets = 1; - } else { - total_bytes = xfer->total_len; - num_packets = tu_div_ceil(total_bytes, xfer->max_size); - if (num_packets == 0) { - num_packets = 1; // zero length packet still count as 1 - } - } - - // transfer size: A full OUT transfer (multiple packets, possibly) triggers XFRC. - dwc2_ep_tsize_t deptsiz = {.value = 0}; - deptsiz.xfer_size = total_bytes; - deptsiz.packet_count = num_packets; - dep->tsiz = deptsiz.value; - - // control - dwc2_depctl_t depctl = {.value = dep->ctl}; - depctl.clear_nak = 1; - depctl.enable = 1; - if (depctl.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) { - const dwc2_dsts_t dsts = {.value = dwc2->dsts}; - const uint32_t odd_now = dsts.frame_number & 1u; - if (odd_now) { - depctl.set_data0_iso_even = 1; - } else { - depctl.set_data1_iso_odd = 1; - } - } - - const bool is_dma = dma_device_enabled(dwc2); - if(is_dma) { - if (dir == TUSB_DIR_IN && total_bytes != 0) { - dcd_dcache_clean(xfer->buffer, total_bytes); - } - dep->diepdma = (uintptr_t) xfer->buffer; - dep->diepctl = depctl.value; // enable endpoint - } else { - dep->diepctl = depctl.value; // enable endpoint - - // Enable tx fifo empty interrupt only if there is data. Note must after depctl enable - if (dir == TUSB_DIR_IN && total_bytes != 0) { - dwc2->diepempmsk |= (1 << epnum); - } - } -} - -//-------------------------------------------------------------------- -// Controller API -//-------------------------------------------------------------------- -bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rh_init; - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - - tu_memclr(&_dcd_data, sizeof(_dcd_data)); - - // Core Initialization - const bool is_highspeed = dwc2_core_is_highspeed(dwc2, TUSB_ROLE_DEVICE); - const bool is_dma = dma_device_enabled(dwc2); - TU_ASSERT(dwc2_core_init(rhport, is_highspeed, is_dma)); - - //------------- 7.1 Device Initialization -------------// - // Set device max speed - uint32_t dcfg = dwc2->dcfg & ~DCFG_DSPD_Msk; - if (is_highspeed) { - dcfg |= DCFG_DSPD_HS << DCFG_DSPD_Pos; - - // 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) - const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; - if (ghwcfg2.hs_phy_type == GHWCFG2_HSPHY_ULPI) { - dcfg |= DCFG_XCVRDLY; - } - } else { - dcfg |= DCFG_DSPD_FS << DCFG_DSPD_Pos; - } - - dcfg |= DCFG_NZLSOHSK; // send STALL back and discard if host send non-zlp during control status - dwc2->dcfg = dcfg; - - dcd_disconnect(rhport); - - // Force device mode - dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD; - - // Clear A override, force B Valid - dwc2->gotgctl = (dwc2->gotgctl & ~GOTGCTL_AVALOEN) | GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL; - - // Enable required interrupts - dwc2->gintmsk |= GINTMSK_OTGINT | GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM; - - // TX FIFO empty level for interrupt is complete empty - uint32_t gahbcfg = dwc2->gahbcfg; - gahbcfg |= GAHBCFG_TX_FIFO_EPMTY_LVL; - gahbcfg |= GAHBCFG_GINT; // Enable global interrupt - dwc2->gahbcfg = gahbcfg; - - dcd_connect(rhport); - return true; -} - -void dcd_int_enable(uint8_t rhport) { - dwc2_dcd_int_enable(rhport); -} - -void dcd_int_disable(uint8_t rhport) { - dwc2_dcd_int_disable(rhport); -} - -void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - dwc2->dcfg = (dwc2->dcfg & ~DCFG_DAD_Msk) | (dev_addr << DCFG_DAD_Pos); - - // Response with status after changing device address - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); -} - -void dcd_remote_wakeup(uint8_t rhport) { - (void) rhport; - - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - - // set remote wakeup - dwc2->dctl |= DCTL_RWUSIG; - - // enable SOF to detect bus resume - dwc2->gintsts = GINTSTS_SOF; - dwc2->gintmsk |= GINTMSK_SOFM; - - // Per specs: remote wakeup signal bit must be clear within 1-15ms - dwc2_remote_wakeup_delay(); - - dwc2->dctl &= ~DCTL_RWUSIG; -} - -void dcd_connect(uint8_t rhport) { - (void) rhport; - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - -#ifdef TUP_USBIP_DWC2_ESP32 - usb_wrap_otg_conf_reg_t conf = USB_WRAP.otg_conf; - conf.pad_pull_override = 0; - conf.dp_pullup = 0; - conf.dp_pulldown = 0; - conf.dm_pullup = 0; - conf.dm_pulldown = 0; - USB_WRAP.otg_conf = conf; -#endif - - dwc2->dctl &= ~DCTL_SDIS; -} - -void dcd_disconnect(uint8_t rhport) { - (void) rhport; - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - -#ifdef TUP_USBIP_DWC2_ESP32 - usb_wrap_otg_conf_reg_t conf = USB_WRAP.otg_conf; - conf.pad_pull_override = 1; - conf.dp_pullup = 0; - conf.dp_pulldown = 1; - conf.dm_pullup = 0; - conf.dm_pulldown = 1; - USB_WRAP.otg_conf = conf; -#endif - - dwc2->dctl |= DCTL_SDIS; -} - -// Be advised: audio, video and possibly other iso-ep classes use dcd_sof_enable() to enable/disable its corresponding ISR on purpose! -void dcd_sof_enable(uint8_t rhport, bool en) { - (void) rhport; - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - - _dcd_data.sof_en = en; - - if (en) { - dwc2->gintsts = GINTSTS_SOF; - dwc2->gintmsk |= GINTMSK_SOFM; - } else { - dwc2->gintmsk &= ~GINTMSK_SOFM; - } -} - -/*------------------------------------------------------------------*/ -/* DCD Endpoint port - *------------------------------------------------------------------*/ - -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { - TU_ASSERT(dfifo_alloc(rhport, desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt))); - edpt_activate(rhport, desc_edpt); - return true; -} - -// Close all non-control endpoints, cancel all pending transfers if any. -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; - - usbd_spin_lock(false); - - _dcd_data.allocated_epin_count = 0; - - // Disable non-control interrupt - dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos); - - for (uint8_t n = 1; n < ep_count; n++) { - for (uint8_t d = 0; d < 2; d++) { - dwc2_dep_t* dep = &dwc2->ep[d][n]; - if (dep->ctl & EPCTL_EPENA) { - dep->ctl |= EPCTL_SNAK | EPCTL_EPDIS; - } - xfer_status[n][1-d].max_size = 0; - } - } - -#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) - _allocated_fifos = 1; -#endif - - dfifo_flush_tx(dwc2, 0x10); // all tx fifo - dfifo_flush_rx(dwc2); - dfifo_device_init(rhport); // re-init dfifo - - usbd_spin_unlock(false); -} - -bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t 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; -} - -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); - bool ret; - - usbd_spin_lock(false); - - if (xfer->max_size == 0) { - ret = false; // Endpoint is closed - } else { - xfer->buffer = buffer; - xfer->ff = NULL; - xfer->total_len = total_bytes; - - // EP0 can only handle one packet - if (epnum == 0) { - _dcd_data.ep0_pending[dir] = total_bytes; - } - - // Schedule packets to be sent within interrupt - edpt_schedule_packets(rhport, epnum, dir); - ret = true; - } - - usbd_spin_unlock(false); - - return ret; -} - -// The number of bytes has to be given explicitly to allow more flexible control of how many -// bytes should be written and second to keep the return value free to give back a boolean -// success message. If total_bytes is too big, the FIFO will copy only what is available -// into the USB buffer! -bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes) { - // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 - TU_ASSERT(ff->item_size == 1); - - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); - bool ret; - - usbd_spin_lock(false); - - if (xfer->max_size == 0) { - ret = false; // Endpoint is closed - } else { - xfer->buffer = NULL; - xfer->ff = ff; - xfer->total_len = total_bytes; - - // Schedule packets to be sent within interrupt - // TODO xfer fifo may only available for slave mode - edpt_schedule_packets(rhport, epnum, dir); - ret = true; - } - - usbd_spin_unlock(false); - - return ret; -} - -void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - edpt_disable(rhport, ep_addr, true); - if((tu_edpt_number(ep_addr) == 0) && dma_device_enabled(dwc2)) { - dma_setup_prepare(rhport); - } -} - -void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum]; - - // Clear stall and reset data toggle - dep->ctl &= ~EPCTL_STALL;; - dep->ctl |= EPCTL_SD0PID_SEVNFRM; -} - -//-------------------------------------------------------------------- -// Interrupt Handler -//-------------------------------------------------------------------- - -// 7.4.1 Initialization on USB Reset -// Must be called from critical section -static void handle_bus_reset(uint8_t rhport) { - dwc2_regs_t *dwc2 = DWC2_REG(rhport); - const uint8_t ep_count = dwc2_ep_count(dwc2); - - tu_memclr(xfer_status, sizeof(xfer_status)); - - _dcd_data.sof_en = false; - _dcd_data.allocated_epin_count = 0; - - // 1. NAK for all OUT endpoints - for (uint8_t n = 0; n < ep_count; n++) { - dwc2->epout[n].doepctl |= DOEPCTL_SNAK; - } - - // Disable all IN endpoints - for (uint8_t n = 0; n < ep_count; n++) { - if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) { - dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS; - } - } - - // 2. Set up interrupt mask for EP0 - dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos); - dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM; - dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM; - - // 4. Set up DFIFO - dfifo_flush_tx(dwc2, 0x10); // all tx fifo - dfifo_flush_rx(dwc2); - dfifo_device_init(rhport); - - // 5. Reset device address - dwc2_dcfg_t dcfg = {.value = dwc2->dcfg}; - dcfg.address = 0; - dwc2->dcfg = dcfg.value; - - // Fixed both control EP0 size to 64 bytes - dwc2->epin[0].ctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); - dwc2->epout[0].ctl &= ~(0x03 << DOEPCTL_MPSIZ_Pos); - - xfer_status[0][TUSB_DIR_OUT].max_size = 64; - xfer_status[0][TUSB_DIR_IN].max_size = 64; - - if(dma_device_enabled(dwc2)) { - dma_setup_prepare(rhport); - } else { - dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); - } - - dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT; -} - -static void handle_enum_done(uint8_t rhport) { - dwc2_regs_t *dwc2 = DWC2_REG(rhport); - const dwc2_dsts_t dsts = {.value = dwc2->dsts}; - tusb_speed_t speed; - switch (dsts.enum_speed) { - case DCFG_SPEED_HIGH: - speed = TUSB_SPEED_HIGH; - break; - - case DCFG_SPEED_LOW: - speed = TUSB_SPEED_LOW; - break; - - case DCFG_SPEED_FULL_30_60MHZ: - case DCFG_SPEED_FULL_48MHZ: - default: - speed = TUSB_SPEED_FULL; - break; - } - - // TODO must update GUSBCFG_TRDT according to link speed - dcd_event_bus_reset(rhport, speed, true); -} - -#if 0 -TU_ATTR_ALWAYS_INLINE static inline void print_doepint(uint32_t doepint) { - const char* str[] = { - "XFRC", "DIS", "AHBERR", "SETUP_DONE", - "ORXED", "STATUS_RX", "SETUP_B2B", "RSV7", - "OPERR", "BNA", "RSV10", "ISODROP", - "BBLERR", "NAK", "NYET", "SETUP_RX" - }; - - for(uint32_t i=0; ififo[0]; - - // Pop control word off FIFO - const dwc2_grxstsp_t grxstsp = {.value = dwc2->grxstsp}; - const uint8_t epnum = grxstsp.ep_ch_num; - - dwc2_dep_t* epout = &dwc2->epout[epnum]; - - switch (grxstsp.packet_status) { - case GRXSTS_PKTSTS_GLOBAL_OUT_NAK: - // Global OUT NAK: do nothing - break; - - case GRXSTS_PKTSTS_SETUP_RX: { - // Setup packet received - uint32_t* setup = (uint32_t*)(uintptr_t) _dcd_usbbuf.setup_packet; - // We can receive up to three setup packets in succession, but only the last one is valid. - setup[0] = (*rx_fifo); - setup[1] = (*rx_fifo); - break; - } - - case GRXSTS_PKTSTS_SETUP_DONE: - // Setup packet done: - // After popping this out, dwc2 asserts a DOEPINT_SETUP interrupt which is handled by handle_epout_irq() - epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); - break; - - case GRXSTS_PKTSTS_RX_DATA: { - // Out packet received - const uint16_t byte_count = grxstsp.byte_count; - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); - - if (byte_count) { - // Read packet off RxFIFO - if (xfer->ff) { - tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void*) (uintptr_t) rx_fifo, byte_count); - } else { - dfifo_read_packet(dwc2, xfer->buffer, byte_count); - xfer->buffer += byte_count; - } - - // short packet, minus remaining bytes (xfer_size) - if (byte_count < xfer->max_size) { - const dwc2_ep_tsize_t tsiz = {.value = epout->tsiz}; - xfer->total_len -= tsiz.xfer_size; - if (epnum == 0) { - xfer->total_len -= _dcd_data.ep0_pending[TUSB_DIR_OUT]; - _dcd_data.ep0_pending[TUSB_DIR_OUT] = 0; - } - } - } - break; - } - - case GRXSTS_PKTSTS_RX_COMPLETE: - // Out packet done - // After this entry is popped from the receive FIFO, dwc2 asserts a Transfer Completed interrupt on - // the specified OUT endpoint which will be handled by handle_epout_irq() - break; - - default: break; - } -} - -static void handle_epout_slave(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepint_bm) { - if (doepint_bm.setup_phase_done) { - dcd_event_setup_received(rhport, _dcd_usbbuf.setup_packet, true); - return; - } - - // Normal OUT transfer complete - if (doepint_bm.xfer_complete) { - // only handle data skip if it is setup or status related - // Note: even though (xfer_complete + status_phase_rx) is for buffered DMA only, for STM32L47x (dwc2 v3.00a) they - // can is set when GRXSTS_PKTSTS_SETUP_RX is popped therefore they can bet set before/together with setup_phase_done - if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) { - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); - - if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_OUT]) { - // EP0 can only handle one packet, Schedule another packet to be received. - edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT); - } else { - dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); - } - } - } -} - -static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepint_bm) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - dwc2_dep_t* epin = &dwc2->epin[epnum]; - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN); - - if (diepint_bm.xfer_complete) { - if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_IN]) { - // EP0 can only handle one packet. Schedule another packet to be transmitted. - edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN); - } else { - dcd_event_xfer_complete(rhport, epnum | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); - } - } - - // TX FIFO empty bit is read-only. It will only be cleared by hardware when written bytes is more than - // - 64 bytes or - // - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL) - if (diepint_bm.txfifo_empty && (dwc2->diepempmsk & (1 << epnum))) { - dwc2_ep_tsize_t tsiz = {.value = epin->tsiz}; - const uint16_t remain_packets = tsiz.packet_count; - - // Process every single packet (only whole packets can be written to fifo) - for (uint16_t i = 0; i < remain_packets; i++) { - tsiz.value = epin->tsiz; - const uint16_t remain_bytes = (uint16_t) tsiz.xfer_size; - const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size); - - // Check if dtxfsts has enough space available - if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) { - break; - } - - // Push packet to Tx-FIFO - if (xfer->ff) { - volatile uint32_t* tx_fifo = dwc2->fifo[epnum]; - tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*)(uintptr_t)tx_fifo, xact_bytes); - } else { - dfifo_write_packet(dwc2, epnum, xfer->buffer, xact_bytes); - xfer->buffer += xact_bytes; - } - } - - // Turn off TXFE if all bytes are written. - tsiz.value = epin->tsiz; - if (tsiz.xfer_size == 0) { - dwc2->diepempmsk &= ~(1 << epnum); - } - } -} -#endif - -#if CFG_TUD_DWC2_DMA_ENABLE -static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepint_bm) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - - if (doepint_bm.setup_phase_done) { - dma_setup_prepare(rhport); - dcd_dcache_invalidate(_dcd_usbbuf.setup_packet, 8); - dcd_event_setup_received(rhport, _dcd_usbbuf.setup_packet, true); - return; - } - - // OUT XFER complete - if (doepint_bm.xfer_complete) { - // only handle data skip if it is setup or status related - // Normal OUT transfer complete - if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) { - if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_OUT]) { - // EP0 can only handle one packet Schedule another packet to be received. - edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT); - } else { - dwc2_dep_t* epout = &dwc2->epout[epnum]; - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); - - // determine actual received bytes - const dwc2_ep_tsize_t tsiz = {.value = epout->tsiz}; - const uint16_t remain = tsiz.xfer_size; - xfer->total_len -= remain; - - // this is ZLP, so prepare EP0 for next setup - // TODO use status phase rx - if(epnum == 0 && xfer->total_len == 0) { - dma_setup_prepare(rhport); - } - - dcd_dcache_invalidate(xfer->buffer, xfer->total_len); - dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); - } - } - } -} - -static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepint_bm) { - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN); - - if (diepint_bm.xfer_complete) { - if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_IN]) { - // EP0 can only handle one packet. Schedule another packet to be transmitted. - edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN); - } else { - if(epnum == 0) { - dma_setup_prepare(rhport); - } - dcd_event_xfer_complete(rhport, epnum | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); - } - } -} -#endif - -static void handle_ep_irq(uint8_t rhport, uint8_t dir) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - const bool is_dma = dma_device_enabled(dwc2); - const uint8_t ep_count = dwc2_ep_count(dwc2); - const uint8_t daint_offset = (dir == TUSB_DIR_IN) ? DAINT_IEPINT_Pos : DAINT_OEPINT_Pos; - dwc2_dep_t* ep_base = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][0]; - - // DAINT for a given EP clears when DEPINTx is cleared. - // EPINT will be cleared when DAINT bits are cleared. - for (uint8_t epnum = 0; epnum < ep_count; epnum++) { - if (dwc2->daint & TU_BIT(daint_offset + epnum)) { - dwc2_dep_t* epout = &ep_base[epnum]; - union { - uint32_t value; - dwc2_diepint_t diepint_bm; - dwc2_doepint_t doepint_bm; - } intr; - intr.value = epout->intr; - - epout->intr = intr.value; // Clear interrupt - - if (is_dma) { - #if CFG_TUD_DWC2_DMA_ENABLE - if (dir == TUSB_DIR_IN) { - handle_epin_dma(rhport, epnum, intr.diepint_bm); - } else { - handle_epout_dma(rhport, epnum, intr.doepint_bm); - } - #endif - } else { - #if CFG_TUD_DWC2_SLAVE_ENABLE - if (dir == TUSB_DIR_IN) { - handle_epin_slave(rhport, epnum, intr.diepint_bm); - } else { - handle_epout_slave(rhport, epnum, intr.doepint_bm); - } - #endif - } - } - } -} - -/* Interrupt Hierarchy - DIEPINT DIEPINT - \ / - \ / - DAINT - / \ - / \ - GINTSTS: OEPInt IEPInt | USBReset | EnumDone | USBSusp | WkUpInt | OTGInt | SOF | RXFLVL - - Note: when OTG_MULTI_PROC_INTRPT = 1, Device Each endpoint interrupt deachint/deachmsk/diepeachmsk/doepeachmsk - are combined to generate dedicated interrupt line for each endpoint. - */ -void dcd_int_handler(uint8_t rhport) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - const uint32_t gintmask = dwc2->gintmsk; - const uint32_t gintsts = dwc2->gintsts & gintmask; - - if (gintsts & GINTSTS_USBRST) { - // USBRST is start of reset. - dwc2->gintsts = GINTSTS_USBRST; -#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) - _allocated_fifos = 1; -#endif - - usbd_spin_lock(true); - handle_bus_reset(rhport); - usbd_spin_unlock(true); - } - - if (gintsts & GINTSTS_ENUMDNE) { - // ENUMDNE is the end of reset where speed of the link is detected - dwc2->gintsts = GINTSTS_ENUMDNE; - handle_enum_done(rhport); - } - - if (gintsts & GINTSTS_USBSUSP) { - dwc2->gintsts = GINTSTS_USBSUSP; - //dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); - dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); -#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) - _allocated_fifos = 1; -#endif - } - - if (gintsts & GINTSTS_WKUINT) { - dwc2->gintsts = GINTSTS_WKUINT; - dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); - } - - // TODO check GINTSTS_DISCINT for disconnect detection - // if(int_status & GINTSTS_DISCINT) - - if (gintsts & GINTSTS_OTGINT) { - // OTG INT bit is read-only - const uint32_t otg_int = dwc2->gotgint; - - if (otg_int & GOTGINT_SEDET) { - dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); -#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) - _allocated_fifos = 1; -#endif - } - - dwc2->gotgint = otg_int; - } - - if(gintsts & GINTSTS_SOF) { - dwc2->gintsts = GINTSTS_SOF; - const uint32_t frame = (dwc2->dsts & DSTS_FNSOF) >> DSTS_FNSOF_Pos; - - // Disable SOF interrupt if SOF was not explicitly enabled since SOF was used for remote wakeup detection - if (!_dcd_data.sof_en) { - dwc2->gintmsk &= ~GINTMSK_SOFM; - } - - dcd_event_sof(rhport, frame, true); - } - -#if CFG_TUD_DWC2_SLAVE_ENABLE - // RxFIFO non-empty interrupt handling. - if (gintsts & GINTSTS_RXFLVL) { - // RXFLVL bit is read-only - dwc2->gintmsk &= ~GINTMSK_RXFLVLM; // disable RXFLVL interrupt while reading - - do { - handle_rxflvl_irq(rhport); // read all packets - } while(dwc2->gintsts & GINTSTS_RXFLVL); - - dwc2->gintmsk |= GINTMSK_RXFLVLM; - } -#endif - - // OUT endpoint interrupt handling. - if (gintsts & GINTSTS_OEPINT) { - // OEPINT is read-only, clear using DOEPINTn - handle_ep_irq(rhport, TUSB_DIR_OUT); - } - - // IN endpoint interrupt handling. - if (gintsts & GINTSTS_IEPINT) { - // IEPINT bit read-only, clear using DIEPINTn - handle_ep_irq(rhport, TUSB_DIR_IN); - } -} - -#if CFG_TUD_TEST_MODE -void dcd_enter_test_mode(uint8_t rhport, tusb_feature_test_mode_t test_selector) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - - // Enable the test mode - dwc2->dctl = (dwc2->dctl & ~DCTL_TCTL_Msk) | (((uint8_t) test_selector) << DCTL_TCTL_Pos); -} -#endif - -#endif diff --git a/patches/dwc2_esp32_h.diff b/patches/dwc2_esp32_h.diff deleted file mode 100644 index 94cb86f32..000000000 --- a/patches/dwc2_esp32_h.diff +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h -index 49b8c54cb..8b5e99741 100644 ---- a/src/portable/synopsys/dwc2/dwc2_esp32.h -+++ b/src/portable/synopsys/dwc2/dwc2_esp32.h -@@ -70,11 +70,13 @@ static void dwc2_int_handler_wrap(void* arg) { - const tusb_role_t role = (tusb_role_t) tu_u16_high((uint16_t)(uintptr_t)arg); - #if CFG_TUD_ENABLED - if (role == TUSB_ROLE_DEVICE) { -+ void dcd_int_handler(uint8_t rhport); - dcd_int_handler(rhport); - } - #endif - #if CFG_TUH_ENABLED && !CFG_TUH_MAX3421 - if (role == TUSB_ROLE_HOST) { -+ void hcd_int_handler(uint8_t rhport, bool in_isr); - hcd_int_handler(rhport, true); - } - #endif diff --git a/tools/patch-tinyusb.sh b/tools/patch-tinyusb.sh deleted file mode 100755 index eeaa4d43b..000000000 --- a/tools/patch-tinyusb.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -mv components/arduino_tinyusb/src/dcd_dwc2.c components/arduino_tinyusb/src/dcd_dwc2.c.prev -cp components/arduino_tinyusb/tinyusb/src/portable/synopsys/dwc2/dcd_dwc2.c components/arduino_tinyusb/src/dcd_dwc2.c -patch -p1 -N -i components/arduino_tinyusb/patches/dcd_dwc2.patch diff --git a/tools/update-components.sh b/tools/update-components.sh index 18e7b689e..298783c74 100755 --- a/tools/update-components.sh +++ b/tools/update-components.sh @@ -14,7 +14,4 @@ else git -C "$TINYUSB_REPO_DIR" fetch && \ git -C "$TINYUSB_REPO_DIR" pull --ff-only fi -cd $TINYUSB_REPO_DIR -patch -p1 -N -i $AR_PATCHES/dwc2_esp32_h.diff -cd - if [ $? -ne 0 ]; then exit 1; fi