summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c84
-rw-r--r--src/portable/synopsys/dwc2/dwc2_common.c35
-rw-r--r--src/portable/synopsys/dwc2/dwc2_common.h37
-rw-r--r--src/portable/synopsys/dwc2/dwc2_type.h121
-rw-r--r--src/portable/synopsys/dwc2/hcd_dwc2.c64
-rw-r--r--src/tusb_option.h4
6 files changed, 212 insertions, 133 deletions
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index c67c34404..6760af3f3 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -68,22 +68,6 @@ static bool _sof_en;
// DMA
//--------------------------------------------------------------------
-TU_ATTR_ALWAYS_INLINE static inline bool dma_enabled(const dwc2_regs_t* dwc2) {
- #if !CFG_TUD_DWC2_DMA
- (void) dwc2;
- return false;
- #else
- // Internal DMA only
- return (dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA);
- #endif
-}
-
-TU_ATTR_ALWAYS_INLINE static inline uint16_t dma_cal_epfifo_base(uint8_t rhport) {
- // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per endpoint direction
- const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
- return dwc2_controller->ep_fifo_size/4 - 2*dwc2_controller->ep_count;
-}
-
static void dma_setup_prepare(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
@@ -103,16 +87,6 @@ static void dma_setup_prepare(uint8_t rhport) {
// Data FIFO
//--------------------------------------------------------------------+
-TU_ATTR_ALWAYS_INLINE static inline void dfifo_flush_tx(dwc2_regs_t* dwc2, uint8_t epnum) {
- // flush TX fifo and wait for it cleared
- dwc2->grstctl = GRSTCTL_TXFFLSH | (epnum << GRSTCTL_TXFNUM_Pos);
- while (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) {}
-}
-TU_ATTR_ALWAYS_INLINE static inline void dfifo_flush_rx(dwc2_regs_t* dwc2) {
- // flush RX fifo and wait for it cleared
- dwc2->grstctl = GRSTCTL_RXFFLSH;
- while (dwc2->grstctl & GRSTCTL_RXFFLSH_Msk) {}
-}
/* USB Data FIFO Layout
@@ -215,7 +189,7 @@ static void dfifo_init(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
dwc2->grxfsiz = calc_grxfsiz(CFG_TUD_ENDPOINT0_SIZE, dwc2_controller->ep_count);
- if(dma_enabled(dwc2)) {
+ if(dwc2_dma_enabled(dwc2, TUSB_ROLE_DEVICE)) {
// DMA use last DFIFO to store metadata
_dfifo_top = dma_cal_epfifo_base(rhport);
}else {
@@ -395,7 +369,7 @@ static void bus_reset(uint8_t rhport) {
xfer_status[0][TUSB_DIR_OUT].max_size = 64;
xfer_status[0][TUSB_DIR_IN].max_size = 64;
- if(dma_enabled(dwc2)) {
+ if(dwc2_dma_enabled(dwc2, TUSB_ROLE_DEVICE)) {
dma_setup_prepare(rhport);
} else {
dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
@@ -427,7 +401,7 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c
dep->dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) |
((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk);
- if(dma_enabled(dwc2)) {
+ if(dwc2_dma_enabled(dwc2, TUSB_ROLE_DEVICE)) {
dep->diepdma = (uintptr_t)xfer->buffer;
// For ISO endpoint set correct odd/even bit for next frame.
@@ -465,7 +439,7 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c
dep->doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk);
}
- if(dma_enabled(dwc2)) {
+ if(dwc2_dma_enabled(dwc2, TUSB_ROLE_DEVICE)) {
dep->doepdma = (uintptr_t)xfer->buffer;
}
@@ -477,9 +451,9 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c
// Controller API
//--------------------------------------------------------------------
bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
- (void) rh_init;
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ // Core Initialization
TU_ASSERT(dwc2_core_init(rhport, rh_init));
// Device Initialization
@@ -500,9 +474,6 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
}
dwc2->dcfg = dcfg;
- // Enable PHY clock TODO stop/gate clock when suspended mode
- dwc2->pcgcctl &= ~(PCGCCTL_STOPPCLK | PCGCCTL_GATEHCLK | PCGCCTL_PWRCLMP | PCGCCTL_RSTPDWNMODULE);
-
// Force device mode
dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD;
@@ -512,44 +483,13 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
// If USB host misbehaves during status portion of control xfer (non zero-length packet), send STALL back and discard
dwc2->dcfg |= DCFG_NZLSOHSK;
- dfifo_flush_tx(dwc2, 0x10); // all tx fifo
- dfifo_flush_rx(dwc2);
-
- // Clear all interrupts
- uint32_t int_mask = dwc2->gintsts;
- dwc2->gintsts |= int_mask;
- int_mask = dwc2->gotgint;
- dwc2->gotgint |= int_mask;
-
- // Required as part of core initialization.
- dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM;
+ // Enable required interrupts
+ dwc2->gintmsk |= GINTMSK_OTGINT | GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM;
// Configure TX FIFO empty level for interrupt. Default is complete empty
dwc2->gahbcfg |= GAHBCFG_TXFELVL;
- if (dma_enabled(dwc2)) {
- const uint16_t epinfo_base = dma_cal_epfifo_base(rhport);
- dwc2->gdfifocfg = (epinfo_base << GDFIFOCFG_EPINFOBASE_SHIFT) | epinfo_base;
-
- // DMA seems to be only settable after a core reset
- dwc2->gahbcfg |= GAHBCFG_DMAEN | GAHBCFG_HBSTLEN_2;
- }else {
- dwc2->gintmsk |= GINTMSK_RXFLVLM;
- }
-
- // Enable global interrupt
- dwc2->gahbcfg |= GAHBCFG_GINT;
-
- // make sure we are in device mode
-// TU_ASSERT(!(dwc2->gintsts & GINTSTS_CMOD), );
-
-// TU_LOG_HEX(DWC2_DEBUG, dwc2->gotgctl);
-// TU_LOG_HEX(DWC2_DEBUG, dwc2->gusbcfg);
-// TU_LOG_HEX(DWC2_DEBUG, dwc2->dcfg);
-// TU_LOG_HEX(DWC2_DEBUG, dwc2->gahbcfg);
-
dcd_connect(rhport);
-
return true;
}
@@ -749,7 +689,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
edpt_disable(rhport, ep_addr, true);
- if((tu_edpt_number(ep_addr) == 0) && dma_enabled(DWC2_REG(rhport))) {
+ if((tu_edpt_number(ep_addr) == 0) && dwc2_dma_enabled(DWC2_REG(rhport), TUSB_ROLE_DEVICE)) {
dma_setup_prepare(rhport);
}
}
@@ -866,7 +806,7 @@ static void handle_epout_irq(uint8_t rhport) {
if (doepint & DOEPINT_SETUP) {
epout->doepint = DOEPINT_SETUP;
- if(dma_enabled(dwc2)) {
+ if(dwc2_dma_enabled(dwc2, TUSB_ROLE_DEVICE)) {
dma_setup_prepare(rhport);
}
@@ -882,7 +822,7 @@ static void handle_epout_irq(uint8_t rhport) {
if (!(doepint & (DOEPINT_SETUP | DOEPINT_STPKTRX | DOEPINT_STSPHSRX))) {
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
- if(dma_enabled(dwc2)) {
+ if(dwc2_dma_enabled(dwc2, TUSB_ROLE_DEVICE)) {
if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) {
// EP0 can only handle one packet Schedule another packet to be received.
edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]);
@@ -932,7 +872,7 @@ static void handle_epin_irq(uint8_t rhport) {
// Schedule another packet to be transmitted.
edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]);
} else {
- if((n == 0) && dma_enabled(dwc2)) {
+ if((n == 0) && dwc2_dma_enabled(dwc2, TUSB_ROLE_DEVICE)) {
dma_setup_prepare(rhport);
}
dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
@@ -982,7 +922,7 @@ static void handle_epin_irq(uint8_t rhport) {
/* Interrupt Hierarchy
- DxEPMSK.XferComplMsk DxEPINTn.XferCompl
+ DxEPINTn.XferCompl DxEPMSK.XferComplMsk
| |
+---------- AND --------+
|
diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c
index 190dc0734..50d0c28b3 100644
--- a/src/portable/synopsys/dwc2/dwc2_common.c
+++ b/src/portable/synopsys/dwc2/dwc2_common.c
@@ -63,7 +63,7 @@ bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, const tusb_rhport_init_t* rh_init
}
#endif
#if CFG_TUH_ENABLED
- if (rh_init->role == TUSB_ROLE_DEVICE && !TUH_OPT_HIGH_SPEED) {
+ if (rh_init->role == TUSB_ROLE_HOST && !TUH_OPT_HIGH_SPEED) {
return false;
}
#endif
@@ -193,10 +193,39 @@ bool dwc2_core_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
* duration in the core to account for any additional delays
* introduced by the PHY. This can be required, because the delay
* introduced by the PHY in generating the linestate condition
- * can vary from one PHY to another.
- */
+ * can vary from one PHY to another. */
dwc2->gusbcfg |= (7ul << GUSBCFG_TOCAL_Pos);
+ // Enable PHY clock TODO stop/gate clock when suspended mode
+ dwc2->pcgcctl &= ~(PCGCCTL_STOPPCLK | PCGCCTL_GATEHCLK | PCGCCTL_PWRCLMP | PCGCCTL_RSTPDWNMODULE);
+
+ dfifo_flush_tx(dwc2, 0x10); // all tx fifo
+ dfifo_flush_rx(dwc2);
+
+ // Clear all pending interrupts
+ uint32_t int_mask;
+
+ int_mask = dwc2->gintsts;
+ dwc2->gintsts |= int_mask;
+
+ int_mask = dwc2->gotgint;
+ dwc2->gotgint |= int_mask;
+
+ dwc2->gintmsk = GINTMSK_OTGINT;
+
+ if (dwc2_dma_enabled(dwc2, TUSB_ROLE_DEVICE)) {
+ const uint16_t epinfo_base = dma_cal_epfifo_base(rhport);
+ dwc2->gdfifocfg = (epinfo_base << GDFIFOCFG_EPINFOBASE_SHIFT) | epinfo_base;
+
+ // 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 |= GINTMSK_RXFLVLM;
+ }
+
+ // Enable global interrupt
+ dwc2->gahbcfg |= GAHBCFG_GINT;
+
return true;
}
diff --git a/src/portable/synopsys/dwc2/dwc2_common.h b/src/portable/synopsys/dwc2/dwc2_common.h
index 4039ebaa3..538fcd179 100644
--- a/src/portable/synopsys/dwc2/dwc2_common.h
+++ b/src/portable/synopsys/dwc2/dwc2_common.h
@@ -57,6 +57,8 @@ enum {
DWC2_CONTROLLER_COUNT = TU_ARRAY_SIZE(_dwc2_controller)
};
+
+//------------- Core -------------//
TU_ATTR_ALWAYS_INLINE static inline dwc2_regs_t* DWC2_REG(uint8_t rhport) {
if (rhport >= DWC2_CONTROLLER_COUNT) {
// user mis-configured, ignore and use first controller
@@ -68,4 +70,39 @@ TU_ATTR_ALWAYS_INLINE static inline dwc2_regs_t* DWC2_REG(uint8_t rhport) {
bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, const tusb_rhport_init_t* rh_init);
bool dwc2_core_init(uint8_t rhport, const tusb_rhport_init_t* rh_init);
+//------------- DFIFO -------------//
+TU_ATTR_ALWAYS_INLINE static inline void dfifo_flush_tx(dwc2_regs_t* dwc2, uint8_t fnum) {
+ // flush TX fifo and wait for it cleared
+ dwc2->grstctl = GRSTCTL_TXFFLSH | (fnum << GRSTCTL_TXFNUM_Pos);
+ while (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) {}
+}
+TU_ATTR_ALWAYS_INLINE static inline void dfifo_flush_rx(dwc2_regs_t* dwc2) {
+ // flush RX fifo and wait for it cleared
+ dwc2->grstctl = GRSTCTL_RXFFLSH;
+ while (dwc2->grstctl & GRSTCTL_RXFFLSH_Msk) {}
+}
+
+//------------- DMA -------------//
+TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dma_enabled(const dwc2_regs_t* dwc2, tusb_role_t role) {
+ (void) dwc2;
+
+ if (CFG_TUD_DWC2_DMA == 0 && role == TUSB_ROLE_DEVICE) {
+ return false;
+ }
+
+ if (CFG_TUH_DWC2_DMA == 0 && role == TUSB_ROLE_HOST) {
+ return false;
+ }
+
+ // Internal DMA only
+ return dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t dma_cal_epfifo_base(uint8_t rhport) {
+ // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per endpoint direction
+ const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
+ return dwc2_controller->ep_fifo_size/4 - 2*dwc2_controller->ep_count;
+}
+
+
#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h
index 81e3ab6b8..c8f6a5d1f 100644
--- a/src/portable/synopsys/dwc2/dwc2_type.h
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -122,6 +122,12 @@ enum {
GHWCFFG4_PHY_DATA_WIDTH_8_16 = 2, // software selectable
};
+enum {
+ HPRT_SPEED_HIGH = 0,
+ HPRT_SPEED_FULL = 1,
+ HPRT_SPEED_LOW = 2
+};
+
//--------------------------------------------------------------------
// Register bitfield definitions
//--------------------------------------------------------------------
@@ -301,6 +307,24 @@ typedef struct TU_ATTR_PACKED {
}dwc2_ghwcfg4_t;
TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg4_t) == 4, "incorrect size");
+typedef struct TU_ATTR_PACKED {
+ uint32_t conn_status : 1; // 0 Port connect status
+ uint32_t conn_detected : 1; // 1 Port connect detected
+ uint32_t enable : 1; // 2 Port enable status
+ uint32_t enable_change : 1; // 3 Port enable change
+ uint32_t over_current_active : 1; // 4 Port Over-current active
+ uint32_t over_current_change : 1; // 5 Port Over-current change
+ uint32_t resume : 1; // 6 Port resume
+ uint32_t suspend : 1; // 7 Port suspend
+ uint32_t reset : 1; // 8 Port reset
+ uint32_t rsv9 : 1; // 9 Reserved
+ uint32_t line_status : 2; // 10..11 Line status
+ uint32_t power : 1; // 12 Port power
+ uint32_t test_control : 4; // 13..16 Port Test control
+ uint32_t speed : 2; // 17..18 Port speed
+ uint32_t rsv19_31 :13; // 19..31 Reserved
+}dwc2_hprt_t;
+
// Host Channel
typedef struct {
volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics
@@ -1448,56 +1472,53 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#define DIEPEACHMSK1_NAKM DIEPEACHMSK1_NAKM_Msk // NAK interrupt mask
/******************** Bit definition for HPRT register ********************/
-#define HPRT_PCSTS_Pos (0U)
-#define HPRT_PCSTS_Msk (0x1UL << HPRT_PCSTS_Pos) // 0x00000001
-#define HPRT_PCSTS HPRT_PCSTS_Msk // Port connect status
-#define HPRT_PCDET_Pos (1U)
-#define HPRT_PCDET_Msk (0x1UL << HPRT_PCDET_Pos) // 0x00000002
-#define HPRT_PCDET HPRT_PCDET_Msk // Port connect detected
-#define HPRT_PENA_Pos (2U)
-#define HPRT_PENA_Msk (0x1UL << HPRT_PENA_Pos) // 0x00000004
-#define HPRT_PENA HPRT_PENA_Msk // Port enable
-#define HPRT_PENCHNG_Pos (3U)
-#define HPRT_PENCHNG_Msk (0x1UL << HPRT_PENCHNG_Pos) // 0x00000008
-#define HPRT_PENCHNG HPRT_PENCHNG_Msk // Port enable/disable change
-#define HPRT_POCA_Pos (4U)
-#define HPRT_POCA_Msk (0x1UL << HPRT_POCA_Pos) // 0x00000010
-#define HPRT_POCA HPRT_POCA_Msk // Port overcurrent active
-#define HPRT_POCCHNG_Pos (5U)
-#define HPRT_POCCHNG_Msk (0x1UL << HPRT_POCCHNG_Pos) // 0x00000020
-#define HPRT_POCCHNG HPRT_POCCHNG_Msk // Port overcurrent change
-#define HPRT_PRES_Pos (6U)
-#define HPRT_PRES_Msk (0x1UL << HPRT_PRES_Pos) // 0x00000040
-#define HPRT_PRES HPRT_PRES_Msk // Port resume
-#define HPRT_PSUSP_Pos (7U)
-#define HPRT_PSUSP_Msk (0x1UL << HPRT_PSUSP_Pos) // 0x00000080
-#define HPRT_PSUSP HPRT_PSUSP_Msk // Port suspend
-#define HPRT_PRST_Pos (8U)
-#define HPRT_PRST_Msk (0x1UL << HPRT_PRST_Pos) // 0x00000100
-#define HPRT_PRST HPRT_PRST_Msk // Port reset
-
-#define HPRT_PLSTS_Pos (10U)
-#define HPRT_PLSTS_Msk (0x3UL << HPRT_PLSTS_Pos) // 0x00000C00
-#define HPRT_PLSTS HPRT_PLSTS_Msk // Port line status
-#define HPRT_PLSTS_0 (0x1UL << HPRT_PLSTS_Pos) // 0x00000400
-#define HPRT_PLSTS_1 (0x2UL << HPRT_PLSTS_Pos) // 0x00000800
-#define HPRT_PPWR_Pos (12U)
-#define HPRT_PPWR_Msk (0x1UL << HPRT_PPWR_Pos) // 0x00001000
-#define HPRT_PPWR HPRT_PPWR_Msk // Port power
-
-#define HPRT_PTCTL_Pos (13U)
-#define HPRT_PTCTL_Msk (0xFUL << HPRT_PTCTL_Pos) // 0x0001E000
-#define HPRT_PTCTL HPRT_PTCTL_Msk // Port test control
-#define HPRT_PTCTL_0 (0x1UL << HPRT_PTCTL_Pos) // 0x00002000
-#define HPRT_PTCTL_1 (0x2UL << HPRT_PTCTL_Pos) // 0x00004000
-#define HPRT_PTCTL_2 (0x4UL << HPRT_PTCTL_Pos) // 0x00008000
-#define HPRT_PTCTL_3 (0x8UL << HPRT_PTCTL_Pos) // 0x00010000
-
-#define HPRT_PSPD_Pos (17U)
-#define HPRT_PSPD_Msk (0x3UL << HPRT_PSPD_Pos) // 0x00060000
-#define HPRT_PSPD HPRT_PSPD_Msk // Port speed
-#define HPRT_PSPD_0 (0x1UL << HPRT_PSPD_Pos) // 0x00020000
-#define HPRT_PSPD_1 (0x2UL << HPRT_PSPD_Pos) // 0x00040000
+#define HPRT_CONN_STATUS_Pos (0U)
+#define HPRT_CONN_STATUS_Msk (0x1UL << HPRT_CONN_STATUS_Pos) // 0x00000001
+#define HPRT_CONN_STATUS HPRT_CONN_STATUS_Msk // Port connect status
+#define HPRT_CONN_DETECTEDT_Pos (1U)
+#define HPRT_CONN_DETECTEDT_Msk (0x1UL << HPRT_CONN_DETECTEDT_Pos) // 0x00000002
+#define HPRT_CONN_DETECTEDT HPRT_CONN_DETECTEDT_Msk // Port connect detected
+#define HPRT_ENABLE_Pos (2U)
+#define HPRT_ENABLE_Msk (0x1UL << HPRT_ENABLE_Pos) // 0x00000004
+#define HPRT_ENABLE HPRT_ENABLE_Msk // Port enable
+#define HPRT_EN_CHANGE_Pos (3U)
+#define HPRT_EN_CHANGE_Msk (0x1UL << HPRT_EN_CHANGE_Pos) // 0x00000008
+#define HPRT_EN_CHANGE HPRT_EN_CHANGE_Msk // Port enable/disable change
+#define HPRT_OVER_CURRENT_ACTIVE_Pos (4U)
+#define HPRT_OVER_CURRENT_ACTIVE_Msk (0x1UL << HPRT_OVER_CURRENT_ACTIVE_Pos) // 0x00000010
+#define HPRT_OVER_CURRENT_ACTIVE HPRT_OVER_CURRENT_ACTIVE_Msk // Port overcurrent active
+#define HPRT_OVER_CURRENT_CHANGE_Pos (5U)
+#define HPRT_OVER_CURRENT_CHANGE_Msk (0x1UL << HPRT_OVER_CURRENT_CHANGE_Pos) // 0x00000020
+#define HPRT_OVER_CURRENT_CHANGE HPRT_OVER_CURRENT_CHANGE_Msk // Port overcurrent change
+#define HPRT_RESUME_Pos (6U)
+#define HPRT_RESUME_Msk (0x1UL << HPRT_RESUME_Pos) // 0x00000040
+#define HPRT_RESUME HPRT_RESUME_Msk // Port resume
+#define HPRT_SUSPEND_Pos (7U)
+#define HPRT_SUSPEND_Msk (0x1UL << HPRT_SUSPEND_Pos) // 0x00000080
+#define HPRT_SUSPEND HPRT_SUSPEND_Msk // Port suspend
+#define HPRT_RESET_Pos (8U)
+#define HPRT_RESET_Msk (0x1UL << HPRT_RESET_Pos) // 0x00000100
+#define HPRT_RESET HPRT_RESET_Msk // Port reset
+#define HPRT_LINE_STATUS_Pos (10U)
+#define HPRT_LINE_STATUS_Msk (0x3UL << HPRT_LINE_STATUS_Pos) // 0x00000C00
+#define HPRT_LINE_STATUS HPRT_LINE_STATUS_Msk // Port line status
+#define HPRT_LINE_STATUS_0 (0x1UL << HPRT_LINE_STATUS_Pos) // 0x00000400
+#define HPRT_LINE_STATUS_1 (0x2UL << HPRT_LINE_STATUS_Pos) // 0x00000800
+#define HPRT_POWER_Pos (12U)
+#define HPRT_POWER_Msk (0x1UL << HPRT_POWER_Pos) // 0x00001000
+#define HPRT_POWER HPRT_POWER_Msk // Port power
+#define HPRT_TEST_CONTROL_Pos (13U)
+#define HPRT_TEST_CONTROL_Msk (0xFUL << HPRT_TEST_CONTROL_Pos) // 0x0001E000
+#define HPRT_TEST_CONTROL HPRT_TEST_CONTROL_Msk // Port test control
+#define HPRT_TEST_CONTROL_0 (0x1UL << HPRT_TEST_CONTROL_Pos) // 0x00002000
+#define HPRT_TEST_CONTROL_1 (0x2UL << HPRT_TEST_CONTROL_Pos) // 0x00004000
+#define HPRT_TEST_CONTROL_2 (0x4UL << HPRT_TEST_CONTROL_Pos) // 0x00008000
+#define HPRT_TEST_CONTROL_3 (0x8UL << HPRT_TEST_CONTROL_Pos) // 0x00010000
+#define HPRT_SPEED_Pos (17U)
+#define HPRT_SPEED_Msk (0x3UL << HPRT_SPEED_Pos) // 0x00060000
+#define HPRT_SPEED HPRT_SPEED_Msk // Port speed
+#define HPRT_SPEED_0 (0x1UL << HPRT_SPEED_Pos) // 0x00020000
+#define HPRT_SPEED_1 (0x2UL << HPRT_SPEED_Pos) // 0x00040000
/******************** Bit definition for DOEPEACHMSK1 register ********************/
#define DOEPEACHMSK1_XFRCM_Pos (0U)
diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c
index 8798f982c..b383b4069 100644
--- a/src/portable/synopsys/dwc2/hcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/hcd_dwc2.c
@@ -49,15 +49,29 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
// Initialize controller to host mode
bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
- (void) rhport;
- (void) rh_init;
- return false;
-}
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
-// Interrupt Handler
-void hcd_int_handler(uint8_t rhport, bool in_isr) {
- (void) rhport;
- (void) in_isr;
+ // Core Initialization
+ TU_ASSERT(dwc2_core_init(rhport, rh_init));
+
+ // force host mode
+ dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FDMOD) | GUSBCFG_FHMOD;
+
+ //------------- 3.1 Host Initialization -------------//
+ // Enable required interrupts
+ dwc2->gintmsk |= GINTMSK_OTGINT | GINTMSK_PRTIM | GINTMSK_WUIM;
+
+ // max speed
+ if (dwc2_core_is_highspeed(dwc2, rh_init)) {
+ dwc2->hcfg &= ~HCFG_FSLSS;
+ } else {
+ dwc2->hcfg |= HCFG_FSLSS;
+ }
+
+ // port power on -> drive VBUS
+ dwc2->hprt = HPRT_POWER;
+
+ return true;
}
// Enable USB interrupt
@@ -164,4 +178,38 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
return false;
}
+//--------------------------------------------------------------------
+// HCD Event Handler
+//--------------------------------------------------------------------
+
+/* Interrupt Hierarchy
+
+ HCINTn.XferCompl HCINTMSKn.XferComplMsk
+ | |
+ +---------- AND --------+
+ |
+ HAINT.CHn HAINTMSK.CHn
+ | |
+ +---------- AND --------+
+ |
+ GINTSTS.PrtInt GINTMSK.PrtInt
+ | |
+ +---------- AND --------+
+ |
+ GAHBCFG.GblIntrMsk
+ |
+ IRQn
+ */
+void hcd_int_handler(uint8_t rhport, bool in_isr) {
+ (void) in_isr;
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ const uint32_t int_mask = dwc2->gintmsk;
+ const uint32_t int_status = dwc2->gintsts & int_mask;
+
+ if (int_status & GINTSTS_HPRTINT) {
+ TU_LOG1_HEX(dwc2->hprt);
+ }
+}
+
#endif
diff --git a/src/tusb_option.h b/src/tusb_option.h
index d36d0bcad..3607a8c1a 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -254,6 +254,10 @@
#define CFG_TUD_DWC2_DMA 0
#endif
+#ifndef CFG_TUH_DWC2_DMA
+ #define CFG_TUH_DWC2_DMA 0
+#endif
+
// Enable PIO-USB software host controller
#ifndef CFG_TUH_RPI_PIO_USB
#define CFG_TUH_RPI_PIO_USB 0