diff --git a/src/device/dcd.h b/src/device/dcd.h index 8a074ab47b..850c37bc25 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -107,6 +107,9 @@ bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size); // Controller API //--------------------------------------------------------------------+ +// optional dcd configuration, called by tud_configure() +bool dcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param); + // Initialize controller to device mode bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init); diff --git a/src/device/usbd.c b/src/device/usbd.c index 5e7d0ffa7d..4876b8c1eb 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -426,6 +426,11 @@ TU_ATTR_WEAK bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t return false; } +TU_ATTR_WEAK bool dcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { + (void) rhport; (void) cfg_id; (void) cfg_param; + return false; +} + //--------------------------------------------------------------------+ // Debug //--------------------------------------------------------------------+ @@ -495,13 +500,14 @@ void tud_sof_cb_enable(bool en) { usbd_sof_enable(_usbd_rhport, SOF_CONSUMER_USER, en); } -//--------------------------------------------------------------------+ -// USBD Task -//--------------------------------------------------------------------+ bool tud_inited(void) { return _usbd_rhport != RHPORT_INVALID; } +bool tud_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { + return dcd_configure(rhport, cfg_id, cfg_param); +} + bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { if (tud_inited()) { return true; // skip if already initialized @@ -625,6 +631,9 @@ bool tud_task_event_ready(void) { return !osal_queue_empty(_usbd_q); } +//--------------------------------------------------------------------+ +// USBD Task +//--------------------------------------------------------------------+ /* USB Device Driver task * This top level thread manages all device controller event and delegates events to class-specific drivers. * This should be called periodically within the mainloop or rtos thread. diff --git a/src/device/usbd.h b/src/device/usbd.h index c446638c38..efde9377f8 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -33,10 +33,30 @@ extern "C" { #endif +// ConfigID for tud_configure() +enum { + TUD_CFGID_INVALID = 0, + TUD_CFGID_DWC2 = 100, +}; + +typedef struct { + uint16_t bm_double_buffered; // bitmap of IN endpoints to be double buffered, only effective for bulk endpoints +} tud_configure_dwc2_t; + +typedef union { + tud_configure_dwc2_t dwc2; +} tud_configure_param_t; + //--------------------------------------------------------------------+ // Application API //--------------------------------------------------------------------+ +// Configure device stack behavior with dynamic or port-specific parameters. +// Should be called before initialization of the device stack +// - cfg_id : configure ID from TUD_CFGID_* enum values +// - cfg_param: configure data, structure depends on the ID +bool tud_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param); + // New API to replace tud_init() to init device stack on specific roothub port bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init); diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 00e81217b4..ba40498e61 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -39,6 +39,7 @@ #define DWC2_DEBUG 2 #include "device/dcd.h" +#include "device/usbd.h" #include "device/usbd_pvt.h" #include "dwc2_common.h" @@ -76,6 +77,10 @@ CFG_TUD_MEM_SECTION static struct { TUD_EPBUF_DEF(setup_packet, 8); } _dcd_usbbuf; +static tud_configure_dwc2_t _tud_cfg = { + .bm_double_buffered = 0 +}; + TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_ep_count(const dwc2_regs_t* dwc2) { #if TU_CHECK_MCU(OPT_MCU_GD32VF103) (void) dwc2; @@ -186,7 +191,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t calc_device_grxfsiz(uint16_t larges return 13 + 1 + 2 * ((largest_ep_size / 4) + 1) + 2 * ep_count; } -static bool dfifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) { +static bool dfifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size, bool is_bulk) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport]; const uint8_t ep_count = dwc2_controller->ep_count; @@ -212,8 +217,9 @@ static bool dfifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) { _dcd_data.allocated_epin_count++; } - // If The TXFELVL is configured as half empty, the fifo must be twice the max_size. - if ((dwc2->gahbcfg & GAHBCFG_TX_FIFO_EPMTY_LVL) == 0) { + // Enable double buffering if configured, only effective for non-periodic endpoints + // Since we queue only 1 control transfer at a time, it's only applicable for bulk IN endpoints + if (((_tud_cfg.bm_double_buffered & (1 << epnum)) != 0) && epnum > 0 && is_bulk) { fifo_size *= 2; } @@ -248,7 +254,7 @@ static void dfifo_device_init(uint8_t rhport) { dwc2->gdfifocfg = ((uint32_t) _dcd_data.dfifo_top << GDFIFOCFG_EPINFOBASE_SHIFT) | _dcd_data.dfifo_top; // Allocate FIFO for EP0 IN - (void) dfifo_alloc(rhport, 0x80, CFG_TUD_ENDPOINT0_SIZE); + (void) dfifo_alloc(rhport, 0x80, CFG_TUD_ENDPOINT0_SIZE, false); } @@ -446,6 +452,16 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin //-------------------------------------------------------------------- // Controller API //-------------------------------------------------------------------- +// optional dcd configuration, called by tud_configure() +bool dcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { + (void) rhport; + TU_VERIFY(cfg_id == TUD_CFGID_DWC2 && cfg_param != NULL); + + const tud_configure_param_t* const cfg = (const tud_configure_param_t*) cfg_param; + _tud_cfg = cfg->dwc2; + return true; +} + bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { (void) rh_init; dwc2_regs_t* dwc2 = DWC2_REG(rhport); @@ -492,9 +508,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // Enable required interrupts dwc2->gintmsk |= GINTMSK_OTGINT | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM; - // TX FIFO empty level for interrupt is complete empty uint32_t gahbcfg = dwc2->gahbcfg; - gahbcfg |= GAHBCFG_TX_FIFO_EPMTY_LVL; gahbcfg |= GAHBCFG_GINT; // Enable global interrupt dwc2->gahbcfg = gahbcfg; @@ -590,7 +604,8 @@ void dcd_sof_enable(uint8_t rhport, bool en) { *------------------------------------------------------------------*/ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { - TU_ASSERT(dfifo_alloc(rhport, desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt))); + TU_ASSERT(dfifo_alloc(rhport, desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), + desc_edpt->bmAttributes.xfer == TUSB_XFER_BULK)); edpt_activate(rhport, desc_edpt); return true; } @@ -625,7 +640,7 @@ void dcd_edpt_close_all(uint8_t rhport) { } bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { - TU_ASSERT(dfifo_alloc(rhport, ep_addr, largest_packet_size)); + TU_ASSERT(dfifo_alloc(rhport, ep_addr, largest_packet_size, false)); return true; }