feat(esp_hal_usb): Add option to run FS/LS only host on HS target

Add function usb_dwc_hal_init_with_config() that takes a bitmap
of configuration flags.
Currently only FS/LS only flag is implemented, but the design
allows extension in the future.
This commit is contained in:
Tomas Rezucha
2026-08-28 16:00:52 +02:00
parent 1f2a7fffec
commit baddad8fea
2 changed files with 64 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -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,13 +185,25 @@ 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
// 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 */
// 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 */
@@ -201,6 +225,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
*
@@ -224,7 +261,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
@@ -349,14 +389,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

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -128,7 +128,7 @@ static void set_defaults(usb_dwc_hal_context_t *hal)
usb_dwc_ll_gusbcfg_force_host_mode(hal->dev);
}
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);
@@ -151,6 +151,13 @@ void usb_dwc_hal_init(usb_dwc_hal_context_t *hal, int port_id)
hal->constant_config.hsphy_type = usb_dwc_ll_ghwcfg_get_hsphy_type(dev);
hal->constant_config.chan_num_total = usb_dwc_ll_ghwcfg_get_channel_num(dev);
// 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);
}
@@ -255,6 +262,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