summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2026-01-30 19:24:12 +0100
committerHiFiPhile <[email protected]>2026-01-31 00:21:23 +0100
commitfd369937279594eb8c48a81eabebb7f66bd8306a (patch)
treee149e990b3bec3b3c280eca6b67dffdc585abdbc /src
parent78411bbefa2187bee3b9b99561a34aa75c2d562b (diff)
dwc2: add vbus sense config
Signed-off-by: HiFiPhile <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/device/usbd.h1
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c12
-rw-r--r--src/portable/synopsys/dwc2/dwc2_stm32.h130
-rw-r--r--src/portable/synopsys/dwc2/dwc2_type.h39
-rw-r--r--src/portable/synopsys/dwc2/hcd_dwc2.c4
5 files changed, 166 insertions, 20 deletions
diff --git a/src/device/usbd.h b/src/device/usbd.h
index bd5a3c395..f923b1c56 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -41,6 +41,7 @@ enum {
typedef struct {
uint16_t bm_double_buffered; // bitmap of IN endpoints to be double buffered, only effective for bulk endpoints
+ bool vbus_sensing; // Vbus pin is used for device connection detection, mandatory for tud_umount_cb()
} tud_configure_dwc2_t;
typedef union {
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index f73c36d2f..36cb763aa 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -78,7 +78,8 @@ CFG_TUD_MEM_SECTION static struct {
} _dcd_usbbuf;
static tud_configure_dwc2_t _tud_cfg = {
- .bm_double_buffered = 0
+ .bm_double_buffered = 0,
+ .vbus_sensing = false
};
TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_ep_count(const dwc2_regs_t* dwc2) {
@@ -472,12 +473,11 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
// 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;
+ // Clear A override, force B Valid if Vbus sensing is not used
+ dwc2->gotgctl = (dwc2->gotgctl & ~GOTGCTL_AVALOEN) | (_tud_cfg.vbus_sensing ? 0 : GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL);
-#if CFG_TUSB_MCU == OPT_MCU_STM32N6
- // No hardware detection of Vbus B-session is available on the STM32N6
- dwc2->stm32_gccfg |= STM32_GCCFG_VBVALOVAL;
+#ifdef TUP_USBIP_DWC2_STM32
+ dwc2_stm32_gccfg_cfg(dwc2, _tud_cfg.vbus_sensing, false);
#endif
// Enable required interrupts
diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h
index 516eb021b..a87eef068 100644
--- a/src/portable/synopsys/dwc2/dwc2_stm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_stm32.h
@@ -300,6 +300,136 @@ static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
}
}
+//------------- GCCFG configuration -------------//
+static inline void dwc2_stm32_gccfg_cfg(dwc2_regs_t* dwc2, bool vbus_sensing, bool is_host) {
+ if (is_host) {
+ vbus_sensing = false;
+ }
+#if CFG_TUSB_MCU == OPT_MCU_STM32F1
+ // F1: Basic FS-only core, no VBUS sensing support
+ // Only PWRDWN bit is used (set in dwc2_phy_init)
+ (void) vbus_sensing;
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F2 || CFG_TUSB_MCU == OPT_MCU_STM32F4
+ // F2/F4: Dual FS/HS with VBUSBSEN/VBUSASEN/NOVBUSSENS bits
+ if (is_host) {
+ dwc2->stm32_gccfg &= ~(STM32_GCCFG_NOVBUSSENS | STM32_GCCFG_VBUSBSEN | STM32_GCCFG_VBUSASEN);
+ } else {
+ if (vbus_sensing) {
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_NOVBUSSENS;
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBUSBSEN;
+ } else {
+ dwc2->stm32_gccfg |= STM32_GCCFG_NOVBUSSENS;
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_VBUSBSEN;
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_VBUSASEN;
+ }
+ }
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F7
+ // F7: Enhanced FS/HS with battery charging detection
+ if (vbus_sensing) {
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBDEN;
+ } else {
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_VBDEN;
+ }
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32H7
+ if (vbus_sensing) {
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBDEN;
+ } else {
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_VBDEN;
+ }
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32H7RS
+ // H7FS: Port0: Basic FS-only core; Port1: femtoPHY
+ if ((uintptr_t)dwc2 == _dwc2_controller[0].reg_base) {
+ if (vbus_sensing) {
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBDEN;
+ } else {
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_VBDEN;
+ }
+ return;
+ } else {
+ // Uses VBVALEXTOEN and VBVALOVAL for external VBUS sensing override
+ if (is_host) {
+ dwc2->stm32_gccfg |= STM32_GCCFG_PULLDOWNEN;
+ dwc2->stm32_gccfg &= ~(STM32_GCCFG_VBDEN | STM32_GCCFG_VBVALEXTOEN | STM32_GCCFG_VBVALOVAL);
+ } else {
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_PULLDOWNEN;
+ if (vbus_sensing) {
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBDEN;
+ dwc2->stm32_gccfg &= ~(STM32_GCCFG_VBVALEXTOEN | STM32_GCCFG_VBVALOVAL);
+ } else {
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_VBDEN;
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBVALEXTOEN | STM32_GCCFG_VBVALOVAL;
+ }
+ }
+ }
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32N6
+ // N6: femtoPHY
+ // In this device, the software override is always active
+ (void) vbus_sensing;
+ if (is_host) {
+ dwc2->stm32_gccfg |= STM32_GCCFG_PULLDOWNEN;
+ dwc2->stm32_gccfg &= ~(STM32_GCCFG_VBVALOVAL);
+ } else {
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_PULLDOWNEN;
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBVALOVAL;
+ }
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
+ // L4: Low-power FS-only with VBUS detection
+ if (vbus_sensing) {
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBDEN;
+ } else {
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_VBDEN;
+ }
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
+ #ifdef USB_OTG_FS
+ // U5: FS PHY (U575/585 have FS only)
+ if (vbus_sensing) {
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBDEN;
+ } else {
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_VBDEN;
+ }
+ #else
+ // U5: femtoPHY (U59x/5Ax/5Fx/5Gx have HS)
+ // Uses VBVALEXTOEN and VBVALOVAL for external VBUS sensing override
+ if (is_host) {
+ dwc2->stm32_gccfg |= STM32_GCCFG_PULLDOWNEN;
+ dwc2->stm32_gccfg &= ~(STM32_GCCFG_VBDEN | STM32_GCCFG_VBVALEXTOEN | STM32_GCCFG_VBVALOVAL);
+ } else {
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_PULLDOWNEN;
+ if (vbus_sensing) {
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBDEN;
+ dwc2->stm32_gccfg &= ~(STM32_GCCFG_VBVALEXTOEN | STM32_GCCFG_VBVALOVAL);
+ } else {
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_VBDEN;
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBVALEXTOEN | STM32_GCCFG_VBVALOVAL;
+ }
+ }
+ #endif
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WBA
+ // WBA: femtoPHY
+ // In this device, the software override is always active
+ if (is_host) {
+ dwc2->stm32_gccfg |= STM32_GCCFG_PULLDOWNEN;
+ dwc2->stm32_gccfg &= ~(STM32_GCCFG_VBVALOVAL);
+ } else {
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_PULLDOWNEN;
+ if (vbus_sensing) {
+ dwc2->stm32_gccfg &= ~(STM32_GCCFG_VBVALOVAL);
+ } else {
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBVALOVAL;
+ }
+ }
+
+#else
+ #error "Unsupported MCU family"
+#endif
+}
+
//------------- DCache -------------//
#if CFG_TUD_MEM_DCACHE_ENABLE || CFG_TUH_MEM_DCACHE_ENABLE
diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h
index 7693ce02a..2dd73c184 100644
--- a/src/portable/synopsys/dwc2/dwc2_type.h
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -1650,23 +1650,34 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#define STM32_GCCFG_PHYHSEN_Msk (0x1UL << STM32_GCCFG_PHYHSEN_Pos) // 0x00800000
#define STM32_GCCFG_PHYHSEN STM32_GCCFG_PHYHSEN_Msk // HS PHY enable
-// TODO stm32u5a5 SDEN is 22nd bit, conflict with 20th bit above
-//#define STM32_GCCFG_SDEN_Pos (22U)
-//#define STM32_GCCFG_SDEN_Msk (0x1U << STM32_GCCFG_SDEN_Pos) // 0x00400000
-//#define STM32_GCCFG_SDEN STM32_GCCFG_SDEN_Msk // Secondary detection (PD) mode enable
+// stm32f2/stm32f4
+#define STM32_GCCFG_VBUSASEN_Pos (18U)
+#define STM32_GCCFG_VBUSASEN_Msk (0x1UL << STM32_GCCFG_VBUSASEN_Pos) // 0x00040000
+#define STM32_GCCFG_VBUSASEN STM32_GCCFG_VBUSASEN_Msk // Enable A-device (host) VBUS sensing
+#define STM32_GCCFG_VBUSBSEN_Pos (19U)
+#define STM32_GCCFG_VBUSBSEN_Msk (0x1UL << STM32_GCCFG_VBUSBSEN_Pos) // 0x00080000
+#define STM32_GCCFG_VBUSBSEN STM32_GCCFG_VBUSBSEN_Msk // Enable B-device (peripheral) VBUS sensing
+#define STM32_GCCFG_NOVBUSSENS_Pos (21U)
+#define STM32_GCCFG_NOVBUSSENS_Msk (0x1UL << STM32_GCCFG_NOVBUSSENS_Pos) // 0x00200000
+#define STM32_GCCFG_NOVBUSSENS STM32_GCCFG_NOVBUSSENS_Msk // VBUS sensing disable option
-// TODO stm32u5a5 VBVALOVA is 23rd bit, conflict with PHYHSEN bit above
-#define STM32_GCCFG_VBVALOVAL_Pos (23U)
-#define STM32_GCCFG_VBVALOVAL_Msk (0x1U << STM32_GCCFG_VBVALOVAL_Pos) // 0x00800000
-#define STM32_GCCFG_VBVALOVAL STM32_GCCFG_VBVALOVAL_Msk // Value of VBUSVLDEXT0 femtoPHY input
+// TODO: stm32u5a5 SDEN is 22nd bit, conflict with 20th bit above
+// #define STM32_GCCFG_SDEN_Pos (22U)
+// #define STM32_GCCFG_SDEN_Msk (0x1U << STM32_GCCFG_SDEN_Pos) // 0x00400000
+// #define STM32_GCCFG_SDEN STM32_GCCFG_SDEN_Msk // Secondary detection (PD) mode enable
-#define STM32_GCCFG_VBVALEXTOEN_Pos (24U)
-#define STM32_GCCFG_VBVALEXTOEN_Msk (0x1U << STM32_GCCFG_VBVALEXTOEN_Pos) // 0x01000000
-#define STM32_GCCFG_VBVALEXTOEN STM32_GCCFG_VBVALEXTOEN_Msk // Enables of VBUSVLDEXT0 femtoPHY input override
+// stm32u5a5 VBVALOVA is 23rd bit, conflict with PHYHSEN bit above
+#define STM32_GCCFG_VBVALOVAL_Pos (23U)
+#define STM32_GCCFG_VBVALOVAL_Msk (0x1U << STM32_GCCFG_VBVALOVAL_Pos) // 0x00800000
+#define STM32_GCCFG_VBVALOVAL STM32_GCCFG_VBVALOVAL_Msk // Value of VBUSVLDEXT0 femtoPHY input
-#define STM32_GCCFG_PULLDOWNEN_Pos (25U)
-#define STM32_GCCFG_PULLDOWNEN_Msk (0x1U << STM32_GCCFG_PULLDOWNEN_Pos) // 0x02000000
-#define STM32_GCCFG_PULLDOWNEN STM32_GCCFG_PULLDOWNEN_Msk // Enables of femtoPHY pulldown resistors, used when ID PAD is disabled
+#define STM32_GCCFG_VBVALEXTOEN_Pos (24U)
+#define STM32_GCCFG_VBVALEXTOEN_Msk (0x1U << STM32_GCCFG_VBVALEXTOEN_Pos) // 0x01000000
+#define STM32_GCCFG_VBVALEXTOEN STM32_GCCFG_VBVALEXTOEN_Msk // Enables of VBUSVLDEXT0 femtoPHY input override
+
+#define STM32_GCCFG_PULLDOWNEN_Pos (25U)
+#define STM32_GCCFG_PULLDOWNEN_Msk (0x1U << STM32_GCCFG_PULLDOWNEN_Pos) // 0x02000000
+#define STM32_GCCFG_PULLDOWNEN STM32_GCCFG_PULLDOWNEN_Msk // Enables of femtoPHY pulldown resistors, used when ID PAD is disabled
/******************** Bit definition for DEACHINTMSK register ********************/
diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c
index c40703b09..8182fd6cc 100644
--- a/src/portable/synopsys/dwc2/hcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/hcd_dwc2.c
@@ -428,6 +428,10 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
#endif
while ((dwc2->gintsts & GINTSTS_CMOD) != GINTSTS_CMODE_HOST) {}
+#ifdef TUP_USBIP_DWC2_STM32
+ dwc2_stm32_gccfg_cfg(dwc2, false, true);
+#endif
+
// configure fixed-allocated fifo scheme
dfifo_host_init(rhport);