From a39e9cdf2c82401eb61b99dd35e73531bcd76cf1 Mon Sep 17 00:00:00 2001 From: gab-k Date: Fri, 27 Mar 2026 18:34:04 +0100 Subject: Add initial board support for nRF54LM20 DK --- src/common/tusb_mcu.h | 1 + src/portable/synopsys/dwc2/dwc2_nrf.h | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index b12a3177e..77a0bbf1d 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -166,6 +166,7 @@ #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_NRF #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_RHPORT_HIGHSPEED 1 #define CFG_TUH_DWC2_DMA_ENABLE_DEFAULT 0 //--------------------------------------------------------------------+ diff --git a/src/portable/synopsys/dwc2/dwc2_nrf.h b/src/portable/synopsys/dwc2/dwc2_nrf.h index 51f2d684f..067bf39cc 100644 --- a/src/portable/synopsys/dwc2/dwc2_nrf.h +++ b/src/portable/synopsys/dwc2/dwc2_nrf.h @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2025 Ha Thach (tinyusb.org) + * Copyright (c) 2026, Gabriel Koppenstein * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,14 +31,25 @@ #define DWC2_EP_MAX 16 +// Use the auto-resolving peripheral pointer (respects TrustZone secure/non-secure mapping) +#if defined(NRF54LM20A_ENGA_XXAA) + #define _DWC2_NRF_REG_BASE ((uintptr_t) NRF_USBHSCORE) +#else + #define _DWC2_NRF_REG_BASE ((uintptr_t) NRF_USBHSCORE0) +#endif + static const dwc2_controller_t _dwc2_controller[] = { - { .reg_base = NRF_USBHSCORE0_NS_BASE, .irqnum = USBHS_IRQn, .ep_count = 16, .ep_fifo_size = 12288 }, + { .reg_base = _DWC2_NRF_REG_BASE, .irqnum = USBHS_IRQn, .ep_count = 16, .ep_fifo_size = 12160 }, }; TU_ATTR_ALWAYS_INLINE static inline void dwc2_int_set(uint8_t rhport, tusb_role_t role, bool enabled) { (void) rhport; (void) role; - (void) enabled; + if (enabled) { + NVIC_EnableIRQ(USBHS_IRQn); + } else { + NVIC_DisableIRQ(USBHS_IRQn); + } } #define dwc2_dcd_int_enable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, true) @@ -64,4 +76,15 @@ TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint (void)hs_phy_type; } +// nRF54 Cortex-M33 has no D-cache, provide no-op stubs for DMA mode +TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_clean(const void* addr, uint32_t data_size) { + (void)addr; (void)data_size; return true; +} +TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_invalidate(const void* addr, uint32_t data_size) { + (void)addr; (void)data_size; return true; +} +TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_clean_invalidate(const void* addr, uint32_t data_size) { + (void)addr; (void)data_size; return true; +} + #endif -- cgit v1.3.1 From 8849515a0e1d1179d20a42b7b92c0e0a4d1aa131 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 9 Apr 2026 18:22:25 +0700 Subject: rename ep_fifo_size (bytes) to otg_dfifo_depth (words) --- src/portable/synopsys/dwc2/dcd_dwc2.c | 29 ++++++++++++----------- src/portable/synopsys/dwc2/dwc2_at32.h | 20 ++++++++-------- src/portable/synopsys/dwc2/dwc2_bcm.h | 2 +- src/portable/synopsys/dwc2/dwc2_efm32.h | 2 +- src/portable/synopsys/dwc2/dwc2_esp32.h | 8 +++---- src/portable/synopsys/dwc2/dwc2_gd32.h | 2 +- src/portable/synopsys/dwc2/dwc2_info.py | 6 ++--- src/portable/synopsys/dwc2/dwc2_nrf.h | 38 +++++++++++++++++------------ src/portable/synopsys/dwc2/dwc2_stm32.h | 42 ++++++++++++++++----------------- src/portable/synopsys/dwc2/dwc2_type.h | 3 ++- src/portable/synopsys/dwc2/dwc2_xmc.h | 2 +- src/portable/synopsys/dwc2/hcd_dwc2.c | 21 +++++++++++------ 12 files changed, 96 insertions(+), 79 deletions(-) (limited to 'src') diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index e32dedd1b..bdd3a59ed 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -148,22 +148,23 @@ static void dma_setup_prepare(uint8_t rhport) { /* Device Data FIFO scheme - - The FIFO is split up into - - EPInfo: for storing DMA metadata, only required when use DMA. Maximum size is called - EP_LOC_CNT = ep_fifo_size - ghwcfg3.dfifo_depth. For value less than EP_LOC_CNT, gdfifocfg must be configured before - gahbcfg.dmaen is set - - Buffer mode: 1 word per endpoint direction - - Scatter/Gather DMA: 4 words per endpoint direction + The controller has a single SPRAM of otg_dfifo_depth 32-bit words shared between all FIFOs and optional DMA metadata. + otg_dfifo_depth = ghwcfg3.dfifo_depth + EP_LOC_CNT. It is split up into: + + - EPInfo: for storing DMA address registers (DxEPDMAn), only required when DMA is used. + gdfifocfg.EPINFOBASE and gdfifocfg.GDFIFOCfg must be configured before gahbcfg.dmaen is set. + The number of words needed per endpoint direction depends on the DMA mode used at runtime: + - Buffer DMA mode: 1 word per endpoint direction + - Scatter/Gather DMA mode: 4 words per endpoint direction - TX FIFO: one fifo for each IN endpoint. Size is dynamic depending on packet size, starting from top with EP0 IN. - Shared RX FIFO: a shared fifo for all OUT endpoints. Typically, can hold up to 2 packets of the largest EP size. - We allocated TX FIFO from top to bottom (using top pointer), this to allow the RX FIFO to grow dynamically which is + We allocate TX FIFOs from top to bottom (using a top pointer), this to allow the RX FIFO to grow dynamically, which is possible since the free space is located between the RX and TX FIFOs. - ---------------- ep_fifo_size - | DxEPIDMAn | - |-------------|-- gdfifocfg.EPINFOBASE (max is ghwcfg3.dfifo_depth) + --------------- otg_dfifo_depth + | EPInfo | DxEPDMAn (DMA only, sized per runtime DMA mode) + |-------------|-- gdfifocfg.EPINFOBASE (= gdfifocfg.GDFIFOCfg) | IN FIFO 0 | control EP |-------------| | IN FIFO 1 | @@ -184,9 +185,9 @@ static void dma_setup_prepare(uint8_t rhport) { - 13 for setup packets + control words (up to 3 setup packets). - 1 for global NAK (not required/used here). - Largest-EPsize/4 + 1. (FS: 64 bytes, HS: 512 bytes). Recommended is "2 x (Largest-EPsize/4 + 1)" - - 2 for each used OUT endpoint + - 2 for each used OUT endpoint. - Therefore GRXFSIZ = 13 + 1 + 2 x (Largest-EPsize/4 + 1) + 2 x EPOUTnum + Therefore, GRXFSIZ = 13 + 1 + 2 x (Largest-EPsize/4 + 1) + 2 x EPOUTnum */ TU_ATTR_ALWAYS_INLINE static inline uint16_t calc_device_grxfsiz(uint16_t largest_ep_size, uint8_t ep_count) { @@ -249,7 +250,7 @@ static void dfifo_device_init(uint8_t rhport) { // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per endpoint direction const bool is_dma = dma_device_enabled(dwc2); - _dcd_data.dfifo_top = dwc2_controller->ep_fifo_size/4; + _dcd_data.dfifo_top = dwc2_controller->otg_dfifo_depth; if (is_dma) { _dcd_data.dfifo_top -= 2 * dwc2_controller->ep_count; } diff --git a/src/portable/synopsys/dwc2/dwc2_at32.h b/src/portable/synopsys/dwc2/dwc2_at32.h index fa6d10c12..594d350b7 100644 --- a/src/portable/synopsys/dwc2/dwc2_at32.h +++ b/src/portable/synopsys/dwc2/dwc2_at32.h @@ -32,38 +32,38 @@ #if CFG_TUSB_MCU == OPT_MCU_AT32F415 #include - #define OTG1_FIFO_SIZE 1280 + #define OTG1_DFIFO_DEPTH 320 #define OTG1_IRQn OTGFS1_IRQn #define DWC2_OTG1_REG_BASE 0x50000000UL #elif CFG_TUSB_MCU == OPT_MCU_AT32F435_437 #include - #define OTG1_FIFO_SIZE 1280 - #define OTG2_FIFO_SIZE 1280 + #define OTG1_DFIFO_DEPTH 320 + #define OTG2_DFIFO_DEPTH 320 #define OTG1_IRQn OTGFS1_IRQn #define OTG2_IRQn OTGFS2_IRQn #define DWC2_OTG1_REG_BASE 0x50000000UL #define DWC2_OTG2_REG_BASE 0x40040000UL #elif CFG_TUSB_MCU == OPT_MCU_AT32F423 #include - #define OTG1_FIFO_SIZE 1280 + #define OTG1_DFIFO_DEPTH 320 #define OTG1_IRQn OTGFS1_IRQn #define DWC2_OTG1_REG_BASE 0x50000000UL #elif CFG_TUSB_MCU == OPT_MCU_AT32F402_405 #include - #define OTG1_FIFO_SIZE 1280 - #define OTG2_FIFO_SIZE 4096 + #define OTG1_DFIFO_DEPTH 320 + #define OTG2_DFIFO_DEPTH 1024 #define OTG1_IRQn OTGFS1_IRQn #define OTG2_IRQn OTGHS_IRQn #define DWC2_OTG1_REG_BASE 0x50000000UL #define DWC2_OTG2_REG_BASE 0x40040000UL //OTGHS #elif CFG_TUSB_MCU == OPT_MCU_AT32F425 #include - #define OTG1_FIFO_SIZE 1280 + #define OTG1_DFIFO_DEPTH 320 #define OTG1_IRQn OTGFS1_IRQn #define DWC2_OTG1_REG_BASE 0x50000000UL #elif CFG_TUSB_MCU == OPT_MCU_AT32F45X #include - #define OTG1_FIFO_SIZE 1280 + #define OTG1_DFIFO_DEPTH 320 #define OTG1_IRQn OTGFS1_IRQn #define DWC2_OTG1_REG_BASE 0x50000000UL #endif @@ -73,9 +73,9 @@ extern "C" { #endif static const dwc2_controller_t _dwc2_controller[] = { - {.reg_base = DWC2_OTG1_REG_BASE, .irqnum = OTG1_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = OTG1_FIFO_SIZE}, + {.reg_base = DWC2_OTG1_REG_BASE, .irqnum = OTG1_IRQn, .ep_count = DWC2_EP_MAX, .otg_dfifo_depth = OTG1_DFIFO_DEPTH}, #if defined DWC2_OTG2_REG_BASE - {.reg_base = DWC2_OTG2_REG_BASE, .irqnum = OTG2_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = OTG2_FIFO_SIZE} + {.reg_base = DWC2_OTG2_REG_BASE, .irqnum = OTG2_IRQn, .ep_count = DWC2_EP_MAX, .otg_dfifo_depth = OTG2_DFIFO_DEPTH} #endif }; diff --git a/src/portable/synopsys/dwc2/dwc2_bcm.h b/src/portable/synopsys/dwc2/dwc2_bcm.h index 00842bba2..50f3122e8 100644 --- a/src/portable/synopsys/dwc2/dwc2_bcm.h +++ b/src/portable/synopsys/dwc2/dwc2_bcm.h @@ -39,7 +39,7 @@ static const dwc2_controller_t _dwc2_controller[] = { - { .reg_base = USB_OTG_GLOBAL_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 16384 } + { .reg_base = USB_OTG_GLOBAL_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .otg_dfifo_depth = 4096 } }; #define dcache_clean(_addr, _size) data_clean(_addr, _size) diff --git a/src/portable/synopsys/dwc2/dwc2_efm32.h b/src/portable/synopsys/dwc2/dwc2_efm32.h index e1cb7c769..167f5b4cd 100644 --- a/src/portable/synopsys/dwc2/dwc2_efm32.h +++ b/src/portable/synopsys/dwc2/dwc2_efm32.h @@ -40,7 +40,7 @@ static const dwc2_controller_t _dwc2_controller[] = { - { .reg_base = DWC2_REG_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 2048 } + { .reg_base = DWC2_REG_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .otg_dfifo_depth = 512 } }; TU_ATTR_ALWAYS_INLINE diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h index ff9f216bd..99ef9456f 100644 --- a/src/portable/synopsys/dwc2/dwc2_esp32.h +++ b/src/portable/synopsys/dwc2/dwc2_esp32.h @@ -44,7 +44,7 @@ #define DWC2_EP_MAX 7 static const dwc2_controller_t _dwc2_controller[] = { - { .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 } + { .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .otg_dfifo_depth = 256 } }; #elif TU_CHECK_MCU(OPT_MCU_ESP32H4) @@ -61,7 +61,7 @@ static const dwc2_controller_t _dwc2_controller[] = { #define DWC2_EP_MAX 7 static const dwc2_controller_t _dwc2_controller[] = { - { .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 } + { .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .otg_dfifo_depth = 256 } }; #elif TU_CHECK_MCU(OPT_MCU_ESP32P4) @@ -72,8 +72,8 @@ static const dwc2_controller_t _dwc2_controller[] = { // On ESP32 for consistency we associate // - Port0 to OTG_FS, and Port1 to OTG_HS static const dwc2_controller_t _dwc2_controller[] = { - { .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_CH0_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 }, - { .reg_base = DWC2_HS_REG_BASE, .irqnum = ETS_USB_OTG_INTR_SOURCE, .ep_count = 16, .ep_in_count = 8, .ep_fifo_size = 4096 } + { .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_CH0_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .otg_dfifo_depth = 256 }, + { .reg_base = DWC2_HS_REG_BASE, .irqnum = ETS_USB_OTG_INTR_SOURCE, .ep_count = 16, .ep_in_count = 8, .otg_dfifo_depth = 1024 } }; #endif diff --git a/src/portable/synopsys/dwc2/dwc2_gd32.h b/src/portable/synopsys/dwc2/dwc2_gd32.h index ccbf93a76..396d17e30 100644 --- a/src/portable/synopsys/dwc2/dwc2_gd32.h +++ b/src/portable/synopsys/dwc2/dwc2_gd32.h @@ -37,7 +37,7 @@ static const dwc2_controller_t _dwc2_controller[] = { - { .reg_base = DWC2_REG_BASE, .irqnum = 86, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1280 } + { .reg_base = DWC2_REG_BASE, .irqnum = 86, .ep_count = DWC2_EP_MAX, .otg_dfifo_depth = 320 } }; extern uint32_t SystemCoreClock; diff --git a/src/portable/synopsys/dwc2/dwc2_info.py b/src/portable/synopsys/dwc2/dwc2_info.py index bdf63d590..eab95ffe1 100755 --- a/src/portable/synopsys/dwc2/dwc2_info.py +++ b/src/portable/synopsys/dwc2/dwc2_info.py @@ -9,14 +9,14 @@ import pandas as pd dwc2_reg_list = ['GUID', 'GSNPSID', 'GHWCFG1', 'GHWCFG2', 'GHWCFG3', 'GHWCFG4'] dwc2_reg_value = { 'AT32 F405 FS': [0x00002000, 0x4F54400A, 0x00000000, 0x228FDD00, 0x020004E8, 0x1FF0A020], - 'AT32 F405 HS': [0x00000000, 0x4F54400A, 0x00000000, 0x229FDDD0, 0x03F006E8, 0x1FF0A020], + 'AT32 F405 HS': [0, 0x4F54400A, 0x00000000, 0x229FDDD0, 0x03F006E8, 0x1FF0A020], 'AT32 F415': [0x00001000, 0x4F54400A, 0x00000000, 0x228DCD00, 0x020004E8, 0x0F], 'BCM2711 (Pi4)': [0x2708A000, 0x4F54280A, 0, 0x228DDD50, 0xFF000E8, 0x1FF00020], 'EFM32GG': [0, 0x4F54330A, 0, 0x228F5910, 0x01F204E8, 0x1BF08030], 'ESP32-S2/S3': [0, 0x4F54400A, 0, 0x224DD930, 0x0C804B5, 0xD3F0A030], 'ESP32-P4': [0, 0x4F54400A, 0, 0x215FFFD0, 0x03805EB5, 0xDFF1A030], - 'nRF54': [0, 0x4F54430A, 0xAA555000, 0x228BFC72, 0x0BEAC0E8, 0x1E10AA60], - 'nRF54LM20': [0x00000000, 0x4F54500B, 0x00000000, 0x22AFFC52, 0x0BE0C0E8, 0x3E10AA60], + # 'nRF54H20': [0, 0x4F54430A, 0xAA555000, 0x228BFC72, 0x0BEAC0E8, 0x1E10AA60], + 'nRF54LM20': [0, 0x4F54500B, 0x00000000, 0x22AFFC52, 0x0BE0C0E8, 0x3E10AA60], # ST sort by GUID 'ST F407/429 HS': [0x1100, 0x4F54281A, 0, 0x229ED590, 0x03F403E8, 0x17F00030], 'ST F207/F407/411/429 FS': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x020001E8, 0x0FF08030], diff --git a/src/portable/synopsys/dwc2/dwc2_nrf.h b/src/portable/synopsys/dwc2/dwc2_nrf.h index 067bf39cc..fc9cd18bc 100644 --- a/src/portable/synopsys/dwc2/dwc2_nrf.h +++ b/src/portable/synopsys/dwc2/dwc2_nrf.h @@ -2,7 +2,6 @@ * The MIT License (MIT) * * Copyright (c) 2025 Ha Thach (tinyusb.org) - * Copyright (c) 2026, Gabriel Koppenstein * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,6 +22,9 @@ * THE SOFTWARE. * * This file is part of the TinyUSB stack. + * + * Modification + * - Gabriel Koppenstein add nRF54LM20 support */ #ifndef TUSB_DWC2_NRF_H #define TUSB_DWC2_NRF_H @@ -33,18 +35,18 @@ // Use the auto-resolving peripheral pointer (respects TrustZone secure/non-secure mapping) #if defined(NRF54LM20A_ENGA_XXAA) - #define _DWC2_NRF_REG_BASE ((uintptr_t) NRF_USBHSCORE) + #define DWC2_REG_BASE ((uintptr_t)NRF_USBHSCORE) #else - #define _DWC2_NRF_REG_BASE ((uintptr_t) NRF_USBHSCORE0) + #define DWC2_REG_BASE ((uintptr_t)NRF_USBHSCORE0) #endif static const dwc2_controller_t _dwc2_controller[] = { - { .reg_base = _DWC2_NRF_REG_BASE, .irqnum = USBHS_IRQn, .ep_count = 16, .ep_fifo_size = 12160 }, + {.reg_base = DWC2_REG_BASE, .irqnum = USBHS_IRQn, .ep_count = 16, .otg_dfifo_depth = 3072}, }; TU_ATTR_ALWAYS_INLINE static inline void dwc2_int_set(uint8_t rhport, tusb_role_t role, bool enabled) { - (void) rhport; - (void) role; + (void)rhport; + (void)role; if (enabled) { NVIC_EnableIRQ(USBHS_IRQn); } else { @@ -59,32 +61,38 @@ TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) { } // MCU specific PHY init, called BEFORE core reset -TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { +TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_init(dwc2_regs_t *dwc2, uint8_t hs_phy_type) { (void)dwc2; (void)hs_phy_type; } // MCU specific PHY deinit, disable PHY power -TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_deinit(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { +TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_deinit(dwc2_regs_t *dwc2, uint8_t hs_phy_type) { (void)dwc2; (void)hs_phy_type; } // MCU specific PHY update, it is called AFTER init() and core reset -TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { +TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_update(dwc2_regs_t *dwc2, uint8_t hs_phy_type) { (void)dwc2; (void)hs_phy_type; } // nRF54 Cortex-M33 has no D-cache, provide no-op stubs for DMA mode -TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_clean(const void* addr, uint32_t data_size) { - (void)addr; (void)data_size; return true; +TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_clean(const void *addr, uint32_t data_size) { + (void)addr; + (void)data_size; + return true; } -TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_invalidate(const void* addr, uint32_t data_size) { - (void)addr; (void)data_size; return true; +TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_invalidate(const void *addr, uint32_t data_size) { + (void)addr; + (void)data_size; + return true; } -TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_clean_invalidate(const void* addr, uint32_t data_size) { - (void)addr; (void)data_size; return true; +TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_clean_invalidate(const void *addr, uint32_t data_size) { + (void)addr; + (void)data_size; + return true; } #endif diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h index 259ad21b9..5f6e98224 100644 --- a/src/portable/synopsys/dwc2/dwc2_stm32.h +++ b/src/portable/synopsys/dwc2/dwc2_stm32.h @@ -31,36 +31,36 @@ extern "C" { #endif -// EP_MAX : Max number of bi-directional endpoints including EP0 -// EP_FIFO_SIZE : Size of dedicated USB SRAM +// EP_MAX : Max number of bi-directional endpoints including EP0 +// DFIFO_DEPTH_FS/HS : DFIFO depth in 32-bit words (OTG_DFIFO_DEPTH) #if CFG_TUSB_MCU == OPT_MCU_STM32F1 #include "stm32f1xx.h" #define EP_MAX_FS 4 - #define EP_FIFO_SIZE_FS 1280 + #define DFIFO_DEPTH_FS 320 #elif CFG_TUSB_MCU == OPT_MCU_STM32F2 #include "stm32f2xx.h" #define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS - #define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE + #define DFIFO_DEPTH_FS 320 #define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS - #define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE + #define DFIFO_DEPTH_HS 1024 #elif CFG_TUSB_MCU == OPT_MCU_STM32F4 #include "stm32f4xx.h" #define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS - #define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE + #define DFIFO_DEPTH_FS 320 #define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS - #define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE + #define DFIFO_DEPTH_HS 1024 #elif CFG_TUSB_MCU == OPT_MCU_STM32H7 #include "stm32h7xx.h" #define EP_MAX_FS 9 - #define EP_FIFO_SIZE_FS 4096 + #define DFIFO_DEPTH_FS 1024 #define EP_MAX_HS 9 - #define EP_FIFO_SIZE_HS 4096 + #define DFIFO_DEPTH_HS 1024 // NOTE: H7 with only 1 USB port: H72x / H73x / H7Ax / H7Bx // USB_OTG_FS_PERIPH_BASE and OTG_FS_IRQn not defined @@ -72,18 +72,18 @@ extern "C" { #elif CFG_TUSB_MCU == OPT_MCU_STM32H7RS #include "stm32h7rsxx.h" #define EP_MAX_FS 6 - #define EP_FIFO_SIZE_FS 1280 + #define DFIFO_DEPTH_FS 320 #define EP_MAX_HS 9 - #define EP_FIFO_SIZE_HS 4096 + #define DFIFO_DEPTH_HS 1024 #elif CFG_TUSB_MCU == OPT_MCU_STM32N6 #include "stm32n6xx.h" #define EP_MAX_FS 9 - #define EP_FIFO_SIZE_FS 4096 + #define DFIFO_DEPTH_FS 1024 #define EP_MAX_HS 9 - #define EP_FIFO_SIZE_HS 4096 + #define DFIFO_DEPTH_HS 1024 #define USB_OTG_FS_PERIPH_BASE USB1_OTG_HS_BASE #define OTG_FS_IRQn USB1_OTG_HS_IRQn @@ -94,15 +94,15 @@ extern "C" { #elif CFG_TUSB_MCU == OPT_MCU_STM32F7 #include "stm32f7xx.h" #define EP_MAX_FS 6 - #define EP_FIFO_SIZE_FS 1280 + #define DFIFO_DEPTH_FS 320 #define EP_MAX_HS 9 - #define EP_FIFO_SIZE_HS 4096 + #define DFIFO_DEPTH_HS 1024 #elif CFG_TUSB_MCU == OPT_MCU_STM32L4 #include "stm32l4xx.h" #define EP_MAX_FS 6 - #define EP_FIFO_SIZE_FS 1280 + #define DFIFO_DEPTH_FS 320 #elif CFG_TUSB_MCU == OPT_MCU_STM32U5 #include "stm32u5xx.h" @@ -110,11 +110,11 @@ extern "C" { #ifdef USB_OTG_FS #define USB_OTG_FS_PERIPH_BASE USB_OTG_FS_BASE #define EP_MAX_FS 6 - #define EP_FIFO_SIZE_FS 1280 + #define DFIFO_DEPTH_FS 1280 #else #define USB_OTG_HS_PERIPH_BASE USB_OTG_HS_BASE #define EP_MAX_HS 9 - #define EP_FIFO_SIZE_HS 4096 + #define DFIFO_DEPTH_HS 4096 #endif #elif CFG_TUSB_MCU == OPT_MCU_STM32WBA @@ -131,7 +131,7 @@ extern "C" { #define USB_OTG_HS_PERIPH_BASE USB_OTG_HS_BASE_NS #define OTG_HS_IRQn USB_OTG_HS_IRQn #define EP_MAX_HS 9 - #define EP_FIFO_SIZE_HS 4096 + #define DFIFO_DEPTH_HS 4096 #else #error "Unsupported MCUs" #endif @@ -147,11 +147,11 @@ extern "C" { // - Port0 to OTG_FS, and Port1 to OTG_HS static const dwc2_controller_t _dwc2_controller[] = { #ifdef USB_OTG_FS_PERIPH_BASE - { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .ep_fifo_size = EP_FIFO_SIZE_FS }, + { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .otg_dfifo_depth = DFIFO_DEPTH_FS }, #endif #ifdef USB_OTG_HS_PERIPH_BASE - { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .ep_fifo_size = EP_FIFO_SIZE_HS }, + { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .otg_dfifo_depth = DFIFO_DEPTH_HS }, #endif }; diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index 596bd0b34..7c03a4a91 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -47,7 +47,7 @@ typedef struct uint32_t irqnum; uint8_t ep_count; uint8_t ep_in_count; - uint32_t ep_fifo_size; + uint16_t otg_dfifo_depth; // total SPRAM in 32-bit words = ghwcfg3.dfifo_depth + EP_LOC_CNT }dwc2_controller_t; // DWC OTG HW Release versions @@ -63,6 +63,7 @@ typedef struct #define DWC2_CORE_REV_4_00a 0x4f54400a #define DWC2_CORE_REV_4_11a 0x4f54411a #define DWC2_CORE_REV_4_20a 0x4f54420a +#define DWC2_CORE_REV_5_00b 0x4F54500b #define DWC2_FS_IOT_REV_1_00a 0x5531100a #define DWC2_HS_IOT_REV_1_00a 0x5532100a #define DWC2_CORE_REV_MASK 0x0000ffff diff --git a/src/portable/synopsys/dwc2/dwc2_xmc.h b/src/portable/synopsys/dwc2/dwc2_xmc.h index aca3873df..b946444ee 100644 --- a/src/portable/synopsys/dwc2/dwc2_xmc.h +++ b/src/portable/synopsys/dwc2/dwc2_xmc.h @@ -39,7 +39,7 @@ static const dwc2_controller_t _dwc2_controller[] = { // Note: XMC has some custom control registers before DWC registers - { .reg_base = USB0_BASE, .irqnum = USB0_0_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 2048 } + { .reg_base = USB0_BASE, .irqnum = USB0_0_IRQn, .ep_count = DWC2_EP_MAX, .otg_dfifo_depth = 512 } }; TU_ATTR_ALWAYS_INLINE diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index e12e44a41..cd2ddf572 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -323,9 +323,9 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t cal_next_pid(uint8_t pid, uint8_t pa We allocated TX FIFO from top to bottom (using top pointer), this to allow the RX FIFO to grow dynamically which is possible since the free space is located between the RX and TX FIFOs. - ----------------- ep_fifo_size - | HCDMAn | - |--------------|-- gdfifocfg.EPINFOBASE (max is ghwcfg3.dfifo_depth) + ----------------- otg_dfifo_depth + | HCDMAn | (DMA only, sized per runtime DMA mode) + |--------------|-- gdfifocfg.EPINFOBASE (= gdfifocfg.GDFIFOCfg) | Non-Periodic | | TX FIFO | |--------------|--- GNPTXFSIZ.addr (fixed size) @@ -358,15 +358,22 @@ static void dfifo_host_init(uint8_t rhport, bool is_hs_phy) { // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per channel const bool is_dma = dma_host_enabled(dwc2); - uint16_t dfifo_top = dwc2_controller->ep_fifo_size/4; + uint16_t dfifo_top = dwc2_controller->otg_dfifo_depth; if (is_dma) { dfifo_top -= ghwcfg2.num_host_ch; } // fixed allocation for now, improve later: - // - ptx_largest is limited to 256 for FS since most FS core only has 1024 bytes total - uint32_t nptx_largest = is_hs_phy ? TUSB_EPSIZE_BULK_HS / 4 : TUSB_EPSIZE_BULK_FS / 4; - uint32_t ptx_largest = is_hs_phy ? TUSB_EPSIZE_ISO_HS_MAX / 4 : 256 / 4; + // - ptx_largest is limited to 64 words for FS since most FS core only has 256-320 words total + uint32_t nptx_largest; + uint32_t ptx_largest; + if (is_hs_phy) { + nptx_largest = TUSB_EPSIZE_BULK_HS / 4; + ptx_largest = TUSB_EPSIZE_ISO_HS_MAX / 4; + } else { + nptx_largest = TUSB_EPSIZE_BULK_FS / 4; + ptx_largest = 256 / 4; + } uint16_t nptxfsiz = 2 * nptx_largest; uint16_t rxfsiz = 2 * (ptx_largest + 2) + ghwcfg2.num_host_ch; -- cgit v1.3.1 From c96ff6b6d978bdcacc7cd49ad66ef00438cfb9f6 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 10 Apr 2026 16:52:15 +0700 Subject: add dwc2_clock_init() to have nrf54 initial sequence. currently stub for other ports. add board_uart_read() for nrf --- hw/bsp/nrf/family.c | 131 +++++++++++++++---------------- src/portable/synopsys/dwc2/dcd_dwc2.c | 4 +- src/portable/synopsys/dwc2/dwc2_at32.h | 6 ++ src/portable/synopsys/dwc2/dwc2_bcm.h | 6 ++ src/portable/synopsys/dwc2/dwc2_common.h | 16 ++-- src/portable/synopsys/dwc2/dwc2_efm32.h | 6 ++ src/portable/synopsys/dwc2/dwc2_esp32.h | 6 ++ src/portable/synopsys/dwc2/dwc2_gd32.h | 6 ++ src/portable/synopsys/dwc2/dwc2_nrf.h | 52 ++++++++++++ src/portable/synopsys/dwc2/dwc2_stm32.h | 6 ++ src/portable/synopsys/dwc2/dwc2_xmc.h | 6 ++ src/portable/synopsys/dwc2/hcd_dwc2.c | 4 +- 12 files changed, 172 insertions(+), 77 deletions(-) (limited to 'src') diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index 10f0fc460..31a6bac9e 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -81,39 +81,67 @@ enum { // Forward USB interrupt events to TinyUSB IRQ Handler #if defined(NRF54H20_XXAA) || defined(NRF54LM20A_ENGA_XXAA) -#define USBD_IRQn USBHS_IRQn + #define USBD_IRQn USBHS_IRQn void USBHS_IRQHandler(void) { tusb_int_handler(0, true); } -#if defined(NRF54LM20A_ENGA_XXAA) + #if defined(NRF54LM20A_ENGA_XXAA) static nrfx_uarte_t _uart_id = NRFX_UARTE_INSTANCE(20); -#else + #else static nrfx_uarte_t _uart_id = NRFX_UARTE_INSTANCE(120); -#endif - -#else + #endif -#ifdef NRF5340_XXAA -#define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_LFRC -#define VBUSDETECT_Msk USBREG_USBREGSTATUS_VBUSDETECT_Msk -#define OUTPUTRDY_Msk USBREG_USBREGSTATUS_OUTPUTRDY_Msk -#define GPIOTE_IRQn GPIOTE1_IRQn #else -#define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_RC -#define VBUSDETECT_Msk POWER_USBREGSTATUS_VBUSDETECT_Msk -#define OUTPUTRDY_Msk POWER_USBREGSTATUS_OUTPUTRDY_Msk -#endif + #ifdef NRF5340_XXAA + #define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_LFRC + #define VBUSDETECT_Msk USBREG_USBREGSTATUS_VBUSDETECT_Msk + #define OUTPUTRDY_Msk USBREG_USBREGSTATUS_OUTPUTRDY_Msk + #define GPIOTE_IRQn GPIOTE1_IRQn + #else + #define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_RC + #define VBUSDETECT_Msk POWER_USBREGSTATUS_VBUSDETECT_Msk + #define OUTPUTRDY_Msk POWER_USBREGSTATUS_OUTPUTRDY_Msk + #endif -#if CFG_TUSB_OS != OPT_OS_ZEPHYR + #if CFG_TUSB_OS != OPT_OS_ZEPHYR static nrfx_uarte_t _uart_id = NRFX_UARTE_INSTANCE(0); -#endif + #endif void USBD_IRQHandler(void) { - tud_int_handler(0); + tusb_int_handler(0, true); } #endif +//--------------------------------------------------------------------+ +// UART RX ring buffer and event handler +//--------------------------------------------------------------------+ +#if CFG_TUSB_OS != OPT_OS_ZEPHYR + +#define UART_RX_BUFSIZE 64 + +static uint8_t rx_fifo[UART_RX_BUFSIZE]; +static volatile uint16_t rx_fifo_head = 0; +static volatile uint16_t rx_fifo_tail = 0; + +static uint8_t rx_dma_buf[1]; // 1-byte DMA target for continuous RX + +static void uart_event_handler(nrfx_uarte_event_t const* p_event, void* p_context) { + (void) p_context; + if (p_event->type == NRFX_UARTE_EVT_RX_DONE) { + for (size_t i = 0; i < p_event->data.rx.length; i++) { + uint16_t next_head = (rx_fifo_head + 1) & (UART_RX_BUFSIZE - 1); + if (next_head != rx_fifo_tail) { + rx_fifo[rx_fifo_head] = p_event->data.rx.p_buffer[i]; + rx_fifo_head = next_head; + } + } + // re-arm 1-byte RX + nrfx_uarte_rx(&_uart_id, rx_dma_buf, sizeof(rx_dma_buf)); + } +} + +#endif // tinyusb function that handles power event (detected, ready, removed) // We must call it within SD's SOC event handler, or set it as power event handler if SD is not enabled. @@ -136,7 +164,6 @@ static nrfx_gpiote_t _gpiote = NRFX_GPIOTE_INSTANCE(0); //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ - void board_init(void) { #if !defined(NRF54H20_XXAA) && !defined(NRF54LM20A_ENGA_XXAA) // stop LF clock just in case we jump from application without reset @@ -172,12 +199,14 @@ void board_init(void) { #if CFG_TUSB_OS != OPT_OS_ZEPHYR // UART + static uint8_t uart_tx_cache[64]; nrfx_uarte_config_t uart_cfg = { .txd_pin = UART_TX_PIN, .rxd_pin = UART_RX_PIN, .rts_pin = NRF_UARTE_PSEL_DISCONNECTED, .cts_pin = NRF_UARTE_PSEL_DISCONNECTED, .p_context = NULL, + .tx_cache = { .p_buffer = uart_tx_cache, .length = sizeof(uart_tx_cache) }, .baudrate = NRF_UARTE_BAUDRATE_115200, // CFG_BOARD_UART_BAUDRATE .interrupt_priority = 7, .config = { @@ -186,63 +215,21 @@ void board_init(void) { } }; - nrfx_uarte_init(&_uart_id, &uart_cfg, NULL); + nrfx_uarte_init(&_uart_id, &uart_cfg, uart_event_handler); + // start continuous 1-byte RX + nrfx_uarte_rx(&_uart_id, rx_dma_buf, sizeof(rx_dma_buf)); #endif //------------- USB -------------// #if CFG_TUD_ENABLED #if defined(NRF54LM20A_ENGA_XXAA) - // Start the USB voltage regulator - NRF_VREGUSB->TASKS_START = VREGUSB_TASKS_START_TASKS_START_Trigger; - // Request HFXO crystal clock for PCLK24M (required by USBHS core) NRF_CLOCK->TASKS_XO24MSTART = CLOCK_TASKS_XO24MSTART_TASKS_XO24MSTART_Trigger; while (!NRF_CLOCK->EVENTS_XO24MSTARTED) {} NRF_CLOCK->EVENTS_XO24MSTARTED = 0; #endif -#if defined(NRF54H20_XXAA) - // Enable the USBHS wrapper (core + PHY) before any DWC2 register access - NRF_USBHS->ENABLE = (USBHS_ENABLE_PHY_Enabled << USBHS_ENABLE_PHY_Pos) | - (USBHS_ENABLE_CORE_Enabled << USBHS_ENABLE_CORE_Pos); - NRF_USBHS->TASKS_START = USBHS_TASKS_START_TASKS_START_Trigger; - // Brief delay for PHY PLL lock and core power-up - for (volatile int i = 0; i < 1000; i++) {} -#endif - -#if defined(NRF54LM20A_ENGA_XXAA) - // 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_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_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 - // Priorities 0, 1, 4 (nRF52) are reserved for SoftDevice // 2 is highest for application NVIC_SetPriority(USBD_IRQn, 2); @@ -329,11 +316,18 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) { } int board_uart_read(uint8_t* buf, int len) { +#if CFG_TUSB_OS == OPT_OS_ZEPHYR (void) buf; (void) len; return -1; -// nrfx_err_t err = nrfx_uarte_rx(&_uart_id, buf, (size_t) len); -// return NRFX_SUCCESS == err ? len : 0; +#else + int count = 0; + while (count < len && rx_fifo_tail != rx_fifo_head) { + buf[count++] = rx_fifo[rx_fifo_tail]; + rx_fifo_tail = (rx_fifo_tail + 1) & (UART_RX_BUFSIZE - 1); + } + return count; +#endif } int board_uart_write(void const* buf, int len) { @@ -341,7 +335,10 @@ int board_uart_write(void const* buf, int len) { (void) buf; return len; #else - nrfx_err_t err = nrfx_uarte_tx(&_uart_id, (uint8_t const*) buf, (size_t) len ,0); + if (nrfx_uarte_tx_in_progress(&_uart_id)) { + return 0; + } + nrfx_err_t err = nrfx_uarte_tx(&_uart_id, (uint8_t const*) buf, (size_t) len, 0); return (NRFX_SUCCESS == err) ? len : 0; #endif } 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 + +#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)); -- cgit v1.3.1 From de59d95c325e9776d344e7e6272bd79335184ae2 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 10 Apr 2026 21:14:01 +0700 Subject: fix DWC2 FIFO depth values for STM32 families --- src/portable/synopsys/dwc2/dwc2_stm32.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h index e5379dfe3..126632fec 100644 --- a/src/portable/synopsys/dwc2/dwc2_stm32.h +++ b/src/portable/synopsys/dwc2/dwc2_stm32.h @@ -110,11 +110,11 @@ extern "C" { #ifdef USB_OTG_FS #define USB_OTG_FS_PERIPH_BASE USB_OTG_FS_BASE #define EP_MAX_FS 6 - #define DFIFO_DEPTH_FS 1280 + #define DFIFO_DEPTH_FS 320 #else #define USB_OTG_HS_PERIPH_BASE USB_OTG_HS_BASE #define EP_MAX_HS 9 - #define DFIFO_DEPTH_HS 4096 + #define DFIFO_DEPTH_HS 1024 #endif #elif CFG_TUSB_MCU == OPT_MCU_STM32WBA @@ -131,7 +131,7 @@ extern "C" { #define USB_OTG_HS_PERIPH_BASE USB_OTG_HS_BASE_NS #define OTG_HS_IRQn USB_OTG_HS_IRQn #define EP_MAX_HS 9 - #define DFIFO_DEPTH_HS 4096 + #define DFIFO_DEPTH_HS 1024 #else #error "Unsupported MCUs" #endif -- cgit v1.3.1 From b2b498f17e403b006943ca15d9884b4f596eacfb Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 10 Apr 2026 21:17:46 +0700 Subject: clean up --- hw/bsp/nrf/boards/nrf54lm20dk/board.cmake | 3 --- src/portable/synopsys/dwc2/dwc2_info.md | 2 +- src/portable/synopsys/dwc2/dwc2_info.py | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/hw/bsp/nrf/boards/nrf54lm20dk/board.cmake b/hw/bsp/nrf/boards/nrf54lm20dk/board.cmake index fb0ccdfdf..8c2b83346 100644 --- a/hw/bsp/nrf/boards/nrf54lm20dk/board.cmake +++ b/hw/bsp/nrf/boards/nrf54lm20dk/board.cmake @@ -5,7 +5,4 @@ function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC CFG_EXAMPLE_VIDEO_READONLY ) - target_sources(${TARGET} PRIVATE -# ${NRFX_PATH}/drivers/src/nrfx_usbreg.c - ) endfunction() diff --git a/src/portable/synopsys/dwc2/dwc2_info.md b/src/portable/synopsys/dwc2/dwc2_info.md index 051c3ab1f..205684e4b 100644 --- a/src/portable/synopsys/dwc2/dwc2_info.md +++ b/src/portable/synopsys/dwc2/dwc2_info.md @@ -1,4 +1,4 @@ -| | AT32 F405 FS | AT32 F405 HS | AT32 F415 | BCM2711 (Pi4) | EFM32GG | ESP32-S2/S3 | ESP32-P4 | nRF54 | nRF54LM20 | ST F407/429 HS | ST F207/F407/411/429 FS | ST L476 FS | ST F412/76x FS | ST F76x HS | ST H743/H750 | ST F723/L4P5 FS | ST F723 HS | ST H7RS FS | ST U5A5/H7RS/N6 HS | XMC4500 | GD32VF103 | +| | AT32 F405 FS | AT32 F405 HS | AT32 F415 | BCM2711 (Pi4) | EFM32GG | ESP32-S2/S3 | ESP32-P4 | nRF54H20 | nRF54LM20 | ST F407/429 HS | ST F207/F407/411/429 FS | ST L476 FS | ST F412/76x FS | ST F76x HS | ST H743/H750 | ST F723/L4P5 FS | ST F723 HS | ST H7RS FS | ST U5A5/H7RS/N6 HS | XMC4500 | GD32VF103 | |:---------------------------|:---------------|:---------------|:------------|:----------------|:-------------|:--------------|:-------------|:-------------|:-------------|:-----------------|:--------------------------|:-------------|:-----------------|:-------------|:---------------|:------------------|:-------------|:-------------|:---------------------|:-------------|:------------| | GUID | 0x00002000 | 0x00000000 | 0x00001000 | 0x2708A000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00001100 | 0x00001200 | 0x00002000 | 0x00002000 | 0x00002100 | 0x00002300 | 0x00003000 | 0x00003100 | 0x00004000 | 0x00005000 | 0x00AEC000 | 0x00001000 | | GSNPSID | 0x4F54400A | 0x4F54400A | 0x4F54400A | 0x4F54280A | 0x4F54330A | 0x4F54400A | 0x4F54400A | 0x4F54430A | 0x4F54500B | 0x4F54281A | 0x4F54281A | 0x4F54310A | 0x4F54320A | 0x4F54320A | 0x4F54330A | 0x4F54330A | 0x4F54330A | 0x4F54411A | 0x4F54411A | 0x4F54292A | 0x00000000 | diff --git a/src/portable/synopsys/dwc2/dwc2_info.py b/src/portable/synopsys/dwc2/dwc2_info.py index eab95ffe1..8ee04e179 100755 --- a/src/portable/synopsys/dwc2/dwc2_info.py +++ b/src/portable/synopsys/dwc2/dwc2_info.py @@ -15,7 +15,7 @@ dwc2_reg_value = { 'EFM32GG': [0, 0x4F54330A, 0, 0x228F5910, 0x01F204E8, 0x1BF08030], 'ESP32-S2/S3': [0, 0x4F54400A, 0, 0x224DD930, 0x0C804B5, 0xD3F0A030], 'ESP32-P4': [0, 0x4F54400A, 0, 0x215FFFD0, 0x03805EB5, 0xDFF1A030], - # 'nRF54H20': [0, 0x4F54430A, 0xAA555000, 0x228BFC72, 0x0BEAC0E8, 0x1E10AA60], + 'nRF54H20': [0, 0x4F54430A, 0xAA555000, 0x228BFC72, 0x0BEAC0E8, 0x1E10AA60], # base on Preliminary Datasheet v0.7 'nRF54LM20': [0, 0x4F54500B, 0x00000000, 0x22AFFC52, 0x0BE0C0E8, 0x3E10AA60], # ST sort by GUID 'ST F407/429 HS': [0x1100, 0x4F54281A, 0, 0x229ED590, 0x03F403E8, 0x17F00030], -- cgit v1.3.1 From 3f3d65aabab8478ce0c6cce095c327a395eb1ab4 Mon Sep 17 00:00:00 2001 From: Ha Thach Date: Fri, 10 Apr 2026 21:20:57 +0700 Subject: Update src/portable/synopsys/dwc2/dcd_dwc2.c Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/portable/synopsys/dwc2/dcd_dwc2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index da6ee894a..9a9c734a0 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -164,7 +164,7 @@ static void dma_setup_prepare(uint8_t rhport) { --------------- otg_dfifo_depth | EPInfo | DxEPDMAn (DMA only, sized per runtime DMA mode) - |-------------|-- gdfifocfg.EPINFOBASE (= gdfifocfg.GDFIFOCfg) + |-------------|-- gdfifocfg.EPINFOBASE (start of EPInfo; FIFO space sized by GDFIFOCFG) | IN FIFO 0 | control EP |-------------| | IN FIFO 1 | -- cgit v1.3.1