feat(usb/host): Add High Speed enumeration types

This commit is contained in:
Tomas Rezucha
2023-11-23 04:00:22 +01:00
parent 692d15abbe
commit 42277ac868
7 changed files with 43 additions and 69 deletions

View File

@ -468,12 +468,12 @@ static inline bool usb_dwc_hal_port_check_if_connected(usb_dwc_hal_context_t *ha
} }
/** /**
* @brief Check the speed (LS/FS) of the device connected to the host port * @brief Check the speed of the device connected to the host port
* *
* @note This function should only be called after confirming that a device is connected to the host port * @note This function should only be called after confirming that a device is connected to the host port
* *
* @param hal Context of the HAL layer * @param hal Context of the HAL layer
* @return usb_priv_speed_t Speed of the connected device (FS or LS only on the esp32-s2 and esp32-s3) * @return usb_priv_speed_t Speed of the connected device
*/ */
static inline usb_priv_speed_t usb_dwc_hal_port_get_conn_speed(usb_dwc_hal_context_t *hal) static inline usb_priv_speed_t usb_dwc_hal_port_get_conn_speed(usb_dwc_hal_context_t *hal)
{ {

View File

@ -560,13 +560,15 @@ static inline uint32_t usb_dwc_ll_hflbaddr_get_base_addr(usb_dwc_dev_t *hw)
static inline usb_priv_speed_t usb_dwc_ll_hprt_get_speed(usb_dwc_dev_t *hw) static inline usb_priv_speed_t usb_dwc_ll_hprt_get_speed(usb_dwc_dev_t *hw)
{ {
usb_priv_speed_t speed; usb_priv_speed_t speed = USB_PRIV_SPEED_HIGH;
//esp32-s2 and esp32-s3 only support FS or LS
switch (hw->hprt_reg.prtspd) { switch (hw->hprt_reg.prtspd) {
case 0:
speed = USB_PRIV_SPEED_HIGH;
break;
case 1: case 1:
speed = USB_PRIV_SPEED_FULL; speed = USB_PRIV_SPEED_FULL;
break; break;
default: case 2:
speed = USB_PRIV_SPEED_LOW; speed = USB_PRIV_SPEED_LOW;
break; break;
} }

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -55,6 +55,7 @@ typedef enum {
USB_PHY_SPEED_UNDEFINED, USB_PHY_SPEED_UNDEFINED,
USB_PHY_SPEED_LOW, /**< USB Low Speed (1.5 Mbit/s) */ USB_PHY_SPEED_LOW, /**< USB Low Speed (1.5 Mbit/s) */
USB_PHY_SPEED_FULL, /**< USB Full Speed (12 Mbit/s) */ USB_PHY_SPEED_FULL, /**< USB Full Speed (12 Mbit/s) */
USB_PHY_SPEED_HIGH, /**< USB High Speed (480 Mbit/s) */
USB_PHY_SPEED_MAX, USB_PHY_SPEED_MAX,
} usb_phy_speed_t; } usb_phy_speed_t;

View File

@ -22,6 +22,7 @@ extern "C"
* @brief USB speeds supported by the DWC OTG controller * @brief USB speeds supported by the DWC OTG controller
*/ */
typedef enum { typedef enum {
USB_PRIV_SPEED_HIGH,
USB_PRIV_SPEED_FULL, USB_PRIV_SPEED_FULL,
USB_PRIV_SPEED_LOW, USB_PRIV_SPEED_LOW,
} usb_priv_speed_t; } usb_priv_speed_t;

View File

@ -12,14 +12,11 @@
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
#include "soc/interrupts.h" // For interrupt index
#include "esp_err.h" #include "esp_err.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_rom_gpio.h"
#include "hal/usb_dwc_hal.h" #include "hal/usb_dwc_hal.h"
#include "hal/usb_types_private.h" #include "hal/usb_types_private.h"
#include "soc/gpio_pins.h"
#include "soc/gpio_sig_map.h"
#include "esp_private/periph_ctrl.h"
#include "hcd.h" #include "hcd.h"
#include "usb_private.h" #include "usb_private.h"
#include "usb/usb_types_ch9.h" #include "usb/usb_types_ch9.h"
@ -36,18 +33,12 @@
#define RESUME_RECOVERY_MS 20 // Resume recovery of at least 10ms. Make it 20 ms to be safe. This will include the 3 LS bit times of the EOP #define RESUME_RECOVERY_MS 20 // Resume recovery of at least 10ms. Make it 20 ms to be safe. This will include the 3 LS bit times of the EOP
#define CTRL_EP_MAX_MPS_LS 8 // Largest Maximum Packet Size for Low Speed control endpoints #define CTRL_EP_MAX_MPS_LS 8 // Largest Maximum Packet Size for Low Speed control endpoints
#define CTRL_EP_MAX_MPS_FS 64 // Largest Maximum Packet Size for Full Speed control endpoints #define CTRL_EP_MAX_MPS_HSFS 64 // Largest Maximum Packet Size for High & Full Speed control endpoints
#define NUM_PORTS 1 // The controller only has one port. #define NUM_PORTS 1 // The controller only has one port.
// ----------------------- Configs ------------------------- // ----------------------- Configs -------------------------
typedef struct {
int in_mps;
int non_periodic_out_mps;
int periodic_out_mps;
} fifo_mps_limits_t;
/** /**
* @brief Default FIFO sizes (see 2.1.2.4 for programming guide) * @brief Default FIFO sizes (see 2.1.2.4 for programming guide)
* *
@ -70,12 +61,6 @@ const usb_dwc_hal_fifo_config_t fifo_config_default = {
.ptx_fifo_lines = 48, .ptx_fifo_lines = 48,
}; };
const fifo_mps_limits_t mps_limits_default = {
.in_mps = 408,
.non_periodic_out_mps = 192,
.periodic_out_mps = 192,
};
/** /**
* @brief FIFO sizes that bias to giving RX FIFO more capacity * @brief FIFO sizes that bias to giving RX FIFO more capacity
* *
@ -98,12 +83,6 @@ const usb_dwc_hal_fifo_config_t fifo_config_bias_rx = {
.ptx_fifo_lines = 32, .ptx_fifo_lines = 32,
}; };
const fifo_mps_limits_t mps_limits_bias_rx = {
.in_mps = 600,
.non_periodic_out_mps = 64,
.periodic_out_mps = 128,
};
/** /**
* @brief FIFO sizes that bias to giving Periodic TX FIFO more capacity (i.e., ISOC OUT) * @brief FIFO sizes that bias to giving Periodic TX FIFO more capacity (i.e., ISOC OUT)
* *
@ -126,12 +105,6 @@ const usb_dwc_hal_fifo_config_t fifo_config_bias_ptx = {
.ptx_fifo_lines = 150, .ptx_fifo_lines = 150,
}; };
const fifo_mps_limits_t mps_limits_bias_ptx = {
.in_mps = 128,
.non_periodic_out_mps = 64,
.periodic_out_mps = 600,
};
#define FRAME_LIST_LEN USB_HAL_FRAME_LIST_LEN_32 #define FRAME_LIST_LEN USB_HAL_FRAME_LIST_LEN_32
#define NUM_BUFFERS 2 #define NUM_BUFFERS 2
@ -308,7 +281,6 @@ struct port_obj {
bool initialized; bool initialized;
// FIFO biasing related // FIFO biasing related
const usb_dwc_hal_fifo_config_t *fifo_config; const usb_dwc_hal_fifo_config_t *fifo_config;
const fifo_mps_limits_t *fifo_mps_limits;
// Port callback and context // Port callback and context
hcd_port_callback_t callback; hcd_port_callback_t callback;
void *callback_arg; void *callback_arg;
@ -759,6 +731,16 @@ static bool _internal_pipe_event_notify(pipe_t *pipe, bool from_isr)
// ----------------- Interrupt Handlers -------------------- // ----------------- Interrupt Handlers --------------------
static usb_speed_t speed_priv_to_public(usb_priv_speed_t priv)
{
switch (priv) {
case USB_PRIV_SPEED_LOW: return USB_SPEED_LOW;
case USB_PRIV_SPEED_FULL: return USB_SPEED_FULL;
case USB_PRIV_SPEED_HIGH: return USB_SPEED_HIGH;
default: abort();
}
}
/** /**
* @brief Handle a HAL port interrupt and obtain the corresponding port event * @brief Handle a HAL port interrupt and obtain the corresponding port event
* *
@ -784,7 +766,7 @@ static hcd_port_event_t _intr_hdlr_hprt(port_t *port, usb_dwc_hal_port_event_t h
} }
case USB_DWC_HAL_PORT_EVENT_ENABLED: { case USB_DWC_HAL_PORT_EVENT_ENABLED: {
usb_dwc_hal_port_enable(port->hal); // Initialize remaining host port registers usb_dwc_hal_port_enable(port->hal); // Initialize remaining host port registers
port->speed = (usb_dwc_hal_port_get_conn_speed(port->hal) == USB_PRIV_SPEED_FULL) ? USB_SPEED_FULL : USB_SPEED_LOW; port->speed = speed_priv_to_public(usb_dwc_hal_port_get_conn_speed(port->hal));
port->state = HCD_PORT_STATE_ENABLED; port->state = HCD_PORT_STATE_ENABLED;
port->flags.conn_dev_ena = 1; port->flags.conn_dev_ena = 1;
// This was triggered by a command, so no event needs to be propagated. // This was triggered by a command, so no event needs to be propagated.
@ -1309,23 +1291,18 @@ esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, h
// Get a pointer to the correct FIFO bias constant values // Get a pointer to the correct FIFO bias constant values
const usb_dwc_hal_fifo_config_t *fifo_config; const usb_dwc_hal_fifo_config_t *fifo_config;
const fifo_mps_limits_t *mps_limits;
switch (port_config->fifo_bias) { switch (port_config->fifo_bias) {
case HCD_PORT_FIFO_BIAS_BALANCED: case HCD_PORT_FIFO_BIAS_BALANCED:
fifo_config = &fifo_config_default; fifo_config = &fifo_config_default;
mps_limits = &mps_limits_default;
break; break;
case HCD_PORT_FIFO_BIAS_RX: case HCD_PORT_FIFO_BIAS_RX:
fifo_config = &fifo_config_bias_rx; fifo_config = &fifo_config_bias_rx;
mps_limits = &mps_limits_bias_rx;
break; break;
case HCD_PORT_FIFO_BIAS_PTX: case HCD_PORT_FIFO_BIAS_PTX:
fifo_config = &fifo_config_bias_ptx; fifo_config = &fifo_config_bias_ptx;
mps_limits = &mps_limits_bias_ptx;
break; break;
default: default:
fifo_config = NULL; fifo_config = NULL;
mps_limits = NULL;
abort(); abort();
break; break;
} }
@ -1339,7 +1316,6 @@ esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, h
port_obj->state = HCD_PORT_STATE_NOT_POWERED; port_obj->state = HCD_PORT_STATE_NOT_POWERED;
port_obj->last_event = HCD_PORT_EVENT_NONE; port_obj->last_event = HCD_PORT_EVENT_NONE;
port_obj->fifo_config = fifo_config; port_obj->fifo_config = fifo_config;
port_obj->fifo_mps_limits = mps_limits;
port_obj->callback = port_config->callback; port_obj->callback = port_config->callback;
port_obj->callback_arg = port_config->callback_arg; port_obj->callback_arg = port_config->callback_arg;
port_obj->context = port_config->context; port_obj->context = port_config->context;
@ -1431,12 +1407,7 @@ esp_err_t hcd_port_get_speed(hcd_port_handle_t port_hdl, usb_speed_t *speed)
HCD_ENTER_CRITICAL(); HCD_ENTER_CRITICAL();
// Device speed is only valid if there is device connected to the port that has been reset // Device speed is only valid if there is device connected to the port that has been reset
HCD_CHECK_FROM_CRIT(port->flags.conn_dev_ena, ESP_ERR_INVALID_STATE); HCD_CHECK_FROM_CRIT(port->flags.conn_dev_ena, ESP_ERR_INVALID_STATE);
usb_priv_speed_t hal_speed = usb_dwc_hal_port_get_conn_speed(port->hal); *speed = speed_priv_to_public(usb_dwc_hal_port_get_conn_speed(port->hal));
if (hal_speed == USB_PRIV_SPEED_FULL) {
*speed = USB_SPEED_FULL;
} else {
*speed = USB_SPEED_LOW;
}
HCD_EXIT_CRITICAL(); HCD_EXIT_CRITICAL();
return ESP_OK; return ESP_OK;
} }
@ -1514,23 +1485,18 @@ esp_err_t hcd_port_set_fifo_bias(hcd_port_handle_t port_hdl, hcd_port_fifo_bias_
esp_err_t ret; esp_err_t ret;
// Get a pointer to the correct FIFO bias constant values // Get a pointer to the correct FIFO bias constant values
const usb_dwc_hal_fifo_config_t *fifo_config; const usb_dwc_hal_fifo_config_t *fifo_config;
const fifo_mps_limits_t *mps_limits;
switch (bias) { switch (bias) {
case HCD_PORT_FIFO_BIAS_BALANCED: case HCD_PORT_FIFO_BIAS_BALANCED:
fifo_config = &fifo_config_default; fifo_config = &fifo_config_default;
mps_limits = &mps_limits_default;
break; break;
case HCD_PORT_FIFO_BIAS_RX: case HCD_PORT_FIFO_BIAS_RX:
fifo_config = &fifo_config_bias_rx; fifo_config = &fifo_config_bias_rx;
mps_limits = &mps_limits_bias_rx;
break; break;
case HCD_PORT_FIFO_BIAS_PTX: case HCD_PORT_FIFO_BIAS_PTX:
fifo_config = &fifo_config_bias_ptx; fifo_config = &fifo_config_bias_ptx;
mps_limits = &mps_limits_bias_ptx;
break; break;
default: default:
fifo_config = NULL; fifo_config = NULL;
mps_limits = NULL;
abort(); abort();
break; break;
} }
@ -1542,7 +1508,6 @@ esp_err_t hcd_port_set_fifo_bias(hcd_port_handle_t port_hdl, hcd_port_fifo_bias_
if (port->initialized && !port->flags.event_pending && port->num_pipes_idle == 0 && port->num_pipes_queued == 0) { if (port->initialized && !port->flags.event_pending && port->num_pipes_idle == 0 && port->num_pipes_queued == 0) {
usb_dwc_hal_set_fifo_size(port->hal, fifo_config); usb_dwc_hal_set_fifo_size(port->hal, fifo_config);
port->fifo_config = fifo_config; port->fifo_config = fifo_config;
port->fifo_mps_limits = mps_limits;
ret = ESP_OK; ret = ESP_OK;
} else { } else {
ret = ESP_ERR_INVALID_STATE; ret = ESP_ERR_INVALID_STATE;
@ -1629,10 +1594,14 @@ static bool pipe_args_usb_compliance_verification(const hcd_pipe_config_t *pipe_
return true; return true;
} }
static bool pipe_alloc_hcd_support_verification(const usb_ep_desc_t *ep_desc, const fifo_mps_limits_t *mps_limits) static bool pipe_alloc_hcd_support_verification(const usb_ep_desc_t * ep_desc, const usb_dwc_hal_fifo_config_t *fifo_config)
{ {
assert(ep_desc != NULL); assert(ep_desc != NULL);
usb_transfer_type_t type = USB_EP_DESC_GET_XFERTYPE(ep_desc);
const uint32_t limit_in_mps = (fifo_config->rx_fifo_lines - 2) * 4; // Two lines are reserved for status quadlets internally by USB_DWC
const uint32_t limit_non_periodic_out_mps = fifo_config->nptx_fifo_lines * 4;
const uint32_t limit_periodic_out_mps = fifo_config->ptx_fifo_lines * 4;
const usb_transfer_type_t type = USB_EP_DESC_GET_XFERTYPE(ep_desc);
// Check the pipe's interval is not zero // Check the pipe's interval is not zero
if ((type == USB_TRANSFER_TYPE_INTR || type == USB_TRANSFER_TYPE_ISOCHRONOUS) && if ((type == USB_TRANSFER_TYPE_INTR || type == USB_TRANSFER_TYPE_ISOCHRONOUS) &&
@ -1645,12 +1614,12 @@ static bool pipe_alloc_hcd_support_verification(const usb_ep_desc_t *ep_desc, co
// Check if pipe MPS exceeds HCD MPS limits (due to DWC FIFO sizing) // Check if pipe MPS exceeds HCD MPS limits (due to DWC FIFO sizing)
int limit; int limit;
if (USB_EP_DESC_GET_EP_DIR(ep_desc)) { // IN if (USB_EP_DESC_GET_EP_DIR(ep_desc)) { // IN
limit = mps_limits->in_mps; limit = limit_in_mps;
} else { // OUT } else { // OUT
if (type == USB_TRANSFER_TYPE_CTRL || type == USB_TRANSFER_TYPE_BULK) { if (type == USB_TRANSFER_TYPE_CTRL || type == USB_TRANSFER_TYPE_BULK) {
limit = mps_limits->non_periodic_out_mps; limit = limit_non_periodic_out_mps;
} else { } else {
limit = mps_limits->periodic_out_mps; limit = limit_periodic_out_mps;
} }
} }
@ -1686,7 +1655,7 @@ static void pipe_set_ep_char(const hcd_pipe_config_t *pipe_config, usb_transfer_
if (is_default_pipe) { if (is_default_pipe) {
ep_char->bEndpointAddress = 0; ep_char->bEndpointAddress = 0;
// Set the default pipe's MPS to the worst case MPS for the device's speed // Set the default pipe's MPS to the worst case MPS for the device's speed
ep_char->mps = (pipe_config->dev_speed == USB_SPEED_FULL) ? CTRL_EP_MAX_MPS_FS : CTRL_EP_MAX_MPS_LS; ep_char->mps = (pipe_config->dev_speed == USB_SPEED_LOW) ? CTRL_EP_MAX_MPS_LS : CTRL_EP_MAX_MPS_HSFS;
} else { } else {
ep_char->bEndpointAddress = pipe_config->ep_desc->bEndpointAddress; ep_char->bEndpointAddress = pipe_config->ep_desc->bEndpointAddress;
ep_char->mps = pipe_config->ep_desc->wMaxPacketSize; ep_char->mps = pipe_config->ep_desc->wMaxPacketSize;
@ -1840,7 +1809,6 @@ esp_err_t hcd_pipe_alloc(hcd_port_handle_t port_hdl, const hcd_pipe_config_t *pi
// Can only allocate a pipe if the target port is initialized and connected to an enabled device // Can only allocate a pipe if the target port is initialized and connected to an enabled device
HCD_CHECK_FROM_CRIT(port->initialized && port->flags.conn_dev_ena, ESP_ERR_INVALID_STATE); HCD_CHECK_FROM_CRIT(port->initialized && port->flags.conn_dev_ena, ESP_ERR_INVALID_STATE);
usb_speed_t port_speed = port->speed; usb_speed_t port_speed = port->speed;
const fifo_mps_limits_t *mps_limits = port->fifo_mps_limits;
int pipe_idx = port->num_pipes_idle + port->num_pipes_queued; int pipe_idx = port->num_pipes_idle + port->num_pipes_queued;
HCD_EXIT_CRITICAL(); HCD_EXIT_CRITICAL();
@ -1861,7 +1829,7 @@ esp_err_t hcd_pipe_alloc(hcd_port_handle_t port_hdl, const hcd_pipe_config_t *pi
return ESP_ERR_NOT_SUPPORTED; return ESP_ERR_NOT_SUPPORTED;
} }
// Default pipes have a NULL ep_desc thus should skip the HCD support verification // Default pipes have a NULL ep_desc thus should skip the HCD support verification
if (!is_default && !pipe_alloc_hcd_support_verification(pipe_config->ep_desc, mps_limits)) { if (!is_default && !pipe_alloc_hcd_support_verification(pipe_config->ep_desc, port->fifo_config)) {
return ESP_ERR_NOT_SUPPORTED; return ESP_ERR_NOT_SUPPORTED;
} }
// Allocate the pipe resources // Allocate the pipe resources

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -24,6 +24,7 @@ extern "C" {
typedef enum { typedef enum {
USB_SPEED_LOW = 0, /**< USB Low Speed (1.5 Mbit/s) */ USB_SPEED_LOW = 0, /**< USB Low Speed (1.5 Mbit/s) */
USB_SPEED_FULL, /**< USB Full Speed (12 Mbit/s) */ USB_SPEED_FULL, /**< USB Full Speed (12 Mbit/s) */
USB_SPEED_HIGH, /**< USB High Speed (480 Mbit/s) */
} usb_speed_t; } usb_speed_t;
/** /**

View File

@ -147,11 +147,12 @@ esp_err_t usb_phy_otg_dev_set_speed(usb_phy_handle_t handle, usb_phy_speed_t spe
USBPHY_TAG, "set speed not supported"); USBPHY_TAG, "set speed not supported");
handle->otg_speed = speed; handle->otg_speed = speed;
usb_priv_speed_t hal_speed = 0; usb_priv_speed_t hal_speed;
if (speed == USB_PHY_SPEED_LOW) { switch (speed) {
hal_speed = USB_PRIV_SPEED_LOW; case USB_PHY_SPEED_LOW: hal_speed = USB_PRIV_SPEED_LOW; break;
} else if (speed == USB_PHY_SPEED_FULL) { case USB_PHY_SPEED_FULL: hal_speed = USB_PRIV_SPEED_FULL; break;
hal_speed = USB_PRIV_SPEED_FULL; case USB_PHY_SPEED_HIGH: hal_speed = USB_PRIV_SPEED_HIGH; break;
default: abort();
} }
usb_phy_hal_int_load_conf_dev(&(handle->hal_context), hal_speed); usb_phy_hal_int_load_conf_dev(&(handle->hal_context), hal_speed);
return ESP_OK; return ESP_OK;