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 <adrian.chadd@meta.com> Signed-off-by: Adrian Chadd <adrian.chadd@meta.com> Signed-off-by: Marcin Niestroj <m.niestroj@emb.dev>
This commit is contained in:
parent
fafaa58240
commit
f72ef5c237
5 changed files with 142 additions and 17 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
|
||||
|
|
36
dts/bindings/phy/st,stm32u5-otghs-phy.yaml
Normal file
36
dts/bindings/phy/st,stm32u5-otghs-phy.yaml
Normal file
|
@ -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)>;
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue