From 41b0a3efae98b8c4af444cfe53a832da9c8cf0c5 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sun, 9 Oct 2022 17:03:20 +0200 Subject: [PATCH] drivers/usbdev_synopsys_dwc2: add internal UTMI HS PHY support --- drivers/Makefile.dep | 4 + drivers/include/usbdev_synopsys_dwc2.h | 7 +- drivers/periph_common/Kconfig.usbdev | 9 +++ .../usbdev_synopsys_dwc2.c | 74 ++++++++++++++++++- kconfigs/Kconfig.features | 5 ++ 5 files changed, 95 insertions(+), 4 deletions(-) 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.usbdev b/drivers/periph_common/Kconfig.usbdev index 2a94fe7ed0..f6803bdf02 100644 --- a/drivers/periph_common/Kconfig.usbdev +++ b/drivers/periph_common/Kconfig.usbdev @@ -31,6 +31,15 @@ config MODULE_PERIPH_INIT_USBDEV_HS_ULPI 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 diff --git a/drivers/usbdev_synopsys_dwc2/usbdev_synopsys_dwc2.c b/drivers/usbdev_synopsys_dwc2/usbdev_synopsys_dwc2.c index 6043ac02b6..4148e3944b 100644 --- a/drivers/usbdev_synopsys_dwc2/usbdev_synopsys_dwc2.c +++ b/drivers/usbdev_synopsys_dwc2/usbdev_synopsys_dwc2.c @@ -697,11 +697,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 */ @@ -755,12 +756,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 */ @@ -788,14 +853,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