From f72ef5c237240e4888b94ec2cccaec774be5ece1 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Wed, 4 Dec 2024 12:36:19 +0100 Subject: [PATCH] drivers: usb: stm32: fix support of STM32U5 OTG_HS with embedded PHY Introduce new binding "st,stm32u5-otghs-phy" for OTG_HS PHY. This allows to configure clock source and handle STM32U5 specific OTG_HS PHY behavior in driver implementation in a more readable way. Move OTG_HS PHY clock selection (previously <&rcc STM32_SRC_HSI48 ICKLK_SEL(0)>) from OTG_HS node to OTG_HS PHY node. Rename USBPHYC_SEL -> OTGHS_SEL which matches the definition in the stm32u5 CCIPR2 register (RM0456 Rev 5, Section 11.8.47). Support enabling OTG_HS PHY clock, which is bit 15 (OTGHSPHYEN) in RCC_AHB2ENR1. Change OTG_HS clock to be bit 14 (OTGEN). Calculate in runtime OTG_HS PHY clock source frequency. Try to match that to supported (16, 19.2, 20, 24, 26, 32 MHz) frequencies and select proper option with HAL_SYSCFG_SetOTGPHYReferenceClockSelection() API (instead of hardcoded 16 MHz selection). Co-authored-by: Adrian Chadd Signed-off-by: Adrian Chadd Signed-off-by: Marcin Niestroj --- drivers/usb/device/Kconfig | 2 +- drivers/usb/device/usb_dc_stm32.c | 111 ++++++++++++++++-- dts/arm/st/u5/stm32u595.dtsi | 8 +- dts/bindings/phy/st,stm32u5-otghs-phy.yaml | 36 ++++++ .../zephyr/dt-bindings/clock/stm32u5_clock.h | 2 +- 5 files changed, 142 insertions(+), 17 deletions(-) create mode 100644 dts/bindings/phy/st,stm32u5-otghs-phy.yaml diff --git a/drivers/usb/device/Kconfig b/drivers/usb/device/Kconfig index c286fa39cf2..4cdd0710cda 100644 --- a/drivers/usb/device/Kconfig +++ b/drivers/usb/device/Kconfig @@ -62,7 +62,7 @@ config USB_DC_STM32 config USB_DC_STM32_CLOCK_CHECK bool "Runtime USB 48MHz clock check" depends on USB_DC_STM32 - default y if !(SOC_SERIES_STM32F1X || SOC_SERIES_STM32F3X) + default y if !(SOC_SERIES_STM32F1X || SOC_SERIES_STM32F3X || SOC_SERIES_STM32U5X) help Enable USB clock 48MHz configuration runtime check. In specific cases, this check might provide wrong verdict and should diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index b5fc75c3c2e..dd435842306 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -208,16 +208,67 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) } #endif -static int usb_dc_stm32_clock_enable(void) -{ - const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_otghs_phy) - if (!device_is_ready(clk)) { - LOG_ERR("clock control device not ready"); - return -ENODEV; +static const struct stm32_pclken phy_pclken[] = STM32_DT_CLOCKS(DT_INST_PHANDLE(0, phys)); + +static int usb_dc_stm32u5_phy_clock_select(const struct device *const clk) +{ + static const struct { + uint32_t freq; + uint32_t ref_clk; + } clk_select[] = { + { MHZ(16), SYSCFG_OTG_HS_PHY_CLK_SELECT_1 }, + { KHZ(19200), SYSCFG_OTG_HS_PHY_CLK_SELECT_2 }, + { MHZ(20), SYSCFG_OTG_HS_PHY_CLK_SELECT_3 }, + { MHZ(24), SYSCFG_OTG_HS_PHY_CLK_SELECT_4 }, + { MHZ(26), SYSCFG_OTG_HS_PHY_CLK_SELECT_5 }, + { MHZ(32), SYSCFG_OTG_HS_PHY_CLK_SELECT_6 }, + }; + uint32_t freq; + + if (clock_control_get_rate(clk, + (clock_control_subsys_t)&phy_pclken[1], + &freq) != 0) { + LOG_ERR("Failed to get USB_PHY clock source rate"); + return -EIO; } -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) && defined(CONFIG_SOC_SERIES_STM32U5X) + for (size_t i = 0; ARRAY_SIZE(clk_select); i++) { + if (clk_select[i].freq == freq) { + HAL_SYSCFG_SetOTGPHYReferenceClockSelection(clk_select[i].ref_clk); + return 0; + } + } + + LOG_ERR("Unsupported PHY clock source frequency (%"PRIu32")", freq); + + return -EINVAL; +} + +static int usb_dc_stm32u5_phy_clock_enable(const struct device *const clk) +{ + int err; + + err = clock_control_configure(clk, (clock_control_subsys_t)&phy_pclken[1], NULL); + if (err) { + LOG_ERR("Could not select USB_PHY clock source"); + return -EIO; + } + + err = clock_control_on(clk, (clock_control_subsys_t)&phy_pclken[0]); + if (err) { + LOG_ERR("Unable to enable USB_PHY clock"); + return -EIO; + } + + return usb_dc_stm32u5_phy_clock_select(clk); +} + +static int usb_dc_stm32_phy_specific_clock_enable(const struct device *const clk) +{ + int err; + /* Sequence to enable the power of the OTG HS on a stm32U5 serie : Enable VDDUSB */ bool pwr_clk = LL_AHB3_GRP1_IsEnabledClock(LL_AHB3_GRP1_PERIPH_PWR); @@ -246,10 +297,28 @@ static int usb_dc_stm32_clock_enable(void) /* Set the OTG PHY reference clock selection (through SYSCFG) block */ LL_APB3_GRP1_EnableClock(LL_APB3_GRP1_PERIPH_SYSCFG); - HAL_SYSCFG_SetOTGPHYReferenceClockSelection(SYSCFG_OTG_HS_PHY_CLK_SELECT_1); + + err = usb_dc_stm32u5_phy_clock_enable(clk); + if (err) { + return err; + } + /* Configuring the SYSCFG registers OTG_HS PHY : OTG_HS PHY enable*/ HAL_SYSCFG_EnableOTGPHY(SYSCFG_OTG_HS_PHY_ENABLE); -#elif defined(PWR_USBSCR_USB33SV) || defined(PWR_SVMCR_USV) + + if (clock_control_on(clk, (clock_control_subsys_t)&pclken[0]) != 0) { + LOG_ERR("Unable to enable USB clock"); + return -EIO; + } + + return 0; +} + +#else /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_otghs_phy) */ + +static int usb_dc_stm32_phy_specific_clock_enable(const struct device *const clk) +{ +#if defined(PWR_USBSCR_USB33SV) || defined(PWR_SVMCR_USV) /* * VDDUSB independent USB supply (PWR clock is on) * with LL_PWR_EnableVDDUSB function (higher case) @@ -286,6 +355,26 @@ static int usb_dc_stm32_clock_enable(void) } } + return 0; +} + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_otghs_phy) */ + +static int usb_dc_stm32_clock_enable(void) +{ + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + int err; + + if (!device_is_ready(clk)) { + LOG_ERR("clock control device not ready"); + return -ENODEV; + } + + err = usb_dc_stm32_phy_specific_clock_enable(clk); + if (err) { + return err; + } + /* Previous check won't work in case of F1/F3. Add build time check */ #if defined(RCC_CFGR_OTGFSPRE) || defined(RCC_CFGR_USBPRE) @@ -333,8 +422,8 @@ static int usb_dc_stm32_clock_disable(void) LOG_ERR("Unable to disable USB clock"); return -EIO; } -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) && defined(CONFIG_SOC_SERIES_STM32U5X) - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_USBPHY); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_otghs_phy) + clock_control_off(clk, (clock_control_subsys_t)&phy_pclken[0]); #endif return 0; diff --git a/dts/arm/st/u5/stm32u595.dtsi b/dts/arm/st/u5/stm32u595.dtsi index c0c856dc273..78a3370b8a3 100644 --- a/dts/arm/st/u5/stm32u595.dtsi +++ b/dts/arm/st/u5/stm32u595.dtsi @@ -106,16 +106,16 @@ num-bidir-endpoints = <9>; ram-size = <4096>; maximum-speed = "high-speed"; - clocks = <&rcc STM32_CLOCK(AHB2, 15U)>, - <&rcc STM32_SRC_HSI48 ICKLK_SEL(0)>; + clocks = <&rcc STM32_CLOCK(AHB2, 14U)>; phys = <&otghs_phy>; status = "disabled"; }; }; otghs_phy: otghs_phy { - /* Clock source defined by USBPHYC_SEL in */ - compatible = "usb-nop-xceiv"; + compatible = "st,stm32u5-otghs-phy"; + clocks = <&rcc STM32_CLOCK(AHB2, 15U)>, + <&rcc STM32_SRC_HSE OTGHS_SEL(0)>; #phy-cells = <0>; }; diff --git a/dts/bindings/phy/st,stm32u5-otghs-phy.yaml b/dts/bindings/phy/st,stm32u5-otghs-phy.yaml new file mode 100644 index 00000000000..f844d813a99 --- /dev/null +++ b/dts/bindings/phy/st,stm32u5-otghs-phy.yaml @@ -0,0 +1,36 @@ +# Copyright (c) 2024 Marcin Niestroj +# Copyright (c) 2024 Meta +# SPDX-License-Identifier: Apache-2.0 + +description: | + This binding is to be used by the STM32U5xx transceivers which are built-in + with USB HS PHY IP and a configurable HSE clock source. + +compatible: "st,stm32u5-otghs-phy" + +include: phy-controller.yaml + +properties: + "#phy-cells": + const: 0 + + clocks: + required: true + description: | + Supported configurations: + + /* HSE */ + clocks = <&rcc STM32_CLOCK(AHB2, 15U)>, + <&rcc STM32_SRC_HSE OTGHS_SEL(0)>; + + /* HSE/2 */ + clocks = <&rcc STM32_CLOCK(AHB2, 15U)>, + <&rcc (STM32_SRC_HSE | STM32_CLOCK_DIV(2)) OTGHS_SEL(2)>; + + /* PLL1_P_CK */ + clocks = <&rcc STM32_CLOCK(AHB2, 15U)>, + <&rcc STM32_SRC_PLL1_P OTGHS_SEL(1)>; + + /* PLL1_P_CK/2 */ + clocks = <&rcc STM32_CLOCK(AHB2, 15U)>, + <&rcc (STM32_SRC_PLL1_P | STM32_CLOCK_DIV(2)) OTGHS_SEL(3)>; diff --git a/include/zephyr/dt-bindings/clock/stm32u5_clock.h b/include/zephyr/dt-bindings/clock/stm32u5_clock.h index ca333b6ae14..4bb1f349cdd 100644 --- a/include/zephyr/dt-bindings/clock/stm32u5_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32u5_clock.h @@ -122,7 +122,7 @@ #define HSPI_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, CCIPR2_REG) #define I2C5_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 24, CCIPR2_REG) #define I2C6_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 26, CCIPR2_REG) -#define USBPHYC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 30, CCIPR2_REG) +#define OTGHS_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 30, CCIPR2_REG) /** CCIPR3 devices */ #define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, CCIPR3_REG) #define SPI3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 3, CCIPR3_REG)