From d4f2689e92a185a693aa3ddf410367d204a56bb6 Mon Sep 17 00:00:00 2001 From: Ibrahim Abdelkader Date: Sat, 12 Apr 2025 09:21:36 +0200 Subject: [PATCH] ports/stm32: Update ULPI code. (#2656) - Add support for reset to recover ULPI. - Clean up formatting, comments. Signed-off-by: iabdalkader --- src/omv/ports/stm32/ulpi.c | 85 ++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/src/omv/ports/stm32/ulpi.c b/src/omv/ports/stm32/ulpi.c index 0ab0b50ce..3fa4ceb16 100644 --- a/src/omv/ports/stm32/ulpi.c +++ b/src/omv/ports/stm32/ulpi.c @@ -38,19 +38,21 @@ #include "ulpi.h" #include "omv_gpio.h" +#if defined(STM32H7) +#define GPIO_AF10_OTG_HS (GPIO_AF10_OTG2_HS) +#endif + #define USBULPI_PHYCR ((uint32_t) (0x40040000 + 0x034)) #define USBULPI_D07 ((uint32_t) 0x000000FF) #define USBULPI_New ((uint32_t) 0x02000000) #define USBULPI_RW ((uint32_t) 0x00400000) #define USBULPI_S_BUSY ((uint32_t) 0x04000000) #define USBULPI_S_DONE ((uint32_t) 0x08000000) +#define USBULPI_TIMEOUT_COUNT (500) #define USB_OTG_READ_REG32(reg) (*(__IO uint32_t *) (reg)) #define USB_OTG_WRITE_REG32(reg, value) (*(__IO uint32_t *) (reg) = (value)) -#if defined(STM32H7) -#define GPIO_AF10_OTG_HS (GPIO_AF10_OTG2_HS) -#endif extern void __fatal_error(const char *msg); @@ -61,7 +63,7 @@ extern void __fatal_error(const char *msg); */ static uint32_t USB_ULPI_Read(uint32_t Addr) { __IO uint32_t val = 0; - __IO uint32_t timeout = 100; /* Can be tuned based on the Clock or etc... */ + __IO uint32_t timeout = USBULPI_TIMEOUT_COUNT; USB_OTG_WRITE_REG32(USBULPI_PHYCR, USBULPI_New | (Addr << 16)); val = USB_OTG_READ_REG32(USBULPI_PHYCR); @@ -69,7 +71,7 @@ static uint32_t USB_ULPI_Read(uint32_t Addr) { val = USB_OTG_READ_REG32(USBULPI_PHYCR); } val = USB_OTG_READ_REG32(USBULPI_PHYCR); - return (val & 0x000000ff); + return val & 0x000000ff; } /** @@ -80,7 +82,7 @@ static uint32_t USB_ULPI_Read(uint32_t Addr) { */ static uint32_t USB_ULPI_Write(uint32_t Addr, uint32_t Data) { __IO uint32_t val; - __IO uint32_t timeout = 10; /* Can be tuned based on the Clock or etc... */ + __IO uint32_t timeout = USBULPI_TIMEOUT_COUNT; USB_OTG_WRITE_REG32(USBULPI_PHYCR, USBULPI_New | USBULPI_RW | (Addr << 16) | (Data & 0x000000ff)); val = USB_OTG_READ_REG32(USBULPI_PHYCR); @@ -92,6 +94,17 @@ static uint32_t USB_ULPI_Write(uint32_t Addr, uint32_t Data) { return 0; } +#ifdef OMV_USB_ULPI_RST_PIN +void ulpi_reset(void) { + omv_gpio_clock_enable(OMV_USB_ULPI_RST_PIN, true); + omv_gpio_config(OMV_USB_ULPI_RST_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_LOW, -1); + omv_gpio_write(OMV_USB_ULPI_RST_PIN, 0); + HAL_Delay(10); + omv_gpio_write(OMV_USB_ULPI_RST_PIN, 1); + HAL_Delay(100); +} +#endif + /** * @brief This function configures the USB PHY to enter the low power mode * @param None @@ -100,8 +113,8 @@ static uint32_t USB_ULPI_Write(uint32_t Addr, uint32_t Data) { void ulpi_enter_low_power(void) { __IO uint32_t regval = 0; - /* disable ULPI_CLK by accessing ULPI_PHY */ - /* read Vendor ID : (Low, High) 0x24,0x04 for USB3300 */ + // Disable ULPI_CLK by accessing ULPI_PHY + // Read Vendor ID : (Low, High) 0x24,0x04 for USB3300 regval = USB_ULPI_Read(0x00); if (regval != 0x24) { __fatal_error("ULPI Error 0x00 != 0x24"); @@ -112,7 +125,7 @@ void ulpi_enter_low_power(void) { __fatal_error("ULPI Error 0x01 != 0x04"); } - /* read Product ID */ + // Read Product ID regval = USB_ULPI_Read(0x02); if (regval != 0x07) { __fatal_error("ULPI Error 0x02 != 0x07"); @@ -123,34 +136,36 @@ void ulpi_enter_low_power(void) { __fatal_error("ULPI Error 0x03 != 0x00"); } - /* Write to scratch register the pattern 0x55 */ + // Write to scratch register the pattern 0x55 USB_ULPI_Write(0x16, 0x55); - /* Read to scratch Register and check-it again the written Pattern */ + // Read to scratch Register and check-it again the written Pattern regval = USB_ULPI_Read(0x16); if (regval != 0x55) { __fatal_error("ULPI Error 0x16 != 0x55"); } - /* Write to scratch register the pattern 0xAA */ + // Write to scratch register the pattern 0xAA USB_ULPI_Write(0x16, 0xAA); - /* Read to scratch Register and check-it again the written Pattern */ + // Read to scratch Register and check-it again the written Pattern regval = USB_ULPI_Read(0x16); if (regval != 0xAA) { __fatal_error("ULPI Error 0x16 != 0xAA"); } - /* read InterfaceControl reg */ + // Read InterfaceControl reg regval = USB_ULPI_Read(0x07); - /* write InterfaceControl reg,to disable PullUp on stp, - to avoid USB_PHY wake up when MCU entering standby */ + + // Write InterfaceControl reg,to disable PullUp on stp, + // to avoid USB_PHY wake up when MCU entering standby USB_ULPI_Write(0x07, regval | 0x80); - /* read InterfaceControl reg */ + + //Read InterfaceControl reg regval = USB_ULPI_Read(0x07); if (regval != 0x80) { __fatal_error("ULPI Error 0x07 != 0x80"); } - /* read FunctionControl reg */ + // Read FunctionControl reg regval = USB_ULPI_Read(0x04); // Reg 0x40 has a different value if USB is disconnected. @@ -158,16 +173,15 @@ void ulpi_enter_low_power(void) { __fatal_error("ULPI Error 0x04 != 0x40 || 0x45"); } - /* write FunctionControl reg,to put PHY into LowPower mode */ + // Write FunctionControl reg,to put PHY into LowPower mode USB_ULPI_Write(0x04, regval & (~0x40)); - /* read FunctionControl reg again */ + // Read FunctionControl reg again regval = USB_ULPI_Read(0x04); if (regval != 0x00) { __fatal_error("ULPI Error 0x04 != 0x00"); } - /* Delay 4 ms */ HAL_Delay(10); } @@ -177,25 +191,32 @@ void ulpi_enter_low_power(void) { * @retval None */ void ulpi_leave_low_power(void) { - /* Enable GPIO clock for OTG USB STP pin */ + // Configure STP as an output pin omv_gpio_clock_enable(OMV_USB_ULPI_STP_PIN, true); - omv_gpio_clock_enable(OMV_USB_ULPI_DIR_PIN, true); - - /* Configure OTG STP and DIR pin as GP Output */ omv_gpio_config(OMV_USB_ULPI_STP_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_LOW, -1); + + // Configure DIR as an input pin + omv_gpio_clock_enable(OMV_USB_ULPI_DIR_PIN, true); omv_gpio_config(OMV_USB_ULPI_DIR_PIN, OMV_GPIO_MODE_INPUT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_LOW, -1); - /* Set OTG STP pin to High */ + // Set STP pin high omv_gpio_write(OMV_USB_ULPI_STP_PIN, 1); - /* Wait for DIR to go low */ - for (uint32_t ticks = HAL_GetTick(); - ((HAL_GetTick() - ticks) < 500) - && omv_gpio_read(OMV_USB_ULPI_DIR_PIN);) { - __WFI(); + // Wait for DIR to go low + for (uint32_t i = 0; i < 1000; i++, HAL_Delay(1)) { + if (!omv_gpio_read(OMV_USB_ULPI_DIR_PIN)) { + break; + } } - /* Configure OTG STP and DIR pin as USB AF */ + #ifdef OMV_USB_ULPI_RST_PIN + if (omv_gpio_read(OMV_USB_ULPI_DIR_PIN)) { + // Failed to exit suspend mode, reset the ULPI. + ulpi_reset(); + } + #endif + + // Configure OTG STP and DIR pin as USB AF omv_gpio_config(OMV_USB_ULPI_STP_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MAX, -1); omv_gpio_config(OMV_USB_ULPI_DIR_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MAX, -1); }