Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/device/dcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
15 changes: 12 additions & 3 deletions src/device/usbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
//--------------------------------------------------------------------+
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
20 changes: 20 additions & 0 deletions src/device/usbd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
31 changes: 23 additions & 8 deletions src/portable/synopsys/dwc2/dcd_dwc2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
}


Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is no need to set FIFO level to complete empty in any case ?

gahbcfg |= GAHBCFG_GINT; // Enable global interrupt
dwc2->gahbcfg = gahbcfg;

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down