diff --git a/components/esp_hal_usb/include/hal/usb_dwc_hal.h b/components/esp_hal_usb/include/hal/usb_dwc_hal.h index 9e1d777b821..16a4095ff61 100644 --- a/components/esp_hal_usb/include/hal/usb_dwc_hal.h +++ b/components/esp_hal_usb/include/hal/usb_dwc_hal.h @@ -19,6 +19,8 @@ that don't support USB OTG. #include "hal/assert.h" #endif // SOC_USB_OTG_SUPPORTED +#define USB_DWC_HAL_INIT_HAS_CONFIG (1) // This version of HAL has usb_dwc_hal_init_with_config() + #ifdef __cplusplus extern "C" { #endif @@ -53,6 +55,16 @@ typedef struct { uint32_t ptx_fifo_lines; /**< Size of the Periodic FIFO in terms the number of FIFO lines */ } usb_dwc_hal_fifo_config_t; +// USB DWC HAL configuration flags +#define USB_DWC_HAL_CONFIG_FLAG_FSLS_ONLY (0x01u) // Init a High-Speed capable USB-DWC core as Full/Low-Speed only host + +/** + * @brief USB DWC HAL configuration structure + */ +typedef struct { + uint32_t flags; /**< USB DWC HAL configuration flags, see USB_DWC_HAL_CONFIG_FLAG_* macros */ +} usb_dwc_hal_config_t; + // --------------------- HAL Events ------------------------ /** @@ -173,16 +185,27 @@ typedef struct { // FIFO related usb_dwc_hal_fifo_config_t fifo_config; /**< FIFO sizes configuration */ - // Configuration of the USB-DWC core. Read from read-only HW registers - // These constants are cached from HW registers to avoid repeated reads + // Constants, do not change after HAL init struct { + // Configuration of the USB-DWC core + // These constants are cached from read-only HW registers to avoid repeated reads unsigned chan_num_total; /**< Total number of channels for this configuration */ unsigned hsphy_type; /**< HS PHY type of this configuration */ unsigned fifo_size; /**< Total FIFO size [in lines] in this configuration */ unsigned max_size_byte_limit; /**< Maximum size of a transfer in bytes */ unsigned max_size_packet_limit; /**< Maximum size of a transfer in packets */ + + // Constant HAL configuration + union { + struct { + uint32_t fsls_only: 1; /**< Even if USB Core supports HS, force FS/LS only. Can be configured only during HAL init */ + uint32_t reserved: 31; + }; + uint32_t val; + } flags; } constant_config; + // HAL internal flags. Reset (zeroized) during soft-reset procedure union { struct { uint32_t dbnc_lock_enabled: 1; /**< Debounce lock enabled */ @@ -204,6 +227,19 @@ typedef struct { // -------------------------------------------------- Core (Global) ---------------------------------------------------- +/** + * @brief Initialize the HAL context and check if DWC_OTG is alive + * + * Same as `usb_dwc_hal_init()` but accepts configuration structure. + * + * @attention The user must allocate memory for channel handlers with + * `hal->channels.hdls = malloc(hal->constant_config.chan_num_total * sizeof(usb_dwc_hal_chan_t*))` + * @param[inout] hal Context of the HAL layer + * @param[in] port_id USB port ID + * @param[in] config USB DWC HAL configuration. Can be NULL. + */ +void usb_dwc_hal_init_with_config(usb_dwc_hal_context_t *hal, int port_id, const usb_dwc_hal_config_t *config); + /** * @brief Initialize the HAL context and check if DWC_OTG is alive * @@ -227,7 +263,10 @@ typedef struct { * @param[inout] hal Context of the HAL layer * @param[in] port_id USB port ID */ -void usb_dwc_hal_init(usb_dwc_hal_context_t *hal, int port_id); +static inline void usb_dwc_hal_init(usb_dwc_hal_context_t *hal, int port_id) +{ + usb_dwc_hal_init_with_config(hal, port_id, NULL); +} /** * @brief Deinitialize the HAL context @@ -370,14 +409,13 @@ static inline void usb_dwc_hal_port_toggle_power(usb_dwc_hal_context_t *hal, boo * @note If the host port is already enabled, then issuing a reset will cause it be disabled and generate a * USB_DWC_HAL_PORT_EVENT_DISABLED event. The host port will not be enabled until the reset signal is released (thus * generating the USB_DWC_HAL_PORT_EVENT_ENABLED event) + * @note If this port is HS an it is configured for FS/LS operation only, HCFG.fslssupp will be set + * so the host port does not respond to device's HS chirp. * * @param hal Context of the HAL layer * @param enable Enable/disable reset signal */ -static inline void usb_dwc_hal_port_toggle_reset(usb_dwc_hal_context_t *hal, bool enable) -{ - usb_dwc_ll_hprt_set_port_reset(hal->dev, enable); -} +void usb_dwc_hal_port_toggle_reset(usb_dwc_hal_context_t *hal, bool enable); /** * @brief Enable the host port diff --git a/components/esp_hal_usb/usb_dwc_hal.c b/components/esp_hal_usb/usb_dwc_hal.c index 6f3c6a71a27..ee780d5db90 100644 --- a/components/esp_hal_usb/usb_dwc_hal.c +++ b/components/esp_hal_usb/usb_dwc_hal.c @@ -156,7 +156,7 @@ static void set_defaults(usb_dwc_hal_context_t *hal) #endif // SOC_IS(ESP32P4) } -void usb_dwc_hal_init(usb_dwc_hal_context_t *hal, int port_id) +void usb_dwc_hal_init_with_config(usb_dwc_hal_context_t *hal, int port_id, const usb_dwc_hal_config_t *config) { // Check if a peripheral is alive by reading the core ID registers HAL_ASSERT(port_id < SOC_USB_OTG_PERIPH_NUM); @@ -181,6 +181,13 @@ void usb_dwc_hal_init(usb_dwc_hal_context_t *hal, int port_id) hal->constant_config.max_size_byte_limit = (1U << usb_dwc_ll_ghwcfg_get_xfer_size_width(dev)) - 1; hal->constant_config.max_size_packet_limit = (1U << usb_dwc_ll_ghwcfg_get_packet_size_width(dev)) - 1; + // Check passed configuration flags + if (config) { + if (config->flags & USB_DWC_HAL_CONFIG_FLAG_FSLS_ONLY) { + hal->constant_config.flags.fsls_only = 1; + } + } + set_defaults(hal); } @@ -301,6 +308,15 @@ static inline void debounce_lock_enable(usb_dwc_hal_context_t *hal) hal->flags.dbnc_lock_enabled = 1; } +void usb_dwc_hal_port_toggle_reset(usb_dwc_hal_context_t *hal, bool enable) +{ + // If the core is connected to HS PHY but configuration is FS/LS only + if (enable && hal->constant_config.hsphy_type && hal->constant_config.flags.fsls_only) { + usb_dwc_ll_hcfg_set_fsls_supp_only(hal->dev); + } + usb_dwc_ll_hprt_set_port_reset(hal->dev, enable); +} + void usb_dwc_hal_port_enable(usb_dwc_hal_context_t *hal) { // Host Configuration