summaryrefslogtreecommitdiff
path: root/src/portable
diff options
context:
space:
mode:
authorhathach <[email protected]>2025-10-09 12:27:30 +0700
committerhathach <[email protected]>2025-10-09 12:27:30 +0700
commit970384d6dbb012e5b27095b0f065fd73d00ebf4c (patch)
tree3f12ef5058f0e7772834b3bc98dceefdba25f8f1 /src/portable
parentb9378eb8e79691907aae40b3fc26cb57d4ffaeb4 (diff)
parent87523f2494109b45307644a36f035b5ad11d5ba9 (diff)
Merge branch 'master' into fork/ArcaneNibble/ohci-upstream
Diffstat (limited to 'src/portable')
-rw-r--r--src/portable/ehci/ehci.c79
-rw-r--r--src/portable/espressif/esp32sx/dcd_esp32sx.c889
-rw-r--r--src/portable/microchip/pic32mz/dcd_pic32mz.c8
-rw-r--r--src/portable/ohci/ohci.c18
-rw-r--r--src/portable/renesas/rusb2/rusb2_common.c4
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c48
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_at32.h5
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_ch32.h5
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_stm32.h49
-rw-r--r--src/portable/sunxi/dcd_sunxi_musb.c12
-rw-r--r--src/portable/synopsys/dwc2/dwc2_common.c45
-rw-r--r--src/portable/synopsys/dwc2/dwc2_esp32.h17
-rw-r--r--src/portable/synopsys/dwc2/dwc2_info.md116
-rwxr-xr-xsrc/portable/synopsys/dwc2/dwc2_info.py4
-rw-r--r--src/portable/synopsys/dwc2/dwc2_stm32.h23
-rw-r--r--src/portable/ti/msp430x5xx/dcd_msp430x5xx.c18
-rw-r--r--src/portable/wch/hcd_ch32_usbfs.c138
17 files changed, 390 insertions, 1088 deletions
diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c
index da9f49d29..953483583 100644
--- a/src/portable/ehci/ehci.c
+++ b/src/portable/ehci/ehci.c
@@ -35,9 +35,15 @@
#include "host/hcd.h"
#include "host/usbh.h"
+#include "host/usbh_pvt.h"
#include "ehci_api.h"
#include "ehci.h"
+// NXP specific fixes
+#if TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX, OPT_MCU_LPC55, OPT_MCU_MCXN9)
+#include "fsl_device_registers.h"
+#endif
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
@@ -179,12 +185,43 @@ static void ehci_enable_schedule(ehci_registers_t* regs, bool is_period) {
}
}
+#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
+static void nxp_usbphy_disconn_detector_set(uint8_t port, bool enable) {
+ // unify naming convention
+#if !defined(USBPHY1) && defined(USBPHY)
+ #define USBPHY1 USBPHY
+#endif
+
+ if (port == 0) {
+ if (enable) {
+ USBPHY1->CTRL_SET = USBPHY_CTRL_ENHOSTDISCONDETECT_MASK;
+ } else {
+ USBPHY1->CTRL_CLR = USBPHY_CTRL_ENHOSTDISCONDETECT_MASK;
+ }
+ }
+#if FSL_FEATURE_SOC_USBPHY_COUNT > 1U
+ else if (port == 1) {
+ if (enable) {
+ USBPHY2->CTRL_SET = USBPHY_CTRL_ENHOSTDISCONDETECT_MASK;
+ } else {
+ USBPHY2->CTRL_CLR = USBPHY_CTRL_ENHOSTDISCONDETECT_MASK;
+ }
+ }
+#endif
+
+#if !defined(USBPHY1) && defined(USBPHY)
+ #undef USBPHY1
+#endif
+}
+#endif
+
//--------------------------------------------------------------------+
// HCD API
//--------------------------------------------------------------------+
uint32_t hcd_frame_number(uint8_t rhport) {
(void) rhport;
- return (ehci_data.uframe_number + ehci_data.regs->frame_index) >> 3;
+ uint32_t uframe = ehci_data.regs->frame_index;
+ return (ehci_data.uframe_number + uframe) >> 3;
}
void hcd_port_reset(uint8_t rhport) {
@@ -212,16 +249,21 @@ void hcd_port_reset_end(uint8_t rhport) {
(void) rhport;
ehci_registers_t* regs = ehci_data.regs;
- // skip if reset is already complete
- if (!regs->portsc_bm.port_reset) {
- return;
- }
+ // stop reset only if is not complete yet
+ if (regs->portsc_bm.port_reset) {
+ // mask out all change bits since they are Write 1 to clear
+ uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_W1C;
+ portsc &= ~EHCI_PORTSC_MASK_PORT_RESET;
- // mask out all change bits since they are Write 1 to clear
- uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_W1C;
- portsc &= ~EHCI_PORTSC_MASK_PORT_RESET;
+ regs->portsc = portsc;
+ }
- regs->portsc = portsc;
+#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
+ // Enable disconnect detector for highspeed device only
+ if (hcd_port_speed_get(rhport) == TUSB_SPEED_HIGH) {
+ nxp_usbphy_disconn_detector_set(rhport, true);
+ }
+#endif
}
bool hcd_port_connect_status(uint8_t rhport) {
@@ -578,6 +620,10 @@ void port_connect_status_change_isr(uint8_t rhport) {
hcd_event_device_attach(rhport, true);
} else // device unplugged
{
+#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
+ // Disable disconnect detector
+ nxp_usbphy_disconn_detector_set(rhport, false);
+#endif
hcd_event_device_remove(rhport, true);
}
}
@@ -821,14 +867,21 @@ static ehci_qhd_t *qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr) {
}
ehci_qhd_t *qhd_pool = ehci_data.qhd_pool;
+
+ // protect qhd_pool since 'used' and 'removing' can be changed in isr
+ ehci_qhd_t *result = NULL;
+ usbh_spin_lock(false);
for (uint32_t i = 0; i < QHD_MAX; i++) {
if ((qhd_pool[i].dev_addr == dev_addr) &&
- ep_addr == qhd_ep_addr(&qhd_pool[i])) {
- return &qhd_pool[i];
+ ep_addr == qhd_ep_addr(&qhd_pool[i]) &&
+ qhd_pool[i].used && !qhd_pool[i].removing) {
+ result = &qhd_pool[i];
+ break;
}
}
+ usbh_spin_unlock(false);
- return NULL;
+ return result;
}
// Init queue head with endpoint descriptor
@@ -896,7 +949,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
p_qhd->used = 1;
p_qhd->removing = 0;
p_qhd->attached_qtd = NULL;
- p_qhd->pid = tu_edpt_dir(ep_desc->bEndpointAddress) ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint
+ p_qhd->pid = tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint
//------------- active, but no TD list -------------//
p_qhd->qtd_overlay.halted = 0;
diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c
deleted file mode 100644
index 1b6aae026..000000000
--- a/src/portable/espressif/esp32sx/dcd_esp32sx.c
+++ /dev/null
@@ -1,889 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2018 Scott Shawcroft, 2019 William D. Jones for Adafruit Industries
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
- * Additions Copyright (c) 2020, Espressif Systems (Shanghai) Co. Ltd.
- *
- * 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_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && CFG_TUD_ENABLED)
-
-// Espressif
-#include "xtensa/xtensa_api.h"
-
-#include "esp_intr_alloc.h"
-#include "esp_log.h"
-#include "soc/dport_reg.h"
-#include "soc/gpio_sig_map.h"
-#include "soc/usb_periph.h"
-#include "soc/usb_reg.h"
-#include "soc/usb_struct.h"
-#include "soc/periph_defs.h" // for interrupt source
-
-#include "device/dcd.h"
-
-#ifndef USB_OUT_EP_NUM
-#define USB_OUT_EP_NUM ((int) (sizeof(USB0.out_ep_reg) / sizeof(USB0.out_ep_reg[0])))
-#endif
-
-#ifndef USB_IN_EP_NUM
-#define USB_IN_EP_NUM ((int) (sizeof(USB0.in_ep_reg) / sizeof(USB0.in_ep_reg[0])))
-#endif
-
-// Max number of bi-directional endpoints including EP0
-// Note: ESP32S2 specs say there are only up to 5 IN active endpoints include EP0
-// We should probably prohibit enabling Endpoint IN > 4 (not done yet)
-#define EP_MAX USB_OUT_EP_NUM
-
-// FIFO size in bytes
-#define EP_FIFO_SIZE 1024
-
-// Max number of IN EP FIFOs
-#define EP_FIFO_NUM 5
-
-typedef struct {
- uint8_t *buffer;
- // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
- uint16_t total_len;
- uint16_t queued_len;
- uint16_t max_size;
- bool short_packet;
- uint8_t interval;
-} xfer_ctl_t;
-
-static const char *TAG = "TUSB:DCD";
-static intr_handle_t usb_ih;
-
-
-static uint32_t _setup_packet[2];
-
-#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
-static xfer_ctl_t xfer_status[EP_MAX][2];
-
-// 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 < EP_FIFO_NUM) return _allocated_fifos++;
- return 0;
-}
-
-// Setup the control endpoint 0.
-static void bus_reset(void)
-{
- for (int ep_num = 0; ep_num < USB_OUT_EP_NUM; ep_num++) {
- USB0.out_ep_reg[ep_num].doepctl |= USB_DO_SNAK0_M; // DOEPCTL0_SNAK
- }
-
- // clear device address
- USB0.dcfg &= ~USB_DEVADDR_M;
-
- USB0.daintmsk = USB_OUTEPMSK0_M | USB_INEPMSK0_M;
- USB0.doepmsk = USB_SETUPMSK_M | USB_XFERCOMPLMSK;
- USB0.diepmsk = USB_TIMEOUTMSK_M | USB_DI_XFERCOMPLMSK_M /*| USB_INTKNTXFEMPMSK_M*/;
-
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO MAX |
- // ---------------
- // | ... |
- // --------------- y + x + 16 + GRXFSIZ
- // | IN FIFO 2 |
- // --------------- x + 16 + GRXFSIZ
- // | IN FIFO 1 |
- // --------------- 16 + GRXFSIZ
- // | IN FIFO 0 |
- // --------------- 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
- // * 10 locations in hardware for setup packets + setup control words (up to 3 setup packets).
- // * 2 locations for OUT endpoint control words.
- // * 16 for largest packet size of 64 bytes. ( TODO Highspeed is 512 bytes)
- // * 1 location for global NAK (not required/used here).
- // * It is recommended to allocate 2 times the largest packet size, therefore
- // Recommended value = 10 + 1 + 2 x (16+2) = 47 --> Let's make it 52
- USB0.grstctl |= 0x10 << USB_TXFNUM_S; // fifo 0x10,
- USB0.grstctl |= USB_TXFFLSH_M; // Flush fifo
- USB0.grxfsiz = 52;
-
- // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
- USB0.gnptxfsiz = (16 << USB_NPTXFDEP_S) | (USB0.grxfsiz & 0x0000ffffUL);
-
- // Ready to receive SETUP packet
- USB0.out_ep_reg[0].doeptsiz |= USB_SUPCNT0_M;
-
- USB0.gintmsk |= USB_IEPINTMSK_M | USB_OEPINTMSK_M;
-}
-
-static void enum_done_processing(void)
-{
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - Speed enumeration done! Sending DCD_EVENT_BUS_RESET then");
- // On current silicon on the Full Speed core, speed is fixed to Full Speed.
- // However, keep for debugging and in case Low Speed is ever supported.
- uint32_t enum_spd = (USB0.dsts >> USB_ENUMSPD_S) & (USB_ENUMSPD_V);
-
- // Maximum packet size for EP 0 is set for both directions by writing DIEPCTL
- if (enum_spd == 0x03) { // Full-Speed (PHY on 48 MHz)
- USB0.in_ep_reg[0].diepctl &= ~USB_D_MPS0_V; // 64 bytes
- USB0.in_ep_reg[0].diepctl &= ~USB_D_STALL0_M; // clear Stall
- xfer_status[0][TUSB_DIR_OUT].max_size = 64;
- xfer_status[0][TUSB_DIR_IN].max_size = 64;
- } else {
- USB0.in_ep_reg[0].diepctl |= USB_D_MPS0_V; // 8 bytes
- USB0.in_ep_reg[0].diepctl &= ~USB_D_STALL0_M; // clear Stall
- xfer_status[0][TUSB_DIR_OUT].max_size = 8;
- xfer_status[0][TUSB_DIR_IN].max_size = 8;
- }
-}
-
-
-/*------------------------------------------------------------------*/
-/* Controller API
- *------------------------------------------------------------------*/
-bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
- (void) rh_init;
- ESP_LOGV(TAG, "DCD init - Start");
-
- // A. Disconnect
- ESP_LOGV(TAG, "DCD init - Soft DISCONNECT and Setting up");
- USB0.dctl |= USB_SFTDISCON_M; // Soft disconnect
-
- // B. Programming DCFG
- /* If USB host misbehaves during status portion of control xfer
- (non zero-length packet), send STALL back and discard. Full speed. */
- USB0.dcfg |= USB_NZSTSOUTHSHK_M | // NonZero .... STALL
- (3 << 0); // dev speed: fullspeed 1.1 on 48 mhz // TODO no value in usb_reg.h (IDF-1476)
-
- USB0.gahbcfg |= USB_NPTXFEMPLVL_M | USB_GLBLLNTRMSK_M; // Global interruptions ON
- USB0.gusbcfg |= USB_FORCEDEVMODE_M; // force devmode
- USB0.gotgctl &= ~(USB_BVALIDOVVAL_M | USB_BVALIDOVEN_M | USB_VBVALIDOVVAL_M); //no overrides
-
- // C. Setting SNAKs, then connect
- for (int n = 0; n < USB_OUT_EP_NUM; n++) {
- USB0.out_ep_reg[n].doepctl |= USB_DO_SNAK0_M; // DOEPCTL0_SNAK
- }
-
- // D. Interruption masking
- USB0.gintmsk = 0; //mask all
- USB0.gotgint = ~0U; //clear OTG ints
- USB0.gintsts = ~0U; //clear pending ints
- USB0.gintmsk = USB_OTGINTMSK_M |
- USB_MODEMISMSK_M |
- USB_RXFLVIMSK_M |
- USB_ERLYSUSPMSK_M |
- USB_USBSUSPMSK_M |
- USB_USBRSTMSK_M |
- USB_ENUMDONEMSK_M |
- USB_RESETDETMSK_M |
- USB_WKUPINT_M |
- USB_DISCONNINTMSK_M; // host most only
-
- dcd_connect(rhport);
- return true;
-}
-
-void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
-{
- (void)rhport;
- ESP_LOGV(TAG, "DCD init - Set address : %u", dev_addr);
- USB0.dcfg |= ((dev_addr & USB_DEVADDR_V) << USB_DEVADDR_S);
- // 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;
-
- // set remote wakeup
- USB0.dctl |= USB_RMTWKUPSIG_M;
-
- // enable SOF to detect bus resume
- USB0.gintsts = USB_SOF_M;
- USB0.gintmsk |= USB_SOFMSK_M;
-
- // Per specs: remote wakeup signal bit must be clear within 1-15ms
- vTaskDelay(pdMS_TO_TICKS(1));
-
- USB0.dctl &= ~USB_RMTWKUPSIG_M;
-}
-
-// connect by enabling internal pull-up resistor on D+/D-
-void dcd_connect(uint8_t rhport)
-{
- (void) rhport;
- USB0.dctl &= ~USB_SFTDISCON_M;
-}
-
-// disconnect by disabling internal pull-up resistor on D+/D-
-void dcd_disconnect(uint8_t rhport)
-{
- (void) rhport;
- USB0.dctl |= USB_SFTDISCON_M;
-}
-
-void dcd_sof_enable(uint8_t rhport, bool en)
-{
- (void) rhport;
- (void) en;
-
- // TODO implement later
-}
-
-/*------------------------------------------------------------------*/
-/* DCD Endpoint port
- *------------------------------------------------------------------*/
-
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
-{
- ESP_LOGV(TAG, "DCD endpoint opened");
- (void)rhport;
-
- usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
- usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
-
- 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);
-
- xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
- xfer->max_size = tu_edpt_packet_size(desc_edpt);
- xfer->interval = desc_edpt->bInterval;
-
- if (dir == TUSB_DIR_OUT) {
- out_ep[epnum].doepctl |= USB_USBACTEP1_M |
- desc_edpt->bmAttributes.xfer << USB_EPTYPE1_S |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_DO_SETD0PID1_M : 0) |
- xfer->max_size << USB_MPS1_S;
- USB0.daintmsk |= (1 << (16 + epnum));
- } else {
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO MAX |
- // ---------------
- // | ... |
- // --------------- y + x + 16 + GRXFSIZ
- // | IN FIFO 2 |
- // --------------- x + 16 + GRXFSIZ
- // | IN FIFO 1 |
- // --------------- 16 + GRXFSIZ
- // | IN FIFO 0 |
- // --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
- // --------------- 0
- //
- // Since OUT FIFO = GRXFSIZ, FIFO 0 = 16, for simplicity, we equally allocated for the rest of endpoints
- // - Size : (FIFO_SIZE/4 - GRXFSIZ - 16) / (EP_MAX-1)
- // - Offset: GRXFSIZ + 16 + Size*(epnum-1)
- // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
-
- uint8_t fifo_num = get_free_fifo();
- TU_ASSERT(fifo_num != 0);
-
- in_ep[epnum].diepctl &= ~(USB_D_TXFNUM1_M | USB_D_EPTYPE1_M | USB_DI_SETD0PID1 | USB_D_MPS1_M);
- in_ep[epnum].diepctl |= USB_D_USBACTEP1_M |
- fifo_num << USB_D_TXFNUM1_S |
- desc_edpt->bmAttributes.xfer << USB_D_EPTYPE1_S |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? (1 << USB_DI_SETD0PID1_S) : 0) |
- xfer->max_size << 0;
-
- USB0.daintmsk |= (1 << (0 + epnum));
-
- // Both TXFD and TXSA are in unit of 32-bit words.
- // IN FIFO 0 was configured during enumeration, hence the "+ 16".
- uint16_t const allocated_size = (USB0.grxfsiz & 0x0000ffff) + 16;
- uint16_t const fifo_size = (EP_FIFO_SIZE/4 - allocated_size) / (EP_FIFO_NUM-1);
- uint32_t const fifo_offset = allocated_size + fifo_size*(fifo_num-1);
-
- // DIEPTXF starts at FIFO #1.
- USB0.dieptxf[epnum - 1] = (fifo_size << USB_NPTXFDEP_S) | fifo_offset;
- }
- return true;
-}
-
-void dcd_edpt_close_all(uint8_t rhport)
-{
- (void) rhport;
-
- usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
- usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
-
- // Disable non-control interrupt
- USB0.daintmsk = USB_OUTEPMSK0_M | USB_INEPMSK0_M;
-
- for(uint8_t n = 1; n < EP_MAX; n++)
- {
- // disable OUT endpoint
- out_ep[n].doepctl = 0;
- xfer_status[n][TUSB_DIR_OUT].max_size = 0;
-
- // disable IN endpoint
- in_ep[n].diepctl = 0;
- xfer_status[n][TUSB_DIR_IN].max_size = 0;
- }
-
- _allocated_fifos = 1;
-}
-
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
-{
- (void)rhport;
-
- 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);
- xfer->buffer = buffer;
- // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
- xfer->total_len = total_bytes;
- xfer->queued_len = 0;
- xfer->short_packet = false;
-
- uint16_t num_packets = (total_bytes / xfer->max_size);
- uint8_t short_packet_size = total_bytes % xfer->max_size;
-
- // Zero-size packet is special case.
- if (short_packet_size > 0 || (total_bytes == 0)) {
- num_packets++;
- }
-
- ESP_LOGV(TAG, "Transfer <-> EP%i, %s, pkgs: %i, bytes: %i",
- epnum, ((dir == TUSB_DIR_IN) ? "USB0.HOST (in)" : "HOST->DEV (out)"),
- num_packets, total_bytes);
-
- // IN and OUT endpoint xfers are interrupt-driven, we just schedule them
- // here.
- if (dir == TUSB_DIR_IN) {
- // A full IN transfer (multiple packets, possibly) triggers XFRC.
- USB0.in_ep_reg[epnum].dieptsiz = (num_packets << USB_D_PKTCNT0_S) | total_bytes;
- USB0.in_ep_reg[epnum].diepctl |= USB_D_EPENA1_M | USB_D_CNAK1_M; // Enable | CNAK
-
- // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame
- if ((USB0.in_ep_reg[epnum].diepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) {
- // Take odd/even bit from frame counter.
- uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S));
- USB0.in_ep_reg[epnum].diepctl |= (odd_frame_now ? USB_DI_SETD0PID1 : USB_DI_SETD1PID1);
- }
-
- // Enable fifo empty interrupt only if there are something to put in the fifo.
- if(total_bytes != 0) {
- USB0.dtknqr4_fifoemptymsk |= (1 << epnum);
- }
- } else {
- // Each complete packet for OUT xfers triggers XFRC.
- USB0.out_ep_reg[epnum].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
- USB0.out_ep_reg[epnum].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
-
- // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame
- if ((USB0.out_ep_reg[epnum].doepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) {
- // Take odd/even bit from frame counter.
- uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S));
- USB0.out_ep_reg[epnum].doepctl |= (odd_frame_now ? USB_DO_SETD0PID1 : USB_DO_SETD1PID1);
- }
- }
- return true;
-}
-
-#if 0 // TODO support dcd_edpt_xfer_fifo API
-bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
-{
- (void)rhport;
-}
-#endif
-
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
-{
- (void)rhport;
-
- usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
- usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if (dir == TUSB_DIR_IN) {
- // Only disable currently enabled non-control endpoint
- if ((epnum == 0) || !(in_ep[epnum].diepctl & USB_D_EPENA1_M)) {
- in_ep[epnum].diepctl |= (USB_DI_SNAK1_M | USB_D_STALL1_M);
- } else {
- // Stop transmitting packets and NAK IN xfers.
- in_ep[epnum].diepctl |= USB_DI_SNAK1_M;
- while ((in_ep[epnum].diepint & USB_DI_SNAK1_M) == 0) ;
-
- // Disable the endpoint. Note that both SNAK and STALL are set here.
- in_ep[epnum].diepctl |= (USB_DI_SNAK1_M | USB_D_STALL1_M | USB_D_EPDIS1_M);
- while ((in_ep[epnum].diepint & USB_D_EPDISBLD0_M) == 0) ;
- in_ep[epnum].diepint = USB_D_EPDISBLD0_M;
- }
-
- // Flush the FIFO, and wait until we have confirmed it cleared.
- uint8_t const fifo_num = ((in_ep[epnum].diepctl >> USB_D_TXFNUM1_S) & USB_D_TXFNUM1_V);
- USB0.grstctl |= (fifo_num << USB_TXFNUM_S);
- USB0.grstctl |= USB_TXFFLSH_M;
- while ((USB0.grstctl & USB_TXFFLSH_M) != 0) ;
- } else {
- // Only disable currently enabled non-control endpoint
- if ((epnum == 0) || !(out_ep[epnum].doepctl & USB_EPENA0_M)) {
- out_ep[epnum].doepctl |= USB_STALL0_M;
- } 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.
- USB0.dctl |= USB_SGOUTNAK_M;
- while ((USB0.gintsts & USB_GOUTNAKEFF_M) == 0) ;
-
- // Ditto here- disable the endpoint. Note that only STALL and not SNAK
- // is set here.
- out_ep[epnum].doepctl |= (USB_STALL0_M | USB_EPDIS0_M);
- while ((out_ep[epnum].doepint & USB_EPDISBLD0_M) == 0) ;
- out_ep[epnum].doepint = USB_EPDISBLD0_M;
-
- // Allow other OUT endpoints to keep receiving.
- USB0.dctl |= USB_CGOUTNAK_M;
- }
- }
-}
-
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
-{
- (void)rhport;
-
- usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
- usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if (dir == TUSB_DIR_IN) {
- in_ep[epnum].diepctl &= ~USB_D_STALL1_M;
-
- uint8_t eptype = (in_ep[epnum].diepctl & USB_D_EPTYPE1_M) >> USB_D_EPTYPE1_S;
- // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt
- // and bulk endpoints.
- if (eptype == 2 || eptype == 3) {
- in_ep[epnum].diepctl |= USB_DI_SETD0PID1_M;
- }
- } else {
- out_ep[epnum].doepctl &= ~USB_STALL1_M;
-
- uint8_t eptype = (out_ep[epnum].doepctl & USB_EPTYPE1_M) >> USB_EPTYPE1_S;
- // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt
- // and bulk endpoints.
- if (eptype == 2 || eptype == 3) {
- out_ep[epnum].doepctl |= USB_DO_SETD0PID1_M;
- }
- }
-}
-
-/*------------------------------------------------------------------*/
-
-static void receive_packet(xfer_ctl_t *xfer, /* usb_out_endpoint_t * out_ep, */ uint16_t xfer_size)
-{
- ESP_EARLY_LOGV(TAG, "USB - receive_packet");
- volatile uint32_t *rx_fifo = USB0.fifo[0];
-
- // See above TODO
- // uint16_t remaining = (out_ep->DOEPTSIZ & UsbDOEPTSIZ_XFRSIZ_Msk) >> UsbDOEPTSIZ_XFRSIZ_Pos;
- // xfer->queued_len = xfer->total_len - remaining;
-
- uint16_t remaining = xfer->total_len - xfer->queued_len;
- uint16_t to_recv_size;
-
- if (remaining <= xfer->max_size) {
- // Avoid buffer overflow.
- to_recv_size = (xfer_size > remaining) ? remaining : xfer_size;
- } else {
- // Room for full packet, choose recv_size based on what the microcontroller
- // claims.
- to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
- }
-
- // Common buffer read
-#if 0 // TODO support dcd_edpt_xfer_fifo API
- if (xfer->ff)
- {
- // Ring buffer
- tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) rx_fifo, to_recv_size);
- }
- else
-#endif
- {
- uint8_t to_recv_rem = to_recv_size % 4;
- uint16_t to_recv_size_aligned = to_recv_size - to_recv_rem;
-
- // Do not assume xfer buffer is aligned.
- uint8_t *base = (xfer->buffer + xfer->queued_len);
-
- // This for loop always runs at least once- skip if less than 4 bytes
- // to collect.
- if (to_recv_size >= 4) {
- for (uint16_t i = 0; i < to_recv_size_aligned; i += 4) {
- uint32_t tmp = (*rx_fifo);
- base[i] = tmp & 0x000000FF;
- base[i + 1] = (tmp & 0x0000FF00) >> 8;
- base[i + 2] = (tmp & 0x00FF0000) >> 16;
- base[i + 3] = (tmp & 0xFF000000) >> 24;
- }
- }
-
- // Do not read invalid bytes from RX FIFO.
- if (to_recv_rem != 0) {
- uint32_t tmp = (*rx_fifo);
- uint8_t *last_32b_bound = base + to_recv_size_aligned;
-
- last_32b_bound[0] = tmp & 0x000000FF;
- if (to_recv_rem > 1) {
- last_32b_bound[1] = (tmp & 0x0000FF00) >> 8;
- }
- if (to_recv_rem > 2) {
- last_32b_bound[2] = (tmp & 0x00FF0000) >> 16;
- }
- }
- }
-
- xfer->queued_len += xfer_size;
-
- // Per USB spec, a short OUT packet (including length 0) is always
- // indicative of the end of a transfer (at least for ctl, bulk, int).
- xfer->short_packet = (xfer_size < xfer->max_size);
-}
-
-static void transmit_packet(xfer_ctl_t *xfer, volatile usb_in_endpoint_t *in_ep, uint8_t fifo_num)
-{
- ESP_EARLY_LOGV(TAG, "USB - transmit_packet");
- volatile uint32_t *tx_fifo = USB0.fifo[fifo_num];
-
- uint16_t remaining = (in_ep->dieptsiz & 0x7FFFFU) >> USB_D_XFERSIZE0_S;
- xfer->queued_len = xfer->total_len - remaining;
-
- uint16_t to_xfer_size = (remaining > xfer->max_size) ? xfer->max_size : remaining;
-
-#if 0 // TODO support dcd_edpt_xfer_fifo API
- if (xfer->ff)
- {
- tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) tx_fifo, to_xfer_size);
- }
- else
-#endif
- {
- uint8_t to_xfer_rem = to_xfer_size % 4;
- uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem;
-
- // Buffer might not be aligned to 32b, so we need to force alignment
- // by copying to a temp var.
- uint8_t *base = (xfer->buffer + xfer->queued_len);
-
- // This for loop always runs at least once- skip if less than 4 bytes
- // to send off.
- if (to_xfer_size >= 4) {
- for (uint16_t i = 0; i < to_xfer_size_aligned; i += 4) {
- uint32_t tmp = base[i] | (base[i + 1] << 8) |
- (base[i + 2] << 16) | (base[i + 3] << 24);
- (*tx_fifo) = tmp;
- }
- }
-
- // Do not read beyond end of buffer if not divisible by 4.
- if (to_xfer_rem != 0) {
- uint32_t tmp = 0;
- uint8_t *last_32b_bound = base + to_xfer_size_aligned;
-
- tmp |= last_32b_bound[0];
- if (to_xfer_rem > 1) {
- tmp |= (last_32b_bound[1] << 8);
- }
- if (to_xfer_rem > 2) {
- tmp |= (last_32b_bound[2] << 16);
- }
-
- (*tx_fifo) = tmp;
- }
- }
-}
-
-static void read_rx_fifo(void)
-{
- // Pop control word off FIFO (completed xfers will have 2 control words,
- // we only pop one ctl word each interrupt).
- uint32_t const ctl_word = USB0.grxstsp;
- uint8_t const pktsts = (ctl_word & USB_PKTSTS_M) >> USB_PKTSTS_S;
- uint8_t const epnum = (ctl_word & USB_CHNUM_M ) >> USB_CHNUM_S;
- uint16_t const bcnt = (ctl_word & USB_BCNT_M ) >> USB_BCNT_S;
-
- switch (pktsts) {
- case 0x01: // Global OUT NAK (Interrupt)
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX type : Global OUT NAK");
- break;
-
- case 0x02: { // Out packet recvd
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX type : Out packet");
- xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
- receive_packet(xfer, bcnt);
- }
- break;
-
- case 0x03: // Out packet done (Interrupt)
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX type : Out packet done");
- break;
-
- case 0x04: // Step 2: Setup transaction completed (Interrupt)
- // After this event, OEPINT interrupt will occur with SETUP bit set
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX : Setup packet done");
- USB0.out_ep_reg[epnum].doeptsiz |= USB_SUPCNT0_M;
- break;
-
- case 0x06: { // Step1: Setup data packet received
- volatile uint32_t *rx_fifo = USB0.fifo[0];
-
- // We can receive up to three setup packets in succession, but
- // only the last one is valid. Therefore we just overwrite it
- _setup_packet[0] = (*rx_fifo);
- _setup_packet[1] = (*rx_fifo);
-
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX : Setup packet : 0x%08x 0x%08x", _setup_packet[0], _setup_packet[1]);
- }
- break;
-
- default: // Invalid, do something here, like breakpoint?
- TU_BREAKPOINT();
- break;
- }
-}
-
-static void handle_epout_ints(void)
-{
- // GINTSTS will be cleared with DAINT == 0
- // DAINT for a given EP clears when DOEPINTx is cleared.
- // DOEPINT will be cleared when DAINT's out bits are cleared.
- for (int n = 0; n < USB_OUT_EP_NUM; n++) {
- xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
-
- if (USB0.daint & (1 << (16 + n))) {
- // SETUP packet Setup Phase done.
- if ((USB0.out_ep_reg[n].doepint & USB_SETUP0_M)) {
- USB0.out_ep_reg[n].doepint = USB_STUPPKTRCVD0_M | USB_SETUP0_M; // clear
- dcd_event_setup_received(0, (uint8_t *)&_setup_packet[0], true);
- }
-
- // OUT XFER complete (single packet).q
- if (USB0.out_ep_reg[n].doepint & USB_XFERCOMPL0_M) {
-
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - EP OUT - XFER complete (single packet)");
- USB0.out_ep_reg[n].doepint = USB_XFERCOMPL0_M;
-
- // Transfer complete if short packet or total len is transferred
- if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
- xfer->short_packet = false;
- dcd_event_xfer_complete(0, n, xfer->queued_len, XFER_RESULT_SUCCESS, true);
- } else {
- // Schedule another packet to be received.
- USB0.out_ep_reg[n].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
- USB0.out_ep_reg[n].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
- }
- }
- }
- }
-}
-
-static void handle_epin_ints(void)
-{
- // GINTSTS will be cleared with DAINT == 0
- // DAINT for a given EP clears when DIEPINTx is cleared.
- // IEPINT will be cleared when DAINT's out bits are cleared.
- for (uint32_t n = 0; n < USB_IN_EP_NUM; n++) {
- xfer_ctl_t *xfer = &xfer_status[n][TUSB_DIR_IN];
-
- if (USB0.daint & (1 << (0 + n))) {
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - EP IN %u", n);
- // IN XFER complete (entire xfer).
- if (USB0.in_ep_reg[n].diepint & USB_D_XFERCOMPL0_M) {
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - IN XFER complete!");
- USB0.in_ep_reg[n].diepint = USB_D_XFERCOMPL0_M;
- dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
- }
-
- // XFER FIFO empty
- if (USB0.in_ep_reg[n].diepint & USB_D_TXFEMP0_M) {
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - IN XFER FIFO empty!");
- USB0.in_ep_reg[n].diepint = USB_D_TXFEMP0_M;
- transmit_packet(xfer, &USB0.in_ep_reg[n], n);
-
- // Turn off TXFE if all bytes are written.
- if (xfer->queued_len == xfer->total_len)
- {
- USB0.dtknqr4_fifoemptymsk &= ~(1 << n);
- }
- }
-
- // XFER Timeout
- if (USB0.in_ep_reg[n].diepint & USB_D_TIMEOUT0_M) {
- // Clear interrupt or endpoint will hang.
- USB0.in_ep_reg[n].diepint = USB_D_TIMEOUT0_M;
- // Maybe retry?
- }
- }
- }
-}
-
-
-static void _dcd_int_handler(void* arg)
-{
- (void) arg;
- uint8_t const rhport = 0;
-
- const uint32_t int_msk = USB0.gintmsk;
- const uint32_t int_status = USB0.gintsts & int_msk;
-
- if (int_status & USB_USBRST_M) {
- // start of reset
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - reset");
- USB0.gintsts = USB_USBRST_M;
- // FIFOs will be reassigned when the endpoints are reopen
- _allocated_fifos = 1;
- bus_reset();
- }
-
- if (int_status & USB_RESETDET_M) {
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - reset while suspend");
- USB0.gintsts = USB_RESETDET_M;
- bus_reset();
- }
-
- if (int_status & USB_ENUMDONE_M) {
- // ENUMDNE detects speed of the link. For full-speed, we
- // always expect the same value. This interrupt is considered
- // the end of reset.
- USB0.gintsts = USB_ENUMDONE_M;
- enum_done_processing();
- dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
- }
-
- if(int_status & USB_USBSUSP_M)
- {
- USB0.gintsts = USB_USBSUSP_M;
- dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
- }
-
- if(int_status & USB_WKUPINT_M)
- {
- USB0.gintsts = USB_WKUPINT_M;
- dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
- }
-
- if (int_status & USB_OTGINT_M)
- {
- // OTG INT bit is read-only
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - disconnected");
-
- uint32_t const otg_int = USB0.gotgint;
-
- if (otg_int & USB_SESENDDET_M)
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
- }
-
- USB0.gotgint = otg_int;
- }
-
- if (int_status & USB_SOF_M) {
- USB0.gintsts = USB_SOF_M;
-
- // Disable SOF interrupt since currently only used for remote wakeup detection
- USB0.gintmsk &= ~USB_SOFMSK_M;
-
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
- }
-
-
- if (int_status & USB_RXFLVI_M) {
- // RXFLVL bit is read-only
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - rx!");
-
- // Mask out RXFLVL while reading data from FIFO
- USB0.gintmsk &= ~USB_RXFLVIMSK_M;
- read_rx_fifo();
- USB0.gintmsk |= USB_RXFLVIMSK_M;
- }
-
- // OUT endpoint interrupt handling.
- if (int_status & USB_OEPINT_M) {
- // OEPINT is read-only
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - OUT endpoint!");
- handle_epout_ints();
- }
-
- // IN endpoint interrupt handling.
- if (int_status & USB_IEPINT_M) {
- // IEPINT bit read-only
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - IN endpoint!");
- handle_epin_ints();
- }
-
- // Without handling
- USB0.gintsts |= USB_CURMOD_INT_M |
- USB_MODEMIS_M |
- USB_OTGINT_M |
- USB_NPTXFEMP_M |
- USB_GINNAKEFF_M |
- USB_GOUTNAKEFF |
- USB_ERLYSUSP_M |
- USB_USBSUSP_M |
- USB_ISOOUTDROP_M |
- USB_EOPF_M |
- USB_EPMIS_M |
- USB_INCOMPISOIN_M |
- USB_INCOMPIP_M |
- USB_FETSUSP_M |
- USB_PTXFEMP_M;
-}
-
-void dcd_int_enable (uint8_t rhport)
-{
- (void) rhport;
- esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, (intr_handler_t) _dcd_int_handler, NULL, &usb_ih);
-}
-
-void dcd_int_disable (uint8_t rhport)
-{
- (void) rhport;
- esp_intr_free(usb_ih);
-}
-
-#endif // #if OPT_MCU_ESP32S2 || OPT_MCU_ESP32S3
diff --git a/src/portable/microchip/pic32mz/dcd_pic32mz.c b/src/portable/microchip/pic32mz/dcd_pic32mz.c
index 8709baf67..cbd157d6b 100644
--- a/src/portable/microchip/pic32mz/dcd_pic32mz.c
+++ b/src/portable/microchip/pic32mz/dcd_pic32mz.c
@@ -162,13 +162,7 @@ void dcd_remote_wakeup(uint8_t rhport)
(void) rhport;
USB_REGS->POWERbits.RESUME = 1;
-#if CFG_TUSB_OS != OPT_OS_NONE
- osal_task_delay(10);
-#else
- // TODO: Wait in non blocking mode
- unsigned cnt = 2000;
- while (cnt--) __asm__("nop");
-#endif
+ tusb_time_delay_ms_api(10);
USB_REGS->POWERbits.RESUME = 0;
}
diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c
index a9246e1cd..340d8c56a 100644
--- a/src/portable/ohci/ohci.c
+++ b/src/portable/ohci/ohci.c
@@ -177,14 +177,12 @@ static gtd_extra_data_t *gtd_get_extra_data(ohci_gtd_t const * const gtd);
// tusb_app_virt_to_phys and tusb_app_virt_to_phys in your application.
TU_ATTR_ALWAYS_INLINE static inline void *_phys_addr(void *virtual_address)
{
- if (tusb_app_virt_to_phys) return tusb_app_virt_to_phys(virtual_address);
- return virtual_address;
+ return tusb_app_virt_to_phys(virtual_address);
}
TU_ATTR_ALWAYS_INLINE static inline void *_virt_addr(void *physical_address)
{
- if (tusb_app_phys_to_virt) return tusb_app_phys_to_virt(physical_address);
- return physical_address;
+ return tusb_app_phys_to_virt(physical_address);
}
// Initialization according to 5.1.1.4
@@ -217,12 +215,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
//Wait 20 ms. (Ref Usb spec 7.1.7.7)
OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_RESUME;
-#if CFG_TUSB_OS != OPT_OS_NONE
- // os_none implement task delay using usb frame counter which is not started yet
- // therefore cause infinite delay.
- // TODO find a way to delay in case of os none e.g __nop
- osal_task_delay(20);
-#endif
+ tusb_time_delay_ms_api(20);
}
hcd_dcache_clean(&ohci_data, sizeof(ohci_data));
@@ -252,10 +245,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_OPERATIONAL; // make HC's state to operational state TODO use this to suspend (save power)
OHCI_REG->rh_status_bit.local_power_status_change = 1; // set global power for ports
-#if CFG_TUSB_OS != OPT_OS_NONE
- // TODO as above delay
- osal_task_delay(OHCI_REG->rh_descriptorA_bit.power_on_to_good_time * 2); // Wait POTG after power up
-#endif
+ tusb_time_delay_ms_api(OHCI_REG->rh_descriptorA_bit.power_on_to_good_time * 2); // Wait POTG after power up
return true;
}
diff --git a/src/portable/renesas/rusb2/rusb2_common.c b/src/portable/renesas/rusb2/rusb2_common.c
index 72e65736b..856f9714f 100644
--- a/src/portable/renesas/rusb2/rusb2_common.c
+++ b/src/portable/renesas/rusb2/rusb2_common.c
@@ -50,10 +50,6 @@ void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum) {
rusb2_controller[rhport].irqnum = irqnum;
}
-// void osal_task_delay(uint32_t msec) {
-// R_BSP_SoftwareDelay(msec, BSP_DELAY_UNITS_MILLISECONDS);
-// }
-
#else
#error "Unsupported MCU"
#endif
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index 5d6033a66..ed823a832 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -333,8 +333,13 @@ static void handle_ctr_rx(uint32_t ep_id) {
xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT);
uint8_t buf_id;
- if (is_iso) {
- buf_id = (ep_reg & USB_EP_DTOG_RX) ? 0 : 1; // ISO are double buffered
+#if FSDEV_USE_SBUF_ISO == 0
+ bool const dbl_buf = is_iso;
+#else
+ bool const dbl_buf = false;
+#endif
+ if (dbl_buf) {
+ buf_id = (ep_reg & USB_EP_DTOG_RX) ? 0 : 1;
} else {
buf_id = BTABLE_BUF_RX;
}
@@ -529,10 +534,16 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
return i;
}
+#if FSDEV_USE_SBUF_ISO == 0
+ bool const dbl_buf = ep_type == TUSB_XFER_ISOCHRONOUS;
+#else
+ bool const dbl_buf = false;
+#endif
+
// If EP of current direction is not allocated
- // Except for ISO endpoint, both direction should be free
+ // For double-buffered mode both directions needs to be free
if (!ep_alloc_status[i].allocated[dir] &&
- (ep_type != TUSB_XFER_ISOCHRONOUS || !ep_alloc_status[i].allocated[dir ^ 1])) {
+ (!dbl_buf || !ep_alloc_status[i].allocated[dir ^ 1])) {
// Check if EP number is the same
if (ep_alloc_status[i].ep_num == 0xFF || ep_alloc_status[i].ep_num == epnum) {
// One EP pair has to be the same type
@@ -654,9 +665,7 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet
uint8_t const dir = tu_edpt_dir(ep_addr);
uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS);
- /* Create a packet memory buffer area. Enable double buffering for devices with 2048 bytes PMA,
- for smaller devices double buffering occupy too much space. */
-#if FSDEV_PMA_SIZE > 1024u
+#if CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP != 0
uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true);
uint16_t pma_addr2 = pma_addr >> 16;
#else
@@ -664,8 +673,13 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet
uint16_t pma_addr2 = pma_addr;
#endif
+#if FSDEV_USE_SBUF_ISO == 0
btable_set_addr(ep_idx, 0, pma_addr);
btable_set_addr(ep_idx, 1, pma_addr2);
+#else
+ btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr);
+ (void) pma_addr2;
+#endif
xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir);
xfer->ep_idx = ep_idx;
@@ -686,10 +700,23 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK;
ep_reg |= tu_edpt_number(ep_addr) | USB_EP_ISOCHRONOUS | USB_EP_CTR_TX | USB_EP_CTR_RX;
+#if FSDEV_USE_SBUF_ISO != 0
+ ep_reg |= USB_EP_KIND;
+
+ ep_change_status(&ep_reg, dir, EP_STAT_DISABLED);
+ ep_change_dtog(&ep_reg, dir, 0);
+
+ if (dir == TUSB_DIR_IN) {
+ ep_reg &= ~(USB_EPRX_STAT | USB_EP_DTOG_RX);
+ } else {
+ ep_reg &= ~(USB_EPTX_STAT | USB_EP_DTOG_TX);
+ }
+#else
ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_DISABLED);
ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_DISABLED);
ep_change_dtog(&ep_reg, dir, 0);
ep_change_dtog(&ep_reg, (tusb_dir_t)(1 - dir), 1);
+#endif
ep_write(ep_idx, ep_reg, true);
@@ -704,7 +731,12 @@ static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) {
bool const is_iso = ep_is_iso(ep_reg);
uint8_t buf_id;
- if (is_iso) {
+#if FSDEV_USE_SBUF_ISO == 0
+ bool const dbl_buf = is_iso;
+#else
+ bool const dbl_buf = false;
+#endif
+ if (dbl_buf) {
buf_id = (ep_reg & USB_EP_DTOG_TX) ? 1 : 0;
} else {
buf_id = BTABLE_BUF_TX;
diff --git a/src/portable/st/stm32_fsdev/fsdev_at32.h b/src/portable/st/stm32_fsdev/fsdev_at32.h
index 3a785bbbd..f7ee89995 100644
--- a/src/portable/st/stm32_fsdev/fsdev_at32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_at32.h
@@ -36,9 +36,14 @@
#endif
#define FSDEV_PMA_SIZE (512u)
+#define FSDEV_USE_SBUF_ISO 0
#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL)
#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL)
+#ifndef CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP
+ #define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 0
+#endif
+
/**************************** ISTR interrupt events *************************/
#define USB_ISTR_CTR ((uint16_t)0x8000U) /*!< Correct TRansfer (clear-only bit) */
#define USB_ISTR_PMAOVR ((uint16_t)0x4000U) /*!< DMA OVeR/underrun (clear-only bit) */
diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h
index 518197c47..ceebb6dab 100644
--- a/src/portable/st/stm32_fsdev/fsdev_ch32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h
@@ -54,9 +54,14 @@
#endif
#define FSDEV_PMA_SIZE (512u)
+#define FSDEV_USE_SBUF_ISO 0
#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL)
#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL)
+#ifndef CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP
+ #define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 0
+#endif
+
/**************************** ISTR interrupt events *************************/
#define USB_ISTR_CTR ((uint16_t)0x8000U) /*!< Correct TRansfer (clear-only bit) */
#define USB_ISTR_PMAOVR ((uint16_t)0x4000U) /*!< DMA OVeR/underrun (clear-only bit) */
diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h
index ccf31e035..63b50f13d 100644
--- a/src/portable/st/stm32_fsdev/fsdev_stm32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h
@@ -36,6 +36,7 @@
#include "stm32f0xx.h"
#define FSDEV_PMA_SIZE (1024u)
#define FSDEV_REG_BASE USB_BASE
+ #define FSDEV_HAS_SBUF_ISO 0
// F0x2 models are crystal-less
// All have internal D+ pull-up
// 070RB: 2 x 16 bits/word memory LPM Support, BCD Support
@@ -44,6 +45,7 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
#include "stm32f1xx.h"
#define FSDEV_PMA_SIZE (512u)
+ #define FSDEV_HAS_SBUF_ISO 0
// NO internal Pull-ups
// *B, and *C: 2 x 16 bits/word
@@ -55,6 +57,7 @@
defined(STM32F373xC)
#include "stm32f3xx.h"
#define FSDEV_PMA_SIZE (512u)
+ #define FSDEV_HAS_SBUF_ISO 0
// NO internal Pull-ups
// *B, and *C: 1 x 16 bits/word
// PMA dedicated to USB (no sharing with CAN)
@@ -64,6 +67,7 @@
defined(STM32F303xD) || defined(STM32F303xE)
#include "stm32f3xx.h"
#define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_HAS_SBUF_ISO 0
// NO internal Pull-ups
// *6, *8, *D, and *E: 2 x 16 bits/word LPM Support
// When CAN clock is enabled, USB can use first 768 bytes ONLY.
@@ -71,18 +75,22 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32L0
#include "stm32l0xx.h"
#define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_HAS_SBUF_ISO 0
#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
#include "stm32l1xx.h"
#define FSDEV_PMA_SIZE (512u)
+ #define FSDEV_HAS_SBUF_ISO 0
#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
#include "stm32g4xx.h"
#define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_HAS_SBUF_ISO 0
#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
#include "stm32g0xx.h"
#define FSDEV_PMA_SIZE (2048u)
+ #define FSDEV_HAS_SBUF_ISO 1
#define USB USB_DRD_FS
#define USB_EP_CTR_RX USB_EP_VTRX
@@ -107,6 +115,7 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32C0
#include "stm32c0xx.h"
#define FSDEV_PMA_SIZE (2048u)
+ #define FSDEV_HAS_SBUF_ISO 1
#define USB USB_DRD_FS
#define USB_EP_CTR_RX USB_CHEP_VTRX
#define USB_EP_CTR_TX USB_CHEP_VTTX
@@ -121,6 +130,7 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
#include "stm32h5xx.h"
#define FSDEV_PMA_SIZE (2048u)
+ #define FSDEV_HAS_SBUF_ISO 1
#define USB USB_DRD_FS
#define USB_EP_CTR_RX USB_EP_VTRX
@@ -145,16 +155,19 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
#include "stm32wbxx.h"
#define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_HAS_SBUF_ISO 0
/* ST provided header has incorrect value of USB_PMAADDR */
#define FSDEV_PMA_BASE USB1_PMAADDR
#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
#include "stm32l4xx.h"
#define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_HAS_SBUF_ISO 0
#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
#include "stm32l5xx.h"
#define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_HAS_SBUF_ISO 0
#ifndef USB_PMAADDR
#define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
@@ -163,6 +176,7 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
#include "stm32u5xx.h"
#define FSDEV_PMA_SIZE (2048u)
+ #define FSDEV_HAS_SBUF_ISO 1
#define USB USB_DRD_FS
#define USB_EP_CTR_RX USB_EP_VTRX
@@ -186,7 +200,10 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32U0
#include "stm32u0xx.h"
- #define FSDEV_PMA_SIZE (2048u)
+ #define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_BUS_32BIT
+ // Disable SBUF_ISO on U0 for now due to bad performance (audio glitching)
+ #define FSDEV_HAS_SBUF_ISO 0
#define USB USB_DRD_FS
#define USB_EP_CTR_RX USB_EP_VTRX
@@ -248,6 +265,36 @@
#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \
USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED )
+#ifndef FSDEV_HAS_SBUF_ISO
+ #error "FSDEV_HAS_SBUF_ISO not defined"
+#endif
+
+#ifndef CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP
+ // Default configuration for double-buffered isochronous endpoints:
+ // - Enable double buffering on devices with >1KB Packet Memory Area (PMA)
+ // to improve isochronous transfer reliability and performance
+ // - Disable on devices with limited PMA to conserve memory space
+ #if FSDEV_PMA_SIZE > 1024u
+ #define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 1
+ #else
+ #define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 0
+ #endif
+#endif
+
+#if FSDEV_HAS_SBUF_ISO != 0 && CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP == 0
+ // SBUF_ISO configuration:
+ // - Some STM32 devices have special hardware support for single-buffered isochronous endpoints
+ // - When SBUF_ISO bit is available and double buffering is disabled:
+ // Enable SBUF_ISO to optimize endpoint register usage (one half of endpoint pair register)
+ #define FSDEV_USE_SBUF_ISO 1
+#else
+ // When either:
+ // - Hardware doesn't support SBUF_ISO feature, or
+ // - Double buffering is enabled for isochronous endpoints
+ // We must use the entire endpoint pair register
+ #define FSDEV_USE_SBUF_ISO 0
+#endif
+
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c
index 21f13b279..9801a485f 100644
--- a/src/portable/sunxi/dcd_sunxi_musb.c
+++ b/src/portable/sunxi/dcd_sunxi_musb.c
@@ -99,22 +99,12 @@ static void usb_phy_write(int addr, int data, int len)
}
}
-static void delay_ms(uint32_t ms)
-{
-#if CFG_TUSB_OS == OPT_OS_NONE
- int now = board_millis();
- while (board_millis() - now <= ms) asm("nop");
-#else
- osal_task_delay(ms);
-#endif
-}
-
static void USBC_HardwareReset(void)
{
// Reset phy and controller
USBC_REG_set_bit_l(USBPHY_CLK_RST_BIT, USBPHY_CLK_REG);
USBC_REG_set_bit_l(BUS_RST_USB_BIT, BUS_CLK_RST_REG);
- delay_ms(2);
+ tusb_time_delay_ms_api(2);
USBC_REG_set_bit_l(USBPHY_CLK_GAT_BIT, USBPHY_CLK_REG);
USBC_REG_set_bit_l(USBPHY_CLK_RST_BIT, USBPHY_CLK_REG);
diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c
index b001f343d..5ff18ab94 100644
--- a/src/portable/synopsys/dwc2/dwc2_common.c
+++ b/src/portable/synopsys/dwc2/dwc2_common.c
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
- * Copyright (c) 2024 Ha Thach (tinyusb.org)
+ * Copyright (c) 2024-2025 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
@@ -45,17 +45,26 @@
//
//--------------------------------------------------------------------
static void reset_core(dwc2_regs_t* dwc2) {
+ // The software must check that bit 31 in this register is set to 1 (AHB Master is Idle) before starting any operation
+ while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {
+ }
+
+ // load gsnpsid (it is not readable after reset is asserted)
+ const uint32_t gsnpsid = dwc2->gsnpsid;
+
// reset core
dwc2->grstctl |= GRSTCTL_CSRST;
- if ((dwc2->gsnpsid & DWC2_CORE_REV_MASK) < (DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) {
- // prior v42.0 CSRST is self-clearing
+ if ((gsnpsid & DWC2_CORE_REV_MASK) < (DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) {
+ // prior v4.20a: CSRST is self-clearing and the core clears this bit after all the necessary logic is reset in
+ // the core, which can take several clocks, depending on the current state of the core. Once this bit has been
+ // cleared, the software must wait at least 3 PHY clocks before accessing the PHY domain (synchronization delay).
while (dwc2->grstctl & GRSTCTL_CSRST) {}
} else {
- // From v4.20a CSRST bit is write only, CSRT_DONE (w1c) is introduced for checking.
- // CSRST must also be explicitly cleared
+ // From v4.20a: CSRST bit is write only. The application must clear this bit after checking the bit 29 of this
+ // register i.e Core Soft Reset Done CSRT_DONE (w1c)
while (!(dwc2->grstctl & GRSTCTL_CSRST_DONE)) {}
- dwc2->grstctl = (dwc2->grstctl & ~GRSTCTL_CSRST) | GRSTCTL_CSRST_DONE;
+ dwc2->grstctl = (dwc2->grstctl & ~GRSTCTL_CSRST) | GRSTCTL_CSRST_DONE;
}
while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {} // wait for AHB master IDLE
@@ -92,6 +101,14 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
const dwc2_ghwcfg4_t ghwcfg4 = {.value = dwc2->ghwcfg4};
+ uint8_t phy_width;
+ if (CFG_TUSB_MCU != OPT_MCU_AT32F402_405 && // at32f402_405 does not support 16-bit
+ ghwcfg4.phy_data_width) {
+ phy_width = 16; // 16-bit PHY interface if supported
+ } else {
+ phy_width = 8; // 8-bit PHY interface
+ }
+
// De-select FS PHY
gusbcfg &= ~GUSBCFG_PHYSEL;
@@ -119,12 +136,10 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
gusbcfg &= ~GUSBCFG_ULPI_UTMI_SEL;
// Set 16-bit interface if supported
- if (ghwcfg4.phy_data_width) {
- #if CFG_TUSB_MCU != OPT_MCU_AT32F402_405 // at32f402_405 does not actually support 16-bit
- gusbcfg |= GUSBCFG_PHYIF16; // 16 bit
- #endif
+ if (phy_width == 16) {
+ gusbcfg |= GUSBCFG_PHYIF16;
} else {
- gusbcfg &= ~GUSBCFG_PHYIF16; // 8 bit
+ gusbcfg &= ~GUSBCFG_PHYIF16;
}
}
@@ -141,13 +156,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
// - 9 if using 8-bit PHY interface
// - 5 if using 16-bit PHY interface
gusbcfg &= ~GUSBCFG_TRDT_Msk;
-
-#if CFG_TUSB_MCU == OPT_MCU_AT32F402_405 // at32f402_405 does not actually support 16-bit
- gusbcfg |= 9u << GUSBCFG_TRDT_Pos;
-#else
- gusbcfg |= (dwc2->ghwcfg4_bm.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos;
-#endif
-
+ gusbcfg |= (phy_width == 16 ? 5u : 9u) << GUSBCFG_TRDT_Pos;
dwc2->gusbcfg = gusbcfg;
// MCU specific PHY update post reset
diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h
index 49b8c54cb..a4e0d1770 100644
--- a/src/portable/synopsys/dwc2/dwc2_esp32.h
+++ b/src/portable/synopsys/dwc2/dwc2_esp32.h
@@ -47,6 +47,23 @@ static const dwc2_controller_t _dwc2_controller[] = {
{ .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 }
};
+#elif TU_CHECK_MCU(OPT_MCU_ESP32H4)
+// H4's USB_WRAP register block uses "wrap_*" field names. Map them to the
+// names used by TinyUSB's DWC2 port to keep the source unchanged.
+#define otg_conf wrap_otg_conf
+#define pad_pull_override wrap_pad_pull_override
+#define dp_pullup wrap_dp_pullup
+#define dp_pulldown wrap_dp_pulldown
+#define dm_pullup wrap_dm_pullup
+#define dm_pulldown wrap_dm_pulldown
+
+#define DWC2_FS_REG_BASE 0x60040000UL
+#define DWC2_EP_MAX 7
+
+static const dwc2_controller_t _dwc2_controller[] = {
+ { .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 }
+};
+
#elif TU_CHECK_MCU(OPT_MCU_ESP32P4)
#define DWC2_FS_REG_BASE 0x50040000UL
#define DWC2_HS_REG_BASE 0x50000000UL
diff --git a/src/portable/synopsys/dwc2/dwc2_info.md b/src/portable/synopsys/dwc2/dwc2_info.md
index 595c89b75..f655e4dba 100644
--- a/src/portable/synopsys/dwc2/dwc2_info.md
+++ b/src/portable/synopsys/dwc2/dwc2_info.md
@@ -1,58 +1,58 @@
-| | BCM2711 (Pi4) | EFM32GG | ESP32-S2/S3 | ESP32-P4 | ST F207/F407/411/429 FS | ST F407/429 HS | ST F412/76x FS | ST F723/L4P5 FS | ST F723 HS | ST F76x HS | ST H743/H750 | ST L476 FS | ST U5A5/H7RS/N6 HS | XMC4500 | GD32VF103 |
-|:---------------------------|:----------------|:-------------|:--------------|:-------------|:--------------------------|:-----------------|:-----------------|:------------------|:-------------|:-------------|:---------------|:-------------|:---------------------|:-------------|:------------|
-| GUID | 0x2708A000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00001200 | 0x00001100 | 0x00002000 | 0x00003000 | 0x00003100 | 0x00002100 | 0x00002300 | 0x00002000 | 0x00005000 | 0x00AEC000 | 0x00001000 |
-| GSNPSID | 0x4F54280A | 0x4F54330A | 0x4F54400A | 0x4F54400A | 0x4F54281A | 0x4F54281A | 0x4F54320A | 0x4F54330A | 0x4F54330A | 0x4F54320A | 0x4F54330A | 0x4F54310A | 0x4F54411A | 0x4F54292A | 0x00000000 |
-| - specs version | 2.80a | 3.30a | 4.00a | 4.00a | 2.81a | 2.81a | 3.20a | 3.30a | 3.30a | 3.20a | 3.30a | 3.10a | 4.11a | 2.92a | 0.00W |
-| GHWCFG1 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 |
-| GHWCFG2 | 0x228DDD50 | 0x228F5910 | 0x224DD930 | 0x215FFFD0 | 0x229DCD20 | 0x229ED590 | 0x229ED520 | 0x229ED520 | 0x229FE1D0 | 0x229FE190 | 0x229FE190 | 0x229ED520 | 0x228FE052 | 0x228F5930 | 0x00000000 |
-| - op_mode | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | noHNP noSRP | HNP SRP | HNP SRP |
-| - arch | DMA internal | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | Slave only | Slave only | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | DMA internal | Slave only |
-| - single_point | hub | hub | n/a | hub | n/a | hub | n/a | n/a | hub | hub | hub | n/a | hub | n/a | hub |
-| - hs_phy_type | UTMI+ | n/a | n/a | UTMI+/ULPI | n/a | ULPI | n/a | n/a | UTMI+/ULPI | ULPI | ULPI | n/a | UTMI+ | n/a | n/a |
-| - fs_phy_type | Dedicated | Dedicated | Dedicated | Shared ULPI | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | n/a | Dedicated | n/a |
-| - num_dev_ep | 7 | 6 | 6 | 15 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
-| - num_host_ch | 7 | 13 | 7 | 15 | 7 | 11 | 11 | 11 | 15 | 15 | 15 | 11 | 15 | 13 | 0 |
-| - period_channel_support | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - enable_dynamic_fifo | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - mul_proc_intrpt | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
-| - reserved21 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - nptx_q_depth | 8 | 8 | 4 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
-| - ptx_q_depth | 8 | 8 | 8 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
-| - token_q_depth | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 |
-| - otg_enable_ic_usb | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| GHWCFG3 | 0x0FF000E8 | 0x01F204E8 | 0x00C804B5 | 0x03805EB5 | 0x020001E8 | 0x03F403E8 | 0x0200D1E8 | 0x0200D1E8 | 0x03EED2E8 | 0x03EED2E8 | 0x03B8D2E8 | 0x0200D1E8 | 0x03B882E8 | 0x027A01E5 | 0x00000000 |
-| - xfer_size_width | 8 | 8 | 5 | 5 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 5 | 0 |
-| - packet_size_width | 6 | 6 | 3 | 3 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 0 |
-| - otg_enable | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - i2c_enable | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
-| - vendor_ctrl_itf | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 |
-| - optional_feature_removed | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - synch_reset | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - otg_adp_support | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
-| - otg_enable_hsic | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - battery_charger_support | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
-| - lpm_mode | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
-| - dfifo_depth | 4080 | 498 | 200 | 896 | 512 | 1012 | 512 | 512 | 1006 | 1006 | 952 | 512 | 952 | 634 | 0 |
-| GHWCFG4 | 0x1FF00020 | 0x1BF08030 | 0xD3F0A030 | 0xDFF1A030 | 0x0FF08030 | 0x17F00030 | 0x17F08030 | 0x17F08030 | 0x23F00030 | 0x23F00030 | 0xE3F00030 | 0x17F08030 | 0xE2103E30 | 0xDBF08030 | 0x00000000 |
-| - num_dev_period_in_ep | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - partial_powerdown | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - ahb_freq_min | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - extended_hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - reserved8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - enhanced_lpm_support1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - service_interval_flow | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - ipg_isoc_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - acg_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - enhanced_lpm_support | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - phy_data_width | 8 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8 bit | 8/16 bit | 8/16 bit | 8 bit | 8 bit | 8 bit | 8/16 bit | 8 bit | 8/16 bit | 8 bit |
-| - ctrl_ep_num | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - iddg_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - vbus_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
-| - a_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
-| - b_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
-| - session_end_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
-| - dedicated_fifos | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - num_dev_in_eps | 7 | 6 | 4 | 7 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
-| - dma_desc_enable | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
-| - dma_desc_dynamic | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
+| | AT32 F405 FS | AT32 F405 HS | AT32 F415 | BCM2711 (Pi4) | EFM32GG | ESP32-S2/S3 | ESP32-P4 | nRF54 | ST F207/F407/411/429 FS | ST F407/429 HS | ST F412/76x FS | ST F723/L4P5 FS | ST F723 HS | ST F76x HS | ST H743/H750 | ST L476 FS | ST U5A5/H7RS/N6 HS | XMC4500 | GD32VF103 |
+|:---------------------------|:---------------|:---------------|:------------|:----------------|:-------------|:--------------|:-------------|:-------------|:--------------------------|:-----------------|:-----------------|:------------------|:-------------|:-------------|:---------------|:-------------|:---------------------|:-------------|:------------|
+| GUID | 0x00002000 | 0x00000000 | 0x00001000 | 0x2708A000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00001200 | 0x00001100 | 0x00002000 | 0x00003000 | 0x00003100 | 0x00002100 | 0x00002300 | 0x00002000 | 0x00005000 | 0x00AEC000 | 0x00001000 |
+| GSNPSID | 0x4F54400A | 0x4F54400A | 0x4F54400A | 0x4F54280A | 0x4F54330A | 0x4F54400A | 0x4F54400A | 0x4F54430A | 0x4F54281A | 0x4F54281A | 0x4F54320A | 0x4F54330A | 0x4F54330A | 0x4F54320A | 0x4F54330A | 0x4F54310A | 0x4F54411A | 0x4F54292A | 0x00000000 |
+| - specs version | 4.00a | 4.00a | 4.00a | 2.80a | 3.30a | 4.00a | 4.00a | 4.30a | 2.81a | 2.81a | 3.20a | 3.30a | 3.30a | 3.20a | 3.30a | 3.10a | 4.11a | 2.92a | 0.00W |
+| GHWCFG1 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0xAA555000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 |
+| GHWCFG2 | 0x228FDD00 | 0x229FDDD0 | 0x228DCD00 | 0x228DDD50 | 0x228F5910 | 0x224DD930 | 0x215FFFD0 | 0x228BFC72 | 0x229DCD20 | 0x229ED590 | 0x229ED520 | 0x229ED520 | 0x229FE1D0 | 0x229FE190 | 0x229FE190 | 0x229ED520 | 0x228FE052 | 0x228F5930 | 0x00000000 |
+| - op_mode | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | noHNP noSRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | noHNP noSRP | HNP SRP | HNP SRP |
+| - arch | Slave only | DMA internal | Slave only | DMA internal | DMA internal | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | Slave only | Slave only | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | DMA internal | Slave only |
+| - single_point | hub | hub | hub | hub | hub | n/a | hub | n/a | n/a | hub | n/a | n/a | hub | hub | hub | n/a | hub | n/a | hub |
+| - hs_phy_type | n/a | UTMI+/ULPI | n/a | UTMI+ | n/a | n/a | UTMI+/ULPI | UTMI+ | n/a | ULPI | n/a | n/a | UTMI+/ULPI | ULPI | ULPI | n/a | UTMI+ | n/a | n/a |
+| - fs_phy_type | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Shared ULPI | n/a | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | n/a | Dedicated | n/a |
+| - num_dev_ep | 7 | 7 | 3 | 7 | 6 | 6 | 15 | 15 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
+| - num_host_ch | 15 | 15 | 7 | 7 | 13 | 7 | 15 | 15 | 7 | 11 | 11 | 11 | 15 | 15 | 15 | 11 | 15 | 13 | 0 |
+| - period_channel_support | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - enable_dynamic_fifo | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - mul_proc_intrpt | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - reserved21 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - nptx_q_depth | 8 | 8 | 8 | 8 | 8 | 4 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
+| - ptx_q_depth | 8 | 8 | 8 | 8 | 8 | 8 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
+| - token_q_depth | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 |
+| - otg_enable_ic_usb | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| GHWCFG3 | 0x020004E8 | 0x03F006E8 | 0x020004E8 | 0x0FF000E8 | 0x01F204E8 | 0x00C804B5 | 0x03805EB5 | 0x0BEAC0E8 | 0x020001E8 | 0x03F403E8 | 0x0200D1E8 | 0x0200D1E8 | 0x03EED2E8 | 0x03EED2E8 | 0x03B8D2E8 | 0x0200D1E8 | 0x03B882E8 | 0x027A01E5 | 0x00000000 |
+| - xfer_size_width | 8 | 8 | 8 | 8 | 8 | 5 | 5 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 5 | 0 |
+| - packet_size_width | 6 | 6 | 6 | 6 | 6 | 3 | 3 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 0 |
+| - otg_enable | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - i2c_enable | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
+| - vendor_ctrl_itf | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 |
+| - optional_feature_removed | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - synch_reset | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - otg_adp_support | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - otg_enable_hsic | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - battery_charger_support | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - lpm_mode | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
+| - dfifo_depth | 512 | 1008 | 512 | 4080 | 498 | 200 | 896 | 3050 | 512 | 1012 | 512 | 512 | 1006 | 1006 | 952 | 512 | 952 | 634 | 0 |
+| GHWCFG4 | 0x1FF0A020 | 0x1FF0A020 | 0x0000000F | 0x1FF00020 | 0x1BF08030 | 0xD3F0A030 | 0xDFF1A030 | 0x1E10AA60 | 0x0FF08030 | 0x17F00030 | 0x17F08030 | 0x17F08030 | 0x23F00030 | 0x23F00030 | 0xE3F00030 | 0x17F08030 | 0xE2103E30 | 0xDBF08030 | 0x00000000 |
+| - num_dev_period_in_ep | 0 | 0 | 15 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - partial_powerdown | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - ahb_freq_min | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - extended_hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - reserved8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - enhanced_lpm_support1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - service_interval_flow | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - ipg_isoc_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - acg_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - enhanced_lpm_support | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - phy_data_width | 8/16 bit | 8/16 bit | 8 bit | 8 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8 bit | 8/16 bit | 8/16 bit | 8 bit | 8 bit | 8 bit | 8/16 bit | 8 bit | 8/16 bit | 8 bit |
+| - ctrl_ep_num | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - iddg_filter | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - vbus_valid_filter | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - a_valid_filter | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - b_valid_filter | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - session_end_filter | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - dedicated_fifos | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - num_dev_in_eps | 7 | 7 | 0 | 7 | 6 | 4 | 7 | 7 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
+| - dma_desc_enable | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
+| - dma_desc_dynamic | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
diff --git a/src/portable/synopsys/dwc2/dwc2_info.py b/src/portable/synopsys/dwc2/dwc2_info.py
index 3b1993cc5..f6bd2785a 100755
--- a/src/portable/synopsys/dwc2/dwc2_info.py
+++ b/src/portable/synopsys/dwc2/dwc2_info.py
@@ -9,10 +9,14 @@ import pandas as pd
# Note: FS is FullSpeed, HS is HighSpeed
dwc2_reg_list = ['GUID', 'GSNPSID', 'GHWCFG1', 'GHWCFG2', 'GHWCFG3', 'GHWCFG4']
dwc2_reg_value = {
+ 'AT32 F405 FS': [0x00002000, 0x4F54400A, 0x00000000, 0x228FDD00, 0x020004E8, 0x1FF0A020],
+ 'AT32 F405 HS': [0x00000000, 0x4F54400A, 0x00000000, 0x229FDDD0, 0x03F006E8, 0x1FF0A020],
+ 'AT32 F415': [0x00001000, 0x4F54400A, 0x00000000, 0x228DCD00, 0x020004E8, 0x0F],
'BCM2711 (Pi4)': [0x2708A000, 0x4F54280A, 0, 0x228DDD50, 0xFF000E8, 0x1FF00020],
'EFM32GG': [0, 0x4F54330A, 0, 0x228F5910, 0x01F204E8, 0x1BF08030],
'ESP32-S2/S3': [0, 0x4F54400A, 0, 0x224DD930, 0x0C804B5, 0xD3F0A030],
'ESP32-P4': [0, 0x4F54400A, 0, 0x215FFFD0, 0x03805EB5, 0xDFF1A030],
+ 'nRF54': [0, 0x4F54430A, 0xAA555000, 0x228BFC72, 0x0BEAC0E8, 0x1E10AA60],
'ST F207/F407/411/429 FS': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x020001E8, 0x0FF08030],
'ST F407/429 HS': [0x1100, 0x4F54281A, 0, 0x229ED590, 0x03F403E8, 0x17F00030],
'ST F412/76x FS': [0x2000, 0x4F54320A, 0, 0x229ED520, 0x0200D1E8, 0x17F08030],
diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h
index 5f2b8419c..08950ccc0 100644
--- a/src/portable/synopsys/dwc2/dwc2_stm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_stm32.h
@@ -113,6 +113,22 @@ extern "C" {
#define EP_MAX_HS 9
#define EP_FIFO_SIZE_HS 4096
#endif
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WBA
+ #if defined(STM32WBA62xx)
+ #include "stm32wba62xx.h"
+ #elif defined(STM32WBA64xx)
+ #include "stm32wba64xx.h"
+ #elif defined(STM32WBA65xx)
+ #include "stm32wba65xx.h"
+ #else
+ #error "The selected STM32WBA series chip does not support OTG USB HS"
+ #endif
+
+ #define USB_OTG_HS_PERIPH_BASE USB_OTG_HS_BASE_NS
+ #define OTG_HS_IRQn USB_OTG_HS_IRQn
+ #define EP_MAX_HS 9
+ #define EP_FIFO_SIZE_HS 4096
#else
#error "Unsupported MCUs"
#endif
@@ -166,6 +182,7 @@ TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) {
// MCU specific PHY init, called BEFORE core reset
// - dwc2 3.30a (H5) use USB_HS_PHYC
// - dwc2 4.11a (U5) use femtoPHY
+// - dwc2 x.xxx (WBA) use USB_OTG_HS
static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
if (hs_phy_type == GHWCFG2_HSPHY_NOT_SUPPORTED) {
// Enable on-chip FS PHY
@@ -194,11 +211,10 @@ static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
#endif
} else {
-#if CFG_TUSB_MCU != OPT_MCU_STM32U5
+#if CFG_TUSB_MCU != OPT_MCU_STM32U5 && CFG_TUSB_MCU != OPT_MCU_STM32WBA
// Disable FS PHY, TODO on U5A5 (dwc2 4.11a) 16th bit is 'Host CDP behavior enable'
dwc2->stm32_gccfg &= ~STM32_GCCFG_PWRDWN;
#endif
-
// Enable on-chip HS PHY
if (hs_phy_type == GHWCFG2_HSPHY_UTMI || hs_phy_type == GHWCFG2_HSPHY_UTMI_ULPI) {
#ifdef USB_HS_PHYC
@@ -233,6 +249,9 @@ static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
// Enable PLL internal PHY
USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN;
+
+ // Wait ~2ms until the PLL is ready (there's no RDY bit to query)
+ tusb_time_delay_ms_api(2);
#else
#endif
diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
index 3752ae251..64cbc5087 100644
--- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
+++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
@@ -662,24 +662,10 @@ static void handle_setup_packet(void)
dcd_event_setup_received(0, (uint8_t*) &_setup_packet[0], true);
}
-#if CFG_TUSB_OS == OPT_OS_NONE
-TU_ATTR_ALWAYS_INLINE static inline void tu_delay(uint32_t ms) {
- // msp430 can run up to 25Mhz -> 40ns per cycle. 1 ms = 25000 cycles
- // each loop need 4 cycle: 1 sub, 1 cmp, 1 jump, 1 nop
- volatile uint32_t cycles = (25000 * ms) >> 2;
- while (cycles > 0) {
- cycles--;
- asm("nop");
- }
-}
-#else
-#define tu_delay(ms) osal_task_delay(ms)
-#endif
-
static void handle_bus_power_event(void *param) {
(void) param;
- tu_delay(5); // Bus power settling delay.
+ tusb_time_delay_ms_api(5); // Bus power settling delay.
USBKEYPID = USBKEY;
@@ -694,7 +680,7 @@ static void handle_bus_power_event(void *param) {
uint16_t attempts = 0;
do { // Poll the PLL, checking for a successful lock.
USBPLLIR = 0;
- tu_delay(1);
+ tusb_time_delay_ms_api(1);
attempts++;
} while ((attempts < 10) && (USBPLLIR != 0));
diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c
index d176f40c5..200136906 100644
--- a/src/portable/wch/hcd_ch32_usbfs.c
+++ b/src/portable/wch/hcd_ch32_usbfs.c
@@ -28,6 +28,8 @@
#if CFG_TUH_ENABLED && defined(TUP_USBIP_WCH_USBFS) && defined(CFG_TUH_WCH_USBIP_USBFS) && CFG_TUH_WCH_USBIP_USBFS
+#include <stdlib.h>
+
#include "host/hcd.h"
#include "host/usbh.h"
#include "host/usbh_pvt.h"
@@ -55,19 +57,17 @@ TU_ATTR_ALIGNED(4) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN];
#define LOG_CH32_USBFSH(...) TU_LOG3(__VA_ARGS__)
// Busywait for delay microseconds/nanoseconds
-// static void loopdelay(uint32_t count)
-// {
-// volatile uint32_t c = count / 3;
-// if (c == 0) { return; }
-// // while (c-- != 0);
-// asm volatile(
-// "1: \n" // loop label
-// " addi %0, %0, -1 \n" // c--
-// " bne %0, zero, 1b \n" // if (c != 0) goto loop
-// : "+r"(c) // c is input/output operand
-// );
-// }
-
+TU_ATTR_ALWAYS_INLINE static inline void loopdelay(uint32_t count) {
+ volatile uint32_t c = count / 3;
+ if (c == 0) { return; }
+ // while (c-- != 0);
+ asm volatile(
+ "1: \n" // loop label
+ " addi %0, %0, -1 \n" // c--
+ " bne %0, zero, 1b \n" // if (c != 0) goto loop
+ : "+r"(c) // c is input/output operand
+ );
+}
// Endpoint status
typedef struct usb_edpt {
@@ -82,6 +82,10 @@ typedef struct usb_edpt {
// Data toggle (0 or not 0) for DATA0/1
uint8_t data_toggle;
+
+ bool is_nak_pending;
+ uint16_t buflen;
+ uint8_t* buf;
} usb_edpt_t;
static usb_edpt_t usb_edpt_list[CFG_TUH_DEVICE_MAX * 6] = {};
@@ -95,6 +99,7 @@ typedef struct usb_current_xfer_st {
uint8_t *buffer;
uint16_t bufferlen;
uint16_t xferred_len;
+ bool nak_pending;
} usb_current_xfer_t;
static volatile usb_current_xfer_t usb_current_xfer_info = {};
@@ -120,9 +125,6 @@ static usb_edpt_t *get_empty_record_slot(void) {
static usb_edpt_t *add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) {
usb_edpt_t *slot = get_empty_record_slot();
- if (slot == NULL) {
- PANIC("add_edpt_record(0x%02x, 0x%02x, ...) no slot for new record\r\n", dev_addr, ep_addr);
- }
TU_ASSERT(slot != NULL, NULL);
slot->dev_addr = dev_addr;
@@ -130,6 +132,9 @@ static usb_edpt_t *add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t m
slot->max_packet_size = max_packet_size;
slot->xfer_type = xfer_type;
slot->data_toggle = 0;
+ slot->is_nak_pending = false;
+ slot->buflen = 0;
+ slot->buf = NULL;
slot->configured = true;
@@ -197,10 +202,13 @@ static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggl
: "(other)",
pid, ep_addr, data_toggle);
- // if (pid == USB_PID_IN)
- // { // FIXME: long delay needed (at release build) about 30msec
- // loopdelay(SystemCoreClock / 1000 * 30);
- // }
+ //WORKAROUND: For LowSpeed device, insert small delay
+ bool is_lowspeed_device = tuh_speed_get(usb_current_xfer_info.dev_addr) == TUSB_SPEED_LOW;
+ if (is_lowspeed_device) {
+ //NOTE: worked -> SystemCoreClock / 1000000 * 50, 25
+ // NOT worked -> 20 and less (at 144MHz internal clock)
+ loopdelay(SystemCoreClock / 1000000 * 40);
+ }
uint8_t pid_edpt = (pid << 4) | (tu_edpt_number(ep_addr) & 0x0f);
USBOTG_H_FS->HOST_TX_CTRL = (data_toggle != 0) ? USBFS_UH_T_TOG : 0;
@@ -336,7 +344,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
uint32_t hcd_frame_number(uint8_t rhport) {
(void) rhport;
- return board_millis();
+ return tusb_time_millis_api();
}
void hcd_int_enable(uint8_t rhport) {
@@ -351,6 +359,28 @@ void hcd_int_disable(uint8_t rhport) {
interrupt_enabled = false;
}
+
+static void xfer_retry(void* _params) {
+ LOG_CH32_USBFSH("xfer_retry()\r\n");
+ usb_edpt_t* edpt_info = (usb_edpt_t*)_params;
+ if (usb_current_xfer_info.nak_pending) {
+ usb_current_xfer_info.nak_pending = false;
+ edpt_info->is_nak_pending = false;
+
+ uint8_t dev_addr = edpt_info->dev_addr;
+ uint8_t ep_addr = edpt_info->ep_addr;
+ uint16_t buflen = edpt_info->buflen;
+ uint8_t* buf = edpt_info->buf;
+
+ // Check connectivity
+ usb_edpt_t* edpt_info_current = get_edpt_record(dev_addr, ep_addr);
+ if (edpt_info_current) {
+ hcd_edpt_xfer(0, dev_addr, ep_addr, buf, buflen);
+ }
+ }
+}
+
+
void hcd_int_handler(uint8_t rhport, bool in_isr) {
(void) rhport;
(void) in_isr;
@@ -407,15 +437,12 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
if (usb_current_xfer_info.bufferlen == 0) {
LOG_CH32_USBFSH("USB_PID_%s completed %d bytes\r\n", request_pid == USB_PID_OUT ? "OUT" : "SETUP", usb_current_xfer_info.xferred_len);
usb_current_xfer_info.is_busy = false;
- hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.xferred_len, XFER_RESULT_SUCCESS, true);
+ hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.xferred_len, XFER_RESULT_SUCCESS, in_isr);
return;
} else {
LOG_CH32_USBFSH("USB_PID_OUT continue...\r\n");
usb_current_xfer_info.buffer += tx_len;
- uint16_t copylen = USBFS_TX_BUF_LEN;
- if (copylen > usb_current_xfer_info.bufferlen) {
- copylen = usb_current_xfer_info.bufferlen;
- }
+ uint16_t copylen = TU_MIN(edpt_info->max_packet_size, usb_current_xfer_info.bufferlen);
memcpy(USBFS_TX_Buf, usb_current_xfer_info.buffer, copylen);
hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle);
return;
@@ -435,7 +462,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
// USB device sent all data.
LOG_CH32_USBFSH("USB_PID_IN completed\r\n");
usb_current_xfer_info.is_busy = false;
- hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true);
+ hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, in_isr);
return;
} else {
// USB device may send more data.
@@ -445,7 +472,10 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
}
}
default: {
- PANIC("Unknown PID: 0x%02x\n", request_pid);
+ LOG_CH32_USBFSH("hcd_int_handler() L%d: unexpected response PID: 0x%02x\r\n", __LINE__, response_pid);
+ usb_current_xfer_info.is_busy = false;
+ hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr);
+ return;
}
}
} else {
@@ -457,26 +487,42 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
return;
} else if (response_pid == USB_PID_NAK) {
LOG_CH32_USBFSH("NAK reposense\r\n");
- uint32_t elapsed_time = board_millis() - usb_current_xfer_info.start_ms;
+ uint32_t elapsed_time = tusb_time_millis_api() - usb_current_xfer_info.start_ms;
+ (void)elapsed_time;
if (edpt_info->xfer_type == TUSB_XFER_INTERRUPT) {
usb_current_xfer_info.is_busy = false;
- hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true);
- } else if (elapsed_time > USB_XFER_TIMEOUT_MILLIS) {
- usb_current_xfer_info.is_busy = false;
- hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true);
+ hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, in_isr);
+
} else {
- hardware_start_xfer(request_pid, ep_addr, edpt_info->data_toggle);
+ usb_current_xfer_info.is_busy = false;
+ usb_current_xfer_info.nak_pending = true;
+
+
+ edpt_info->is_nak_pending = true;
+ edpt_info->buflen = usb_current_xfer_info.bufferlen;
+ edpt_info->buf = usb_current_xfer_info.buffer;
+
+ hcd_event_t event = {
+ .rhport = rhport,
+ .dev_addr = dev_addr,
+ .event_id = USBH_EVENT_FUNC_CALL,
+ .func_call = {
+ .func = xfer_retry,
+ .param = edpt_info
+ }
+ };
+ hcd_event_handler(&event, in_isr);
}
return;
} else if (response_pid == USB_PID_DATA0 || response_pid == USB_PID_DATA1) {
LOG_CH32_USBFSH("Data toggle mismatched and DATA0/1 (not STALL). RX_LEN=%d\r\n", USBOTG_H_FS->RX_LEN);
usb_current_xfer_info.is_busy = false;
- hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true);
+ hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr);
return;
} else {
- LOG_CH32_USBFSH("In USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid);
+ LOG_CH32_USBFSH("hcd_int_handler() L%d: unexpected response PID: 0x%02x\r\n", __LINE__, response_pid);
usb_current_xfer_info.is_busy = false;
- hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true);
+ hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr);
return;
}
}
@@ -495,6 +541,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
uint8_t xfer_type = ep_desc->bmAttributes.xfer;
LOG_CH32_USBFSH("hcd_edpt_open(rhport=%d, dev_addr=0x%02x, %p) EndpointAdderss=0x%02x,maxPacketSize=%d,xfer_type=%d\r\n", rhport, dev_addr, ep_desc, ep_addr, max_packet_size, xfer_type);
+ while (usb_current_xfer_info.is_busy) { }
+
if (ep_num == 0x00) {
TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x00, max_packet_size, xfer_type) != NULL, false);
TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x80, max_packet_size, xfer_type) != NULL, false);
@@ -519,9 +567,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
usb_current_xfer_info.is_busy = true;
usb_edpt_t *edpt_info = get_edpt_record(dev_addr, ep_addr);
- if (edpt_info == NULL) {
- PANIC("get_edpt_record() returned NULL in hcd_edpt_xfer()\r\n");
- }
+ TU_ASSERT(edpt_info != NULL);
hardware_set_port_address_speed(dev_addr);
@@ -529,18 +575,16 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
usb_current_xfer_info.ep_addr = ep_addr;
usb_current_xfer_info.buffer = buffer;
usb_current_xfer_info.bufferlen = buflen;
- usb_current_xfer_info.start_ms = board_millis();
+ usb_current_xfer_info.start_ms = tusb_time_millis_api();
usb_current_xfer_info.xferred_len = 0;
+ usb_current_xfer_info.nak_pending = false;
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
LOG_CH32_USBFSH("hcd_edpt_xfer(): READ, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen);
return hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle);
} else {
LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen);
- uint16_t copylen = USBFS_TX_BUF_LEN;
- if (copylen > buflen) {
- copylen = buflen;
- }
+ uint16_t copylen = TU_MIN(edpt_info->max_packet_size, buflen);
USBOTG_H_FS->HOST_TX_LEN = copylen;
memcpy(USBFS_TX_Buf, buffer, copylen);
return hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle);
@@ -582,10 +626,11 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
uint8_t ep_addr = (setup_packet[0] & 0x80) ? 0x80 : 0x00;
usb_current_xfer_info.dev_addr = dev_addr;
usb_current_xfer_info.ep_addr = ep_addr;
- usb_current_xfer_info.start_ms = board_millis();
+ usb_current_xfer_info.start_ms = tusb_time_millis_api();
usb_current_xfer_info.buffer = USBFS_TX_Buf;
usb_current_xfer_info.bufferlen = setup_packet_datalen;
usb_current_xfer_info.xferred_len = 0;
+ usb_current_xfer_info.nak_pending = false;
hardware_start_xfer(USB_PID_SETUP, 0, 0);
@@ -596,7 +641,6 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
(void) rhport;
(void) dev_addr;
LOG_CH32_USBFSH("hcd_edpt_clear_stall(rhport=%d, dev_addr=0x%02x, ep_addr=0x%02x)\r\n", rhport, dev_addr, ep_addr);
- // PANIC("\r\install\r\n");
uint8_t edpt_num = tu_edpt_number(ep_addr);
uint8_t setup_request_clear_stall[8] = {
0x02, 0x01, 0x00, 0x00, edpt_num, 0x00, 0x00, 0x00