From 31134f41a17c004aa48d87e397a6bae061f5b328 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 3 Jun 2022 17:24:28 +0700 Subject: [PATCH] make dwc2 stm32 rhport support dynamic --- src/portable/synopsys/dwc2/dcd_dwc2.c | 80 ++++++++++++++----------- src/portable/synopsys/dwc2/dwc2_stm32.h | 63 ++++++++++++------- src/portable/synopsys/dwc2/dwc2_type.h | 17 ++++-- 3 files changed, 98 insertions(+), 62 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index e489f6445..4d9e43ba8 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -50,12 +50,14 @@ #error "Unsupported MCUs" #endif +// Note _dwc2_controller[] must be defined by port header + //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM //--------------------------------------------------------------------+ // DWC2 registers -#define DWC2_REG(_port) ((dwc2_regs_t*) DWC2_REG_BASE) +#define DWC2_REG(_port) ((dwc2_regs_t*) _dwc2_controller[_port].reg_base) // Debug level for DWC2 #define DWC2_DEBUG 2 @@ -72,7 +74,6 @@ #define dcache_clean_invalidate(_addr, _size) #endif - static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2]; typedef struct { @@ -97,34 +98,32 @@ static bool _out_ep_closed; // Flag to check if RX FIFO si static bool _sof_en; // Calculate the RX FIFO size according to recommendations from reference manual -static inline uint16_t calc_rx_ff_size(uint16_t ep_size) +static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) { - return 15 + 2*(ep_size/4) + 2*DWC2_EP_MAX; + return 15 + 2*(max_ep_size/4) + 2*ep_count; } static void update_grxfsiz(uint8_t rhport) { - (void) rhport; - - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; // Determine largest EP size for RX FIFO uint16_t max_epsize = 0; - for (uint8_t epnum = 0; epnum < DWC2_EP_MAX; epnum++) + for (uint8_t epnum = 0; epnum < ep_count; epnum++) { max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size); } // Update size of RX FIFO - dwc2->grxfsiz = calc_rx_ff_size(max_epsize); + dwc2->grxfsiz = calc_grxfsiz(max_epsize, ep_count); } -// Setup the control endpoint 0. +// Start of Bus Reset static void bus_reset(uint8_t rhport) { - (void) rhport; - - dwc2_regs_t * dwc2 = DWC2_REG(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)); _out_ep_closed = false; @@ -135,7 +134,7 @@ static void bus_reset(uint8_t rhport) dwc2->dcfg &= ~DCFG_DAD_Msk; // 1. NAK for all OUT endpoints - for ( uint8_t n = 0; n < DWC2_EP_MAX; n++ ) + for ( uint8_t n = 0; n < ep_count; n++ ) { dwc2->epout[n].doepctl |= DOEPCTL_SNAK; } @@ -185,22 +184,24 @@ static void bus_reset(uint8_t rhport) // - 2 for each used OUT endpoint // // Therefore GRXFSIZ = 13 + 1 + 1 + 2 x (Largest-EPsize/4) + 2 x EPOUTnum - // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x DWC2_EP_MAX = 47 + 2 x DWC2_EP_MAX - // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x DWC2_EP_MAX = 271 + 2 x DWC2_EP_MAX + // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x ep_count = 47 + 2 x ep_count + // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x ep_count = 271 + 2 x ep_count // // NOTE: Largest-EPsize & EPOUTnum is actual used endpoints in configuration. Since DCD has no knowledge - // of the overall picture yet. We will use the worst scenario: largest possible + DWC2_EP_MAX + // of the overall picture yet. We will use the worst scenario: largest possible + ep_count // // For Isochronous, largest EP size can be 1023/1024 for FS/HS respectively. In addition if multiple ISO // are enabled at least "2 x (Largest-EPsize/4) + 1" are recommended. Maybe provide a macro for application to // overwrite this. - dwc2->grxfsiz = calc_rx_ff_size(TUD_OPT_HIGH_SPEED ? 512 : 64); + // EP0 out max is 64 + dwc2->grxfsiz = calc_grxfsiz(64, ep_count); + // Setup the control endpoint 0 _allocated_fifo_words_tx = 16; // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) - dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx); + dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx); // Fixed control EP0 size to 64 bytes dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); @@ -363,7 +364,11 @@ static void reset_core(dwc2_regs_t * dwc2) static bool phy_hs_supported(dwc2_regs_t * dwc2) { // note: esp32 incorrect report its hs_phy_type as utmi +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + return false; +#else return TUD_OPT_HIGH_SPEED && dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE; +#endif } static void phy_fs_init(dwc2_regs_t * dwc2) @@ -620,12 +625,13 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) { (void) rhport; - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress); uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress); - TU_ASSERT(epnum < DWC2_EP_MAX); + TU_ASSERT(epnum < ep_count); xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); xfer->max_size = tu_edpt_packet_size(desc_edpt); @@ -636,12 +642,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) if(dir == TUSB_DIR_OUT) { // Calculate required size of RX FIFO - uint16_t const sz = calc_rx_ff_size(4*fifo_size); + uint16_t const sz = calc_grxfsiz(4*fifo_size, ep_count); // If size_rx needs to be extended check if possible and if so enlarge it if (dwc2->grxfsiz < sz) { - TU_ASSERT(sz + _allocated_fifo_words_tx <= DWC2_EP_FIFO_SIZE/4); + TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size/4); // Enlarge RX FIFO dwc2->grxfsiz = sz; @@ -678,15 +684,15 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". // Check if free space is available - TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= DWC2_EP_FIFO_SIZE/4); + TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size/4); _allocated_fifo_words_tx += fifo_size; - TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %u", fifo_size*4, DWC2_EP_FIFO_SIZE-_allocated_fifo_words_tx*4); + TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %lu", fifo_size*4, _dwc2_controller[rhport].ep_fifo_size-_allocated_fifo_words_tx*4); // DIEPTXF starts at FIFO #1. // Both TXFD and TXSA are in unit of 32-bit words. - dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx); + dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx); dwc2->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) | (epnum << DIEPCTL_TXFNUM_Pos) | @@ -703,14 +709,13 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) // Close all non-control endpoints, cancel all pending transfers if any. void dcd_edpt_close_all (uint8_t rhport) { - (void) rhport; - - dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; // Disable non-control interrupt dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos); - for(uint8_t n = 1; n < DWC2_EP_MAX; n++) + for(uint8_t n = 1; n < ep_count; n++) { // disable OUT endpoint dwc2->epout[n].doepctl = 0; @@ -871,8 +876,9 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) { uint16_t const fifo_size = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXFD_Msk) >> DIEPTXF_INEPTXFD_Pos; uint16_t const fifo_start = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXSA_Msk) >> DIEPTXF_INEPTXSA_Pos; + // For now only the last opened endpoint can be closed without fuss. - TU_ASSERT(fifo_start == DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx,); + TU_ASSERT(fifo_start == _dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx,); _allocated_fifo_words_tx -= fifo_size; } else @@ -1075,11 +1081,12 @@ static void handle_rxflvl_irq(uint8_t rhport) static void handle_epout_irq (uint8_t rhport) { - dwc2_regs_t *dwc2 = DWC2_REG(rhport); + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; // DAINT for a given EP clears when DOEPINTx is cleared. // OEPINT will be cleared when DAINT's out bits are cleared. - for ( uint8_t n = 0; n < DWC2_EP_MAX; n++ ) + for ( uint8_t n = 0; n < ep_count; n++ ) { if ( dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n) ) { @@ -1126,12 +1133,13 @@ static void handle_epout_irq (uint8_t rhport) static void handle_epin_irq (uint8_t rhport) { - dwc2_regs_t *dwc2 = DWC2_REG(rhport); - dwc2_epin_t* epin = dwc2->epin; + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + dwc2_epin_t* epin = dwc2->epin; // 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 < DWC2_EP_MAX; n++ ) + for ( uint8_t n = 0; n < ep_count; n++ ) { if ( dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n) ) { diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h index d54bf1fd7..23632616a 100644 --- a/src/portable/synopsys/dwc2/dwc2_stm32.h +++ b/src/portable/synopsys/dwc2/dwc2_stm32.h @@ -56,12 +56,9 @@ #define EP_FIFO_SIZE_FS 4096 #define EP_MAX_HS 9 #define EP_FIFO_SIZE_HS 4096 - #if (! defined USB2_OTG_FS) - // H7 with only 1 USB port: H72x / H73x / H7Ax / H7Bx - // USB_OTG_FS_PERIPH_BASE and OTG_FS_IRQn not defined - #define USB_OTG_FS_PERIPH_BASE USB1_OTG_HS_PERIPH_BASE - #define OTG_FS_IRQn OTG_HS_IRQn - #endif + + // NOTE: H7 with only 1 USB port: H72x / H73x / H7Ax / H7Bx + // USB_OTG_FS_PERIPH_BASE and OTG_FS_IRQn not defined #elif CFG_TUSB_MCU == OPT_MCU_STM32F7 #include "stm32f7xx.h" @@ -79,35 +76,57 @@ #error "Unsupported MCUs" #endif -// On STM32 we associate Port0 to OTG_FS, and Port1 to OTG_HS -#if TUD_OPT_RHPORT == 0 - #define DWC2_REG_BASE USB_OTG_FS_PERIPH_BASE - #define DWC2_EP_MAX EP_MAX_FS - #define DWC2_EP_FIFO_SIZE EP_FIFO_SIZE_FS - #define RHPORT_IRQn OTG_FS_IRQn - +// OTG HS always has higher number of endpoints than FS +#ifdef EP_MAX_HS + #define DWC2_EP_MAX EP_MAX_HS #else - #define DWC2_REG_BASE USB_OTG_HS_PERIPH_BASE - #define DWC2_EP_MAX EP_MAX_HS - #define DWC2_EP_FIFO_SIZE EP_FIFO_SIZE_HS - #define RHPORT_IRQn OTG_HS_IRQn - + #define DWC2_EP_MAX EP_MAX_FS #endif +// On STM32 we associate Port0 to OTG_FS, and Port1 to OTG_HS +//#if TUD_OPT_RHPORT == 0 +// #define DWC2_REG_BASE USB_OTG_FS_PERIPH_BASE +// #define DWC2_EP_MAX EP_MAX_FS +// #define DWC2_EP_FIFO_SIZE EP_FIFO_SIZE_FS +// #define RHPORT_IRQn OTG_FS_IRQn +// +//#else +// #define DWC2_REG_BASE USB_OTG_HS_PERIPH_BASE +// #define DWC2_EP_MAX EP_MAX_HS +// #define DWC2_EP_FIFO_SIZE EP_FIFO_SIZE_HS +// #define RHPORT_IRQn OTG_HS_IRQn +// +//#endif + +// On STM32 for consistency we associate +// - Port0 to OTG_FS, and Port1 to OTG_HS +static const dwc2_controller_t _dwc2_controller[] = +{ +#ifdef USB_OTG_FS_PERIPH_BASE + { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .ep_fifo_size = EP_FIFO_SIZE_FS}, +#endif + +#ifdef USB_OTG_HS_PERIPH_BASE + { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .ep_fifo_size = EP_FIFO_SIZE_HS}, +#endif +}; + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + extern uint32_t SystemCoreClock; TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_enable(uint8_t rhport) { - (void) rhport; - NVIC_EnableIRQ(RHPORT_IRQn); + NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum); } TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_disable (uint8_t rhport) { - (void) rhport; - NVIC_DisableIRQ(RHPORT_IRQn); + NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum); } TU_ATTR_ALWAYS_INLINE diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index 7fa2028eb..e9df7335e 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -19,6 +19,19 @@ #include "stdint.h" +#ifdef __cplusplus + extern "C" { +#endif + +// Controller +typedef struct +{ + uint32_t reg_base; + uint32_t irqnum; + uint8_t ep_count; + uint32_t ep_fifo_size; +}dwc2_controller_t; + /* DWC OTG HW Release versions */ #define DWC2_CORE_REV_2_71a 0x4f54271a #define DWC2_CORE_REV_2_72a 0x4f54272a @@ -40,10 +53,6 @@ #define DWC2_FS_IOT_ID 0x55310000 #define DWC2_HS_IOT_ID 0x55320000 -#ifdef __cplusplus - extern "C" { -#endif - #if 0 // HS PHY typedef struct