From daef846aa73dc2b8edf5e072832833a6ae68b42a Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 14 Nov 2024 13:26:11 +0700 Subject: [PATCH 1/9] rename CFG_TUD_DWC2_DMA to CFG_TUD_DWC2_DMA_ENABLE --- src/common/tusb_mcu.h | 2 +- src/portable/synopsys/dwc2/dcd_dwc2.c | 4 +--- src/tusb_option.h | 4 ++-- test/hil/tinyusb.json | 8 ++++---- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 41f552d33d..0a039eadf0 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -538,7 +538,7 @@ #define TUP_DCD_EDPT_ISO_ALLOC #endif -#if defined(TUP_USBIP_DWC2) // && CFG_TUD_DWC2_DMA == 0 +#if defined(TUP_USBIP_DWC2) // && CFG_TUD_DWC2_DMA_ENABLE == 0 #define TUP_MEM_CONST_ADDR #endif diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index fe67de8dc1..80287305a4 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -71,7 +71,7 @@ static bool _sof_en; TU_ATTR_ALWAYS_INLINE static inline bool dma_device_enabled(const dwc2_regs_t* dwc2) { (void) dwc2; // Internal DMA only - return CFG_TUD_DWC2_DMA && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA; + return CFG_TUD_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA; } static void dma_setup_prepare(uint8_t rhport) { @@ -897,8 +897,6 @@ static void handle_epin_irq(uint8_t rhport) { Note: when OTG_MULTI_PROC_INTRPT = 1, Device Each endpoint interrupt deachint/deachmsk/diepeachmsk/doepeachmsk are combined to generate dedicated interrupt line for each endpoint. */ - - void dcd_int_handler(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); diff --git a/src/tusb_option.h b/src/tusb_option.h index e9b6a5806f..6257a87ba4 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -252,8 +252,8 @@ // (defined by CFG_TUSB_MEM_SECTION) must be declared as non-cacheable. // For example, on Cortex-M7 the MPU region can be configured as normal // non-cacheable, with RASR register value: TEX=1 C=0 B=0 S=0. -#ifndef CFG_TUD_DWC2_DMA - #define CFG_TUD_DWC2_DMA 0 +#ifndef CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUD_DWC2_DMA_ENABLE 0 #endif // Enable DWC2 Slave mode for host diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index c15daf1d99..b6c9b540ac 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -17,7 +17,7 @@ "name": "espressif_s3_devkitm", "uid": "84F703C084E4", "build" : { - "flags_on": ["", "CFG_TUD_DWC2_DMA"] + "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"] }, "tests": { "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos"] @@ -130,7 +130,7 @@ "name": "stm32f723disco", "uid": "460029001951373031313335", "build" : { - "flags_on": ["", "CFG_TUD_DWC2_DMA"] + "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"] }, "tests": { "device": true, "host": true, "dual": false, @@ -146,7 +146,7 @@ "name": "stm32h743nucleo", "uid": "110018000951383432343236", "build" : { - "flags_on": ["", "CFG_TUD_DWC2_DMA"] + "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"] }, "tests": { "device": true, "host": false, "dual": false @@ -175,7 +175,7 @@ "name": "stm32f769disco", "uid": "21002F000F51363531383437", "build" : { - "flags_on": ["", "CFG_TUD_DWC2_DMA"] + "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"] }, "tests": { "device": true, "host": false, "dual": false From a68c53fb8e3cdf58a95a92b6e079105d194e2c0d Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 14 Nov 2024 17:34:14 +0700 Subject: [PATCH 2/9] clean up, add typdef for dwc2 type for device --- src/portable/synopsys/dwc2/dcd_dwc2.c | 192 +++++++++++------------ src/portable/synopsys/dwc2/dwc2_common.c | 9 +- src/portable/synopsys/dwc2/dwc2_common.h | 2 +- src/portable/synopsys/dwc2/dwc2_type.h | 173 +++++++++++++++----- src/portable/synopsys/dwc2/hcd_dwc2.c | 10 +- 5 files changed, 243 insertions(+), 143 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 80287305a4..ae6377a49b 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -37,6 +37,12 @@ #include "device/dcd.h" #include "dwc2_common.h" +#if TU_CHECK_MCU(OPT_MCU_GD32VF103) + #define DWC2_EP_COUNT(_dwc2) DWC2_EP_MAX +#else + #define DWC2_EP_COUNT(_dwc2) ((_dwc2)->ghwcfg2_bm.num_dev_ep) +#endif + //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM //--------------------------------------------------------------------+ @@ -282,58 +288,6 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { } } -// Start of Bus Reset -static void bus_reset(uint8_t rhport) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - uint8_t const ep_count = _dwc2_controller[rhport].ep_count; - - tu_memclr(xfer_status, sizeof(xfer_status)); - - _sof_en = false; - _allocated_ep_in_count = 1; - - // 1. NAK for all OUT endpoints - for (uint8_t n = 0; n < ep_count; n++) { - dwc2->epout[n].doepctl |= DOEPCTL_SNAK; - } - - // 2. Disable all IN endpoints - for (uint8_t n = 0; n < ep_count; n++) { - if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) { - dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS; - } - } - - dfifo_flush_tx(dwc2, 0x10); // all tx fifo - dfifo_flush_rx(dwc2); - - // 3. Set up interrupt mask for EP0 - dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos); - dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM; - dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM; - - // 4. Set up DFIFO - dfifo_device_init(rhport); - - // 5. Reset device address - dwc2->dcfg &= ~DCFG_DAD_Msk; - - // Fixed both control EP0 size to 64 bytes - dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); - dwc2->epout[0].doepctl &= ~(0x03 << DOEPCTL_MPSIZ_Pos); - - xfer_status[0][TUSB_DIR_OUT].max_size = 64; - xfer_status[0][TUSB_DIR_IN].max_size = 64; - - if(dma_device_enabled(dwc2)) { - dma_setup_prepare(rhport); - } else { - dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); - } - - dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT; -} - static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, uint16_t total_bytes) { (void) rhport; @@ -412,18 +366,10 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // Core Initialization const bool is_highspeed = dwc2_core_is_highspeed(dwc2, TUSB_ROLE_DEVICE); - TU_ASSERT(dwc2_core_init(rhport, is_highspeed)); - - if (dma_device_enabled(dwc2)) { - // 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 { - dwc2->gintmsk |= GINTSTS_RXFLVL; - } - - // Device Initialization - dcd_disconnect(rhport); + const bool is_dma = dma_device_enabled(dwc2); + TU_ASSERT(dwc2_core_init(rhport, is_highspeed, is_dma)); + //------------- 7.1 Device Initialization -------------// // Set device max speed uint32_t dcfg = dwc2->dcfg & ~DCFG_DSPD_Msk; if (is_highspeed) { @@ -434,20 +380,21 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) { dcfg |= DCFG_XCVRDLY; } - }else { + } else { dcfg |= DCFG_DSPD_FS << DCFG_DSPD_Pos; } + + dcfg |= DCFG_NZLSOHSK; // send STALL back and discard if host send non-zlp during control status dwc2->dcfg = dcfg; + dcd_disconnect(rhport); + // Force device mode dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD; // Clear A override, force B Valid dwc2->gotgctl = (dwc2->gotgctl & ~GOTGCTL_AVALOEN) | GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL; - // If USB host misbehaves during status portion of control xfer (non zero-length packet), send STALL back and discard - dwc2->dcfg |= DCFG_NZLSOHSK; - // Enable required interrupts dwc2->gintmsk |= GINTMSK_OTGINT | GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM; @@ -677,6 +624,57 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { // Interrupt Handler //-------------------------------------------------------------------- +// 7.4.1 Initialization on USB Reset +static void handle_bus_reset(uint8_t rhport) { + dwc2_regs_t *dwc2 = DWC2_REG(rhport); + const uint8_t ep_count = DWC2_EP_COUNT(dwc2); + + tu_memclr(xfer_status, sizeof(xfer_status)); + + _sof_en = false; + _allocated_ep_in_count = 1; + + // 1. NAK for all OUT endpoints + for (uint8_t n = 0; n < ep_count; n++) { + dwc2->epout[n].doepctl |= DOEPCTL_SNAK; + } + + // Disable all IN endpoints + for (uint8_t n = 0; n < ep_count; n++) { + if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) { + dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS; + } + } + + // 2. Set up interrupt mask for EP0 + dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos); + dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM; + dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM; + + // 4. Set up DFIFO + dfifo_flush_tx(dwc2, 0x10); // all tx fifo + dfifo_flush_rx(dwc2); + dfifo_device_init(rhport); + + // 5. Reset device address + dwc2->dcfg_bm.address = 0; + + // Fixed both control EP0 size to 64 bytes + dwc2->epin[0].ctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); + dwc2->epout[0].ctl &= ~(0x03 << DOEPCTL_MPSIZ_Pos); + + xfer_status[0][TUSB_DIR_OUT].max_size = 64; + xfer_status[0][TUSB_DIR_IN].max_size = 64; + + if(dma_device_enabled(dwc2)) { + dma_setup_prepare(rhport); + } else { + dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); + } + + dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT; +} + // Process shared receive FIFO, this interrupt is only used in Slave mode static void handle_rxflvl_irq(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); @@ -686,7 +684,7 @@ static void handle_rxflvl_irq(uint8_t rhport) { const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm; const uint8_t epnum = grxstsp_bm.ep_ch_num; const uint16_t byte_count = grxstsp_bm.byte_count; - dwc2_epout_t* epout = &dwc2->epout[epnum]; + dwc2_dep_t* epout = &dwc2->epout[epnum]; switch (grxstsp_bm.packet_status) { // Global OUT NAK: do nothing @@ -724,7 +722,7 @@ static void handle_rxflvl_irq(uint8_t rhport) { // short packet, minus remaining bytes (xfer_size) if (byte_count < xfer->max_size) { - xfer->total_len -= epout->doeptsiz_bm.xfer_size; + xfer->total_len -= epout->tsiz_bm.xfer_size; if (epnum == 0) { xfer->total_len -= ep0_pending[TUSB_DIR_OUT]; ep0_pending[TUSB_DIR_OUT] = 0; @@ -753,7 +751,7 @@ static void handle_epout_irq(uint8_t rhport) { // OEPINT will be cleared when DAINT's out bits are cleared. for (uint8_t epnum = 0; epnum < ep_count; epnum++) { if (dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + epnum)) { - dwc2_epout_t* epout = &dwc2->epout[epnum]; + dwc2_dep_t* epout = &dwc2->epout[epnum]; const uint32_t doepint = epout->doepint; TU_ASSERT((epout->doepint & DOEPINT_AHBERR) == 0, ); @@ -829,7 +827,7 @@ static void handle_epin_irq(uint8_t rhport) { if (dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n)) { // IN XFER complete (entire xfer). xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); - dwc2_epin_t* epin = &dwc2->epin[n]; + dwc2_dep_t* epin = &dwc2->epin[n]; if (epin->diepint & DIEPINT_XFRC) { epin->diepint = DIEPINT_XFRC; @@ -852,11 +850,11 @@ static void handle_epin_irq(uint8_t rhport) { // It will only be cleared by hardware when written bytes is more than // - 64 bytes or // - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL) - const uint16_t remain_packets = epin->dieptsiz_bm.packet_count; + const uint16_t remain_packets = epin->tsiz_bm.packet_count; // Process every single packet (only whole packets can be written to fifo) for (uint16_t i = 0; i < remain_packets; i++) { - const uint16_t remain_bytes = (uint16_t) epin->dieptsiz_bm.xfer_size; + const uint16_t remain_bytes = (uint16_t) epin->tsiz_bm.xfer_size; // Packet can not be larger than ep max size const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size); @@ -878,7 +876,7 @@ static void handle_epin_irq(uint8_t rhport) { } // Turn off TXFE if all bytes are written. - if (epin->dieptsiz_bm.xfer_size == 0) { + if (epin->tsiz_bm.xfer_size == 0) { dwc2->diepempmsk &= ~(1 << n); } } @@ -887,12 +885,13 @@ static void handle_epin_irq(uint8_t rhport) { } /* Interrupt Hierarchy - - DxEPINTn - | - DAINT.xEPn - | - GINTSTS: xEPInt + DIEPINT DIEPINT + \ / + \ / + DAINT + / \ + / \ + GINTSTS: OEPInt IEPInt | USBReset | EnumDone | USBSusp | WkUpInt | OTGInt | SOF | RXFLVL Note: when OTG_MULTI_PROC_INTRPT = 1, Device Each endpoint interrupt deachint/deachmsk/diepeachmsk/doepeachmsk are combined to generate dedicated interrupt line for each endpoint. @@ -901,46 +900,45 @@ void dcd_int_handler(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint32_t const int_mask = dwc2->gintmsk; - uint32_t const int_status = dwc2->gintsts & int_mask; + uint32_t const gintsts = dwc2->gintsts & int_mask; - if (int_status & GINTSTS_USBRST) { + if (gintsts & GINTSTS_USBRST) { // USBRST is start of reset. dwc2->gintsts = GINTSTS_USBRST; - bus_reset(rhport); + handle_bus_reset(rhport); } - if (int_status & GINTSTS_ENUMDNE) { + if (gintsts & GINTSTS_ENUMDNE) { // ENUMDNE is the end of reset where speed of the link is detected dwc2->gintsts = GINTSTS_ENUMDNE; tusb_speed_t speed; - switch ((dwc2->dsts & DSTS_ENUMSPD_Msk) >> DSTS_ENUMSPD_Pos) { - case DSTS_ENUMSPD_HS: + switch (dwc2->dsts_bm.enum_speed) { + case DCFG_SPEED_HIGH: speed = TUSB_SPEED_HIGH; break; - case DSTS_ENUMSPD_LS: + case DCFG_SPEED_LOW: speed = TUSB_SPEED_LOW; break; - case DSTS_ENUMSPD_FS_HSPHY: - case DSTS_ENUMSPD_FS: + case DCFG_SPEED_FULL_30_60MHZ: + case DCFG_SPEED_FULL_48MHZ: default: speed = TUSB_SPEED_FULL; break; } // TODO must update GUSBCFG_TRDT according to link speed - dcd_event_bus_reset(rhport, speed, true); } - if (int_status & GINTSTS_USBSUSP) { + if (gintsts & GINTSTS_USBSUSP) { dwc2->gintsts = GINTSTS_USBSUSP; dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); } - if (int_status & GINTSTS_WKUINT) { + if (gintsts & GINTSTS_WKUINT) { dwc2->gintsts = GINTSTS_WKUINT; dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); } @@ -948,7 +946,7 @@ void dcd_int_handler(uint8_t rhport) { // TODO check GINTSTS_DISCINT for disconnect detection // if(int_status & GINTSTS_DISCINT) - if (int_status & GINTSTS_OTGINT) { + if (gintsts & GINTSTS_OTGINT) { // OTG INT bit is read-only uint32_t const otg_int = dwc2->gotgint; @@ -959,7 +957,7 @@ void dcd_int_handler(uint8_t rhport) { dwc2->gotgint = otg_int; } - if(int_status & GINTSTS_SOF) { + if(gintsts & GINTSTS_SOF) { dwc2->gintsts = GINTSTS_SOF; const uint32_t frame = (dwc2->dsts & DSTS_FNSOF) >> DSTS_FNSOF_Pos; @@ -972,7 +970,7 @@ void dcd_int_handler(uint8_t rhport) { } // RxFIFO non-empty interrupt handling. - if (int_status & GINTSTS_RXFLVL) { + if (gintsts & GINTSTS_RXFLVL) { // RXFLVL bit is read-only dwc2->gintmsk &= ~GINTMSK_RXFLVLM; // disable RXFLVL interrupt while reading @@ -984,13 +982,13 @@ void dcd_int_handler(uint8_t rhport) { } // OUT endpoint interrupt handling. - if (int_status & GINTSTS_OEPINT) { + if (gintsts & GINTSTS_OEPINT) { // OEPINT is read-only, clear using DOEPINTn handle_epout_irq(rhport); } // IN endpoint interrupt handling. - if (int_status & GINTSTS_IEPINT) { + if (gintsts & GINTSTS_IEPINT) { // IEPINT bit read-only, clear using DIEPINTn handle_epin_irq(rhport); } diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c index 4d62cf3c60..ef155c8f78 100644 --- a/src/portable/synopsys/dwc2/dwc2_common.c +++ b/src/portable/synopsys/dwc2/dwc2_common.c @@ -194,7 +194,7 @@ bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) { * In addition, UTMI+/ULPI can be shared to run at fullspeed mode with 48Mhz * */ -bool dwc2_core_init(uint8_t rhport, bool is_highspeed) { +bool dwc2_core_init(uint8_t rhport, bool is_highspeed, bool is_dma) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); // Check Synopsys ID register, failed if controller clock/power is not enabled @@ -229,6 +229,13 @@ bool dwc2_core_init(uint8_t rhport, bool is_highspeed) { dwc2->gotgint = 0xFFFFFFFFU; dwc2->gintmsk = 0; + if (is_dma) { + // 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 { + dwc2->gintmsk |= GINTSTS_RXFLVL; + } + return true; } diff --git a/src/portable/synopsys/dwc2/dwc2_common.h b/src/portable/synopsys/dwc2/dwc2_common.h index 3f7f23c3a1..18b93894f9 100644 --- a/src/portable/synopsys/dwc2/dwc2_common.h +++ b/src/portable/synopsys/dwc2/dwc2_common.h @@ -73,7 +73,7 @@ TU_ATTR_ALWAYS_INLINE static inline dwc2_regs_t* DWC2_REG(uint8_t rhport) { } bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role); -bool dwc2_core_init(uint8_t rhport, bool is_highspeed); +bool dwc2_core_init(uint8_t rhport, bool is_highspeed, bool is_dma); void dwc2_core_handle_common_irq(uint8_t rhport, bool in_isr); //--------------------------------------------------------------------+ diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index 1247f19a37..01e10ee005 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -171,6 +171,13 @@ enum { HCCHAR_EPTYPE_INTERRUPT = 3 }; +enum { + DCFG_SPEED_HIGH = 0, // Highspeed with 30/60 Mhz + DCFG_SPEED_FULL_30_60MHZ = 1, // Fullspeed with UTMI+/ULPI 30/60 Mhz + DCFG_SPEED_LOW = 2, // Lowspeed with FS PHY at 6 Mhz + DCFG_SPEED_FULL_48MHZ = 3, // Fullspeed with dedicated FS PHY at 48 Mhz +}; + //-------------------------------------------------------------------- // Common Register Bitfield //-------------------------------------------------------------------- @@ -469,47 +476,126 @@ typedef struct { // Device Register Bitfield //-------------------------------------------------------------------- typedef struct TU_ATTR_PACKED { - uint32_t xfer_size : 19; // 0..18 Transfer size in bytes - uint32_t packet_count : 10; // 19..28 Number of packets - uint32_t mc_pid : 2; // 29..30 IN: Multi Count, OUT: PID -} dwc2_ep_tsize_t; -TU_VERIFY_STATIC(sizeof(dwc2_ep_tsize_t) == 4, "incorrect size"); + uint32_t speed : 2; // 0..1 Speed + uint32_t nzsts_out_handshake : 1; // 2 Non-zero-length status OUT handshake + uint32_t en_32khz_suspsend : 1; // 3 Enable 32-kHz SUSPEND mode + uint32_t address : 7; // 4..10 Device address + uint32_t period_frame_interval : 2; // 11..12 Periodic frame interval + uint32_t en_out_nak : 1; // 13 Enable Device OUT NAK + uint32_t xcvr_delay : 1; // 14 Transceiver delay + uint32_t erratic_int_mask : 1; // 15 Erratic interrupt mask + uint32_t rsv16 : 1; // 16 Reserved + uint32_t ipg_iso_support : 1; // 17 Interpacket gap ISO support + uint32_t epin_mismatch_count : 5; // 18..22 EP IN mismatch count + uint32_t dma_desc : 1; // 23 Enable scatter/gatter DMA descriptor + uint32_t period_schedule_interval : 2; // 24..25 Periodic schedule interval for scatter/gatter DMA + uint32_t resume_valid : 6; // 26..31 Resume valid period +} dwc2_dcfg_t; +TU_VERIFY_STATIC(sizeof(dwc2_dcfg_t) == 4, "incorrect size"); -// Endpoint IN -typedef struct { - volatile uint32_t diepctl; // 900 + 20*ep Device IN Endpoint Control - uint32_t reserved04; // 904 - volatile uint32_t diepint; // 908 + 20*ep Device IN Endpoint Interrupt - uint32_t reserved0c; // 90C - union { - volatile uint32_t dieptsiz; // 910 + 20*ep Device IN Endpoint Transfer Size - volatile dwc2_ep_tsize_t dieptsiz_bm; - }; - volatile uint32_t diepdma; // 914 + 20*ep Device IN Endpoint DMA Address - volatile uint32_t dtxfsts; // 918 + 20*ep Device IN Endpoint Tx FIFO Status - uint32_t reserved1c; // 91C -} dwc2_epin_t; +typedef struct TU_ATTR_PACKED { + uint32_t remote_wakeup_signal : 1; // 0 Remote wakeup signal + uint32_t soft_disconnet : 1; // 1 Soft disconnect + uint32_t gnp_in_nak_status : 1; // 2 Global non-periodic NAK IN status + uint32_t gout_nak_status : 1; // 3 Global OUT NAK status + uint32_t test_control : 3; // 4..6 Test control + uint32_t set_gnp_in_nak : 1; // 7 Set global non-periodic IN NAK + uint32_t clear_gnp_in_nak : 1; // 8 Clear global non-periodic IN NAK + uint32_t set_gout_nak : 1; // 9 Set global OUT NAK + uint32_t clear_gout_nak : 1; // 10 Clear global OUT NAK + uint32_t poweron_prog_done : 1; // 11 Power-on programming done + uint32_t rsv12 : 1; // 12 Reserved + uint32_t global_multi_count : 2; // 13..14 Global multi-count + uint32_t ignore_frame_number : 1; // 15 Ignore frame number + uint32_t nak_on_babble : 1; // 16 NAK on babble + uint32_t en_cont_on_bna : 1; // 17 Enable continue on BNA + uint32_t deep_sleep_besl_reject : 1 ; // 18 Deep sleep BESL reject + uint32_t service_interval : 1; // 19 Service interval for ISO IN endpoint + uint32_t rsv20_31 : 12; // 20..31 Reserved +} dwc2_dctl_t; +TU_VERIFY_STATIC(sizeof(dwc2_dctl_t) == 4, "incorrect size"); -// Endpoint OUT -typedef struct { - volatile uint32_t doepctl; // B00 + 20*ep Device OUT Endpoint Control - uint32_t reserved04; // B04 - volatile uint32_t doepint; // B08 + 20*ep Device OUT Endpoint Interrupt - uint32_t reserved0c; // B0C - union { - volatile uint32_t doeptsiz; // B10 + 20*ep Device OUT Endpoint Transfer Size - volatile dwc2_ep_tsize_t doeptsiz_bm; - }; - volatile uint32_t doepdma; // B14 + 20*ep Device OUT Endpoint DMA Address - uint32_t reserved18[2]; // B18..B1C -} dwc2_epout_t; +typedef struct TU_ATTR_PACKED { + uint32_t suspend_status : 1; // 0 Suspend status + uint32_t enum_speed : 2; // 1..2 Enumerated speed + uint32_t erratic_err : 1; // 3 Erratic error + uint32_t rsv4_7 : 4; // 4..7 Reserved + uint32_t frame_number : 14; // 8..21 Frame/MicroFrame number + uint32_t line_status : 2; // 22..23 Line status + uint32_t rsv24_31 : 8; // 24..31 Reserved +} dwc2_dsts_t; +TU_VERIFY_STATIC(sizeof(dwc2_dsts_t) == 4, "incorrect size"); + +typedef struct TU_ATTR_PACKED { + uint32_t xfer_complete : 1; // 0 Transfer complete + uint32_t disabled : 1; // 1 Endpoint disabled + uint32_t ahb_err : 1; // 2 AHB error + uint32_t timeout : 1; // 3 Timeout + uint32_t in_rx_txfe : 1; // 4 IN token received when TxFIFO is empty + uint32_t in_rx_ep_mismatch : 1; // 5 IN token received with EP mismatch + uint32_t in_ep_nak_effective : 1; // 6 IN endpoint NAK effective + uint32_t rsv7 : 1; // 7 Reserved + uint32_t txfifo_underrun : 1; // 8 Tx FIFO underrun + uint32_t bna : 1; // 9 Buffer not available + uint32_t rsv10_12 : 3; // 10..12 Reserved + uint32_t nak : 1; // 13 NAK + uint32_t rsv14_31 : 18; // 14..31 Reserved +} dwc2_diepint_t; +TU_VERIFY_STATIC(sizeof(dwc2_diepint_t) == 4, "incorrect size"); + +typedef struct TU_ATTR_PACKED { + uint32_t mps : 11; // 0..10 Maximum packet size, EP0 only use 2 bit + uint32_t next_ep : 4; // 11..14 Next endpoint number + uint32_t active : 1; // 15 Active + const uint32_t dpid_iso_odd : 1; // 16 DATA0/DATA1 for bulk/interrupt, odd frame for isochronous + const uint32_t nak_status : 1; // 17 NAK status + uint32_t type : 2; // 18..19 Endpoint type + uint32_t rsv20 : 1; // 20 Reserved + uint32_t stall : 1; // 21 Stall + uint32_t tx_fifo_num : 4; // 22..25 Tx FIFO number (IN) + uint32_t clear_nak : 1; // 26 Clear NAK + uint32_t set_nak : 1; // 27 Set NAK + uint32_t set_data0_iso_even : 1; // 28 Set DATA0 if bulk/interrupt, even frame for isochronous + uint32_t set_data1_iso_odd : 1; // 29 Set DATA1 if bulk/interrupt, odd frame for isochronous + uint32_t disable : 1; // 30 Disable + uint32_t enable : 1; // 31 Enable +} dwc2_depctl_t; +TU_VERIFY_STATIC(sizeof(dwc2_depctl_t) == 4, "incorrect size"); -// Universal Endpoint +typedef struct TU_ATTR_PACKED { + uint32_t xfer_complete : 1; // 0 Transfer complete + uint32_t disabled : 1; // 1 Endpoint disabled + uint32_t ahb_err : 1; // 2 AHB error + uint32_t setup_phase_done : 1; // 3 Setup phase done + uint32_t out_rx_ep_disabled : 1; // 4 OUT token received when endpoint disabled + uint32_t status_phase_rx : 1; // 5 Status phase received + uint32_t setup_b2b : 1; // 6 Setup packet back-to-back + uint32_t rsv7 : 1; // 7 Reserved + uint32_t out_packet_err : 1; // 8 OUT packet error + uint32_t bna : 1; // 9 Buffer not available + uint32_t rsv10_11 : 2; // 10..11 Reserved + uint32_t babble_err : 1; // 12 Babble error + uint32_t nak : 1; // 13 NAK + uint32_t nyet : 1; // 14 NYET + uint32_t rsv15_31 : 16; // 15..31 Reserved +} dwc2_doepint_t; +TU_VERIFY_STATIC(sizeof(dwc2_doepint_t) == 4, "incorrect size"); + +typedef struct TU_ATTR_PACKED { + uint32_t xfer_size : 19; // 0..18 Transfer size in bytes + uint32_t packet_count : 10; // 19..28 Number of packets + uint32_t mc_pid : 2; // 29..30 IN: Multi Count, OUT: PID +} dwc2_ep_tsize_t; +TU_VERIFY_STATIC(sizeof(dwc2_ep_tsize_t) == 4, "incorrect size"); + +// Device IN/OUT Endpoint typedef struct { union { volatile uint32_t diepctl; volatile uint32_t doepctl; + volatile uint32_t ctl; + volatile dwc2_depctl_t ctrl_bm; }; uint32_t rsv04; union { @@ -520,7 +606,7 @@ typedef struct { union { volatile uint32_t dieptsiz; volatile uint32_t doeptsiz; - volatile dwc2_ep_tsize_t deptsiz_bm; + volatile dwc2_ep_tsize_t tsiz_bm; }; union { volatile uint32_t diepdma; @@ -631,12 +717,27 @@ typedef struct { uint32_t reserved700[64]; // 700..7FF //------------- Device -----------// + union { volatile uint32_t dcfg; // 800 Device Configuration + volatile dwc2_dcfg_t dcfg_bm; + }; + union { volatile uint32_t dctl; // 804 Device Control + volatile dwc2_dctl_t dctl_bm; + }; + union { volatile uint32_t dsts; // 808 Device Status (RO) + volatile dwc2_dsts_t dsts_bm; + }; uint32_t reserved80c; // 80C + union { volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask + volatile dwc2_diepint_t diepmsk_bm; + }; + union { volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask + volatile dwc2_doepint_t doepmsk_bm; + }; volatile uint32_t daint; // 818 Device All Endpoints Interrupt volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1 @@ -658,8 +759,8 @@ typedef struct { union { dwc2_dep_t ep[2][16]; // 0: IN, 1 OUT struct { - dwc2_epin_t epin[16]; // 900..AFF IN Endpoints - dwc2_epout_t epout[16]; // B00..CFF OUT Endpoints + dwc2_dep_t epin[16]; // 900..AFF IN Endpoints + dwc2_dep_t epout[16]; // B00..CFF OUT Endpoints }; }; uint32_t reservedd00[64]; // D00..DFF diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 53583426f3..550778876a 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -336,14 +336,8 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // Core Initialization const bool is_highspeed = dwc2_core_is_highspeed(dwc2, TUSB_ROLE_HOST); - TU_ASSERT(dwc2_core_init(rhport, is_highspeed)); - - if (dma_host_enabled(dwc2)) { - // 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 { - dwc2->gintmsk |= GINTSTS_RXFLVL; - } + const bool is_dma = dma_host_enabled(dwc2); + TU_ASSERT(dwc2_core_init(rhport, is_highspeed, is_dma)); //------------- 3.1 Host Initialization -------------// From db7670a3bcd502193d138041c20d401bc3f59001 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 18 Nov 2024 11:35:46 +0700 Subject: [PATCH 3/9] separate handle out dma and slave separate edpt_schedule_packets into epout/epin xfer --- src/portable/synopsys/dwc2/dcd_dwc2.c | 357 +++++++++++++++---------- src/portable/synopsys/dwc2/dwc2_type.h | 41 +-- src/portable/synopsys/dwc2/hcd_dwc2.c | 4 +- 3 files changed, 243 insertions(+), 159 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index ae6377a49b..6ca1433a60 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -288,72 +288,118 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { } } -static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, - uint16_t total_bytes) { - (void) rhport; +static inline void iso_set_odd_even(dwc2_regs_t* dwc2, dwc2_depctl_t* depctl_bm) { + // Take odd/even bit from frame counter. + const uint32_t odd_now = (dwc2->dsts_bm.frame_number & 1u); + if (odd_now) { + depctl_bm->set_data0_iso_even = 1; + } else { + depctl_bm->set_data1_iso_odd = 1; + } +} - dwc2_regs_t* dwc2 = DWC2_REG(rhport); +static void epout_xfer(dwc2_regs_t* dwc2, const uint8_t epnum, const uint16_t num_packets, uint16_t total_bytes) { + const uint8_t dir = TUSB_DIR_OUT; xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); + dwc2_dep_t* dep = &dwc2->epout[epnum]; // EP0 is limited to one packet each xfer // We use multiple transaction of xfer->max_size length to get a whole transfer done - if (epnum == 0) { - total_bytes = tu_min16(ep0_pending[dir], xfer->max_size); - ep0_pending[dir] -= total_bytes; + // if (epnum == 0) { + // total_bytes = tu_min16(ep0_pending[dir], xfer->max_size); + // ep0_pending[dir] -= total_bytes; + // } + + // transfer size: A full OUT transfer (multiple packets, possibly) triggers XFRC. + union { + uint32_t value; + dwc2_ep_tsize_t bm; + } deptsiz; + deptsiz.value = 0; + deptsiz.bm.xfer_size = total_bytes; + deptsiz.bm.packet_count = num_packets; + + dep->tsiz = deptsiz.value; + + // control + union { + dwc2_depctl_t bm; + uint32_t value; + } depctl; + depctl.value = dep->ctl; + + if (depctl.bm.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) { + iso_set_odd_even(dwc2, &depctl.bm); + } + + if(dma_device_enabled(dwc2)) { + dep->doepdma = (uintptr_t) xfer->buffer; } - // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here. - const uint8_t is_epout = 1 - dir; - dwc2_dep_t* dep = &dwc2->ep[is_epout][epnum]; + depctl.bm.clear_nak = 1; + depctl.bm.enable = 1; - if (dir == TUSB_DIR_IN) { - // A full IN transfer (multiple packets, possibly) triggers XFRC. - dep->dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) | - ((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk); - - if(dma_device_enabled(dwc2)) { - dep->diepdma = (uintptr_t)xfer->buffer; - - // For ISO endpoint set correct odd/even bit for next frame. - if ((dep->diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) { - // Take odd/even bit from frame counter. - uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); - dep->diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); - } + dep->doepctl = depctl.value; +} - dep->diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; - } else { - dep->diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; +static void epin_xfer(dwc2_regs_t* dwc2, const uint8_t epnum, const uint16_t num_packets, uint16_t total_bytes) { + const uint8_t dir = TUSB_DIR_IN; + xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); + dwc2_dep_t* dep = &dwc2->epin[epnum]; + + // A full IN transfer (multiple packets, possibly) triggers XFRC. + union { + uint32_t value; + dwc2_ep_tsize_t bm; + } deptsiz; + deptsiz.value = 0; + deptsiz.bm.xfer_size = total_bytes; + deptsiz.bm.packet_count = num_packets; + + dep->tsiz = deptsiz.value; + + // control + union { + dwc2_depctl_t bm; + uint32_t value; + } depctl; + depctl.value = dep->ctl; + + depctl.bm.clear_nak = 1; + depctl.bm.enable = 1; + if (depctl.bm.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) { + iso_set_odd_even(dwc2, &depctl.bm); + } - // For ISO endpoint set correct odd/even bit for next frame. - if ((dep->diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) { - // Take odd/even bit from frame counter. - uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); - dep->diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); - } - // Enable fifo empty interrupt only if there are something to put in the fifo. - if (total_bytes != 0) { - dwc2->diepempmsk |= (1 << epnum); - } - } + if(dma_device_enabled(dwc2)) { + dep->diepdma = (uintptr_t)xfer->buffer; + dep->diepctl = depctl.value; } else { - // A full OUT transfer (multiple packets, possibly) triggers XFRC. - dep->doeptsiz &= ~(DOEPTSIZ_PKTCNT_Msk | DOEPTSIZ_XFRSIZ); - dep->doeptsiz |= (num_packets << DOEPTSIZ_PKTCNT_Pos) | - ((total_bytes << DOEPTSIZ_XFRSIZ_Pos) & DOEPTSIZ_XFRSIZ_Msk); - - if ((dep->doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 && - XFER_CTL_BASE(epnum, dir)->interval == 1) { - // Take odd/even bit from frame counter. - uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); - dep->doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk); - } + dep->diepctl = depctl.value; - if(dma_device_enabled(dwc2)) { - dep->doepdma = (uintptr_t)xfer->buffer; + // Enable fifo empty interrupt only if there are something to put in the fifo. + if (total_bytes != 0) { + dwc2->diepempmsk |= (1 << epnum); } + } +} + +static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, + uint16_t total_bytes) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); + + // EP0 is limited to one packet each xfer + // We use multiple transaction of xfer->max_size length to get a whole transfer done + if (epnum == 0) { + total_bytes = tu_min16(ep0_pending[dir], xfer->max_size); + ep0_pending[dir] -= total_bytes; + } - dep->doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK; + if (dir == TUSB_DIR_IN) { + epin_xfer(dwc2, epnum, num_packets, total_bytes); + } else { + epout_xfer(dwc2, epnum, num_packets, total_bytes); } } @@ -683,135 +729,164 @@ static void handle_rxflvl_irq(uint8_t rhport) { // Pop control word off FIFO const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm; const uint8_t epnum = grxstsp_bm.ep_ch_num; - const uint16_t byte_count = grxstsp_bm.byte_count; + dwc2_dep_t* epout = &dwc2->epout[epnum]; switch (grxstsp_bm.packet_status) { - // Global OUT NAK: do nothing - case GRXSTS_PKTSTS_GLOBALOUTNAK: + case GRXSTS_PKTSTS_GLOBAL_OUT_NAK: + // Global OUT NAK: do nothing break; - case GRXSTS_PKTSTS_SETUPRX: + case GRXSTS_PKTSTS_SETUP_RX: // Setup packet received - // We can receive up to three setup packets in succession, but only the last one is valid. + // 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: + case GRXSTS_PKTSTS_SETUP_DONE: // Setup packet done: // After popping this out, dwc2 asserts a DOEPINT_SETUP interrupt which is handled by handle_epout_irq() epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); break; - case GRXSTS_PKTSTS_OUTRX: { + case GRXSTS_PKTSTS_RX_DATA: { // Out packet received + const uint16_t byte_count = grxstsp_bm.byte_count; 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, byte_count); - } else { - // Linear buffer - dfifo_read_packet(dwc2, xfer->buffer, byte_count); - - // Increment pointer to xfer data - xfer->buffer += byte_count; - } + if (byte_count) { + // Read packet off RxFIFO + if (xfer->ff) { + tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void*) (uintptr_t) rx_fifo, byte_count); + } else { + dfifo_read_packet(dwc2, xfer->buffer, byte_count); + xfer->buffer += byte_count; + } - // short packet, minus remaining bytes (xfer_size) - if (byte_count < xfer->max_size) { - xfer->total_len -= epout->tsiz_bm.xfer_size; - if (epnum == 0) { - xfer->total_len -= ep0_pending[TUSB_DIR_OUT]; - ep0_pending[TUSB_DIR_OUT] = 0; + // short packet, minus remaining bytes (xfer_size) + if (byte_count < xfer->max_size) { + xfer->total_len -= epout->tsiz_bm.xfer_size; + 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() */ + case GRXSTS_PKTSTS_RX_COMPLETE: + // Out packet done + // After this entry is popped from the receive FIFO, dwc2 asserts a Transfer Completed interrupt on + // the specified OUT endpoint which will be handled by handle_epout_irq() break; - default: - TU_BREAKPOINT(); - break; + default: break; } } -static void handle_epout_irq(uint8_t rhport) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - uint8_t const ep_count = _dwc2_controller[rhport].ep_count; +static void handle_epout_slave(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepint_bm) { + // dwc2_regs_t* dwc2 = DWC2_REG(rhport); - // DAINT for a given EP clears when DOEPINTx is cleared. - // OEPINT will be cleared when DAINT's out bits are cleared. - for (uint8_t epnum = 0; epnum < ep_count; epnum++) { - if (dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + epnum)) { - dwc2_dep_t* epout = &dwc2->epout[epnum]; - const uint32_t doepint = epout->doepint; - TU_ASSERT((epout->doepint & DOEPINT_AHBERR) == 0, ); + if (doepint_bm.setup_phase_done) { + dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); + return; + } - // Setup and/or STPKTRX/STSPHSRX (from 3.00a) can be set along with XFRC, and also set independently. - if (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a) { - if (doepint & DOEPINT_STSPHSRX) { - // Status phase received for control write: In token received from Host - epout->doepint = DOEPINT_STSPHSRX; - } + // Normal OUT transfer complete + if (doepint_bm.xfer_complete) { + // only handle data skip if it is setup or status related + // Note: even though (xfer_complete + status_phase_rx) is for buffered DMA only, for STM32L47x (dwc2 v3.00a) they + // can is set when GRXSTS_PKTSTS_SETUP_RX is popped therefore they can bet set before/together with setup_phase_done + if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) { + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); - if (doepint & DOEPINT_STPKTRX) { - // New setup packet received, but wait for Setup done, since we can receive up to 3 setup consecutively - epout->doepint = DOEPINT_STPKTRX; - } + // EP0 can only handle one packet + if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) { + // Schedule another packet to be received. + edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + } else { + dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); } + } + } +} + +static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepint_bm) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + + if (doepint_bm.setup_phase_done) { + dma_setup_prepare(rhport); + dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); + return; + } + + // OUT XFER complete + if (doepint_bm.xfer_complete) { + // only handle data skip if it is setup or status related + // Normal OUT transfer complete + if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) { + if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) { + // EP0 can only handle one packet Schedule another packet to be received. + edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + } else { + dwc2_dep_t* epout = &dwc2->epout[epnum]; + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); - if (doepint & DOEPINT_SETUP) { - epout->doepint = DOEPINT_SETUP; + // determine actual received bytes + const uint16_t remain = epout->tsiz_bm.xfer_size; + xfer->total_len -= remain; - if(dma_device_enabled(dwc2)) { + // this is ZLP, so prepare EP0 for next setup + if(epnum == 0 && xfer->total_len == 0) { dma_setup_prepare(rhport); } - dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); + dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); } + } + } +} - // OUT XFER complete - if (doepint & DOEPINT_XFRC) { - epout->doepint = DOEPINT_XFRC; - - // only handle data skip if it is setup or status related - // Normal OUT transfer complete - if (!(doepint & (DOEPINT_SETUP | DOEPINT_STPKTRX | DOEPINT_STSPHSRX))) { - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); - - if(dma_device_enabled(dwc2)) { - if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) { - // EP0 can only handle one packet Schedule another packet to be received. - edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); - } else { - // Fix packet length - uint16_t remain = (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; - xfer->total_len -= remain; - // this is ZLP, so prepare EP0 for next setup - if(epnum == 0 && xfer->total_len == 0) { - dma_setup_prepare(rhport); - } - - dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); - } - } else { - // EP0 can only handle one packet - if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) { - // Schedule another packet to be received. - edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); - } else { - dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); - } - } - } +#if 0 +TU_ATTR_ALWAYS_INLINE static inline void print_doepint(uint32_t doepint) { + const char* str[] = { + "XFRC", "DIS", "AHBERR", "SETUP_DONE", + "ORXED", "STATUS_RX", "SETUP_B2B", "RSV7", + "OPERR", "BNA", "RSV10", "ISODROP", + "BBLERR", "NAK", "NYET", "SETUP_RX" + }; + + for(uint32_t i=0; idaint & TU_BIT(DAINT_OEPINT_Pos + epnum)) { + dwc2_dep_t* epout = &dwc2->epout[epnum]; + const uint32_t doepint = epout->doepint; + const dwc2_doepint_t doepint_bm = epout->doepint_bm; + + epout->doepint = doepint; // Clear interrupt + + // print_doepint(doepint); + if (is_dma) { + handle_epout_dma(rhport, epnum, doepint_bm); + } else { + handle_epout_slave(rhport, epnum, doepint_bm); } } } diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index 01e10ee005..b67771a4dc 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -149,17 +149,12 @@ enum { }; enum { - GRXSTS_PKTSTS_GLOBALOUTNAK = 1, - GRXSTS_PKTSTS_OUTRX = 2, - GRXSTS_PKTSTS_OUTDONE = 3, - GRXSTS_PKTSTS_SETUPDONE = 4, - GRXSTS_PKTSTS_SETUPRX = 6 -}; - -enum { - GRXSTS_PKTSTS_RX_DATA = 2, - GRXSTS_PKTSTS_RX_COMPLETE = 3, + GRXSTS_PKTSTS_GLOBAL_OUT_NAK = 1, + GRXSTS_PKTSTS_RX_DATA = 2, + GRXSTS_PKTSTS_RX_COMPLETE = 3, + GRXSTS_PKTSTS_SETUP_DONE = 4, GRXSTS_PKTSTS_HOST_DATATOGGLE_ERR = 5, + GRXSTS_PKTSTS_SETUP_RX = 6, GRXSTS_PKTSTS_HOST_CHANNEL_HALTED = 7 }; @@ -178,6 +173,14 @@ enum { DCFG_SPEED_FULL_48MHZ = 3, // Fullspeed with dedicated FS PHY at 48 Mhz }; +// Same as TUSB_XFER_* +enum { + DEPCTL_EPTYPE_CONTROL = 0, + DEPCTL_EPTYPE_ISOCHRONOUS = 1, + DEPCTL_EPTYPE_BULK = 2, + DEPCTL_EPTYPE_INTERRUPT = 3 +}; + //-------------------------------------------------------------------- // Common Register Bitfield //-------------------------------------------------------------------- @@ -507,11 +510,11 @@ typedef struct TU_ATTR_PACKED { uint32_t rsv12 : 1; // 12 Reserved uint32_t global_multi_count : 2; // 13..14 Global multi-count uint32_t ignore_frame_number : 1; // 15 Ignore frame number - uint32_t nak_on_babble : 1; // 16 NAK on babble + uint32_t nak_on_babble : 1; // 16 NAK on babble uint32_t en_cont_on_bna : 1; // 17 Enable continue on BNA - uint32_t deep_sleep_besl_reject : 1 ; // 18 Deep sleep BESL reject + uint32_t deep_sleep_besl_reject : 1; // 18 Deep sleep BESL reject uint32_t service_interval : 1; // 19 Service interval for ISO IN endpoint - uint32_t rsv20_31 : 12; // 20..31 Reserved + uint32_t rsv20_31 :12; // 20..31 Reserved } dwc2_dctl_t; TU_VERIFY_STATIC(sizeof(dwc2_dctl_t) == 4, "incorrect size"); @@ -573,11 +576,13 @@ typedef struct TU_ATTR_PACKED { uint32_t rsv7 : 1; // 7 Reserved uint32_t out_packet_err : 1; // 8 OUT packet error uint32_t bna : 1; // 9 Buffer not available - uint32_t rsv10_11 : 2; // 10..11 Reserved + uint32_t rsv10 : 1; // 10 Reserved + uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status uint32_t babble_err : 1; // 12 Babble error uint32_t nak : 1; // 13 NAK uint32_t nyet : 1; // 14 NYET - uint32_t rsv15_31 : 16; // 15..31 Reserved + uint32_t setup_packet_rx : 1; // 15 Setup packet received (Buffer DMA Mode only) + uint32_t rsv16_31 :15; // 16..31 Reserved } dwc2_doepint_t; TU_VERIFY_STATIC(sizeof(dwc2_doepint_t) == 4, "incorrect size"); @@ -595,17 +600,21 @@ typedef struct { volatile uint32_t doepctl; volatile uint32_t ctl; - volatile dwc2_depctl_t ctrl_bm; + volatile dwc2_depctl_t ctl_bm; }; uint32_t rsv04; union { volatile uint32_t diepint; + volatile dwc2_diepint_t diepint_bm; + volatile uint32_t doepint; + volatile dwc2_doepint_t doepint_bm; }; uint32_t rsv0c; union { volatile uint32_t dieptsiz; volatile uint32_t doeptsiz; + volatile uint32_t tsiz; volatile dwc2_ep_tsize_t tsiz_bm; }; union { diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 550778876a..8e0162ed6c 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -1116,8 +1116,8 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) { TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,); dwc2_channel_char_t hcchar_bm = channel->hcchar_bm; - uint32_t hcint = channel->hcint; - channel->hcint = hcint; + const uint32_t hcint = channel->hcint; + channel->hcint = hcint; // clear interrupt bool is_done; if (is_dma) { From a2ab783db7928bbfe1f0ddf1be25660a50184ecb Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 18 Nov 2024 12:39:00 +0700 Subject: [PATCH 4/9] seperate handle_epin_dma/slave --- src/portable/synopsys/dwc2/dcd_dwc2.c | 147 ++++++++++++++----------- src/portable/synopsys/dwc2/dwc2_type.h | 15 ++- 2 files changed, 94 insertions(+), 68 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 6ca1433a60..706661706c 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -629,12 +629,9 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t xfer->ff = ff; xfer->total_len = total_bytes; - uint16_t num_packets = (total_bytes / xfer->max_size); - uint16_t const short_packet_size = total_bytes % xfer->max_size; - - // Zero-size packet is special case. - if (short_packet_size > 0 || (total_bytes == 0)) { - num_packets++; + uint16_t num_packets = tu_div_ceil(total_bytes, xfer->max_size); + if (num_packets == 0) { + num_packets = 1; // zero length packet still count as 1 } // Schedule packets to be sent within interrupt @@ -839,6 +836,7 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi xfer->total_len -= remain; // this is ZLP, so prepare EP0 for next setup + // TODO use status phase rx if(epnum == 0 && xfer->total_len == 0) { dma_setup_prepare(rhport); } @@ -877,10 +875,10 @@ static void handle_epout_irq(uint8_t rhport) { for (uint8_t epnum = 0; epnum < ep_count; epnum++) { if (dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + epnum)) { dwc2_dep_t* epout = &dwc2->epout[epnum]; - const uint32_t doepint = epout->doepint; + const uint32_t doepint = epout->intr; const dwc2_doepint_t doepint_bm = epout->doepint_bm; - epout->doepint = doepint; // Clear interrupt + epout->intr = doepint; // Clear interrupt // print_doepint(doepint); if (is_dma) { @@ -892,68 +890,91 @@ static void handle_epout_irq(uint8_t rhport) { } } +static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepint_bm) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN); + + if (diepint_bm.xfer_complete) { + if ((epnum == 0) && ep0_pending[TUSB_DIR_IN]) { + // EP0 can only handle one packet. Schedule another packet to be transmitted. + edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); + } else { + dcd_event_xfer_complete(rhport, epnum | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); + } + } + + // TX FIFO empty bit is read-only. It will only be cleared by hardware when written bytes is more than + // - 64 bytes or + // - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL) + if (diepint_bm.txfifo_empty && (dwc2->diepempmsk & (1 << epnum))) { + dwc2_dep_t* epin = &dwc2->epin[epnum]; + const uint16_t remain_packets = epin->tsiz_bm.packet_count; + + // Process every single packet (only whole packets can be written to fifo) + for (uint16_t i = 0; i < remain_packets; i++) { + const uint16_t remain_bytes = (uint16_t) epin->tsiz_bm.xfer_size; + const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size); + + // Check if dtxfsts has enough space available + if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) { + break; + } + + // Push packet to Tx-FIFO + if (xfer->ff) { + volatile uint32_t* tx_fifo = dwc2->fifo[epnum]; + tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*)(uintptr_t)tx_fifo, xact_bytes); + } else { + dfifo_write_packet(dwc2, epnum, xfer->buffer, xact_bytes); + xfer->buffer += xact_bytes; + } + } + + // Turn off TXFE if all bytes are written. + if (epin->tsiz_bm.xfer_size == 0) { + dwc2->diepempmsk &= ~(1 << epnum); + } + } +} + +static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepint_bm) { + // dwc2_regs_t* dwc2 = DWC2_REG(rhport); + // dwc2_dep_t* epin = &dwc2->epin[epnum]; + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN); + + if (diepint_bm.xfer_complete) { + if ((epnum == 0) && ep0_pending[TUSB_DIR_IN]) { + // EP0 can only handle one packet. Schedule another packet to be transmitted. + edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); + } else { + if(epnum == 0) { + dma_setup_prepare(rhport); + } + dcd_event_xfer_complete(rhport, epnum | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); + } + } +} + static void handle_epin_irq(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); - const uint8_t ep_count = _dwc2_controller[rhport].ep_count; + const bool is_dma = dma_device_enabled(dwc2); + const uint8_t ep_count = DWC2_EP_COUNT(dwc2); // DAINT for a given EP clears when DIEPINTx is cleared. // IEPINT will be cleared when DAINT's out bits are cleared. - for (uint8_t n = 0; n < ep_count; n++) { - if (dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n)) { - // IN XFER complete (entire xfer). - xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); - dwc2_dep_t* epin = &dwc2->epin[n]; - - if (epin->diepint & DIEPINT_XFRC) { - epin->diepint = DIEPINT_XFRC; - - // EP0 can only handle one packet - if ((n == 0) && ep0_pending[TUSB_DIR_IN]) { - // Schedule another packet to be transmitted. - edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); - } else { - if((n == 0) && dma_device_enabled(dwc2)) { - dma_setup_prepare(rhport); - } - dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); - } - } + for (uint8_t epnum = 0; epnum < ep_count; epnum++) { + if (dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + epnum)) { + dwc2_dep_t* epin = &dwc2->epin[epnum]; + const uint32_t diepint = epin->intr; + const dwc2_diepint_t diepint_bm = epin->diepint_bm; - // XFER FIFO empty - if ((epin->diepint & DIEPINT_TXFE) && (dwc2->diepempmsk & (1 << n))) { - // diepint's TXFE bit is read-only, software cannot clear it. - // It will only be cleared by hardware when written bytes is more than - // - 64 bytes or - // - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL) - const uint16_t remain_packets = epin->tsiz_bm.packet_count; - - // Process every single packet (only whole packets can be written to fifo) - for (uint16_t i = 0; i < remain_packets; i++) { - const uint16_t remain_bytes = (uint16_t) epin->tsiz_bm.xfer_size; - - // Packet can not be larger than ep max size - const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size); - - // It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current - // EP has to be checked if the buffer can take another WHOLE packet - if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) { - break; - } + epin->intr = diepint; // Clear interrupt - // Push packet to Tx-FIFO - if (xfer->ff) { - volatile uint32_t* tx_fifo = dwc2->fifo[n]; - tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*) (uintptr_t) tx_fifo, xact_bytes); - } else { - dfifo_write_packet(dwc2, n, xfer->buffer, xact_bytes); - xfer->buffer += xact_bytes; - } - } - - // Turn off TXFE if all bytes are written. - if (epin->tsiz_bm.xfer_size == 0) { - dwc2->diepempmsk &= ~(1 << n); - } + // print_doepint(doepint); + if (is_dma) { + handle_epin_dma(rhport, epnum, diepint_bm); + } else { + handle_epin_slave(rhport, epnum, diepint_bm); } } } diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index b67771a4dc..8120967598 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -537,12 +537,15 @@ typedef struct TU_ATTR_PACKED { uint32_t in_rx_txfe : 1; // 4 IN token received when TxFIFO is empty uint32_t in_rx_ep_mismatch : 1; // 5 IN token received with EP mismatch uint32_t in_ep_nak_effective : 1; // 6 IN endpoint NAK effective - uint32_t rsv7 : 1; // 7 Reserved - uint32_t txfifo_underrun : 1; // 8 Tx FIFO underrun + uint32_t txfifo_empty : 1; // 7 TX FIFO empty + uint32_t txfifo_underrun : 1; // 8 Tx FIFO under run uint32_t bna : 1; // 9 Buffer not available - uint32_t rsv10_12 : 3; // 10..12 Reserved + uint32_t rsv10 : 1; // 10 Reserved + uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status + uint32_t babble_err : 1; // 12 Babble error uint32_t nak : 1; // 13 NAK - uint32_t rsv14_31 : 18; // 14..31 Reserved + uint32_t nyet : 1; // 14 NYET + uint32_t rsv14_31 :17; // 15..31 Reserved } dwc2_diepint_t; TU_VERIFY_STATIC(sizeof(dwc2_diepint_t) == 4, "incorrect size"); @@ -582,7 +585,7 @@ typedef struct TU_ATTR_PACKED { uint32_t nak : 1; // 13 NAK uint32_t nyet : 1; // 14 NYET uint32_t setup_packet_rx : 1; // 15 Setup packet received (Buffer DMA Mode only) - uint32_t rsv16_31 :15; // 16..31 Reserved + uint32_t rsv16_31 :16; // 16..31 Reserved } dwc2_doepint_t; TU_VERIFY_STATIC(sizeof(dwc2_doepint_t) == 4, "incorrect size"); @@ -604,6 +607,8 @@ typedef struct { }; uint32_t rsv04; union { + volatile uint32_t intr; + volatile uint32_t diepint; volatile dwc2_diepint_t diepint_bm; From dab600bea2bb5ff426e69f10aafa6332f7c8507e Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 18 Nov 2024 15:13:00 +0700 Subject: [PATCH 5/9] merge back and improve edpt_schedule_packets --- src/portable/synopsys/dwc2/dcd_dwc2.c | 144 +++++++------------------- 1 file changed, 40 insertions(+), 104 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 706661706c..2ca4dc88d6 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -288,66 +288,29 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { } } -static inline void iso_set_odd_even(dwc2_regs_t* dwc2, dwc2_depctl_t* depctl_bm) { - // Take odd/even bit from frame counter. - const uint32_t odd_now = (dwc2->dsts_bm.frame_number & 1u); - if (odd_now) { - depctl_bm->set_data0_iso_even = 1; - } else { - depctl_bm->set_data1_iso_odd = 1; - } -} - -static void epout_xfer(dwc2_regs_t* dwc2, const uint8_t epnum, const uint16_t num_packets, uint16_t total_bytes) { - const uint8_t dir = TUSB_DIR_OUT; +static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); - dwc2_dep_t* dep = &dwc2->epout[epnum]; - - // EP0 is limited to one packet each xfer - // We use multiple transaction of xfer->max_size length to get a whole transfer done - // if (epnum == 0) { - // total_bytes = tu_min16(ep0_pending[dir], xfer->max_size); - // ep0_pending[dir] -= total_bytes; - // } - - // transfer size: A full OUT transfer (multiple packets, possibly) triggers XFRC. - union { - uint32_t value; - dwc2_ep_tsize_t bm; - } deptsiz; - deptsiz.value = 0; - deptsiz.bm.xfer_size = total_bytes; - deptsiz.bm.packet_count = num_packets; + const uint8_t is_epout = dir ? 0 : 1; + dwc2_dep_t* dep = &dwc2->ep[is_epout][epnum]; - dep->tsiz = deptsiz.value; + uint16_t num_packets; + uint16_t total_bytes; - // control - union { - dwc2_depctl_t bm; - uint32_t value; - } depctl; - depctl.value = dep->ctl; - - if (depctl.bm.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) { - iso_set_odd_even(dwc2, &depctl.bm); - } - - if(dma_device_enabled(dwc2)) { - dep->doepdma = (uintptr_t) xfer->buffer; + // EP0 is limited to one packet per xfer + if (epnum == 0) { + total_bytes = tu_min16(ep0_pending[dir], xfer->max_size); + ep0_pending[dir] -= total_bytes; + num_packets = 1; + } else { + total_bytes = xfer->total_len; + num_packets = tu_div_ceil(total_bytes, xfer->max_size); + if (num_packets == 0) { + num_packets = 1; // zero length packet still count as 1 + } } - depctl.bm.clear_nak = 1; - depctl.bm.enable = 1; - - dep->doepctl = depctl.value; -} - -static void epin_xfer(dwc2_regs_t* dwc2, const uint8_t epnum, const uint16_t num_packets, uint16_t total_bytes) { - const uint8_t dir = TUSB_DIR_IN; - xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); - dwc2_dep_t* dep = &dwc2->epin[epnum]; - - // A full IN transfer (multiple packets, possibly) triggers XFRC. + // transfer size: A full OUT transfer (multiple packets, possibly) triggers XFRC. union { uint32_t value; dwc2_ep_tsize_t bm; @@ -368,38 +331,24 @@ static void epin_xfer(dwc2_regs_t* dwc2, const uint8_t epnum, const uint16_t num depctl.bm.clear_nak = 1; depctl.bm.enable = 1; if (depctl.bm.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) { - iso_set_odd_even(dwc2, &depctl.bm); - } - - if(dma_device_enabled(dwc2)) { - dep->diepdma = (uintptr_t)xfer->buffer; - dep->diepctl = depctl.value; - } else { - dep->diepctl = depctl.value; - - // Enable fifo empty interrupt only if there are something to put in the fifo. - if (total_bytes != 0) { - dwc2->diepempmsk |= (1 << epnum); + const uint32_t odd_now = (dwc2->dsts_bm.frame_number & 1u); + if (odd_now) { + depctl.bm.set_data0_iso_even = 1; + } else { + depctl.bm.set_data1_iso_odd = 1; } } -} - -static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, - uint16_t total_bytes) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); - // EP0 is limited to one packet each xfer - // We use multiple transaction of xfer->max_size length to get a whole transfer done - if (epnum == 0) { - total_bytes = tu_min16(ep0_pending[dir], xfer->max_size); - ep0_pending[dir] -= total_bytes; + const bool is_dma = dma_device_enabled(dwc2); + if(is_dma) { + dep->diepdma = (uintptr_t) xfer->buffer; } - if (dir == TUSB_DIR_IN) { - epin_xfer(dwc2, epnum, num_packets, total_bytes); - } else { - epout_xfer(dwc2, epnum, num_packets, total_bytes); + dep->diepctl = depctl.value; // enable endpoint + + // Slave: enable tx fifo empty interrupt only if there is data. Note must after depctl enable + if (!is_dma && dir == TUSB_DIR_IN && total_bytes != 0) { + dwc2->diepempmsk |= (1 << epnum); } } @@ -597,19 +546,11 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to // EP0 can only handle one packet if (epnum == 0) { ep0_pending[dir] = total_bytes; - - // Schedule the first transaction for EP0 transfer - edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]); - } else { - uint16_t num_packets = tu_div_ceil(total_bytes, xfer->max_size); - if (num_packets == 0) { - num_packets = 1; // zero length packet still count as 1 - } - - // Schedule packets to be sent within interrupt - edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); } + // Schedule packets to be sent within interrupt + edpt_schedule_packets(rhport, epnum, dir); + return true; } @@ -629,13 +570,8 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t xfer->ff = ff; xfer->total_len = total_bytes; - uint16_t num_packets = tu_div_ceil(total_bytes, xfer->max_size); - if (num_packets == 0) { - num_packets = 1; // zero length packet still count as 1 - } - // Schedule packets to be sent within interrupt - edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); + edpt_schedule_packets(rhport, epnum, dir); return true; } @@ -802,7 +738,7 @@ static void handle_epout_slave(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doe // EP0 can only handle one packet if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) { // Schedule another packet to be received. - edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT); } else { dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); } @@ -826,7 +762,7 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) { if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) { // EP0 can only handle one packet Schedule another packet to be received. - edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT); } else { dwc2_dep_t* epout = &dwc2->epout[epnum]; xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); @@ -892,12 +828,13 @@ static void handle_epout_irq(uint8_t rhport) { static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepint_bm) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); + dwc2_dep_t* epin = &dwc2->epin[epnum]; xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN); if (diepint_bm.xfer_complete) { if ((epnum == 0) && ep0_pending[TUSB_DIR_IN]) { // EP0 can only handle one packet. Schedule another packet to be transmitted. - edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); + edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN); } else { dcd_event_xfer_complete(rhport, epnum | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); } @@ -907,7 +844,6 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep // - 64 bytes or // - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL) if (diepint_bm.txfifo_empty && (dwc2->diepempmsk & (1 << epnum))) { - dwc2_dep_t* epin = &dwc2->epin[epnum]; const uint16_t remain_packets = epin->tsiz_bm.packet_count; // Process every single packet (only whole packets can be written to fifo) @@ -945,7 +881,7 @@ static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepin if (diepint_bm.xfer_complete) { if ((epnum == 0) && ep0_pending[TUSB_DIR_IN]) { // EP0 can only handle one packet. Schedule another packet to be transmitted. - edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); + edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN); } else { if(epnum == 0) { dma_setup_prepare(rhport); From d37707d6dd6147511cfaa10f21bdc4e28f2cdf69 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 18 Nov 2024 23:00:16 +0700 Subject: [PATCH 6/9] move handle ep slave/dma wihtin compiler macro --- hw/bsp/family_support.cmake | 5 + src/portable/synopsys/dwc2/dcd_dwc2.c | 262 +++++++++++++------------- 2 files changed, 141 insertions(+), 126 deletions(-) diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index aa5e037d1c..57fa63261e 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -289,6 +289,11 @@ function(family_add_tinyusb TARGET OPT_MCU RTOS) ) endif () + # compile define from command line + if(DEFINED CFLAGS_CLI) + target_compile_options(${TARGET}-tinyusb PUBLIC ${CFLAGS_CLI}) + endif() + endfunction() # Add bin/hex output diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 2ca4dc88d6..b1cb8c3eab 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -217,24 +217,32 @@ static void dfifo_device_init(uint8_t rhport) { //-------------------------------------------------------------------- static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); - uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); - uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); + const uint8_t epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); + const uint8_t dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); xfer->max_size = tu_edpt_packet_size(p_endpoint_desc); xfer->interval = p_endpoint_desc->bInterval; - // USBAEP, EPTYP, SD0PID_SEVNFRM, MPSIZ are the same for IN and OUT endpoints. - uint32_t epctl = (1 << DOEPCTL_USBAEP_Pos) | - (p_endpoint_desc->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) | - (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) | - (xfer->max_size << DOEPCTL_MPSIZ_Pos); + // Endpoint control + union { + uint32_t value; + dwc2_depctl_t bm; + } depctl; + depctl.value = 0; + + depctl.bm.mps = xfer->max_size; + depctl.bm.active = 1; + depctl.bm.type = p_endpoint_desc->bmAttributes.xfer; + if (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) { + depctl.bm.set_data0_iso_even = 1; + } if (dir == TUSB_DIR_IN) { - epctl |= (epnum << DIEPCTL_TXFNUM_Pos); + depctl.bm.tx_fifo_num = epnum; } dwc2_dep_t* dep = &dwc2->ep[1 - dir][epnum]; - dep->ctl = epctl; + dep->ctl = depctl.value; dwc2->daintmsk |= TU_BIT(epnum + DAINT_SHIFT(dir)); } @@ -288,7 +296,7 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { } } -static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir) { +static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uint8_t dir) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); const uint8_t is_epout = dir ? 0 : 1; @@ -571,6 +579,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t xfer->total_len = total_bytes; // Schedule packets to be sent within interrupt + // TODO xfer fifo may only available for slave mode edpt_schedule_packets(rhport, epnum, dir); return true; @@ -654,6 +663,48 @@ static void handle_bus_reset(uint8_t rhport) { dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT; } +static void handle_enum_done(uint8_t rhport) { + dwc2_regs_t *dwc2 = DWC2_REG(rhport); + tusb_speed_t speed; + switch (dwc2->dsts_bm.enum_speed) { + case DCFG_SPEED_HIGH: + speed = TUSB_SPEED_HIGH; + break; + + case DCFG_SPEED_LOW: + speed = TUSB_SPEED_LOW; + break; + + case DCFG_SPEED_FULL_30_60MHZ: + case DCFG_SPEED_FULL_48MHZ: + default: + speed = TUSB_SPEED_FULL; + break; + } + + // TODO must update GUSBCFG_TRDT according to link speed + dcd_event_bus_reset(rhport, speed, true); +} + +#if 0 +TU_ATTR_ALWAYS_INLINE static inline void print_doepint(uint32_t doepint) { + const char* str[] = { + "XFRC", "DIS", "AHBERR", "SETUP_DONE", + "ORXED", "STATUS_RX", "SETUP_B2B", "RSV7", + "OPERR", "BNA", "RSV10", "ISODROP", + "BBLERR", "NAK", "NYET", "SETUP_RX" + }; + + for(uint32_t i=0; itotal_len, XFER_RESULT_SUCCESS, true); - } - } - } -} - -static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepint_bm) { - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - - if (doepint_bm.setup_phase_done) { - dma_setup_prepare(rhport); - dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); - return; - } - - // OUT XFER complete - if (doepint_bm.xfer_complete) { - // only handle data skip if it is setup or status related - // Normal OUT transfer complete - if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) { if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) { - // EP0 can only handle one packet Schedule another packet to be received. + // EP0 can only handle one packet, Schedule another packet to be received. edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT); } else { - dwc2_dep_t* epout = &dwc2->epout[epnum]; - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); - - // determine actual received bytes - const uint16_t remain = epout->tsiz_bm.xfer_size; - xfer->total_len -= remain; - - // this is ZLP, so prepare EP0 for next setup - // TODO use status phase rx - if(epnum == 0 && xfer->total_len == 0) { - dma_setup_prepare(rhport); - } - dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); } } } } -#if 0 -TU_ATTR_ALWAYS_INLINE static inline void print_doepint(uint32_t doepint) { - const char* str[] = { - "XFRC", "DIS", "AHBERR", "SETUP_DONE", - "ORXED", "STATUS_RX", "SETUP_B2B", "RSV7", - "OPERR", "BNA", "RSV10", "ISODROP", - "BBLERR", "NAK", "NYET", "SETUP_RX" - }; - - for(uint32_t i=0; idaint & TU_BIT(DAINT_OEPINT_Pos + epnum)) { - dwc2_dep_t* epout = &dwc2->epout[epnum]; - const uint32_t doepint = epout->intr; - const dwc2_doepint_t doepint_bm = epout->doepint_bm; - - epout->intr = doepint; // Clear interrupt - - // print_doepint(doepint); - if (is_dma) { - handle_epout_dma(rhport, epnum, doepint_bm); - } else { - handle_epout_slave(rhport, epnum, doepint_bm); - } - } - } -} - static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepint_bm) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); dwc2_dep_t* epin = &dwc2->epin[epnum]; @@ -872,6 +842,45 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep } } } +#endif + +#if CFG_TUD_DWC2_DMA_ENABLE +static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepint_bm) { + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + + if (doepint_bm.setup_phase_done) { + dma_setup_prepare(rhport); + dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); + return; + } + + // OUT XFER complete + if (doepint_bm.xfer_complete) { + // only handle data skip if it is setup or status related + // Normal OUT transfer complete + if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) { + if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) { + // EP0 can only handle one packet Schedule another packet to be received. + edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT); + } else { + dwc2_dep_t* epout = &dwc2->epout[epnum]; + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); + + // determine actual received bytes + const uint16_t remain = epout->tsiz_bm.xfer_size; + xfer->total_len -= remain; + + // this is ZLP, so prepare EP0 for next setup + // TODO use status phase rx + if(epnum == 0 && xfer->total_len == 0) { + dma_setup_prepare(rhport); + } + + dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); + } + } + } +} static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepint_bm) { // dwc2_regs_t* dwc2 = DWC2_REG(rhport); @@ -890,27 +899,45 @@ static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepin } } } +#endif -static void handle_epin_irq(uint8_t rhport) { +static void handle_ep_irq(uint8_t rhport, uint8_t dir) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); const bool is_dma = dma_device_enabled(dwc2); const uint8_t ep_count = DWC2_EP_COUNT(dwc2); + const uint8_t daint_offset = (dir == TUSB_DIR_IN) ? DAINT_IEPINT_Pos : DAINT_OEPINT_Pos; - // DAINT for a given EP clears when DIEPINTx is cleared. - // IEPINT will be cleared when DAINT's out bits are cleared. + // DAINT for a given EP clears when DEPINTx is cleared. + // EPINT will be cleared when DAINT bits are cleared. for (uint8_t epnum = 0; epnum < ep_count; epnum++) { - if (dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + epnum)) { - dwc2_dep_t* epin = &dwc2->epin[epnum]; - const uint32_t diepint = epin->intr; - const dwc2_diepint_t diepint_bm = epin->diepint_bm; + if (dwc2->daint & TU_BIT(daint_offset + epnum)) { + dwc2_dep_t* epout = &dwc2->ep[1-dir][epnum]; + union { + uint32_t value; + dwc2_diepint_t diepint_bm; + dwc2_doepint_t doepint_bm; + } intr; + intr.value = epout->intr; - epin->intr = diepint; // Clear interrupt + epout->intr = intr.value; // Clear interrupt // print_doepint(doepint); if (is_dma) { - handle_epin_dma(rhport, epnum, diepint_bm); + #if CFG_TUD_DWC2_DMA_ENABLE + if (dir == TUSB_DIR_IN) { + handle_epin_dma(rhport, epnum, intr.diepint_bm); + } else { + handle_epout_dma(rhport, epnum, intr.doepint_bm); + } + #endif } else { - handle_epin_slave(rhport, epnum, diepint_bm); + #if CFG_TUD_DWC2_SLAVE_ENABLE + if (dir == TUSB_DIR_IN) { + handle_epin_slave(rhport, epnum, intr.diepint_bm); + } else { + handle_epout_slave(rhport, epnum, intr.doepint_bm); + } + #endif } } } @@ -931,8 +958,8 @@ static void handle_epin_irq(uint8_t rhport) { void dcd_int_handler(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); - uint32_t const int_mask = dwc2->gintmsk; - uint32_t const gintsts = dwc2->gintsts & int_mask; + const uint32_t gintmask = dwc2->gintmsk; + const uint32_t gintsts = dwc2->gintsts & gintmask; if (gintsts & GINTSTS_USBRST) { // USBRST is start of reset. @@ -943,26 +970,7 @@ void dcd_int_handler(uint8_t rhport) { if (gintsts & GINTSTS_ENUMDNE) { // ENUMDNE is the end of reset where speed of the link is detected dwc2->gintsts = GINTSTS_ENUMDNE; - - tusb_speed_t speed; - switch (dwc2->dsts_bm.enum_speed) { - case DCFG_SPEED_HIGH: - speed = TUSB_SPEED_HIGH; - break; - - case DCFG_SPEED_LOW: - speed = TUSB_SPEED_LOW; - break; - - case DCFG_SPEED_FULL_30_60MHZ: - case DCFG_SPEED_FULL_48MHZ: - default: - speed = TUSB_SPEED_FULL; - break; - } - - // TODO must update GUSBCFG_TRDT according to link speed - dcd_event_bus_reset(rhport, speed, true); + handle_enum_done(rhport); } if (gintsts & GINTSTS_USBSUSP) { @@ -1001,6 +1009,7 @@ void dcd_int_handler(uint8_t rhport) { dcd_event_sof(rhport, frame, true); } +#if CFG_TUD_DWC2_SLAVE_ENABLE // RxFIFO non-empty interrupt handling. if (gintsts & GINTSTS_RXFLVL) { // RXFLVL bit is read-only @@ -1012,17 +1021,18 @@ void dcd_int_handler(uint8_t rhport) { dwc2->gintmsk |= GINTMSK_RXFLVLM; } +#endif // OUT endpoint interrupt handling. if (gintsts & GINTSTS_OEPINT) { // OEPINT is read-only, clear using DOEPINTn - handle_epout_irq(rhport); + handle_ep_irq(rhport, TUSB_DIR_OUT); } // IN endpoint interrupt handling. if (gintsts & GINTSTS_IEPINT) { // IEPINT bit read-only, clear using DIEPINTn - handle_epin_irq(rhport); + handle_ep_irq(rhport, TUSB_DIR_IN); } // // Check for Incomplete isochronous IN transfer From 6d4a60d8ac4c0b3e6add8843216e99122b186ee4 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 18 Nov 2024 23:07:05 +0700 Subject: [PATCH 7/9] clean up --- src/portable/synopsys/dwc2/dcd_dwc2.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index b1cb8c3eab..c42ec4a8d0 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -241,7 +241,7 @@ static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoin depctl.bm.tx_fifo_num = epnum; } - dwc2_dep_t* dep = &dwc2->ep[1 - dir][epnum]; + dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum]; dep->ctl = depctl.value; dwc2->daintmsk |= TU_BIT(epnum + DAINT_SHIFT(dir)); } @@ -252,7 +252,7 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); const uint8_t epnum = tu_edpt_number(ep_addr); const uint8_t dir = tu_edpt_dir(ep_addr); - dwc2_dep_t* dep = &dwc2->ep[1 - dir][epnum]; + dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum]; if (dir == TUSB_DIR_IN) { // Only disable currently enabled non-control endpoint @@ -299,8 +299,7 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uint8_t dir) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); - const uint8_t is_epout = dir ? 0 : 1; - dwc2_dep_t* dep = &dwc2->ep[is_epout][epnum]; + dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum]; uint16_t num_packets; uint16_t total_bytes; @@ -601,7 +600,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - dwc2_dep_t* dep = &dwc2->ep[1 - dir][epnum]; + dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum]; // Clear stall and reset data toggle dep->ctl &= ~EPCTL_STALL;; @@ -906,12 +905,13 @@ static void handle_ep_irq(uint8_t rhport, uint8_t dir) { const bool is_dma = dma_device_enabled(dwc2); const uint8_t ep_count = DWC2_EP_COUNT(dwc2); const uint8_t daint_offset = (dir == TUSB_DIR_IN) ? DAINT_IEPINT_Pos : DAINT_OEPINT_Pos; + dwc2_dep_t* ep_base = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][0]; // DAINT for a given EP clears when DEPINTx is cleared. // EPINT will be cleared when DAINT bits are cleared. for (uint8_t epnum = 0; epnum < ep_count; epnum++) { if (dwc2->daint & TU_BIT(daint_offset + epnum)) { - dwc2_dep_t* epout = &dwc2->ep[1-dir][epnum]; + dwc2_dep_t* epout = &ep_base[epnum]; union { uint32_t value; dwc2_diepint_t diepint_bm; From ac9bc01132e3a396ceb977d16b808c4fb6226392 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 18 Nov 2024 23:15:17 +0700 Subject: [PATCH 8/9] add CFG_TUD_DWC2_SLAVE_ENABLE = 1 as default --- src/tusb_option.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tusb_option.h b/src/tusb_option.h index 6257a87ba4..cb4641ad51 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -247,6 +247,10 @@ // USBIP //--------------------------------------------------------------------+ +#ifndef CFG_TUD_DWC2_SLAVE_ENABLE + #define CFG_TUD_DWC2_SLAVE_ENABLE 1 +#endif + // DWC2 controller: use DMA for data transfer // For processors with data cache enabled, USB endpoint buffer region // (defined by CFG_TUSB_MEM_SECTION) must be declared as non-cacheable. From 3fe7e612c8df25dd66802c6da2183101eed2f83c Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 18 Nov 2024 23:38:25 +0700 Subject: [PATCH 9/9] remove commented code --- src/portable/synopsys/dwc2/dcd_dwc2.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index c42ec4a8d0..2b3ef096f9 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -770,8 +770,6 @@ static void handle_rxflvl_irq(uint8_t rhport) { } static void handle_epout_slave(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepint_bm) { - // dwc2_regs_t* dwc2 = DWC2_REG(rhport); - if (doepint_bm.setup_phase_done) { dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); return; @@ -882,8 +880,6 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi } static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepint_bm) { - // dwc2_regs_t* dwc2 = DWC2_REG(rhport); - // dwc2_dep_t* epin = &dwc2->epin[epnum]; xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN); if (diepint_bm.xfer_complete) { @@ -921,7 +917,6 @@ static void handle_ep_irq(uint8_t rhport, uint8_t dir) { epout->intr = intr.value; // Clear interrupt - // print_doepint(doepint); if (is_dma) { #if CFG_TUD_DWC2_DMA_ENABLE if (dir == TUSB_DIR_IN) { @@ -1034,12 +1029,6 @@ void dcd_int_handler(uint8_t rhport) { // IEPINT bit read-only, clear using DIEPINTn handle_ep_irq(rhport, TUSB_DIR_IN); } - - // // Check for Incomplete isochronous IN transfer - // if(int_status & GINTSTS_IISOIXFR) { - // printf(" IISOIXFR!\r\n"); - //// TU_LOG(DWC2_DEBUG, " IISOIXFR!\r\n"); - // } } #if CFG_TUD_TEST_MODE