make dwc2 stm32 rhport support dynamic

This commit is contained in:
hathach 2022-06-03 17:24:28 +07:00
parent 2571211957
commit 31134f41a1
3 changed files with 98 additions and 62 deletions

View File

@ -50,12 +50,14 @@
#error "Unsupported MCUs" #error "Unsupported MCUs"
#endif #endif
// Note _dwc2_controller[] must be defined by port header
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM // MACRO TYPEDEF CONSTANT ENUM
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// DWC2 registers // 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 // Debug level for DWC2
#define DWC2_DEBUG 2 #define DWC2_DEBUG 2
@ -72,7 +74,6 @@
#define dcache_clean_invalidate(_addr, _size) #define dcache_clean_invalidate(_addr, _size)
#endif #endif
static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2]; static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2];
typedef struct { typedef struct {
@ -97,34 +98,32 @@ static bool _out_ep_closed; // Flag to check if RX FIFO si
static bool _sof_en; static bool _sof_en;
// Calculate the RX FIFO size according to recommendations from reference manual // 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) static void update_grxfsiz(uint8_t rhport)
{ {
(void) rhport; dwc2_regs_t * dwc2 = DWC2_REG(rhport);
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
dwc2_regs_t * dwc2 = DWC2_REG(rhport);
// Determine largest EP size for RX FIFO // Determine largest EP size for RX FIFO
uint16_t max_epsize = 0; 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); max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size);
} }
// Update size of RX FIFO // 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) static void bus_reset(uint8_t rhport)
{ {
(void) rhport; dwc2_regs_t * dwc2 = DWC2_REG(rhport);
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
dwc2_regs_t * dwc2 = DWC2_REG(rhport);
tu_memclr(xfer_status, sizeof(xfer_status)); tu_memclr(xfer_status, sizeof(xfer_status));
_out_ep_closed = false; _out_ep_closed = false;
@ -135,7 +134,7 @@ static void bus_reset(uint8_t rhport)
dwc2->dcfg &= ~DCFG_DAD_Msk; dwc2->dcfg &= ~DCFG_DAD_Msk;
// 1. NAK for all OUT endpoints // 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; dwc2->epout[n].doepctl |= DOEPCTL_SNAK;
} }
@ -185,22 +184,24 @@ static void bus_reset(uint8_t rhport)
// - 2 for each used OUT endpoint // - 2 for each used OUT endpoint
// //
// Therefore GRXFSIZ = 13 + 1 + 1 + 2 x (Largest-EPsize/4) + 2 x EPOUTnum // 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 // - 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 DWC2_EP_MAX = 271 + 2 x DWC2_EP_MAX // - 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 // 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 // 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 // are enabled at least "2 x (Largest-EPsize/4) + 1" are recommended. Maybe provide a macro for application to
// overwrite this. // 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; _allocated_fifo_words_tx = 16;
// Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) // 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 // Fixed control EP0 size to 64 bytes
dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); 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) static bool phy_hs_supported(dwc2_regs_t * dwc2)
{ {
// note: esp32 incorrect report its hs_phy_type as utmi // 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; 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) 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; (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 epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(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_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
xfer->max_size = tu_edpt_packet_size(desc_edpt); 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) if(dir == TUSB_DIR_OUT)
{ {
// Calculate required size of RX FIFO // 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 size_rx needs to be extended check if possible and if so enlarge it
if (dwc2->grxfsiz < sz) 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 // Enlarge RX FIFO
dwc2->grxfsiz = sz; 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". // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
// Check if free space is available // 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; _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. // DIEPTXF starts at FIFO #1.
// Both TXFD and TXSA are in unit of 32-bit words. // 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) | dwc2->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) |
(epnum << DIEPCTL_TXFNUM_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. // Close all non-control endpoints, cancel all pending transfers if any.
void dcd_edpt_close_all (uint8_t rhport) void dcd_edpt_close_all (uint8_t rhport)
{ {
(void) rhport; dwc2_regs_t * dwc2 = DWC2_REG(rhport);
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
dwc2_regs_t * dwc2 = DWC2_REG(rhport);
// Disable non-control interrupt // Disable non-control interrupt
dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos); 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 // disable OUT endpoint
dwc2->epout[n].doepctl = 0; 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_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; 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. // 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; _allocated_fifo_words_tx -= fifo_size;
} }
else else
@ -1075,11 +1081,12 @@ static void handle_rxflvl_irq(uint8_t rhport)
static void handle_epout_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. // DAINT for a given EP clears when DOEPINTx is cleared.
// OEPINT will be cleared when DAINT's out bits are 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) ) 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) static void handle_epin_irq (uint8_t rhport)
{ {
dwc2_regs_t *dwc2 = DWC2_REG(rhport); dwc2_regs_t * dwc2 = DWC2_REG(rhport);
dwc2_epin_t* epin = dwc2->epin; 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. // DAINT for a given EP clears when DIEPINTx is cleared.
// IEPINT will be cleared when DAINT's out bits are 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) ) if ( dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n) )
{ {

View File

@ -56,12 +56,9 @@
#define EP_FIFO_SIZE_FS 4096 #define EP_FIFO_SIZE_FS 4096
#define EP_MAX_HS 9 #define EP_MAX_HS 9
#define EP_FIFO_SIZE_HS 4096 #define EP_FIFO_SIZE_HS 4096
#if (! defined USB2_OTG_FS)
// H7 with only 1 USB port: H72x / H73x / H7Ax / H7Bx // NOTE: H7 with only 1 USB port: H72x / H73x / H7Ax / H7Bx
// USB_OTG_FS_PERIPH_BASE and OTG_FS_IRQn not defined // 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
#elif CFG_TUSB_MCU == OPT_MCU_STM32F7 #elif CFG_TUSB_MCU == OPT_MCU_STM32F7
#include "stm32f7xx.h" #include "stm32f7xx.h"
@ -79,35 +76,57 @@
#error "Unsupported MCUs" #error "Unsupported MCUs"
#endif #endif
// On STM32 we associate Port0 to OTG_FS, and Port1 to OTG_HS // OTG HS always has higher number of endpoints than FS
#if TUD_OPT_RHPORT == 0 #ifdef EP_MAX_HS
#define DWC2_REG_BASE USB_OTG_FS_PERIPH_BASE #define DWC2_EP_MAX EP_MAX_HS
#define DWC2_EP_MAX EP_MAX_FS
#define DWC2_EP_FIFO_SIZE EP_FIFO_SIZE_FS
#define RHPORT_IRQn OTG_FS_IRQn
#else #else
#define DWC2_REG_BASE USB_OTG_HS_PERIPH_BASE #define DWC2_EP_MAX EP_MAX_FS
#define DWC2_EP_MAX EP_MAX_HS
#define DWC2_EP_FIFO_SIZE EP_FIFO_SIZE_HS
#define RHPORT_IRQn OTG_HS_IRQn
#endif #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; extern uint32_t SystemCoreClock;
TU_ATTR_ALWAYS_INLINE TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport) static inline void dwc2_dcd_int_enable(uint8_t rhport)
{ {
(void) rhport; NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum);
NVIC_EnableIRQ(RHPORT_IRQn);
} }
TU_ATTR_ALWAYS_INLINE TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_disable (uint8_t rhport) static inline void dwc2_dcd_int_disable (uint8_t rhport)
{ {
(void) rhport; NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum);
NVIC_DisableIRQ(RHPORT_IRQn);
} }
TU_ATTR_ALWAYS_INLINE TU_ATTR_ALWAYS_INLINE

View File

@ -19,6 +19,19 @@
#include "stdint.h" #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 */ /* DWC OTG HW Release versions */
#define DWC2_CORE_REV_2_71a 0x4f54271a #define DWC2_CORE_REV_2_71a 0x4f54271a
#define DWC2_CORE_REV_2_72a 0x4f54272a #define DWC2_CORE_REV_2_72a 0x4f54272a
@ -40,10 +53,6 @@
#define DWC2_FS_IOT_ID 0x55310000 #define DWC2_FS_IOT_ID 0x55310000
#define DWC2_HS_IOT_ID 0x55320000 #define DWC2_HS_IOT_ID 0x55320000
#ifdef __cplusplus
extern "C" {
#endif
#if 0 #if 0
// HS PHY // HS PHY
typedef struct typedef struct