diff --git a/boards/common/stm32/include/cfg_usb_otg_hs_phy_utmi.h b/boards/common/stm32/include/cfg_usb_otg_hs_phy_utmi.h new file mode 100644 index 0000000000..f2bb4a6e6a --- /dev/null +++ b/boards/common/stm32/include/cfg_usb_otg_hs_phy_utmi.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2019 Koen Zandberg + * 2022 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup boards_common_stm32 + * @{ + * + * @file + * @brief Common configuration for STM32 OTG HS peripheral with internal UTMI HS PHY + * + * All STM32 boards which use the internal UTMI HS PHY for the USB OTG HS + * peripheral use the same configuration. Therefore a common configuration file + * can be used for these boards. + * + * @author Koen Zandberg + * @author Gunar Schorcht + */ + +#ifndef CFG_USB_OTG_HS_PHY_UTMI_H +#define CFG_USB_OTG_HS_PHY_UTMI_H + +#include "periph_cpu.h" +#include "usbdev_synopsys_dwc2.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Enable the high speed USB OTG peripheral + */ +#define DWC2_USB_OTG_HS_ENABLED + +#ifndef USBPHYC_TUNE_VALUE +/** + * @brief Default value of USBPHYC tuning control register + * + * The value of the USBPHYC tuning control register (USBPHYC_TUNE) is used by + * the USB HS PHY controller for the tuning interface of the internal + * USB HS PHY, please refer the Reference Manual for STM32F72xxx and STM32F73xxx + * for details. + * + * The value as defined in the [STM32CubeF7 HAL Driver MCU Component for F7] + * (https://bit.ly/3es9eFA) is used as default value. + * If necessary, it can be overridden by the board configuration in + * `periph_conf.h` by defining the value before this file is included. + */ +#define USBPHYC_TUNE_VALUE 0x00000f13U +#endif + +/** + * @brief Common USB OTG HS configuration + */ +static const dwc2_usb_otg_fshs_config_t dwc2_usb_otg_fshs_config[] = { + { + .periph = USB_OTG_HS_PERIPH_BASE, + .type = DWC2_USB_OTG_HS, + .phy = DWC2_USB_OTG_PHY_UTMI, + .rcc_mask = RCC_AHB1ENR_OTGHSEN, + .irqn = OTG_HS_IRQn, + .ahb = AHB1, + .dm = GPIO_PIN(PORT_B, 14), + .dp = GPIO_PIN(PORT_B, 15), + .af = GPIO_AF10, + .phy_tune = USBPHYC_TUNE_VALUE, + } +}; + +/** + * @brief Number of available USB OTG peripherals + */ +#define USBDEV_NUMOF ARRAY_SIZE(dwc2_usb_otg_fshs_config) + +#ifdef __cplusplus +} +#endif + +#endif /* CFG_USB_OTG_HS_PHY_UTMI_H */ +/** @} */ diff --git a/boards/stm32f723e-disco/Kconfig b/boards/stm32f723e-disco/Kconfig index 5e3a794970..b987eff9de 100644 --- a/boards/stm32f723e-disco/Kconfig +++ b/boards/stm32f723e-disco/Kconfig @@ -22,6 +22,7 @@ config BOARD_STM32F723E_DISCO select HAS_PERIPH_UART select HAS_PERIPH_UART_HW_FC select HAS_PERIPH_USBDEV + select HAS_PERIPH_USBDEV_HS_UTMI # Put other features for this board (in alphabetical order) select HAS_TINYUSB_DEVICE diff --git a/boards/stm32f723e-disco/Makefile.features b/boards/stm32f723e-disco/Makefile.features index 1e87f7b710..983f775e2b 100644 --- a/boards/stm32f723e-disco/Makefile.features +++ b/boards/stm32f723e-disco/Makefile.features @@ -11,6 +11,7 @@ FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_uart FEATURES_PROVIDED += periph_uart_hw_fc FEATURES_PROVIDED += periph_usbdev +FEATURES_PROVIDED += periph_usbdev_hs_utmi # Put other features for this board (in alphabetical order) FEATURES_PROVIDED += tinyusb_device diff --git a/boards/stm32f723e-disco/doc.txt b/boards/stm32f723e-disco/doc.txt index f44c4124b2..3916d15642 100644 --- a/boards/stm32f723e-disco/doc.txt +++ b/boards/stm32f723e-disco/doc.txt @@ -28,4 +28,10 @@ Use the `term` target to open a terminal: make BOARD=stm32f723e-disco -C examples/hello-world term +### USB OTG Peripheral Device Driver + +By default, the USB OTG FS port is used. To use the USB OTG HS port with the +internal UTMI+ HS PHY, enable the module `periph_usbdev_hs_utmi`: + + make BOARD=stm32f723e-disco USEMODULE=periph_usbdev_hs_utmi -C examples/usbus_minimal */ diff --git a/boards/stm32f723e-disco/include/periph_conf.h b/boards/stm32f723e-disco/include/periph_conf.h index 28e4e7b5ed..7a2213b8c1 100644 --- a/boards/stm32f723e-disco/include/periph_conf.h +++ b/boards/stm32f723e-disco/include/periph_conf.h @@ -35,7 +35,11 @@ #include "periph_cpu.h" #include "clk_conf.h" #include "cfg_rtt_default.h" +#if defined(MODULE_PERIPH_USBDEV_HS_UTMI) +#include "cfg_usb_otg_hs_phy_utmi.h" +#else #include "cfg_usb_otg_fs.h" +#endif #ifdef __cplusplus extern "C" { diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 2d4fb601fd..aa73dee94d 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -145,6 +145,10 @@ ifneq (,$(filter periph_usbdev_hs_ulpi,$(USEMODULE))) FEATURES_REQUIRED += periph_usbdev_hs_ulpi endif +ifneq (,$(filter periph_usbdev_hs_utmi,$(USEMODULE))) + FEATURES_REQUIRED += periph_usbdev_hs_utmi +endif + ifneq (,$(filter pn532_i2c,$(USEMODULE))) FEATURES_REQUIRED += periph_i2c USEMODULE += pn532 diff --git a/drivers/include/usbdev_synopsys_dwc2.h b/drivers/include/usbdev_synopsys_dwc2.h index c4ed930a7a..228199d071 100644 --- a/drivers/include/usbdev_synopsys_dwc2.h +++ b/drivers/include/usbdev_synopsys_dwc2.h @@ -67,7 +67,7 @@ typedef enum { } dwc2_usb_otg_fshs_phy_t; /** - * @brief stm32 USB OTG configuration + * @brief USB OTG configuration */ typedef struct { uintptr_t periph; /**< USB peripheral base address */ @@ -95,6 +95,11 @@ typedef struct { gpio_t dm; /**< Data- gpio */ gpio_t dp; /**< Data+ gpio */ gpio_af_t af; /**< Alternative function */ +#if defined(MODULE_PERIPH_USBDEV_HS_UTMI) || DOXYGEN + uint32_t phy_tune; /**< USB HS PHY controller tuning register + * value (STM32-specific), see USBPHYC_TUNE + * register in STM32 Reference Manual */ +#endif /* defined(MODULE_PERIPH_USBDEV_HS_UTMI) */ #endif /* defined(MCU_STM32) || DOXYGEN */ } dwc2_usb_otg_fshs_config_t; diff --git a/drivers/periph_common/Kconfig b/drivers/periph_common/Kconfig index 67d5d8667f..4a9306642e 100644 --- a/drivers/periph_common/Kconfig +++ b/drivers/periph_common/Kconfig @@ -156,39 +156,7 @@ config MODULE_PERIPH_INIT_TEMPERATURE depends on MODULE_PERIPH_TEMPERATURE rsource "Kconfig.uart" - -config MODULE_PERIPH_USBDEV - bool "USBDEV peripheral driver" - depends on HAS_PERIPH_USBDEV - select MODULE_PERIPH_COMMON - select MODULE_PERIPH_USBDEV_CLK - -config MODULE_PERIPH_INIT_USBDEV - bool "Auto initialize USBDEV peripheral" - default y if MODULE_PERIPH_INIT - depends on MODULE_PERIPH_USBDEV - -config MODULE_PERIPH_USBDEV_HS_ULPI - bool "Use USB HS pripheral with UPLI HS PHY" - depends on HAS_PERIPH_USBDEV_HS_ULPI - depends on MODULE_PERIPH_USBDEV - -config MODULE_PERIPH_INIT_USBDEV_HS_ULPI - bool - default y if MODULE_PERIPH_INIT && MODULE_PERIPH_USBDEV_HS_ULPI - depends on HAS_PERIPH_USBDEV_HS_ULPI - depends on MODULE_PERIPH_USBDEV - -config MODULE_PERIPH_USBDEV_CLK - bool - depends on HAS_PERIPH_USBDEV - help - Enable the USB device specific clock settings, if there are any - -config MODULE_PERIPH_INIT_USBDEV_CLK - bool - default y if MODULE_PERIPH_INIT && MODULE_PERIPH_USBDEV_CLK - depends on HAS_PERIPH_USBDEV +rsource "Kconfig.usbdev" endif # TEST_KCONFIG diff --git a/drivers/periph_common/Kconfig.usbdev b/drivers/periph_common/Kconfig.usbdev new file mode 100644 index 0000000000..f6803bdf02 --- /dev/null +++ b/drivers/periph_common/Kconfig.usbdev @@ -0,0 +1,54 @@ +# Copyright (c) 2020 HAW Hamburg +# 2022 Gunar Schorcht +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. +# + +menuconfig MODULE_PERIPH_USBDEV + bool "USBDEV peripheral driver" + depends on HAS_PERIPH_USBDEV + select MODULE_PERIPH_COMMON + select MODULE_PERIPH_USBDEV_CLK + +if MODULE_PERIPH_USBDEV + +# TODO: the 'init' modules are actually just artifacts from the way +# periph_init_% modules are handled in Makefile. We need to define them to keep +# the list the same for now. We should be able to remove them later on. + +config MODULE_PERIPH_INIT_USBDEV + bool "Auto initialize USBDEV peripheral" + default y if MODULE_PERIPH_INIT + +config MODULE_PERIPH_USBDEV_HS_ULPI + bool "Use USB HS peripheral with ULPI HS PHY" + depends on HAS_PERIPH_USBDEV_HS_ULPI + +config MODULE_PERIPH_INIT_USBDEV_HS_ULPI + bool + depends on MODULE_PERIPH_USBDEV_HS_ULPI + default y if MODULE_PERIPH_INIT + +config MODULE_PERIPH_USBDEV_HS_UTMI + bool "Use USB HS peripheral with internal UTMI+ HS PHY" + depends on HAS_PERIPH_USBDEV_HS_UTMI + +config MODULE_PERIPH_INIT_USBDEV_HS_UTMI + bool + depends on MODULE_PERIPH_USBDEV_HS_UTMI + default y if MODULE_PERIPH_INIT + +endif + +config MODULE_PERIPH_USBDEV_CLK + bool + depends on HAS_PERIPH_USBDEV + help + Enable the USB device specific clock settings, if there are any + +config MODULE_PERIPH_INIT_USBDEV_CLK + bool + depends on MODULE_PERIPH_USBDEV_CLK + default y if MODULE_PERIPH_INIT diff --git a/drivers/usbdev_synopsys_dwc2/usbdev_synopsys_dwc2.c b/drivers/usbdev_synopsys_dwc2/usbdev_synopsys_dwc2.c index 114a647301..ee2e939f9e 100644 --- a/drivers/usbdev_synopsys_dwc2/usbdev_synopsys_dwc2.c +++ b/drivers/usbdev_synopsys_dwc2/usbdev_synopsys_dwc2.c @@ -633,14 +633,17 @@ static void _reset_periph(dwc2_usb_otg_fshs_t *usbdev) #ifdef MCU_STM32 static void _enable_gpio(const dwc2_usb_otg_fshs_config_t *conf) { + (void)conf; +#ifndef MODULE_PERIPH_USBDEV_HS_ULPI /* Enables clock on the GPIO bus */ gpio_init(conf->dp, GPIO_IN); gpio_init(conf->dm, GPIO_IN); /* Configure AF for the pins */ gpio_init_af(conf->dp, conf->af); gpio_init_af(conf->dm, conf->af); +#endif /* MODULE_PERIPH_USBDEV_HS_ULPI */ } -#endif +#endif /* MCU_STM32 */ static void _set_mode_device(dwc2_usb_otg_fshs_t *usbdev) { @@ -693,11 +696,12 @@ static void _usbdev_init(usbdev_t *dev) if (conf->type == DWC2_USB_OTG_HS) { if (conf->phy == DWC2_USB_OTG_PHY_BUILTIN) { /* Disable the ULPI clock in low power mode, this is essential for the - * peripheral when using the built-in phy or UTMI phy */ + * peripheral when using the built-in PHY */ periph_lpclk_dis(conf->ahb, RCC_AHB1LPENR_OTGHSULPILPEN); /* select on-chip builtin PHY */ _global_regs(usbdev->config)->GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL; } + #ifdef MODULE_PERIPH_USBDEV_HS_ULPI else if (conf->phy == DWC2_USB_OTG_PHY_ULPI) { /* initialize ULPI interface */ @@ -729,16 +733,18 @@ static void _usbdev_init(usbdev_t *dev) /* enable ULPI clock */ periph_clk_en(conf->ahb, RCC_AHB1ENR_OTGHSULPIEN); -#if !defined(MCU_STM32) - /* TODO following settings are required for DWC2 HS but are not - * defined for STM32 MCUs where these settings correspond to the - * reset value of the GUSBCFG register */ +#ifdef USB_OTG_GUSBCFG_ULPI_UTMI_SEL /* select ULPI PHY */ - _global_regs(usbdev->config)->GUSBCFG |= USB_OTG_GUSBCFG_ULPI_UTMI_SEL - /* use the 8-bit interface and single data rate */ - _global_regs(usbdev->config)->GUSBCFG &= ~(USB_OTG_GUSBCFG_PHYIF16 | - USB_OTG_GUSBCFG_DDRSEL); -#endif /* !defined(MCU_STM32) */ + _global_regs(usbdev->config)->GUSBCFG |= USB_OTG_GUSBCFG_ULPI_UTMI_SEL; +#endif +#ifdef USB_OTG_GUSBCFG_PHYIF + /* use the 8-bit interface */ + _global_regs(usbdev->config)->GUSBCFG &= ~USB_OTG_GUSBCFG_PHYIF; +#endif /* USB_OTG_GUSBCFG_PHYIF */ +#ifdef USB_OTG_GUSBCFG_DDRSEL + /* use single data rate */ + _global_regs(usbdev->config)->GUSBCFG &= ~USB_OTG_GUSBCFG_DDRSEL; +#endif /* USB_OTG_GUSBCFG_DDRSEL */ /* disable the on-chip FS transceiver */ _global_regs(usbdev->config)->GUSBCFG &= ~USB_OTG_GUSBCFG_PHYSEL; @@ -749,12 +755,76 @@ static void _usbdev_init(usbdev_t *dev) /* disable ULPI FS/LS serial interface */ _global_regs(usbdev->config)->GUSBCFG &= ~USB_OTG_GUSBCFG_ULPIFSLS; } + +#elif defined(MODULE_PERIPH_USBDEV_HS_UTMI) + else if (conf->phy == DWC2_USB_OTG_PHY_UTMI) { + /* enable ULPI clock */ + periph_clk_en(conf->ahb, RCC_AHB1ENR_OTGHSULPIEN); + /* enable UTMI HS PHY Controller clock */ + periph_clk_en(APB2, RCC_APB2ENR_OTGPHYCEN); + +#ifdef USB_OTG_GUSBCFG_ULPI_UTMI_SEL + /* select UTMI+ PHY */ + _global_regs(usbdev->config)->GUSBCFG &= ~USB_OTG_GUSBCFG_ULPI_UTMI_SEL; +#endif /* USB_OTG_GUSBCFG_ULPI_UTMI_SEL */ +#ifdef USB_OTG_GUSBCFG_PHYIF + /* use the 8-bit interface and single data rate */ + _global_regs(usbdev->config)->GUSBCFG &= ~USB_OTG_GUSBCFG_PHYIF; +#endif /* USB_OTG_GUSBCFG_PHYIF */ + + /* disable the on-chip FS transceiver */ + _global_regs(usbdev->config)->GUSBCFG &= ~USB_OTG_GUSBCFG_PHYSEL; + + /* configure the USB HS PHY Controller (USB_HS_PHYC), + * USB_HS_PHYC and GCCFG are STM32 specific */ +#ifdef USB_HS_PHYC + /* enable USB HS PHY Controller */ + _global_regs(usbdev->config)->GCCFG |= USB_OTG_GCCFG_PHYHSEN; + + /* determine the PLL input clock of the USB HS PHY from HSE clock */ + switch (CLOCK_HSE) { + case 12000000: + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL1_PLLSEL_12MHZ; + break; + case 12500000: + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL1_PLLSEL_12_5MHZ; + break; + case 16000000: + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL1_PLLSEL_16MHZ; + break; + case 24000000: + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL1_PLLSEL_24MHZ; + break; + case 25000000: + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL1_PLLSEL_25MHZ; + break; + default: + assert(0); + } + + /* configure the tuning interface of the USB HS PHY */ + USB_HS_PHYC->USB_HS_PHYC_TUNE |= conf->phy_tune; + + /* check whether the LDO regulator is used by on the chip */ + if (USB_HS_PHYC->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_USED) { + /* enable the LDO */ + USB_HS_PHYC->USB_HS_PHYC_LDO |= USB_HS_PHYC_LDO_ENABLE; + /* wait until the LDO is ready */ + while (!(USB_HS_PHYC->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_STATUS)) {} + } + + /* enable the PLL of the USB HS PHY */ + USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN; +#endif /* USB_HS_PHYC */ + } + #else /* MODULE_PERIPH_USBDEV_HS_ULPI */ else { /* only on-chip PHY support enabled */ assert(conf->phy == DWC2_USB_OTG_PHY_BUILTIN); } #endif /* MODULE_PERIPH_USBDEV_HS_ULPI */ + } #endif /* DWC2_USB_OTG_HS_ENABLED */ @@ -782,14 +852,17 @@ static void _usbdev_init(usbdev_t *dev) USB_OTG_GOTGCTL_BVALOEN | USB_OTG_GOTGCTL_BVALOVAL; #endif /* defined(STM32_USB_OTG_CID_1x) */ - if (conf->phy == DWC2_USB_OTG_PHY_BUILTIN) { /* set `Power Down Disable` to activate the on-chip FS transceiver */ _global_regs(usbdev->config)->GCCFG |= USB_OTG_GCCFG_PWRDWN; } else if (IS_USED(MODULE_PERIPH_USBDEV_HS_ULPI) && (conf->phy == DWC2_USB_OTG_PHY_ULPI)) { /* clear `Power Down Disable` to deactivate the on-chip FS transceiver */ - _global_regs(usbdev->config)->GCCFG &= USB_OTG_GCCFG_PWRDWN; + _global_regs(usbdev->config)->GCCFG &= ~USB_OTG_GCCFG_PWRDWN; + } + else if (IS_USED(MODULE_PERIPH_USBDEV_HS_UTMI) && (conf->phy == DWC2_USB_OTG_PHY_UTMI)) { + /* clear `Power Down Disable` to deactivate the on-chip FS transceiver */ + _global_regs(usbdev->config)->GCCFG &= ~USB_OTG_GCCFG_PWRDWN; } #elif defined(MCU_ESP32) diff --git a/kconfigs/Kconfig.features b/kconfigs/Kconfig.features index e843993efd..1d3bc251b4 100644 --- a/kconfigs/Kconfig.features +++ b/kconfigs/Kconfig.features @@ -424,6 +424,11 @@ config HAS_PERIPH_USBDEV help Indicates that an USBDEV peripheral is present. +config HAS_PERIPH_USBDEV_HS_UTMI + bool + help + Indicates that an USBDEV HS peripheral with internal UTMI+ HS PHY is present. + config HAS_PERIPH_USBDEV_HS_ULPI bool help