From 10a3aa3cc8f58a783d2109f5a6c9a4012992f982 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 15 Oct 2024 13:03:12 +0700 Subject: [PATCH] adding hcd dwc2 --- examples/dual/host_hid_to_device_cdc/only.txt | 1 + .../dual/host_info_to_device_cdc/only.txt | 1 + examples/host/device_info/only.txt | 1 + hw/bsp/stm32h7/family.c | 7 +- hw/bsp/stm32h7/family.cmake | 2 + src/portable/synopsys/dwc2/dcd_dwc2.c | 194 +---------------- src/portable/synopsys/dwc2/dwc2_common.c | 196 ++++++++++++++++++ src/portable/synopsys/dwc2/dwc2_common.h | 70 +++++++ src/portable/synopsys/dwc2/dwc2_type.h | 4 +- src/portable/synopsys/dwc2/hcd_dwc2.c | 167 +++++++++++++++ 10 files changed, 447 insertions(+), 196 deletions(-) create mode 100644 src/portable/synopsys/dwc2/dwc2_common.c create mode 100644 src/portable/synopsys/dwc2/dwc2_common.h create mode 100644 src/portable/synopsys/dwc2/hcd_dwc2.c diff --git a/examples/dual/host_hid_to_device_cdc/only.txt b/examples/dual/host_hid_to_device_cdc/only.txt index cfc87eb4e..149ece856 100644 --- a/examples/dual/host_hid_to_device_cdc/only.txt +++ b/examples/dual/host_hid_to_device_cdc/only.txt @@ -4,3 +4,4 @@ board:mcb1800 mcu:RP2040 mcu:ra6m5 mcu:MAX3421 +mcu:STM32H7 diff --git a/examples/dual/host_info_to_device_cdc/only.txt b/examples/dual/host_info_to_device_cdc/only.txt index cfc87eb4e..149ece856 100644 --- a/examples/dual/host_info_to_device_cdc/only.txt +++ b/examples/dual/host_info_to_device_cdc/only.txt @@ -4,3 +4,4 @@ board:mcb1800 mcu:RP2040 mcu:ra6m5 mcu:MAX3421 +mcu:STM32H7 diff --git a/examples/host/device_info/only.txt b/examples/host/device_info/only.txt index b3f4468bb..a38fc251b 100644 --- a/examples/host/device_info/only.txt +++ b/examples/host/device_info/only.txt @@ -12,3 +12,4 @@ mcu:MSP432E4 mcu:RP2040 mcu:RX65X mcu:RAXXX +mcu:STM32H7 diff --git a/hw/bsp/stm32h7/family.c b/hw/bsp/stm32h7/family.c index 6e4b388d6..3bed1f5ec 100644 --- a/hw/bsp/stm32h7/family.c +++ b/hw/bsp/stm32h7/family.c @@ -151,7 +151,7 @@ void board_init(void) { HAL_UART_Init(&UartHandle); #endif -#if BOARD_TUD_RHPORT == 0 + //------------- USB FS -------------// // Despite being call USB2_OTG // OTG_FS is marked as RHPort0 by TinyUSB to be consistent across stm32 port // PA9 VUSB, PA10 ID, PA11 DM, PA12 DP @@ -195,10 +195,9 @@ void board_init(void) { USB_OTG_FS->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL; #endif // vbus sense -#elif BOARD_TUD_RHPORT == 1 + //------------- USB HS -------------// // Despite being call USB2_OTG // OTG_HS is marked as RHPort1 by TinyUSB to be consistent across stm32 port - struct { GPIO_TypeDef* port; uint32_t pin; @@ -238,8 +237,6 @@ void board_init(void) { // For waveshare openh743 ULPI PHY reset walkaround board_stm32h7_post_init(); -#endif // rhport = 1 - } //--------------------------------------------------------------------+ diff --git a/hw/bsp/stm32h7/family.cmake b/hw/bsp/stm32h7/family.cmake index 026c7c3df..e4161ffe5 100644 --- a/hw/bsp/stm32h7/family.cmake +++ b/hw/bsp/stm32h7/family.cmake @@ -106,6 +106,8 @@ function(family_configure_example TARGET RTOS) family_add_tinyusb(${TARGET} OPT_MCU_STM32H7 ${RTOS}) target_sources(${TARGET}-tinyusb PUBLIC ${TOP}/src/portable/synopsys/dwc2/dcd_dwc2.c + ${TOP}/src/portable/synopsys/dwc2/hcd_dwc2.c + ${TOP}/src/portable/synopsys/dwc2/dwc2_common.c ) target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index f30ec5ee3..a9b3770ee 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -35,45 +35,7 @@ #define DWC2_DEBUG 2 #include "device/dcd.h" -#include "dwc2_type.h" - -// 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_dcd_int_enable/dwc2_dcd_int_disable -// - dwc2_remote_wakeup_delay - -#if defined(TUP_USBIP_DWC2_STM32) - #include "dwc2_stm32.h" -#elif defined(TUP_USBIP_DWC2_ESP32) - #include "dwc2_esp32.h" -#elif TU_CHECK_MCU(OPT_MCU_GD32VF103) - #include "dwc2_gd32.h" -#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837) - #include "dwc2_bcm.h" -#elif TU_CHECK_MCU(OPT_MCU_EFM32GG) - #include "dwc2_efm32.h" -#elif TU_CHECK_MCU(OPT_MCU_XMC4000) - #include "dwc2_xmc.h" -#else - #error "Unsupported MCUs" -#endif - -enum { - DWC2_CONTROLLER_COUNT = TU_ARRAY_SIZE(_dwc2_controller) -}; - -// DWC2 registers -//#define DWC2_REG(_port) ((dwc2_regs_t*) _dwc2_controller[_port].reg_base) - -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 - rhport = 0; - } - return (dwc2_regs_t*) _dwc2_controller[rhport].reg_base; -} +#include "dwc2_common.h" //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM @@ -511,162 +473,16 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c } } -/*------------------------------------------------------------------*/ -/* Controller API - *------------------------------------------------------------------*/ - -static void reset_core(dwc2_regs_t* dwc2) { - // reset core - dwc2->grstctl |= GRSTCTL_CSRST; - - // wait for reset bit is cleared - // TODO version 4.20a should wait for RESET DONE mask - while (dwc2->grstctl & GRSTCTL_CSRST) {} - - // wait for AHB master IDLE - while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {} - - // wait for device mode ? -} - -static bool phy_hs_supported(dwc2_regs_t* dwc2) { - (void) dwc2; - -#if !TUD_OPT_HIGH_SPEED - return false; -#else - return dwc2->ghwcfg2_bm.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED; -#endif -} - -static void phy_fs_init(dwc2_regs_t* dwc2) { - TU_LOG(DWC2_DEBUG, "Fullspeed PHY init\r\n"); - - // Select FS PHY - dwc2->gusbcfg |= GUSBCFG_PHYSEL; - - // MCU specific PHY init before reset - dwc2_phy_init(dwc2, GHWCFG2_HSPHY_NOT_SUPPORTED); - - // Reset core after selecting PHY - reset_core(dwc2); - - // USB turnaround time is critical for certification where long cables and 5-Hubs are used. - // So if you need the AHB to run at less than 30 MHz, and if USB turnaround time is not critical, - // these bits can be programmed to a larger value. Default is 5 - dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos); - - // MCU specific PHY update post reset - dwc2_phy_update(dwc2, GHWCFG2_HSPHY_NOT_SUPPORTED); - - // set max speed - dwc2->dcfg = (dwc2->dcfg & ~DCFG_DSPD_Msk) | (DCFG_DSPD_FS << DCFG_DSPD_Pos); -} - -static void phy_hs_init(dwc2_regs_t* dwc2) { - uint32_t gusbcfg = dwc2->gusbcfg; - - // De-select FS PHY - gusbcfg &= ~GUSBCFG_PHYSEL; - - if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) { - TU_LOG(DWC2_DEBUG, "Highspeed ULPI PHY init\r\n"); - - // Select ULPI - gusbcfg |= GUSBCFG_ULPI_UTMI_SEL; - - // ULPI 8-bit interface, single data rate - gusbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); - - // default internal VBUS Indicator and Drive - gusbcfg &= ~(GUSBCFG_ULPIEVBUSD | GUSBCFG_ULPIEVBUSI); - - // Disable FS/LS ULPI - gusbcfg &= ~(GUSBCFG_ULPIFSLS | GUSBCFG_ULPICSM); - } else { - TU_LOG(DWC2_DEBUG, "Highspeed UTMI+ PHY init\r\n"); - - // Select UTMI+ with 8-bit interface - gusbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); - - // Set 16-bit interface if supported - if (dwc2->ghwcfg4_bm.phy_data_width) { - gusbcfg |= GUSBCFG_PHYIF16; - } - } - - // Apply config - dwc2->gusbcfg = gusbcfg; - - // mcu specific phy init - dwc2_phy_init(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); - - // Reset core after selecting PHY - reset_core(dwc2); - - // Set turn-around, must after core reset otherwise it will be clear - // - 9 if using 8-bit PHY interface - // - 5 if using 16-bit PHY interface - gusbcfg &= ~GUSBCFG_TRDT_Msk; - gusbcfg |= (dwc2->ghwcfg4_bm.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos; - dwc2->gusbcfg = gusbcfg; - - // MCU specific PHY update post reset - dwc2_phy_update(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); - - // Set max speed - uint32_t dcfg = dwc2->dcfg; - dcfg &= ~DCFG_DSPD_Msk; - dcfg |= DCFG_DSPD_HS << DCFG_DSPD_Pos; - - // XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required - // when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347) - if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) { - dcfg |= DCFG_XCVRDLY; - } - - dwc2->dcfg = dcfg; -} - -static bool check_dwc2(dwc2_regs_t* dwc2) { -#if CFG_TUSB_DEBUG >= DWC2_DEBUG - // print guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4 - // Run 'python dwc2_info.py' and check dwc2_info.md for bit-field value and comparison with other ports - volatile uint32_t const* p = (volatile uint32_t const*) &dwc2->guid; - TU_LOG1("guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4\r\n"); - for (size_t i = 0; i < 5; i++) { - TU_LOG1("0x%08" PRIX32 ", ", p[i]); - } - TU_LOG1("0x%08" PRIX32 "\r\n", p[5]); -#endif - - // For some reason: GD32VF103 snpsid and all hwcfg register are always zero (skip it) - (void) dwc2; -#if !TU_CHECK_MCU(OPT_MCU_GD32VF103) - uint32_t const gsnpsid = dwc2->gsnpsid & GSNPSID_ID_MASK; - TU_ASSERT(gsnpsid == DWC2_OTG_ID || gsnpsid == DWC2_FS_IOT_ID || gsnpsid == DWC2_HS_IOT_ID); -#endif - - return true; -} - +//-------------------------------------------------------------------- +// Controller API +//-------------------------------------------------------------------- bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rhport; (void) rh_init; - // Programming model begins in the last section of the chapter on the USB - // peripheral in each Reference Manual. dwc2_regs_t* dwc2 = DWC2_REG(rhport); - // Check Synopsys ID register, failed if controller clock/power is not enabled - TU_ASSERT(check_dwc2(dwc2)); + TU_ASSERT(dwc2_controller_init(rhport, rh_init)); dcd_disconnect(rhport); - if (phy_hs_supported(dwc2)) { - phy_hs_init(dwc2); // Highspeed - } else { - phy_fs_init(dwc2); // core does not support highspeed or hs phy is not present - } - // Restart PHY clock dwc2->pcgctl &= ~(PCGCTL_STOPPCLK | PCGCTL_GATEHCLK | PCGCTL_PWRCLMP | PCGCTL_RSTPDWNMODULE); diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c new file mode 100644 index 000000000..7fd2311db --- /dev/null +++ b/src/portable/synopsys/dwc2/dwc2_common.c @@ -0,0 +1,196 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#define DWC2_COMMON_DEBUG 2 + +#if defined(TUP_USBIP_DWC2) && (CFG_TUH_ENABLED || CFG_TUD_ENABLED) + +#include "common/tusb_common.h" +#include "dwc2_common.h" + +static void reset_core(dwc2_regs_t* dwc2) { + // reset core + dwc2->grstctl |= GRSTCTL_CSRST; + + // wait for reset bit is cleared + // TODO version 4.20a should wait for RESET DONE mask + while (dwc2->grstctl & GRSTCTL_CSRST) {} + + // wait for AHB master IDLE + while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {} + + // wait for device mode ? +} + +static bool phy_hs_supported(dwc2_regs_t* dwc2, const tusb_rhport_init_t* rh_init) { + (void) dwc2; + + +#if !TUD_OPT_HIGH_SPEED + return false; +#else + return dwc2->ghwcfg2_bm.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED; +#endif +} + +static void phy_fs_init(dwc2_regs_t* dwc2, const tusb_rhport_init_t* rh_init) { + TU_LOG(DWC2_COMMON_DEBUG, "Fullspeed PHY init\r\n"); + + // Select FS PHY + dwc2->gusbcfg |= GUSBCFG_PHYSEL; + + // MCU specific PHY init before reset + dwc2_phy_init(dwc2, GHWCFG2_HSPHY_NOT_SUPPORTED); + + // Reset core after selecting PHY + reset_core(dwc2); + + // USB turnaround time is critical for certification where long cables and 5-Hubs are used. + // So if you need the AHB to run at less than 30 MHz, and if USB turnaround time is not critical, + // these bits can be programmed to a larger value. Default is 5 + dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos); + + // MCU specific PHY update post reset + dwc2_phy_update(dwc2, GHWCFG2_HSPHY_NOT_SUPPORTED); + + // set max speed + dwc2->dcfg = (dwc2->dcfg & ~DCFG_DSPD_Msk) | (DCFG_DSPD_FS << DCFG_DSPD_Pos); +} + +static void phy_hs_init(dwc2_regs_t* dwc2, const tusb_rhport_init_t* rh_init) { + uint32_t gusbcfg = dwc2->gusbcfg; + + // De-select FS PHY + gusbcfg &= ~GUSBCFG_PHYSEL; + + if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) { + TU_LOG(DWC2_COMMON_DEBUG, "Highspeed ULPI PHY init\r\n"); + + // Select ULPI PHY (external) + gusbcfg |= GUSBCFG_ULPI_UTMI_SEL; + + // ULPI is always 8-bit interface + gusbcfg &= ~GUSBCFG_PHYIF16; + + // ULPI select single data rate + gusbcfg &= ~GUSBCFG_DDRSEL; + + // default internal VBUS Indicator and Drive + gusbcfg &= ~(GUSBCFG_ULPIEVBUSD | GUSBCFG_ULPIEVBUSI); + + // Disable FS/LS ULPI + gusbcfg &= ~(GUSBCFG_ULPIFSLS | GUSBCFG_ULPICSM); + } else { + TU_LOG(DWC2_COMMON_DEBUG, "Highspeed UTMI+ PHY init\r\n"); + + // Select UTMI+ PHY (internal) + gusbcfg &= ~GUSBCFG_ULPI_UTMI_SEL; + + // Set 16-bit interface if supported + if (dwc2->ghwcfg4_bm.phy_data_width) { + gusbcfg |= GUSBCFG_PHYIF16; // 16 bit + }else { + gusbcfg &= ~GUSBCFG_PHYIF16; // 8 bit + } + } + + // Apply config + dwc2->gusbcfg = gusbcfg; + + // mcu specific phy init + dwc2_phy_init(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); + + // Reset core after selecting PHY + reset_core(dwc2); + + // Set turn-around, must after core reset otherwise it will be clear + // - 9 if using 8-bit PHY interface + // - 5 if using 16-bit PHY interface + gusbcfg &= ~GUSBCFG_TRDT_Msk; + gusbcfg |= (dwc2->ghwcfg4_bm.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos; + dwc2->gusbcfg = gusbcfg; + + // MCU specific PHY update post reset + dwc2_phy_update(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); + + // Set max speed + uint32_t dcfg = dwc2->dcfg; + dcfg &= ~DCFG_DSPD_Msk; + dcfg |= DCFG_DSPD_HS << DCFG_DSPD_Pos; + + // XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required + // when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347) + if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) { + dcfg |= DCFG_XCVRDLY; + } + + dwc2->dcfg = dcfg; +} + +static bool check_dwc2(dwc2_regs_t* dwc2) { +#if CFG_TUSB_DEBUG >= DWC2_COMMON_DEBUG + // print guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4 + // Run 'python dwc2_info.py' and check dwc2_info.md for bit-field value and comparison with other ports + volatile uint32_t const* p = (volatile uint32_t const*) &dwc2->guid; + TU_LOG1("guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4\r\n"); + for (size_t i = 0; i < 5; i++) { + TU_LOG1("0x%08" PRIX32 ", ", p[i]); + } + TU_LOG1("0x%08" PRIX32 "\r\n", p[5]); +#endif + + // For some reason: GD32VF103 gsnpsid and all hwcfg register are always zero (skip it) + (void) dwc2; +#if !TU_CHECK_MCU(OPT_MCU_GD32VF103) + uint32_t const gsnpsid = dwc2->gsnpsid & GSNPSID_ID_MASK; + TU_ASSERT(gsnpsid == DWC2_OTG_ID || gsnpsid == DWC2_FS_IOT_ID || gsnpsid == DWC2_HS_IOT_ID); +#endif + + return true; +} + +//-------------------------------------------------------------------- +// +//-------------------------------------------------------------------- +bool dwc2_controller_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { + (void) rh_init; + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + + // Check Synopsys ID register, failed if controller clock/power is not enabled + TU_ASSERT(check_dwc2(dwc2)); + + if (phy_hs_supported(dwc2, rh_init)) { + phy_hs_init(dwc2, rh_init); // Highspeed + } else { + phy_fs_init(dwc2, rh_init); // core does not support highspeed or hs phy is not present + } + + return true; +} + +#endif diff --git a/src/portable/synopsys/dwc2/dwc2_common.h b/src/portable/synopsys/dwc2/dwc2_common.h new file mode 100644 index 000000000..2a48654c0 --- /dev/null +++ b/src/portable/synopsys/dwc2/dwc2_common.h @@ -0,0 +1,70 @@ +/* +* The MIT License (MIT) + * + * Copyright (c) 2024 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_DWC2_COMMON_H +#define TUSB_DWC2_COMMON_H + +#include "dwc2_type.h" + +// 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_dcd_int_enable/dwc2_dcd_int_disable +// - dwc2_remote_wakeup_delay + +#if defined(TUP_USBIP_DWC2_STM32) + #include "dwc2_stm32.h" +#elif defined(TUP_USBIP_DWC2_ESP32) + #include "dwc2_esp32.h" +#elif TU_CHECK_MCU(OPT_MCU_GD32VF103) + #include "dwc2_gd32.h" +#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837) + #include "dwc2_bcm.h" +#elif TU_CHECK_MCU(OPT_MCU_EFM32GG) + #include "dwc2_efm32.h" +#elif TU_CHECK_MCU(OPT_MCU_XMC4000) + #include "dwc2_xmc.h" +#else + #error "Unsupported MCUs" +#endif + +enum { + DWC2_CONTROLLER_COUNT = TU_ARRAY_SIZE(_dwc2_controller) +}; + +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 + rhport = 0; + } + return (dwc2_regs_t*)_dwc2_controller[rhport].reg_base; +} + + +bool dwc2_controller_init(uint8_t rhport, const tusb_rhport_init_t* rh_init); + +#endif diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index cf05bbfec..b9dc413b1 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -31,8 +31,8 @@ * opensource.org/licenses/BSD-3-Clause */ -#ifndef _TUSB_DWC2_TYPES_H_ -#define _TUSB_DWC2_TYPES_H_ +#ifndef TUSB_DWC2_TYPES_H_ +#define TUSB_DWC2_TYPES_H_ #include "stdint.h" diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c new file mode 100644 index 000000000..8798f982c --- /dev/null +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -0,0 +1,167 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUH_ENABLED && defined(TUP_USBIP_DWC2) + +// Debug level for DWC2 +#define DWC2_DEBUG 2 + +#include "host/hcd.h" +#include "dwc2_common.h" + +//--------------------------------------------------------------------+ +// Controller API +//--------------------------------------------------------------------+ + +// optional hcd configuration, called by tuh_configure() +bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { + (void) rhport; + (void) cfg_id; + (void) cfg_param; + + return false; +} + +// 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; +} + +// Interrupt Handler +void hcd_int_handler(uint8_t rhport, bool in_isr) { + (void) rhport; + (void) in_isr; +} + +// Enable USB interrupt +void hcd_int_enable (uint8_t rhport) { + (void) rhport; +} + +// Disable USB interrupt +void hcd_int_disable(uint8_t rhport) { + (void) rhport; +} + +// Get frame number (1ms) +uint32_t hcd_frame_number(uint8_t rhport) { + (void) rhport; + + return 0; +} + +//--------------------------------------------------------------------+ +// Port API +//--------------------------------------------------------------------+ + +// Get the current connect status of roothub port +bool hcd_port_connect_status(uint8_t rhport) { + (void) rhport; + + return false; +} + +// Reset USB bus on the port. Return immediately, bus reset sequence may not be complete. +// 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) { + (void) rhport; +} + +// Complete bus reset sequence, may be required by some controllers +void hcd_port_reset_end(uint8_t rhport) { + (void) rhport; +} + +// Get port link speed +tusb_speed_t hcd_port_speed_get(uint8_t rhport) { + (void) rhport; + + return TUSB_SPEED_FULL; +} + +// HCD closes all opened endpoints belong to this device +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { + (void) rhport; + (void) dev_addr; +} + +//--------------------------------------------------------------------+ +// Endpoints API +//--------------------------------------------------------------------+ + +// Open an endpoint +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) { + (void) rhport; + (void) dev_addr; + (void) ep_desc; + + return false; +} + +// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked +bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { + (void) rhport; + (void) dev_addr; + (void) ep_addr; + (void) buffer; + (void) buflen; + + return false; +} + +// Abort a queued transfer. Note: it can only abort transfer that has not been started +// Return true if a queued transfer is aborted, false if there is no transfer to abort +bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + (void) dev_addr; + (void) ep_addr; + + return false; +} + +// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked +bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { + (void) rhport; + (void) dev_addr; + (void) setup_packet; + + return false; +} + +// clear stall, data toggle is also reset to DATA0 +bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + (void) dev_addr; + (void) ep_addr; + + return false; +} + +#endif