fix(esp_hal_usb): Add API for transfer max size

This commit is contained in:
Tomas Rezucha
2026-03-13 14:52:45 +08:00
committed by BOT
parent 9df5d023bc
commit ea86272a6a
16 changed files with 208 additions and 647 deletions
+17
View File
@@ -51,3 +51,20 @@ The HAL functions primarily serve ESP-IDF USB drivers, primarily the [USB Host s
- `soc`: Provides chip-specific register definitions
- `hal`: Core hardware abstraction utilities and macros
## Hardware configuration
The USB-DWC2 peripheral has many internal configuration parameters. The configuration is saved `GHWCFGx` registers. Configuration parameters which are often checked in run-time, are cached in USB-HAL context variable `usb_dwc_hal_context_t::constant_config` to limit access to the registers and offload system bus.
### Selected configuration parameters across ESP SoCs
| | S2, S3, H4 & P4-OTG1.1 | P4-OTG2.0, version < 3 | P4-OTG2.0, version >= 3 |
|--------------------|------------------------|-------------------------|-------------------------|
| HS PHY interface | None | UTMI+ 16bit | UTMI+ 16bit |
| Single point | Yes | No (SPLIT supported) | No (SPLIT supported) |
| Number of channels | 8 | 16 | 16 |
| FIFO depth | 256 lines (1024 bytes) | 1024 lines (4096 bytes) | 1024 lines (4096 bytes) |
| Perio queue depth | 8 | 4 | 16 |
| NPerio queue depth | 4 | 4 | 8 |
| Transfer cnt width | 16bits (max 65,535) | 16bits (max 65,535) | 19bits (max 524,287) |
| Packet cnt width | 7bits (max 127) | 7bits (max 127) | 10bits (max 1,023) |
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -10,7 +10,6 @@
#include <stdbool.h>
#include "esp_attr.h"
#include "soc/usb_dwc_struct.h"
#include "soc/usb_dwc_cfg.h"
#include "hal/usb_dwc_types.h"
#include "hal/misc.h"
@@ -354,6 +353,41 @@ static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw)
return hw->ghwcfg3_reg.dfifodepth;
}
/**
* @brief Get transfer size counter width
*
* For each transfer, the USB-DWC core keeps track of number of bytes for the particular transfer.
* Hence, maximum transfer size is limited by (2^xfer_size_width - 1) bytes
*
* Minimum transfer size counter width is 11. So value of 0 of xfersizewidth field in the register must be interpreted as 11.
*
* @see USB-DWC databook Table 5-26
* @param[in] hw Start address of the DWC_OTG registers
* @return Effective bitwidth of the transfer size counter
*/
static inline unsigned usb_dwc_ll_ghwcfg_get_xfer_size_width(usb_dwc_dev_t *hw)
{
return hw->ghwcfg3_reg.xfersizewidth + 11;
}
/**
* @brief Get packet counter width
*
* For each transfer, the USB-DWC core keeps track of the number of packets needed for the particular transfer
* and its endpoint's Maximum Packet Size.
* Hence, maximum transfer size is limited by MPS * (2^packet_counter_width - 1)
*
* Minimum packet counter width is 4. So value of 0 of pktsizewidth field in the register must be interpreted as 4.
*
* @see USB-DWC databook Table 5-26
* @param[in] hw Start address of the DWC_OTG registers
* @return Effective bitwidth of the packet counter
*/
static inline unsigned usb_dwc_ll_ghwcfg_get_packet_size_width(usb_dwc_dev_t *hw)
{
return hw->ghwcfg3_reg.pktsizewidth + 4;
}
static inline unsigned usb_dwc_ll_ghwcfg_get_hsphy_type(usb_dwc_dev_t *hw)
{
return hw->ghwcfg2_reg.hsphytype;
@@ -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
*/
@@ -376,6 +376,41 @@ static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw)
return hw->ghwcfg3_reg.dfifodepth;
}
/**
* @brief Get transfer size counter width
*
* For each transfer, the USB-DWC core keeps track of number of bytes for the particular transfer.
* Hence, maximum transfer size is limited by (2^xfer_size_width - 1) bytes
*
* Minimum transfer size counter width is 11. So value of 0 of xfersizewidth field in the register must be interpreted as 11.
*
* @see USB-DWC databook Table 5-26
* @param[in] hw Start address of the DWC_OTG registers
* @return Effective bitwidth of the transfer size counter
*/
static inline unsigned usb_dwc_ll_ghwcfg_get_xfer_size_width(usb_dwc_dev_t *hw)
{
return hw->ghwcfg3_reg.xfersizewidth + 11;
}
/**
* @brief Get packet counter width
*
* For each transfer, the USB-DWC core keeps track of the number of packets needed for the particular transfer
* and its endpoint's Maximum Packet Size.
* Hence, maximum transfer size is limited by MPS * (2^packet_counter_width - 1)
*
* Minimum packet counter width is 4. So value of 0 of pktsizewidth field in the register must be interpreted as 4.
*
* @see USB-DWC databook Table 5-26
* @param[in] hw Start address of the DWC_OTG registers
* @return Effective bitwidth of the packet counter
*/
static inline unsigned usb_dwc_ll_ghwcfg_get_packet_size_width(usb_dwc_dev_t *hw)
{
return hw->ghwcfg3_reg.pktsizewidth + 4;
}
static inline unsigned usb_dwc_ll_ghwcfg_get_hsphy_type(usb_dwc_dev_t *hw)
{
return hw->ghwcfg2_reg.hsphytype;
@@ -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
*/
@@ -10,7 +10,6 @@
#include <stdbool.h>
#include "esp_attr.h"
#include "soc/usb_dwc_struct.h"
#include "soc/usb_dwc_cfg.h"
#include "hal/usb_dwc_types.h"
#include "hal/misc.h"
@@ -352,6 +351,41 @@ static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw)
return hw->ghwcfg3_reg.dfifodepth;
}
/**
* @brief Get transfer size counter width
*
* For each transfer, the USB-DWC core keeps track of number of bytes for the particular transfer.
* Hence, maximum transfer size is limited by (2^xfer_size_width - 1) bytes
*
* Minimum transfer size counter width is 11. So value of 0 of xfersizewidth field in the register must be interpreted as 11.
*
* @see USB-DWC databook Table 5-26
* @param[in] hw Start address of the DWC_OTG registers
* @return Effective bitwidth of the transfer size counter
*/
static inline unsigned usb_dwc_ll_ghwcfg_get_xfer_size_width(usb_dwc_dev_t *hw)
{
return hw->ghwcfg3_reg.xfersizewidth + 11;
}
/**
* @brief Get packet counter width
*
* For each transfer, the USB-DWC core keeps track of the number of packets needed for the particular transfer
* and its endpoint's Maximum Packet Size.
* Hence, maximum transfer size is limited by MPS * (2^packet_counter_width - 1)
*
* Minimum packet counter width is 4. So value of 0 of pktsizewidth field in the register must be interpreted as 4.
*
* @see USB-DWC databook Table 5-26
* @param[in] hw Start address of the DWC_OTG registers
* @return Effective bitwidth of the packet counter
*/
static inline unsigned usb_dwc_ll_ghwcfg_get_packet_size_width(usb_dwc_dev_t *hw)
{
return hw->ghwcfg3_reg.pktsizewidth + 4;
}
static inline unsigned usb_dwc_ll_ghwcfg_get_hsphy_type(usb_dwc_dev_t *hw)
{
return hw->ghwcfg2_reg.hsphytype;
@@ -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
*/
@@ -10,7 +10,6 @@
#include <stdbool.h>
#include "esp_attr.h"
#include "soc/usb_dwc_struct.h"
#include "soc/usb_dwc_cfg.h"
#include "hal/usb_dwc_types.h"
#include "hal/misc.h"
@@ -352,6 +351,41 @@ static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw)
return hw->ghwcfg3_reg.dfifodepth;
}
/**
* @brief Get transfer size counter width
*
* For each transfer, the USB-DWC core keeps track of number of bytes for the particular transfer.
* Hence, maximum transfer size is limited by (2^xfer_size_width - 1) bytes
*
* Minimum transfer size counter width is 11. So value of 0 of xfersizewidth field in the register must be interpreted as 11.
*
* @see USB-DWC databook Table 5-26
* @param[in] hw Start address of the DWC_OTG registers
* @return Effective bitwidth of the transfer size counter
*/
static inline unsigned usb_dwc_ll_ghwcfg_get_xfer_size_width(usb_dwc_dev_t *hw)
{
return hw->ghwcfg3_reg.xfersizewidth + 11;
}
/**
* @brief Get packet counter width
*
* For each transfer, the USB-DWC core keeps track of the number of packets needed for the particular transfer
* and its endpoint's Maximum Packet Size.
* Hence, maximum transfer size is limited by MPS * (2^packet_counter_width - 1)
*
* Minimum packet counter width is 4. So value of 0 of pktsizewidth field in the register must be interpreted as 4.
*
* @see USB-DWC databook Table 5-26
* @param[in] hw Start address of the DWC_OTG registers
* @return Effective bitwidth of the packet counter
*/
static inline unsigned usb_dwc_ll_ghwcfg_get_packet_size_width(usb_dwc_dev_t *hw)
{
return hw->ghwcfg3_reg.pktsizewidth + 4;
}
static inline unsigned usb_dwc_ll_ghwcfg_get_hsphy_type(usb_dwc_dev_t *hw)
{
return hw->ghwcfg2_reg.hsphytype;
@@ -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
*/
@@ -174,10 +174,13 @@ typedef struct {
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
struct {
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_config;
union {
@@ -290,6 +293,25 @@ void usb_dwc_hal_set_fifo_config(usb_dwc_hal_context_t *hal, const usb_dwc_hal_f
*/
void usb_dwc_hal_get_mps_limits(usb_dwc_hal_context_t *hal, usb_hal_fifo_mps_limits_t *mps_limits);
/**
* @brief Get Transfer Size limit
*
* There are 2 constraints on the size of a transfer:
* 1. Maximum transfer size: The maximum total size of data that can be transferred in a single transfer.
* This is determined by the width of the transfer size counter in the hardware
* 2. Maximum packet count: The maximum number of packets that can be transferred in a single transfer.
* This is determined by the width of the packet counter in the hardware
*
* The actual maximum transfer size of a transfer is the minimum of (xfer_size, packet_count * MPS), where MPS is the maximum packet size of the endpoint.
*
* @see USB-DWC databook Table 5-26
*
* @param[in] hal Context of the HAL layer
* @param[in] mps Maximum packet size of the endpoint in bytes
* @return Maximum transfer size in bytes based on the hardware counters
*/
size_t usb_dwc_hal_get_xfer_size_limit(usb_dwc_hal_context_t *hal, uint16_t mps);
// ---------------------------------------------------- Host Port ------------------------------------------------------
// ------------------ Host Port Control --------------------
+20 -1
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
*/
@@ -165,6 +165,8 @@ void usb_dwc_hal_init(usb_dwc_hal_context_t *hal, int port_id)
hal->constant_config.fifo_size = usb_dwc_ll_ghwcfg_get_fifo_depth(dev);
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);
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;
set_defaults(hal);
}
@@ -260,6 +262,23 @@ void usb_dwc_hal_get_mps_limits(usb_dwc_hal_context_t *hal, usb_hal_fifo_mps_lim
mps_limits->periodic_out_mps = fifo_config->ptx_fifo_lines * 4;
}
size_t usb_dwc_hal_get_xfer_size_limit(usb_dwc_hal_context_t *hal, uint16_t mps)
{
HAL_ASSERT(hal);
HAL_ASSERT(mps > 0);
size_t max_xfer_size;
// Minimum of the two limits
if (mps * hal->constant_config.max_size_packet_limit > hal->constant_config.max_size_byte_limit) {
// We hit the overall byte limit
max_xfer_size = hal->constant_config.max_size_byte_limit;
} else {
// We hit the overall packet limit
max_xfer_size = mps * hal->constant_config.max_size_packet_limit;
}
return max_xfer_size;
}
// ---------------------------------------------------- Host Port ------------------------------------------------------
static inline void debounce_lock_enable(usb_dwc_hal_context_t *hal)