summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c4
-rw-r--r--src/portable/synopsys/dwc2/dwc2_at32.h6
-rw-r--r--src/portable/synopsys/dwc2/dwc2_bcm.h6
-rw-r--r--src/portable/synopsys/dwc2/dwc2_common.h16
-rw-r--r--src/portable/synopsys/dwc2/dwc2_efm32.h6
-rw-r--r--src/portable/synopsys/dwc2/dwc2_esp32.h6
-rw-r--r--src/portable/synopsys/dwc2/dwc2_gd32.h6
-rw-r--r--src/portable/synopsys/dwc2/dwc2_nrf.h52
-rw-r--r--src/portable/synopsys/dwc2/dwc2_stm32.h6
-rw-r--r--src/portable/synopsys/dwc2/dwc2_xmc.h6
-rw-r--r--src/portable/synopsys/dwc2/hcd_dwc2.c4
11 files changed, 108 insertions, 10 deletions
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index bdd3a59ed..da6ee894a 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -442,12 +442,12 @@ bool dcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
}
bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
- (void) rh_init;
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ dwc2_clock_init(rhport, rh_init->role);
tu_memclr(&_dcd_data, sizeof(_dcd_data));
// Core Initialization
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const bool is_hs_phy = dwc2_core_is_highspeed_phy(dwc2, TUD_OPT_HIGH_SPEED);
const bool is_dma = dma_device_enabled(dwc2);
TU_ASSERT(dwc2_core_init(rhport, is_hs_phy, is_dma));
diff --git a/src/portable/synopsys/dwc2/dwc2_at32.h b/src/portable/synopsys/dwc2/dwc2_at32.h
index 594d350b7..85fa9b20b 100644
--- a/src/portable/synopsys/dwc2/dwc2_at32.h
+++ b/src/portable/synopsys/dwc2/dwc2_at32.h
@@ -79,6 +79,12 @@ static const dwc2_controller_t _dwc2_controller[] = {
#endif
};
+// MCU specific to enable dwc2 clock/power before any access to register
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_clock_init(uint8_t rhport, tusb_role_t role) {
+ (void) rhport;
+ (void) role;
+}
+
TU_ATTR_ALWAYS_INLINE static inline void dwc2_int_set(uint8_t rhport, tusb_role_t role, bool enabled) {
(void) role;
const IRQn_Type irqn = (IRQn_Type) _dwc2_controller[rhport].irqnum;
diff --git a/src/portable/synopsys/dwc2/dwc2_bcm.h b/src/portable/synopsys/dwc2/dwc2_bcm.h
index 50f3122e8..91cae821e 100644
--- a/src/portable/synopsys/dwc2/dwc2_bcm.h
+++ b/src/portable/synopsys/dwc2/dwc2_bcm.h
@@ -46,6 +46,12 @@ static const dwc2_controller_t _dwc2_controller[] =
#define dcache_invalidate(_addr, _size) data_invalidate(_addr, _size)
#define dcache_clean_invalidate(_addr, _size) data_clean_and_invalidate(_addr, _size)
+// MCU specific to enable dwc2 clock/power before any access to register
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_clock_init(uint8_t rhport, tusb_role_t role) {
+ (void) rhport;
+ (void) role;
+}
+
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
diff --git a/src/portable/synopsys/dwc2/dwc2_common.h b/src/portable/synopsys/dwc2/dwc2_common.h
index 9f28ab2e0..5c4798d21 100644
--- a/src/portable/synopsys/dwc2/dwc2_common.h
+++ b/src/portable/synopsys/dwc2/dwc2_common.h
@@ -38,13 +38,15 @@
#include "host/hcd.h"
#endif
-// Following symbols must be defined by port header
-// - _dwc2_controller[]: array of controllers
-// - DWC2_EP_MAX: largest EP counts of all controllers
-// - dwc2_phy_init/dwc2_phy_update: phy init called before and after core reset
-// - dwc2_phy_deinit(dwc2, hs_phy_type): phy deinit to disable PHY power, only deinit the phy used by core
-// - dwc2_dcd_int_enable/dwc2_dcd_int_disable
-// - dwc2_remote_wakeup_delay
+/* Following symbols must be defined by port header
+ - _dwc2_controller[]: array of controllers
+ - DWC2_EP_MAX: largest EP counts of all controllers
+ - dwc2_clock_init(): clock init call before
+ - dwc2_phy_init/dwc2_phy_update: phy init called before and after core reset
+ - dwc2_phy_deinit(dwc2, hs_phy_type): phy deinit to disable PHY power, only deinit the phy used by core
+ - dwc2_dcd_int_enable/dwc2_dcd_int_disable
+ - dwc2_remote_wakeup_delay
+*/
#if defined(TUP_USBIP_DWC2_STM32)
#include "dwc2_stm32.h"
diff --git a/src/portable/synopsys/dwc2/dwc2_efm32.h b/src/portable/synopsys/dwc2/dwc2_efm32.h
index 167f5b4cd..063360873 100644
--- a/src/portable/synopsys/dwc2/dwc2_efm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_efm32.h
@@ -43,6 +43,12 @@ static const dwc2_controller_t _dwc2_controller[] =
{ .reg_base = DWC2_REG_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .otg_dfifo_depth = 512 }
};
+// MCU specific to enable dwc2 clock/power before any access to register
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_clock_init(uint8_t rhport, tusb_role_t role) {
+ (void) rhport;
+ (void) role;
+}
+
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h
index 99ef9456f..6a10dc7f8 100644
--- a/src/portable/synopsys/dwc2/dwc2_esp32.h
+++ b/src/portable/synopsys/dwc2/dwc2_esp32.h
@@ -97,6 +97,12 @@ static void dwc2_int_handler_wrap(void* arg) {
#endif
}
+// MCU specific to enable dwc2 clock/power before any access to register
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_clock_init(uint8_t rhport, tusb_role_t role) {
+ (void) rhport;
+ (void) role;
+}
+
TU_ATTR_ALWAYS_INLINE static inline void dwc2_int_set(uint8_t rhport, tusb_role_t role, bool enabled) {
if (enabled) {
esp_intr_alloc(_dwc2_controller[rhport].irqnum, ESP_INTR_FLAG_LOWMED,
diff --git a/src/portable/synopsys/dwc2/dwc2_gd32.h b/src/portable/synopsys/dwc2/dwc2_gd32.h
index 396d17e30..28c3fde5e 100644
--- a/src/portable/synopsys/dwc2/dwc2_gd32.h
+++ b/src/portable/synopsys/dwc2/dwc2_gd32.h
@@ -57,6 +57,12 @@ static inline void __eclic_disable_interrupt (uint32_t irq){
*(volatile uint8_t*)(ECLIC_INTERRUPT_ENABLE_BASE + (irq * 4)) = 0;
}
+// MCU specific to enable dwc2 clock/power before any access to register
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_clock_init(uint8_t rhport, tusb_role_t role) {
+ (void) rhport;
+ (void) role;
+}
+
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
diff --git a/src/portable/synopsys/dwc2/dwc2_nrf.h b/src/portable/synopsys/dwc2/dwc2_nrf.h
index fc9cd18bc..a1bf692f8 100644
--- a/src/portable/synopsys/dwc2/dwc2_nrf.h
+++ b/src/portable/synopsys/dwc2/dwc2_nrf.h
@@ -29,8 +29,20 @@
#ifndef TUSB_DWC2_NRF_H
#define TUSB_DWC2_NRF_H
+// NRF is device only without OTG support
#include "nrf.h"
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+#endif
+
+#include <soc/nrfx_coredep.h>
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
#define DWC2_EP_MAX 16
// Use the auto-resolving peripheral pointer (respects TrustZone secure/non-secure mapping)
@@ -44,6 +56,46 @@ static const dwc2_controller_t _dwc2_controller[] = {
{.reg_base = DWC2_REG_BASE, .irqnum = USBHS_IRQn, .ep_count = 16, .otg_dfifo_depth = 3072},
};
+// MCU specific to enable dwc2 clock/power before any access to register
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_clock_init(uint8_t rhport, tusb_role_t role) {
+ (void) rhport;
+ (void) role;
+
+ #if defined(NRF54LM20A_ENGA_XXAA)
+ // Start the USB voltage regulator
+ NRF_VREGUSB->TASKS_START = VREGUSB_TASKS_START_TASKS_START_Trigger;
+
+ // Based on Zephyr usbhs_enable_core() in drivers/usb/udc/udc_dwc2_vendor_quirks.h
+ // Step 1: Power up core only (PHY not yet)
+ NRF_USBHS->ENABLE = USBHS_ENABLE_CORE_Msk;
+
+ // Step 2: Override ID=Device (bit 31), and temporarily override VBUSVALID
+ NRF_USBHS->PHY.OVERRIDEVALUES = (USBHS_PHY_OVERRIDEVALUES_ID_Device << USBHS_PHY_OVERRIDEVALUES_ID_Pos);
+ NRF_USBHS->PHY.INPUTOVERRIDE = USBHS_PHY_INPUTOVERRIDE_ID_Msk | USBHS_PHY_INPUTOVERRIDE_VBUSVALID_Msk;
+
+ // Step 3: Release PHY power-on reset by enabling PHY
+ NRF_USBHS->ENABLE = USBHS_ENABLE_PHY_Msk | USBHS_ENABLE_CORE_Msk;
+
+ // Step 4: Wait 45us for PHY clock to start
+ nrfx_coredep_delay_us(45);
+
+ // Step 5: Release DWC2 reset
+ NRF_USBHS->TASKS_START = USBHS_TASKS_START_TASKS_START_Trigger;
+
+ // Step 6: Wait for clock to start to avoid hang on too early register read
+ nrfx_coredep_delay_us(2);
+
+ // Step 7: Clear VBUSVALID override (keep ID=Device override)
+ // DWC2 is now in Non-Driving opmode; D+ pull-up will activate when DWC2 clears DCTL SftDiscon
+ NRF_USBHS->PHY.INPUTOVERRIDE = USBHS_PHY_INPUTOVERRIDE_ID_Msk;
+
+ // Barrier: USBHS wrapper (0x5005A000) and USBHSCORE (0x50020000) are separate
+ // peripheral blocks. Ensure the ENABLE/TASKS_START writes have propagated from
+ // the Cortex-M33 write buffer to hardware before anyone reads DWC2 core regs.
+ __DSB();
+ #endif
+}
+
TU_ATTR_ALWAYS_INLINE static inline void dwc2_int_set(uint8_t rhport, tusb_role_t role, bool enabled) {
(void)rhport;
(void)role;
diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h
index 5f6e98224..e5379dfe3 100644
--- a/src/portable/synopsys/dwc2/dwc2_stm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_stm32.h
@@ -162,6 +162,12 @@ static const dwc2_controller_t _dwc2_controller[] = {
// SystemCoreClock is already included by family header
// extern uint32_t SystemCoreClock;
+// MCU specific to enable dwc2 clock/power before any access to register
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_clock_init(uint8_t rhport, tusb_role_t role) {
+ (void) rhport;
+ (void) role;
+}
+
TU_ATTR_ALWAYS_INLINE static inline void dwc2_int_set(uint8_t rhport, tusb_role_t role, bool enabled) {
(void) role;
const IRQn_Type irqn = (IRQn_Type) _dwc2_controller[rhport].irqnum;
diff --git a/src/portable/synopsys/dwc2/dwc2_xmc.h b/src/portable/synopsys/dwc2/dwc2_xmc.h
index b946444ee..85b2a2633 100644
--- a/src/portable/synopsys/dwc2/dwc2_xmc.h
+++ b/src/portable/synopsys/dwc2/dwc2_xmc.h
@@ -42,6 +42,12 @@ static const dwc2_controller_t _dwc2_controller[] =
{ .reg_base = USB0_BASE, .irqnum = USB0_0_IRQn, .ep_count = DWC2_EP_MAX, .otg_dfifo_depth = 512 }
};
+// MCU specific to enable dwc2 clock/power before any access to register
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_clock_init(uint8_t rhport, tusb_role_t role) {
+ (void) rhport;
+ (void) role;
+}
+
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c
index cd2ddf572..6098d6eaa 100644
--- a/src/portable/synopsys/dwc2/hcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/hcd_dwc2.c
@@ -407,10 +407,12 @@ 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) {
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ dwc2_clock_init(rhport, rh_init->role);
+
tu_memclr(&_hcd_data, sizeof(_hcd_data));
// Core Initialization
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const bool is_hs_phy = dwc2_core_is_highspeed_phy(dwc2, _tuh_cfg.use_hs_phy);
const bool is_dma = dma_host_enabled(dwc2);
TU_ASSERT(dwc2_core_init(rhport, is_hs_phy, is_dma));