From 29262f3e24326c1a7c06137824e44ffaa6301094 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 4 Nov 2024 17:22:25 +0700 Subject: [PATCH] improve port0_enable(), properly configure hcfg and hfir according to port speed. Enable low power UTMI+ phy mode for ls/fs device. --- src/portable/synopsys/dwc2/dwc2_type.h | 4 + src/portable/synopsys/dwc2/hcd_dwc2.c | 115 +++++++++++++------------ 2 files changed, 63 insertions(+), 56 deletions(-) diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index 89561a5e6..a88a2d389 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -730,6 +730,7 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); #define HCFG_FSLS_PHYCLK_SEL HCFG_FSLS_PHYCLK_SEL_Msk // FS/LS PHY clock select #define HCFG_FSLS_PHYCLK_SEL_30_60MHZ (0x0UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000000 #define HCFG_FSLS_PHYCLK_SEL_48MHZ (0x1UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000001 +#define HCFG_FSLS_PHYCLK_SEL_6MHZ (0x2UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000002 #define HCFG_FSLS_ONLY_Pos (2U) #define HCFG_FSLS_ONLY_Msk (0x1UL << HCFG_FSLS_ONLY_Pos) // 0x00000004 @@ -848,6 +849,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); #define HFIR_FRIVL_Pos (0U) #define HFIR_FRIVL_Msk (0xFFFFUL << HFIR_FRIVL_Pos) // 0x0000FFFF #define HFIR_FRIVL HFIR_FRIVL_Msk // Frame interval +#define HFIR_RELOAD_CTRL_Pos (16U) // available since v2.92a +#define HFIR_RELOAD_CTRL_Msk (0x1UL << HFIR_RELOAD_CTRL_Pos) +#define HFIR_RELOAD_CTRL HFIR_RELOAD_CTRL_Msk /******************** Bit definition for HFNUM register ********************/ #define HFNUM_FRNUM_Pos (0U) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 8bfba442b..b2ca86a36 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -45,7 +45,7 @@ TU_VERIFY_STATIC(CFG_TUH_DWC2_ENDPOINT_MAX <= 255, "currently only use 8-bit for index"); enum { - HPRT_W1C_MASK = HPRT_CONN_DETECT | HPRT_ENABLE | HPRT_ENABLE_CHANGE | HPRT_OVER_CURRENT_CHANGE + HPRT_W1_MASK = HPRT_CONN_DETECT | HPRT_ENABLE | HPRT_ENABLE_CHANGE | HPRT_OVER_CURRENT_CHANGE | HPRT_SUSPEND }; enum { @@ -79,7 +79,7 @@ typedef struct { typedef struct { volatile bool allocated; uint8_t ep_id; - union TU_ATTR_PACKED { + struct TU_ATTR_PACKED { uint8_t err_count : 6; uint8_t do_ping : 1; uint8_t sof_schedule : 1; @@ -336,26 +336,13 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { //------------- 3.1 Host Initialization -------------// - // FS/LS PHY Clock Select - uint32_t hcfg = dwc2->hcfg; - if (is_highspeed) { - hcfg &= ~HCFG_FSLS_ONLY; - } else { - hcfg &= ~HCFG_FSLS_ONLY; // since we are using FS PHY - hcfg &= ~HCFG_FSLS_PHYCLK_SEL; - - if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI && - dwc2->ghwcfg2_bm.fs_phy_type == GHWCFG2_FSPHY_DEDICATED) { - // dedicated FS PHY with 48 mhz - hcfg |= HCFG_FSLS_PHYCLK_SEL_48MHZ; - } else { - // shared HS PHY running at full speed - hcfg |= HCFG_FSLS_PHYCLK_SEL_30_60MHZ; - } - } - dwc2->hcfg = hcfg; + // work at max supported speed + dwc2->hcfg &= ~HCFG_FSLS_ONLY; // Enable HFIR reload + if (dwc2->gsnpsid >= DWC2_CORE_REV_2_92a) { + dwc2->hfir |= HFIR_RELOAD_CTRL; + } // force host mode and wait for mode switch dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FDMOD) | GUSBCFG_FHMOD; @@ -364,7 +351,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // configure fixed-allocated fifo scheme dfifo_host_init(rhport); - dwc2->hprt = HPRT_W1C_MASK; // clear all write-1-clear bits + dwc2->hprt = HPRT_W1_MASK; // clear all write-1-clear bits dwc2->hprt = HPRT_POWER; // turn on VBUS // Enable required interrupts @@ -408,7 +395,7 @@ bool hcd_port_connect_status(uint8_t rhport) { // Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence. void hcd_port_reset(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); - uint32_t hprt = dwc2->hprt & ~HPRT_W1C_MASK; + uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK; hprt |= HPRT_RESET; dwc2->hprt = hprt; } @@ -416,7 +403,7 @@ void hcd_port_reset(uint8_t rhport) { // Complete bus reset sequence, may be required by some controllers void hcd_port_reset_end(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); - uint32_t hprt = dwc2->hprt & ~HPRT_W1C_MASK; // skip w1c bits + uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK; // skip w1c bits hprt &= ~HPRT_RESET; dwc2->hprt = hprt; } @@ -1044,6 +1031,50 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) { return more_isr; } +// Config HCFG FS/LS clock and HFIR for SOF interval according to link speed (value is in PHY clock unit) +static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) { + uint32_t hcfg = dwc2->hcfg & ~HCFG_FSLS_PHYCLK_SEL; + + const dwc2_gusbcfg_t gusbcfg_bm = dwc2->gusbcfg_bm; + uint32_t phy_clock; + + if (gusbcfg_bm.phy_sel) { + phy_clock = 48; // dedicated FS is 48Mhz + if (speed == TUSB_SPEED_LOW) { + hcfg |= HCFG_FSLS_PHYCLK_SEL_6MHZ; + } else { + hcfg |= HCFG_FSLS_PHYCLK_SEL_48MHZ; + } + } else { + if (gusbcfg_bm.ulpi_utmi_sel) { + phy_clock = 60; // ULPI 8-bit is 60Mhz + } else { + // UTMI+ 16-bit is 30Mhz, 8-bit is 60Mhz + phy_clock = gusbcfg_bm.phy_if16 ? 30 : 60; + + // Enable UTMI+ low power mode 48Mhz external clock if not highspeed + if (speed == TUSB_SPEED_HIGH) { + dwc2->gusbcfg &= ~GUSBCFG_PHYLPCS; + } else { + dwc2->gusbcfg |= GUSBCFG_PHYLPCS; + // may need to reset port + } + } + hcfg |= HCFG_FSLS_PHYCLK_SEL_30_60MHZ; + } + + dwc2->hcfg = hcfg; + + uint32_t hfir = dwc2->hfir & ~HFIR_FRIVL_Msk; + if (speed == TUSB_SPEED_HIGH) { + hfir |= 125*phy_clock; + } else { + hfir |= 1000*phy_clock; + } + + dwc2->hfir = hfir; +} + /* Handle Host Port interrupt, possible source are: - Connection Detection - Enable Change @@ -1051,7 +1082,7 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) { */ static void handle_hprt_irq(uint8_t rhport, bool in_isr) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); - uint32_t hprt = dwc2->hprt & ~HPRT_W1C_MASK; + uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK; const dwc2_hprt_t hprt_bm = dwc2->hprt_bm; if (dwc2->hprt & HPRT_CONN_DETECT) { @@ -1071,38 +1102,10 @@ static void handle_hprt_irq(uint8_t rhport, bool in_isr) { if (hprt_bm.enable) { // Port enable - // Config HCFG FS/LS clock and HFIR for SOF interval according to link speed (value is in PHY clock unit) const tusb_speed_t speed = convert_hprt_speed(hprt_bm.speed); - uint32_t hcfg = dwc2->hcfg & ~HCFG_FSLS_PHYCLK_SEL; - - const dwc2_gusbcfg_t gusbcfg_bm = dwc2->gusbcfg_bm; - uint32_t clock = 60; - if (gusbcfg_bm.phy_sel) { - // dedicated FS is 48Mhz - clock = 48; - hcfg |= HCFG_FSLS_PHYCLK_SEL_48MHZ; - } else { - // UTMI+ or ULPI - if (gusbcfg_bm.ulpi_utmi_sel) { - clock = 60; // ULPI 8-bit is 60Mhz - } else if (gusbcfg_bm.phy_if16) { - clock = 30; // UTMI+ 16-bit is 30Mhz - } else { - clock = 60; // UTMI+ 8-bit is 60Mhz - } - hcfg |= HCFG_FSLS_PHYCLK_SEL_30_60MHZ; - } - - dwc2->hcfg = hcfg; - - uint32_t hfir = dwc2->hfir & ~HFIR_FRIVL_Msk; - if (speed == TUSB_SPEED_HIGH) { - hfir |= 125*clock; - } else { - hfir |= 1000*clock; - } - - dwc2->hfir = hfir; + port0_enable(dwc2, speed); + } else { + // TU_ASSERT(false, ); } } @@ -1121,7 +1124,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { const uint32_t gintmsk = dwc2->gintmsk; const uint32_t gintsts = dwc2->gintsts & gintmsk; - // TU_LOG1_HEX(int_status); + // TU_LOG1_HEX(gintsts); if (gintsts & GINTSTS_CONIDSTSCHNG) { // Connector ID status change