diff --git a/bootloader/echoplayer.c b/bootloader/echoplayer.c index 982f16ac96..e2491aa0d5 100644 --- a/bootloader/echoplayer.c +++ b/bootloader/echoplayer.c @@ -29,6 +29,9 @@ #include "storage.h" #include "disk.h" #include "file_internal.h" +#include "usb.h" + +static bool is_usb_connected = false; extern void show_logo(void); @@ -55,6 +58,13 @@ static void demo_storage(void) lcd_clear_display(); lcd_putsf(0, y++, "tick %ld", current_tick); + if (is_usb_connected) + { + lcd_puts(0, y++, "storage disabled by USB"); + lcd_update(); + return; + } + struct partinfo pinfo; if (storage_present(IF_MD(0,)) && disk_partinfo(0, &pinfo)) { @@ -75,15 +85,37 @@ static void demo_storage(void) lcd_update(); } +static void demo_usb(void) +{ + static const char *phyname[] = { + [STM32H743_USBOTG_PHY_ULPI_HS] = "ULPI HS", + [STM32H743_USBOTG_PHY_ULPI_FS] = "ULPI FS", + [STM32H743_USBOTG_PHY_INT_FS] = "internal FS", + }; + + int y = 0; + + lcd_clear_display(); + lcd_putsf(0, y++, "tick %ld", current_tick); + lcd_putsf(0, y++, "usb connected %d", (int)is_usb_connected); + + lcd_putsf(0, y++, "instance = USB%d", STM32H743_USBOTG_INSTANCE + 1); + lcd_putsf(0, y++, "phy = %s", phyname[STM32H743_USBOTG_PHY]); + + lcd_update(); +} + static void (*demo_funcs[]) (void) = { demo_rtc, demo_storage, + demo_usb, }; void main(void) { system_init(); kernel_init(); + power_init(); rtc_init(); lcd_init(); @@ -98,6 +130,9 @@ void main(void) filesystem_init(); disk_mount_all(); + usb_init(); + usb_start_monitoring(); + int demo_page = 0; const int num_pages = ARRAYLEN(demo_funcs); @@ -119,6 +154,14 @@ void main(void) demo_page -= 1; break; + case SYS_USB_CONNECTED: + usb_acknowledge(SYS_USB_CONNECTED_ACK); + is_usb_connected = true; + break; + + case SYS_USB_DISCONNECTED: + is_usb_connected = false; + case BUTTON_X: power_off(); break; diff --git a/firmware/SOURCES b/firmware/SOURCES index 5a540ba7ea..294c3f6185 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -2031,8 +2031,10 @@ target/arm/stm32/sdmmc-stm32h7.c target/arm/stm32/spi-stm32h7.c target/arm/stm32/system-stm32h7.c target/arm/stm32/timer-stm32h7.c +#if defined(HAVE_USBSTACK) target/arm/stm32/usb-stm32h7.c #endif +#endif #if defined(ECHO_R1) target/arm/stm32/echoplayer/audiohw-echoplayer.c @@ -2043,6 +2045,7 @@ target/arm/stm32/echoplayer/lcd-echoplayer.c target/arm/stm32/echoplayer/power-echoplayer.c target/arm/stm32/echoplayer/sdmmc-echoplayer.c target/arm/stm32/echoplayer/system-echoplayer.c +target/arm/stm32/echoplayer/usb-echoplayer.c #endif #if (CONFIG_PLATFORM & PLATFORM_ANDROID) diff --git a/firmware/drivers/usb-designware.c b/firmware/drivers/usb-designware.c index 5dc01fc0b2..6647b9d29c 100644 --- a/firmware/drivers/usb-designware.c +++ b/firmware/drivers/usb-designware.c @@ -79,6 +79,7 @@ #elif CONFIG_CPU == STM32H743 # define USB_DW_PHYSADDR(x) x # define NO_UNCACHED_ADDR /* TODO: maybe implement this */ +# define POST_DMA_FLUSH #elif !defined(USB_DW_ARCH_SLAVE) # error "Must define USB_DW_PHYSADDR / USB_DW_UNCACHEDADDR!" #endif diff --git a/firmware/export/config/echor1.h b/firmware/export/config/echor1.h index 8b74a2cade..3316b2b731 100644 --- a/firmware/export/config/echor1.h +++ b/firmware/export/config/echor1.h @@ -1,3 +1,6 @@ +/* Pull in SoC-specific defines */ +#include "stm32h743-config.h" + /* RoLo-related defines */ #define MODEL_NAME "Echo R1" #define MODEL_NUMBER 119 @@ -92,10 +95,17 @@ /* USB support */ #ifndef SIMULATOR #define CONFIG_USBOTG USBOTG_DESIGNWARE -#define USB_DW_TURNAROUND 5 +#define STM32H743_USBOTG_INSTANCE STM32H743_USBOTG_INSTANCE_USB1 +#define STM32H743_USBOTG_PHY STM32H743_USBOTG_PHY_ULPI_HS +#define STM32H743_USBOTG_CLKSEL STM32H743_USBOTG_CLKSEL_PLL1Q #define HAVE_USBSTACK -#define USB_VENDOR_ID 0x1 -#define USB_PRODUCT_ID 0x2 +/* + * Must force device mode because ID pin on PHY is incorrectly + * connected to ground on Rev1 boards. + */ +#define USB_DW_FORCE_DEVICE_MODE +#define USB_VENDOR_ID 0x6666 /* "prototype device" VID in folklore */ +#define USB_PRODUCT_ID 0xEC01 #define USB_DEVBSS_ATTR __attribute__((aligned(32))) #define HAVE_USB_POWER //#define HAVE_USB_CHARGING_ENABLE diff --git a/firmware/reggen/stm32h743.regs b/firmware/reggen/stm32h743.regs index c05828780c..c6c25cdf4a 100644 --- a/firmware/reggen/stm32h743.regs +++ b/firmware/reggen/stm32h743.regs @@ -254,6 +254,19 @@ RCC @ 0x58024400 : block { 0 LSION } + AHB1ENR @ 0xd8 : reg { + 28 USB2OTGHSULPIEN + 27 USB2OTGHSEN + 26 USB1OTGHSULPIEN + 25 USB1OTGHSEN + 17 ETH1RXEN + 16 ETH1TXEN + 15 ETH1MACEN + 05 ADC12EN + 01 DMA2EN + 00 DMA1EN + } + AHB3RSTR @ 0x7c : reg { 16 SDMMC1RST 14 QSPIRST @@ -418,6 +431,8 @@ SYSCFG @ 0x58000400 : block { PWRCFG @ 0x2c : reg { 0 ODEN } + + EXTICR @ 0x08 [4; 0x04] : reg } FMC @ 0x52004000 : block { @@ -1092,3 +1107,58 @@ block SDMMC { SDMMC1 @ 0x52007000 : SDMMC SDMMC2 @ 0x48022400 : SDMMC + +// Clock recovery system +CRS @ 0x40008400 : block { + CR @ 0x00 : reg { + 13 08 TRIM + -- 07 SWSYNC + -- 06 AUTOTRIMEN + -- 05 CEN + -- 03 ESYNCIE + -- 02 ERRIE + -- 01 SYNCWARNIE + -- 00 SYNCOKIE + } + + CFGR @ 0x04 : reg { + -- 31 SYNCPOL : { 0 = RISING_EDGE; 1 = FALLING_EDGE } + 29 28 SYNCSRC : { 0 = USB2_SOF; 1 = LSE; 2 = USB1_SOF } + 26 24 SYNCDIV + 23 16 FELIM + 15 00 RELOAD + } + + ISR @ 0x08 : reg { + 31 16 FECAP + -- 15 FEDIR + -- 10 TRIMOVF + -- 09 SYNCMISS + -- 08 SYNCERR + -- 03 ESYNCF + -- 02 ERRF + -- 01 SYNCWARNF + -- 00 SYNCOKF + } + + ICR @ 0x0c : reg { + 3 ESYNCC + 2 ERRC + 1 SYNCWARNC + 0 SYNCOKC + } +} + +// Extended interrupt and event controller +EXTI @ 0x58000000 : block { + RTSR @ 0x00 [3; 0x20] : reg + FTSR @ 0x04 [3; 0x20] : reg + SWIER @ 0x08 [3; 0x20] : reg + D3PMR @ 0x0c [3; 0x20] : reg + D3PCRL @ 0x10 [3; 0x20] : reg + D3PCRH @ 0x14 [3; 0x20] : reg + + CPUIMR @ 0x80 [3; 0x10] : reg + CPUEMR @ 0x84 [3; 0x10] : reg + CPUPR @ 0x88 [3; 0x10] : reg +} diff --git a/firmware/target/arm/stm32/cpu-stm32h743.h b/firmware/target/arm/stm32/cpu-stm32h743.h index fc10fdb954..c0a789708d 100644 --- a/firmware/target/arm/stm32/cpu-stm32h743.h +++ b/firmware/target/arm/stm32/cpu-stm32h743.h @@ -21,6 +21,8 @@ #ifndef __CPU_STM32H743_H__ #define __CPU_STM32H743_H__ +#include "config.h" + #define CACHE_SIZE (16 * 1024) #define CACHEALIGN_BITS 5 @@ -34,8 +36,35 @@ #define STM32_CSI_FREQ 4000000 #define STM32_HSI48_FREQ 48000000 -#define OTGBASE 0x40080000 -#define USB_NUM_ENDPOINTS 9 +#if defined(HAVE_USBSTACK) +# if !defined(STM32H743_USBOTG_INSTANCE) +# error "STM32H743_USBOTG_INSTANCE is undefined!" +# endif +# if !defined(STM32H743_USBOTG_PHY) +# error "STM32H743_USBOTG_PHY is undefined!" +# endif +# if !defined(STM32H743_USBOTG_CLKSEL) +# error "STM32H743_USBOTG_CLKSEL is undefined!" +# endif +# if (STM32H743_USBOTG_INSTANCE == STM32H743_USBOTG_INSTANCE_USB1) +# define OTGBASE 0x40040000 +# elif (STM32H743_USBOTG_INSTANCE == STM32H743_USBOTG_INSTANCE_USB2) +# define OTGBASE 0x40080000 +# endif +# if (STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_ULPI_FS) +# define USB_DW_DCFG_SPEED 1 +# elif (STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_INT_FS) +# define USB_DW_DCFG_SPEED 3 +# endif +# define USB_DW_TURNAROUND 5 +/* + * The hardware supports up to 9 endpoints, but since FIFO RAM + * is limited, we can't support more than 5 IN EPs with a max + * packet size of 512 bytes (usb-designware allocates the same + * amount of RAM to each IN endpoint). + */ +# define USB_NUM_ENDPOINTS 6 +#endif #define STM32_ITCM_BASE 0x00000000 #define STM32_ITCM_SIZE (64 * 1024) diff --git a/firmware/target/arm/stm32/echoplayer/gpio-target.h b/firmware/target/arm/stm32/echoplayer/gpio-target.h index 122bef0818..2e92f249c8 100644 --- a/firmware/target/arm/stm32/echoplayer/gpio-target.h +++ b/firmware/target/arm/stm32/echoplayer/gpio-target.h @@ -53,4 +53,6 @@ #define GPIO_LCD_RESET GPIO_PD(11) #define GPIO_BACKLIGHT GPIO_PD(13) +#define GPIO_USB_VBUS GPIO_PA(9) + #endif /* __ECHOPLAYER_GPIO_TARGET_H__ */ diff --git a/firmware/target/arm/stm32/echoplayer/system-echoplayer.c b/firmware/target/arm/stm32/echoplayer/system-echoplayer.c index 97dbb9644a..c624569241 100644 --- a/firmware/target/arm/stm32/echoplayer/system-echoplayer.c +++ b/firmware/target/arm/stm32/echoplayer/system-echoplayer.c @@ -28,9 +28,6 @@ #define F_INPUT_PD GPIOF_INPUT(GPIO_PULL_DOWN) #define F_OUT_LS(x) GPIOF_OUTPUT(x, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_LOW, GPIO_PULL_DISABLED) #define F_SDRAM GPIOF_FUNCTION(12, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) -#define F_OTG_FS GPIOF_ANALOG() -#define F_ULPI GPIOF_FUNCTION(10, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) -#define F_MCO1 GPIOF_FUNCTION(0, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) #define F_I2C1 GPIOF_FUNCTION(4, GPIO_TYPE_OPEN_DRAIN, GPIO_SPEED_LOW, GPIO_PULL_DISABLED) #define F_SDMMC1 GPIOF_FUNCTION(12, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_MEDIUM, GPIO_PULL_UP) #define F_SDMMC1CK GPIOF_FUNCTION(12, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_MEDIUM, GPIO_PULL_DISABLED) @@ -41,6 +38,16 @@ #define F_LPTIM4_OUT GPIOF_FUNCTION(3, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_LOW, GPIO_PULL_DISABLED) #define F_LPTIM1_OUT GPIOF_FUNCTION(1, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +#if STM32H743_USBOTG_INSTANCE == STM32H743_USBOTG_INSTANCE_USB1 +# define F_OTG_FS GPIOF_ANALOG() +# define F_ULPI GPIOF_FUNCTION(10, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +# define F_MCO1 GPIOF_FUNCTION(0, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +#else +# define F_OTG_FS GPIOF_FUNCTION(10, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +# define F_ULPI GPIOF_ANALOG() +# define F_MCO1 GPIOF_ANALOG() +#endif + static const struct gpio_setting gpios[] = { STM_DEFGPIO(GPIO_BUTTON_A, F_INPUT_PU), STM_DEFGPIO(GPIO_BUTTON_B, F_INPUT_PU), @@ -69,6 +76,7 @@ static const struct gpio_setting gpios[] = { STM_DEFGPIO(GPIO_LINEOUT_DETECT, F_INPUT), /* external pullup */ STM_DEFGPIO(GPIO_LCD_RESET, F_OUT_LS(0)), /* active low */ STM_DEFGPIO(GPIO_BACKLIGHT, F_LPTIM1_OUT), + STM_DEFGPIO(GPIO_USB_VBUS, F_INPUT), /* active high */ }; /* TODO - replace hex constants - there are probably mistakes here */ @@ -82,13 +90,13 @@ static const struct pingroup_setting pingroups[] = { STM_DEFPINS(GPIO_F, 0xf83f, F_SDRAM), STM_DEFPINS(GPIO_G, 0x8137, F_SDRAM), /* OTG_FS */ - STM_DEFPINS(GPIO_A, 0x1a00, F_OTG_FS), + STM_DEFPINS(GPIO_A, 0x1800, F_OTG_FS), /* OTG_HS - ULPI */ STM_DEFPINS(GPIO_A, 0x0028, F_ULPI), STM_DEFPINS(GPIO_B, 0x3c23, F_ULPI), STM_DEFPINS(GPIO_C, 0x0001, F_ULPI), STM_DEFPINS(GPIO_H, 0x0010, F_ULPI), - STM_DEFPINS(GPIO_I, 0x0100, F_ULPI), + STM_DEFPINS(GPIO_I, 0x0800, F_ULPI), /* MCO1 for USB PHY */ STM_DEFPINS(GPIO_A, 0x0100, F_MCO1), /* I2C1 */ diff --git a/firmware/target/arm/stm32/echoplayer/usb-echoplayer.c b/firmware/target/arm/stm32/echoplayer/usb-echoplayer.c new file mode 100644 index 0000000000..f16cd8dc7c --- /dev/null +++ b/firmware/target/arm/stm32/echoplayer/usb-echoplayer.c @@ -0,0 +1,153 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2026 Aidan MacDonald + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "usb.h" +#include "usb_core.h" +#include "usb_drv.h" +#include "usb-designware.h" +#include "gpio-stm32h7.h" +#include "nvic-arm.h" +#include "power-echoplayer.h" +#include "regs/stm32h743/rcc.h" +#include "regs/stm32h743/pwr.h" +#include "regs/stm32h743/crs.h" +#include "regs/stm32h743/syscfg.h" +#include "regs/stm32h743/exti.h" + +/* + * Needed because USB core calls usb_enable(false) on boot, + * so we need to keep track if ULPI was enabled or not. + */ +static bool echoplayer_ulpi_enabled = false; + +static void echoplayer_enable_ulpi_phy(void) +{ + if (!echoplayer_ulpi_enabled) + { + /* Enable MCO1 output for PHY reference clock */ + reg_writef(RCC_CFGR, MCO1_V(HSE), MCO1PRE(1)); + + /* Enable power supplies */ + echoplayer_enable_1v8_regulator(true); + gpio_set_level(GPIO_USBPHY_POWER_EN, 0); + + /* Wait for stable clocks/power */ + sleep(1); + + /* Release PHY from reset */ + gpio_set_level(GPIO_USBPHY_RESET, 1); + + echoplayer_ulpi_enabled = true; + } +} + +static void echoplayer_disable_ulpi_phy(void) +{ + if (echoplayer_ulpi_enabled) + { + /* Put PHY into reset */ + gpio_set_level(GPIO_USBPHY_RESET, 0); + + /* Remove power */ + gpio_set_level(GPIO_USBPHY_POWER_EN, 1); + echoplayer_enable_1v8_regulator(false); + + /* Disable PHY reference clock */ + reg_writef(RCC_CFGR, MCO1PRE(0)); + + echoplayer_ulpi_enabled = false; + } +} + +static void echoplayer_usb_enable(void) +{ + if ((STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_ULPI_HS) || + (STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_ULPI_FS)) + { + echoplayer_enable_ulpi_phy(); + } + + usb_core_init(); +} + +static void echoplayer_usb_disable(void) +{ + usb_core_exit(); + + if ((STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_ULPI_HS) || + (STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_ULPI_FS)) + { + echoplayer_disable_ulpi_phy(); + } +} + +void usb_init_device(void) +{ + if (STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_INT_FS) + { + /* Required if internal PHY is used */ + reg_writef(PWR_CR3, USB33DEN(1)); + } + + /* + * This is the only place that needs a GPIO interrupt so + * just setup EXTI directly. + */ + const int gpio_port = GPION_PORT(GPIO_USB_VBUS); + const int gpio_pin = GPION_PIN(GPIO_USB_VBUS); + const int syscfg_idx = gpio_pin / 4; + const int syscfg_pos = gpio_pin % 4; + + /* Set GPIO port in syscfg's exti config registers */ + reg_writef(RCC_APB4ENR, SYSCFGEN(1)); + reg_var(SYSCFG_EXTICR(syscfg_idx)) = gpio_port << syscfg_pos; + reg_writef(RCC_APB4ENR, SYSCFGEN(0)); + + /* Enable rising & falling edge trigger for pin */ + reg_var(EXTI_RTSR(0)) |= 1u << gpio_pin; + reg_var(EXTI_FTSR(0)) |= 1u << gpio_pin; + reg_var(EXTI_CPUIMR(0)) |= 1u << gpio_pin; + + nvic_enable_irq(NVIC_IRQN_EXTI9_5); +} + +void usb_enable(bool on) +{ + if (on) + echoplayer_usb_enable(); + else + echoplayer_usb_disable(); +} + +int usb_detect(void) +{ + if (gpio_get_level(GPIO_USB_VBUS)) + return USB_INSERTED; + + return USB_EXTRACTED; +} + +void exti9_5_irq_handler(void) +{ + reg_var(EXTI_CPUPR(0)) = 1u << GPION_PIN(GPIO_USB_VBUS); + + usb_status_event(usb_detect()); +} diff --git a/firmware/target/arm/stm32/irqhandlers-stm32h743.c b/firmware/target/arm/stm32/irqhandlers-stm32h743.c index e27cdc1b49..8399150e6e 100644 --- a/firmware/target/arm/stm32/irqhandlers-stm32h743.c +++ b/firmware/target/arm/stm32/irqhandlers-stm32h743.c @@ -36,3 +36,10 @@ void spi3_irq_handler(void) ATTR_IRQ_HANDLER; void spi4_irq_handler(void) ATTR_IRQ_HANDLER; void spi5_irq_handler(void) ATTR_IRQ_HANDLER; void spi6_irq_handler(void) ATTR_IRQ_HANDLER; +void exti0_irq_handler(void) ATTR_IRQ_HANDLER; +void exti1_irq_handler(void) ATTR_IRQ_HANDLER; +void exti2_irq_handler(void) ATTR_IRQ_HANDLER; +void exti3_irq_handler(void) ATTR_IRQ_HANDLER; +void exti4_irq_handler(void) ATTR_IRQ_HANDLER; +void exti9_5_irq_handler(void) ATTR_IRQ_HANDLER; +void exti15_10_irq_handler(void) ATTR_IRQ_HANDLER; diff --git a/firmware/target/arm/stm32/stm32h743-config.h b/firmware/target/arm/stm32/stm32h743-config.h new file mode 100644 index 0000000000..6ba760b28c --- /dev/null +++ b/firmware/target/arm/stm32/stm32h743-config.h @@ -0,0 +1,17 @@ +/* + * To be included by config/TARGET.h + */ + +/* STM32H743_USBOTG_INSTANCE */ +#define STM32H743_USBOTG_INSTANCE_USB1 0 /* OTG_HS1 */ +#define STM32H743_USBOTG_INSTANCE_USB2 1 /* OTG_HS2 */ + +/* STM32H743_USBOTG_PHY */ +#define STM32H743_USBOTG_PHY_ULPI_HS 0 /* External ULPI PHY in HS mode */ +#define STM32H743_USBOTG_PHY_ULPI_FS 1 /* External ULPI PHY in FS mode */ +#define STM32H743_USBOTG_PHY_INT_FS 2 /* Internal PHY in FS mode */ + +/* STM32H743_USBOTG_CLKSEL */ +#define STM32H743_USBOTG_CLKSEL_PLL1Q 1 /* PLL1Q output */ +#define STM32H743_USBOTG_CLKSEL_PLL3Q 2 /* PLL3Q output */ +#define STM32H743_USBOTG_CLKSEL_HSI48_CRS 3 /* HSI48 trimmed by CRS */ diff --git a/firmware/target/arm/stm32/usb-stm32h7.c b/firmware/target/arm/stm32/usb-stm32h7.c index 02291a4bab..94611c3940 100644 --- a/firmware/target/arm/stm32/usb-stm32h7.c +++ b/firmware/target/arm/stm32/usb-stm32h7.c @@ -23,62 +23,157 @@ #include "usb_core.h" #include "usb_drv.h" #include "usb-designware.h" +#include "nvic-arm.h" +#include "regs/stm32h743/pwr.h" +#include "regs/stm32h743/rcc.h" +#include "regs/stm32h743/crs.h" + +#if STM32H743_USBOTG_INSTANCE == STM32H743_USBOTG_INSTANCE_USB1 +# define IRQN_USB NVIC_IRQN_OTG_HS +#else +# define IRQN_USB NVIC_IRQN_OTG_FS +#endif + +/* Total size of FIFO RAM */ +#define FIFO_RAMSZ 1024 + +/* + * Must be equal to N * (max packet size / 4) for IN endpoints. + * Due to limited FIFO RAM set N=1; N > 1 increases performance. + * NPTX is only for EP0 so its max packet size is 64 bytes. + */ +#define NPTX_FIFOSZ 16 +#define PTX_FIFOSZ 128 + +#define RX_FIFOSZ \ + (FIFO_RAMSZ - NPTX_FIFOSZ - (PTX_FIFOSZ * (USB_NUM_ENDPOINTS - 1))) + +/* + * See RM0433 -- 57.11.3 FIFO RAM allocation + * We require enough for 2x 512-byte packets / 1x 1024-byte packet + */ +_Static_assert(RX_FIFOSZ >= 14 + 2*(512/4 + 1) + 2*USB_NUM_ENDPOINTS, + "RX FIFO size is too small"); const struct usb_dw_config usb_dw_config = { + .nptx_fifosz = NPTX_FIFOSZ, + .ptx_fifosz = PTX_FIFOSZ, + .rx_fifosz = RX_FIFOSZ, + +#if ((STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_ULPI_HS) || \ + (STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_ULPI_FS)) .phytype = DWC_PHYTYPE_ULPI_SDR, - /* - * Available FIFO memory: 1024 words (TODO: check this) - * Number of endpoints: 9 - * Max packet size: 512 bytes - */ - .rx_fifosz = 224, /* shared RxFIFO */ - .nptx_fifosz = 32, /* only used for EP0 IN */ - .ptx_fifosz = 192, /* room for 4 IN EPs */ +#else + .phytype = PHSEL, +#endif #ifndef USB_DW_ARCH_SLAVE .ahb_burst_len = HBSTLEN_INCR8, - /* Disable Rx FIFO thresholding. It appears to cause problems, - * apparently a known issue -- Synopsys recommends disabling it - * because it can cause issues during certain error conditions. - */ .ahb_threshold = 0, #else .disable_double_buffering = false, #endif }; -void usb_enable(bool on) -{ - if (on) - usb_core_init(); - else - usb_core_exit(); -} +_Static_assert( + (STM32H743_USBOTG_INSTANCE == STM32H743_USBOTG_INSTANCE_USB1) || + (STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_INT_FS), + "ULPI PHY not available on OTG_HS2"); -void usb_init_device(void) -{ - /* TODO - this is highly target specific */ -} +_Static_assert( + STM32H743_USBOTG_CLKSEL_PLL1Q == BV_RCC_D2CCIP2R_USBSEL_PLL1Q && + STM32H743_USBOTG_CLKSEL_PLL3Q == BV_RCC_D2CCIP2R_USBSEL_PLL3Q && + STM32H743_USBOTG_CLKSEL_HSI48_CRS == BV_RCC_D2CCIP2R_USBSEL_HSI48, + "Mismatch between CLKSEL enum and USBSEL register"); -int usb_detect(void) -{ - return USB_EXTRACTED; -} +/* + * The internal PHY seems to need some modifications in usb-designware + * to make it work but it's not clear what's wrong. At minimum it seems + * necessary to set PWRDWN & NOVBUSSENS bits on the GCCFG register in + * addition to setting DSPEED in DCFG, but that is not enough to get it + * to enumerate. ULPI in FS mode works however. + */ +_Static_assert(STM32H743_USBOTG_PHY != STM32H743_USBOTG_PHY_INT_FS, + "internal FS PHY not supported at the moment"); void usb_dw_target_enable_clocks(void) { + if (STM32H743_USBOTG_CLKSEL == STM32H743_USBOTG_CLKSEL_HSI48_CRS) + { + /* Enable HSI48 */ + reg_writef(RCC_CR, HSI48ON(1)); + while (reg_readf(RCC_CR, HSI48RDY) == 0); + + /* Enable CRS */ + reg_writef(RCC_APB1HENR, CRSEN(1)); + + /* Select USBx SOF as input to CRS */ + if (STM32H743_USBOTG_INSTANCE == STM32H743_USBOTG_INSTANCE_USB1) + reg_writef(CRS_CFGR, SYNCSRC_V(USB1_SOF)); + else if (STM32H743_USBOTG_INSTANCE == STM32H743_USBOTG_INSTANCE_USB2) + reg_writef(CRS_CFGR, SYNCSRC_V(USB2_SOF)); + + /* + * Enable CRS, the reset value of its registers contains + * suitable settings for syncing with the USB FS SOF and + * we assume the CRS configuration won't be modified. + */ + reg_writef(CRS_CR, AUTOTRIMEN(1), CEN(1)); + } + + /* Set appropriate input clock */ + reg_writef(RCC_D2CCIP2R, USBSEL(STM32H743_USBOTG_CLKSEL)); + + /* Enable peripheral clock */ + if (STM32H743_USBOTG_INSTANCE == STM32H743_USBOTG_INSTANCE_USB1) + reg_writef(RCC_AHB1ENR, USB1OTGHSEN(1)); + else if (STM32H743_USBOTG_INSTANCE == STM32H743_USBOTG_INSTANCE_USB2) + reg_writef(RCC_AHB1ENR, USB2OTGHSEN(1)); + + /* Enable ULPI clock for USB1 if high speed mode is enabled */ + if ((STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_ULPI_HS) || + (STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_ULPI_FS)) + { + reg_writef(RCC_AHB1ENR, USB1OTGHSULPIEN(1)); + } } void usb_dw_target_disable_clocks(void) { + /* Disable ULPI clock */ + if ((STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_ULPI_HS) || + (STM32H743_USBOTG_PHY == STM32H743_USBOTG_PHY_ULPI_FS)) + { + reg_writef(RCC_AHB1ENR, USB1OTGHSULPIEN(0)); + } + + /* Disable peripheral clock */ + if (STM32H743_USBOTG_INSTANCE == STM32H743_USBOTG_INSTANCE_USB1) + reg_writef(RCC_AHB1ENR, USB1OTGHSEN(0)); + else if (STM32H743_USBOTG_INSTANCE == STM32H743_USBOTG_INSTANCE_USB2) + reg_writef(RCC_AHB1ENR, USB2OTGHSEN(0)); + + if (STM32H743_USBOTG_CLKSEL == STM32H743_USBOTG_CLKSEL_HSI48_CRS) + { + /* Disable CRS */ + reg_writef(CRS_CR, CEN(0)); + reg_writef(RCC_APB1HENR, CRSEN(0)); + + /* Disable HSI48 */ + reg_writef(RCC_CR, HSI48ON(0)); + } } void usb_dw_target_enable_irq(void) { + arm_dsb(); + nvic_enable_irq(IRQN_USB); } void usb_dw_target_disable_irq(void) { + nvic_disable_irq(IRQN_USB); + arm_dsb(); } void usb_dw_target_clear_irq(void) diff --git a/firmware/target/arm/stm32/vectors-stm32h7.S b/firmware/target/arm/stm32/vectors-stm32h7.S index 782e4d9162..d2fb3e2f06 100644 --- a/firmware/target/arm/stm32/vectors-stm32h7.S +++ b/firmware/target/arm/stm32/vectors-stm32h7.S @@ -33,11 +33,11 @@ __vectors_platform: .word UIE /* [ 3] */ .word UIE /* [ 4] */ .word UIE /* [ 5] */ - .word UIE /* [ 6] */ - .word UIE /* [ 7] */ - .word UIE /* [ 8] */ - .word UIE /* [ 9] */ - .word UIE /* [ 10] */ + .word exti0_irq_handler /* [ 6] EXTI0 */ + .word exti1_irq_handler /* [ 7] EXTI1 */ + .word exti2_irq_handler /* [ 8] EXTI2 */ + .word exti3_irq_handler /* [ 9] EXTI3 */ + .word exti4_irq_handler /* [ 10] EXTI4 */ .word dma_irq_handler /* [ 11] DMA1 Stream0 */ .word dma_irq_handler /* [ 12] DMA1 Stream1 */ .word dma_irq_handler /* [ 13] DMA1 Stream2 */ @@ -50,7 +50,7 @@ __vectors_platform: .word UIE /* [ 20] */ .word UIE /* [ 21] */ .word UIE /* [ 22] */ - .word UIE /* [ 23] */ + .word exti9_5_irq_handler /* [ 23] EXTI5 to EXTI9 */ .word UIE /* [ 24] */ .word UIE /* [ 25] */ .word UIE /* [ 26] */ @@ -67,7 +67,7 @@ __vectors_platform: .word UIE /* [ 37] */ .word UIE /* [ 38] */ .word UIE /* [ 39] */ - .word UIE /* [ 40] */ + .word exti15_10_irq_handler /* [ 40] EXTI10 to EXTI15 */ .word UIE /* [ 41] */ .word UIE /* [ 42] */ .word UIE /* [ 43] */ @@ -104,7 +104,7 @@ __vectors_platform: .word UIE /* [ 74] */ .word UIE /* [ 75] */ .word UIE /* [ 76] */ - .word otg_hs_irq_handler /* [ 77] OTG HS */ + .word INT_USB_FUNC /* [ 77] OTG HS */ .word UIE /* [ 78] */ .word UIE /* [ 79] */ .word UIE /* [ 80] */ @@ -128,7 +128,7 @@ __vectors_platform: .word UIE /* [ 98] */ .word UIE /* [ 99] */ .word UIE /* [100] */ - .word UIE /* [101] */ + .word INT_USB_FUNC /* [101] OTG FS */ .word dma_irq_handler /* [102] DMAMUX1 overrun */ .word UIE /* [103] */ .word UIE /* [104] */