From b5a4f18879110d9f5f8fe27c473818f2416e40e4 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 17 Oct 2024 15:56:12 +0700 Subject: [PATCH] get hpri triggered --- src/portable/synopsys/dwc2/dcd_dwc2.c | 4 +- src/portable/synopsys/dwc2/dwc2_common.c | 76 +++++++---- src/portable/synopsys/dwc2/dwc2_stm32.h | 16 ++- src/portable/synopsys/dwc2/dwc2_type.h | 27 ++-- src/portable/synopsys/dwc2/hcd_dwc2.c | 156 ++++++++++++++++++++--- src/tusb.c | 2 +- 6 files changed, 217 insertions(+), 64 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 6760af3f3..55d8f5766 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -486,8 +486,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // Enable required interrupts dwc2->gintmsk |= GINTMSK_OTGINT | GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM; - // Configure TX FIFO empty level for interrupt. Default is complete empty - dwc2->gahbcfg |= GAHBCFG_TXFELVL; + // Enable global interrupt + dwc2->gahbcfg |= GAHBCFG_GINT; dcd_connect(rhport); return true; diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c index 50d0c28b3..12dcdb7c6 100644 --- a/src/portable/synopsys/dwc2/dwc2_common.c +++ b/src/portable/synopsys/dwc2/dwc2_common.c @@ -44,18 +44,21 @@ static void reset_core(dwc2_regs_t* dwc2) { // reset core dwc2->grstctl |= GRSTCTL_CSRST; - // wait for reset bit is cleared - // TODO version 4.20a should wait for RESET DONE mask - while (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 + 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 + while (!(dwc2->grstctl & GRSTCTL_CSRST_DONE)) {} + dwc2->grstctl = (dwc2->grstctl & ~GRSTCTL_CSRST) | GRSTCTL_CSRST_DONE; + } - // wait for AHB master IDLE - while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {} - - // wait for device mode ? + while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {} // wait for AHB master IDLE } bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, const tusb_rhport_init_t* rh_init) { - (void) dwc2; + (void)dwc2; #if CFG_TUD_ENABLED if (rh_init->role == TUSB_ROLE_DEVICE && !TUD_OPT_HIGH_SPEED) { @@ -71,11 +74,14 @@ bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, const tusb_rhport_init_t* rh_init return dwc2->ghwcfg2_bm.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED; } -static void phy_fs_init(dwc2_regs_t* dwc2) { +static void phy_fs_init(dwc2_regs_t* dwc2, tusb_role_t role) { TU_LOG(DWC2_COMMON_DEBUG, "Fullspeed PHY init\r\n"); + uint32_t gusbcfg = dwc2->gusbcfg; + // Select FS PHY - dwc2->gusbcfg |= GUSBCFG_PHYSEL; + gusbcfg |= GUSBCFG_PHYSEL; + dwc2->gusbcfg = gusbcfg; // MCU specific PHY init before reset dwc2_phy_init(dwc2, GHWCFG2_HSPHY_NOT_SUPPORTED); @@ -86,13 +92,33 @@ static void phy_fs_init(dwc2_regs_t* dwc2) { // USB turnaround time is critical for certification where long cables and 5-Hubs are used. // So if you need the AHB to run at less than 30 MHz, and if USB turnaround time is not critical, // these bits can be programmed to a larger value. Default is 5 - dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos); + gusbcfg &= ~GUSBCFG_TRDT_Msk; + gusbcfg |= 5u << GUSBCFG_TRDT_Pos; + dwc2->gusbcfg = gusbcfg; + + // FS/LS PHY Clock Select + if (role == TUSB_ROLE_HOST) { + uint32_t hcfg = dwc2->hcfg; + hcfg |= HCFG_FSLS_ONLY; + hcfg &= ~HCFG_FSLS_PHYCLK_SEL; + + if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI && + dwc2->ghwcfg2_bm.fs_phy_type == GHWCFG2_FSPHY_DEDICATED) { + // dedicated FS PHY with 48 mhz + hcfg |= HCFG_FSLS_PHYCLK_SEL_48MHZ; + } else { + // shared HS PHY running at full speed + hcfg |= HCFG_FSLS_PHYCLK_SEL_30_60MHZ; + } + dwc2->hcfg = hcfg; + } // MCU specific PHY update post reset dwc2_phy_update(dwc2, GHWCFG2_HSPHY_NOT_SUPPORTED); } -static void phy_hs_init(dwc2_regs_t* dwc2) { +static void phy_hs_init(dwc2_regs_t* dwc2, tusb_role_t role) { + (void) role; uint32_t gusbcfg = dwc2->gusbcfg; // De-select FS PHY @@ -123,8 +149,8 @@ static void phy_hs_init(dwc2_regs_t* dwc2) { // Set 16-bit interface if supported if (dwc2->ghwcfg4_bm.phy_data_width) { - gusbcfg |= GUSBCFG_PHYIF16; // 16 bit - }else { + gusbcfg |= GUSBCFG_PHYIF16; // 16 bit + } else { gusbcfg &= ~GUSBCFG_PHYIF16; // 8 bit } } @@ -138,6 +164,10 @@ static void phy_hs_init(dwc2_regs_t* dwc2) { // Reset core after selecting PHY reset_core(dwc2); + if (role == TUSB_ROLE_HOST) { + dwc2->hcfg &= ~HCFG_FSLS_ONLY; + } + // Set turn-around, must after core reset otherwise it will be clear // - 9 if using 8-bit PHY interface // - 5 if using 16-bit PHY interface @@ -162,7 +192,7 @@ static bool check_dwc2(dwc2_regs_t* dwc2) { #endif // For some reason: GD32VF103 gsnpsid and all hwcfg register are always zero (skip it) - (void) dwc2; + (void)dwc2; #if !TU_CHECK_MCU(OPT_MCU_GD32VF103) uint32_t const gsnpsid = dwc2->gsnpsid & GSNPSID_ID_MASK; TU_ASSERT(gsnpsid == DWC2_OTG_ID || gsnpsid == DWC2_FS_IOT_ID || gsnpsid == DWC2_HS_IOT_ID); @@ -175,16 +205,16 @@ static bool check_dwc2(dwc2_regs_t* dwc2) { // //-------------------------------------------------------------------- bool dwc2_core_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rh_init; + (void)rh_init; dwc2_regs_t* dwc2 = DWC2_REG(rhport); // Check Synopsys ID register, failed if controller clock/power is not enabled TU_ASSERT(check_dwc2(dwc2)); if (dwc2_core_is_highspeed(dwc2, rh_init)) { - phy_hs_init(dwc2); // Highspeed + phy_hs_init(dwc2, rh_init->role); } else { - phy_fs_init(dwc2); // core does not support highspeed or hs phy is not present + phy_fs_init(dwc2, rh_init->role); } /* Set HS/FS Timeout Calibration to 7 (max available value). @@ -211,20 +241,20 @@ bool dwc2_core_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { int_mask = dwc2->gotgint; dwc2->gotgint |= int_mask; - dwc2->gintmsk = GINTMSK_OTGINT; + dwc2->gintmsk = 0; - if (dwc2_dma_enabled(dwc2, TUSB_ROLE_DEVICE)) { + if (dwc2_dma_enabled(dwc2, rh_init->role)) { const uint16_t epinfo_base = dma_cal_epfifo_base(rhport); dwc2->gdfifocfg = (epinfo_base << GDFIFOCFG_EPINFOBASE_SHIFT) | epinfo_base; // DMA seems to be only settable after a core reset, and not possible to switch on-the-fly dwc2->gahbcfg |= GAHBCFG_DMAEN | GAHBCFG_HBSTLEN_2; - }else { + } else { dwc2->gintmsk |= GINTMSK_RXFLVLM; } - // Enable global interrupt - dwc2->gahbcfg |= GAHBCFG_GINT; + // Configure TX FIFO empty level for interrupt. Default is complete empty + dwc2->gahbcfg |= GAHBCFG_TXFELVL; return true; } diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h index 395b6d870..8719c4820 100644 --- a/src/portable/synopsys/dwc2/dwc2_stm32.h +++ b/src/portable/synopsys/dwc2/dwc2_stm32.h @@ -124,13 +124,19 @@ static const dwc2_controller_t _dwc2_controller[] = { // SystemCoreClock is already included by family header // extern uint32_t SystemCoreClock; -TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_enable(uint8_t rhport) { - NVIC_EnableIRQ((IRQn_Type) _dwc2_controller[rhport].irqnum); +TU_ATTR_ALWAYS_INLINE static inline void dwc2_int_set(uint8_t rhport, tusb_role_t role, bool enabled) { + (void) role; + const IRQn_Type irqn = (IRQn_Type) _dwc2_controller[rhport].irqnum; + if (enabled) { + NVIC_EnableIRQ(irqn); + } else { + NVIC_DisableIRQ(irqn); + } } -TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_disable(uint8_t rhport) { - NVIC_DisableIRQ((IRQn_Type) _dwc2_controller[rhport].irqnum); -} +#define dwc2_dcd_int_enable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, true) +#define dwc2_dcd_int_disable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, false) + TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) { // try to delay for 1 ms diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index c8f6a5d1f..f99bf3e85 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -566,14 +566,15 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); #define GOTGCTL_OTGVER GOTGCTL_OTGVER_Msk // OTG version /******************** Bit definition for HCFG register ********************/ -#define HCFG_FSLSPCS_Pos (0U) -#define HCFG_FSLSPCS_Msk (0x3UL << HCFG_FSLSPCS_Pos) // 0x00000003 -#define HCFG_FSLSPCS HCFG_FSLSPCS_Msk // FS/LS PHY clock select -#define HCFG_FSLSPCS_0 (0x1UL << HCFG_FSLSPCS_Pos) // 0x00000001 -#define HCFG_FSLSPCS_1 (0x2UL << HCFG_FSLSPCS_Pos) // 0x00000002 -#define HCFG_FSLSS_Pos (2U) -#define HCFG_FSLSS_Msk (0x1UL << HCFG_FSLSS_Pos) // 0x00000004 -#define HCFG_FSLSS HCFG_FSLSS_Msk // FS- and LS-only support +#define HCFG_FSLS_PHYCLK_SEL_Pos (0U) +#define HCFG_FSLS_PHYCLK_SEL_Msk (0x3UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000003 +#define HCFG_FSLS_PHYCLK_SEL HCFG_FSLS_PHYCLK_SEL_Msk // FS/LS PHY clock select +#define HCFG_FSLS_PHYCLK_SEL_30_60MHZ (0x0UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000000 +#define HCFG_FSLS_PHYCLK_SEL_48MHZ (0x1UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000001 + +#define HCFG_FSLS_ONLY_Pos (2U) +#define HCFG_FSLS_ONLY_Msk (0x1UL << HCFG_FSLS_ONLY_Pos) // 0x00000004 +#define HCFG_FSLS_ONLY HCFG_FSLS_ONLY_Msk // FS- and LS-only support /******************** Bit definition for PCGCR register ********************/ #define PCGCR_STPPCLK_Pos (0U) @@ -828,8 +829,8 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); #define GRSTCTL_TXFNUM_2 (0x04UL << GRSTCTL_TXFNUM_Pos) // 0x00000100 #define GRSTCTL_TXFNUM_3 (0x08UL << GRSTCTL_TXFNUM_Pos) // 0x00000200 #define GRSTCTL_TXFNUM_4 (0x10UL << GRSTCTL_TXFNUM_Pos) // 0x00000400 -#define GRSTCTL_CSFTRST_DONE_Pos (29) -#define GRSTCTL_CSFTRST_DONE (1u << GRSTCTL_CSFTRST_DONE_Pos) // Reset Done, only available from v4.20a +#define GRSTCTL_CSRST_DONE_Pos (29) +#define GRSTCTL_CSRST_DONE (1u << GRSTCTL_CSRST_DONE_Pos) // Reset Done, only available from v4.20a #define GRSTCTL_DMAREQ_Pos (30U) #define GRSTCTL_DMAREQ_Msk (0x1UL << GRSTCTL_DMAREQ_Pos) // 0x40000000 #define GRSTCTL_DMAREQ GRSTCTL_DMAREQ_Msk // DMA request signal @@ -1475,9 +1476,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); #define HPRT_CONN_STATUS_Pos (0U) #define HPRT_CONN_STATUS_Msk (0x1UL << HPRT_CONN_STATUS_Pos) // 0x00000001 #define HPRT_CONN_STATUS HPRT_CONN_STATUS_Msk // Port connect status -#define HPRT_CONN_DETECTEDT_Pos (1U) -#define HPRT_CONN_DETECTEDT_Msk (0x1UL << HPRT_CONN_DETECTEDT_Pos) // 0x00000002 -#define HPRT_CONN_DETECTEDT HPRT_CONN_DETECTEDT_Msk // Port connect detected +#define HPRT_CONN_DETECT_Pos (1U) +#define HPRT_CONN_DETECT_Msk (0x1UL << HPRT_CONN_DETECT_Pos) // 0x00000002 +#define HPRT_CONN_DETECT HPRT_CONN_DETECT_Msk // Port connect detected #define HPRT_ENABLE_Pos (2U) #define HPRT_ENABLE_Msk (0x1UL << HPRT_ENABLE_Pos) // 0x00000004 #define HPRT_ENABLE HPRT_ENABLE_Msk // Port enable diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index b383b4069..97068d4c5 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -34,6 +34,10 @@ #include "host/hcd.h" #include "dwc2_common.h" +enum { + HPRT_W1C_MASK = HPRT_CONN_DETECT | HPRT_ENABLE | HPRT_EN_CHANGE | HPRT_OVER_CURRENT_CHANGE +}; + //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ @@ -54,40 +58,41 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // Core Initialization TU_ASSERT(dwc2_core_init(rhport, rh_init)); + //------------- 3.1 Host Initialization -------------// + + // max speed + // if (dwc2_core_is_highspeed(dwc2, rh_init)) { + // dwc2->hcfg &= ~HCFG_FSLS_ONLY; + // } else { + // dwc2->hcfg |= HCFG_FSLS_ONLY; + // } + // force host mode dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FDMOD) | GUSBCFG_FHMOD; - //------------- 3.1 Host Initialization -------------// + dwc2->hprt = HPRT_W1C_MASK; // clear all write-1-clear bits + dwc2->hprt = HPRT_POWER; // port power on -> drive VBUS + // Enable required interrupts dwc2->gintmsk |= GINTMSK_OTGINT | GINTMSK_PRTIM | GINTMSK_WUIM; - - // max speed - if (dwc2_core_is_highspeed(dwc2, rh_init)) { - dwc2->hcfg &= ~HCFG_FSLSS; - } else { - dwc2->hcfg |= HCFG_FSLSS; - } - - // port power on -> drive VBUS - dwc2->hprt = HPRT_POWER; + dwc2->gahbcfg |= GAHBCFG_GINT; // Enable global interrupt return true; } // Enable USB interrupt void hcd_int_enable (uint8_t rhport) { - (void) rhport; + dwc2_int_set(rhport, TUSB_ROLE_HOST, true); } // Disable USB interrupt void hcd_int_disable(uint8_t rhport) { - (void) rhport; + dwc2_int_set(rhport, TUSB_ROLE_HOST, false); } // Get frame number (1ms) uint32_t hcd_frame_number(uint8_t rhport) { (void) rhport; - return 0; } @@ -97,20 +102,23 @@ uint32_t hcd_frame_number(uint8_t rhport) { // Get the current connect status of roothub port bool hcd_port_connect_status(uint8_t rhport) { - (void) rhport; - - return false; + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + return dwc2->hprt & HPRT_CONN_STATUS; } // Reset USB bus on the port. Return immediately, bus reset sequence may not be complete. // Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence. void hcd_port_reset(uint8_t rhport) { - (void) rhport; + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + dwc2->hprt = HPRT_RESET; } // Complete bus reset sequence, may be required by some controllers void hcd_port_reset_end(uint8_t rhport) { - (void) rhport; + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + uint32_t hprt = dwc2->hprt & ~HPRT_W1C_MASK; // skip w1c bits + hprt &= ~HPRT_RESET; + dwc2->hprt = hprt; } // Get port link speed @@ -182,6 +190,101 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { // HCD Event Handler //-------------------------------------------------------------------- +#if 1 +static void handle_rxflvl_irq(uint8_t rhport) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + volatile uint32_t const* rx_fifo = dwc2->fifo[0]; + + // Pop control word off FIFO + uint32_t const grxstsp = dwc2->grxstsp; + uint8_t const pktsts = (grxstsp & GRXSTSP_PKTSTS_Msk) >> GRXSTSP_PKTSTS_Pos; + uint8_t const epnum = (grxstsp & GRXSTSP_EPNUM_Msk) >> GRXSTSP_EPNUM_Pos; + uint16_t const bcnt = (grxstsp & GRXSTSP_BCNT_Msk) >> GRXSTSP_BCNT_Pos; + // dwc2_epout_t* epout = &dwc2->epout[epnum]; + + (void) epnum; (void) bcnt; (void) rx_fifo; + + TU_LOG1_INT(pktsts); + + // switch (pktsts) { + // // Global OUT NAK: do nothing + // case GRXSTS_PKTSTS_GLOBALOUTNAK: + // break; + // + // case GRXSTS_PKTSTS_SETUPRX: + // // Setup packet received + // // We can receive up to three setup packets in succession, but only the last one is valid. + // _setup_packet[0] = (*rx_fifo); + // _setup_packet[1] = (*rx_fifo); + // break; + // + // case GRXSTS_PKTSTS_SETUPDONE: + // // 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_OUTRX: { + // // Out packet received + // xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); + // + // // Read packet off RxFIFO + // if (xfer->ff) { + // // Ring buffer + // tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void*) (uintptr_t) rx_fifo, bcnt); + // } else { + // // Linear buffer + // dfifo_read_packet(rhport, xfer->buffer, bcnt); + // + // // Increment pointer to xfer data + // xfer->buffer += bcnt; + // } + // + // // Truncate transfer length in case of short packet + // if (bcnt < xfer->max_size) { + // xfer->total_len -= (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; + // if (epnum == 0) { + // xfer->total_len -= ep0_pending[TUSB_DIR_OUT]; + // ep0_pending[TUSB_DIR_OUT] = 0; + // } + // } + // break; + // } + // + // case GRXSTS_PKTSTS_OUTDONE: + // /* 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: + // TU_BREAKPOINT(); + // break; + // } +} +#endif + +/* Handle Host Port interrupt, possible source are: + - Connection Detection + - Enable Change + - Over Current Change +*/ +TU_ATTR_ALWAYS_INLINE static inline void handle_hprt_irq(uint8_t rhport, bool in_isr) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + uint32_t hprt = dwc2->hprt; + + if (hprt & HPRT_CONN_DETECT) { + // Port Connect Detect + dwc2->hprt = HPRT_CONN_DETECT; // clear + + if (hprt & HPRT_CONN_STATUS) { + hcd_event_device_attach(rhport, in_isr); + } else { + hcd_event_device_remove(rhport, in_isr); + } + } +} + /* Interrupt Hierarchy HCINTn.XferCompl HCINTMSKn.XferComplMsk @@ -201,7 +304,6 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { IRQn */ void hcd_int_handler(uint8_t rhport, bool in_isr) { - (void) in_isr; dwc2_regs_t* dwc2 = DWC2_REG(rhport); const uint32_t int_mask = dwc2->gintmsk; @@ -209,7 +311,21 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { if (int_status & GINTSTS_HPRTINT) { TU_LOG1_HEX(dwc2->hprt); + handle_hprt_irq(rhport, in_isr); } + + // RxFIFO non-empty interrupt handling. + if (int_status & 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 diff --git a/src/tusb.c b/src/tusb.c index e6f8055b7..6a0cc0805 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -77,6 +77,7 @@ bool tusb_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // new API with explicit rhport and role TU_ASSERT(rhport < TUP_USBIP_CONTROLLER_NUM && rh_init->role != TUSB_ROLE_INVALID); + _rhport_role[rhport] = rh_init->role; #if CFG_TUD_ENABLED if (rh_init->role == TUSB_ROLE_DEVICE) { @@ -90,7 +91,6 @@ bool tusb_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { } #endif - _rhport_role[rhport] = rh_init->role; return true; }