summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c192
-rw-r--r--src/portable/synopsys/dwc2/dwc2_common.c9
-rw-r--r--src/portable/synopsys/dwc2/dwc2_common.h2
-rw-r--r--src/portable/synopsys/dwc2/dwc2_type.h173
-rw-r--r--src/portable/synopsys/dwc2/hcd_dwc2.c10
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 80287305a..ae6377a49 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 4d62cf3c6..ef155c8f7 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 3f7f23c3a..18b93894f 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 1247f19a3..01e10ee00 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 53583426f..550778876 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 -------------//