From 8d9d3d9a2ac51378e7cb973628972e93ba356e1d Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 16 Oct 2024 13:19:28 +0700 Subject: [PATCH] move gahbcfg/gintmsk with dma to dwc2 common --- src/portable/synopsys/dwc2/dcd_dwc2.c | 84 +++------------- src/portable/synopsys/dwc2/dwc2_common.c | 35 ++++++- src/portable/synopsys/dwc2/dwc2_common.h | 37 +++++++ src/portable/synopsys/dwc2/dwc2_type.h | 121 +++++++++++++---------- src/portable/synopsys/dwc2/hcd_dwc2.c | 64 ++++++++++-- src/tusb_option.h | 4 + 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