From d9223c6d914062607f10fdd0d6ae1e3f375a103a Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Thu, 23 Nov 2023 04:00:22 +0100 Subject: [PATCH 1/3] feat(usb/host): Add High Speed enumeration types --- components/hal/include/hal/usb_dwc_hal.h | 4 +- components/hal/include/hal/usb_dwc_ll.h | 8 +- components/hal/include/hal/usb_phy_types.h | 3 +- .../hal/include/hal/usb_types_private.h | 1 + components/usb/hcd_dwc.c | 82 ++++++------------- components/usb/include/usb/usb_types_stack.h | 3 +- components/usb/usb_phy.c | 11 +-- 7 files changed, 43 insertions(+), 69 deletions(-) diff --git a/components/hal/include/hal/usb_dwc_hal.h b/components/hal/include/hal/usb_dwc_hal.h index 4369ff3ac0..447eb873cb 100644 --- a/components/hal/include/hal/usb_dwc_hal.h +++ b/components/hal/include/hal/usb_dwc_hal.h @@ -465,12 +465,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 * * @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) { diff --git a/components/hal/include/hal/usb_dwc_ll.h b/components/hal/include/hal/usb_dwc_ll.h index 385e93f444..a3c7757bcf 100644 --- a/components/hal/include/hal/usb_dwc_ll.h +++ b/components/hal/include/hal/usb_dwc_ll.h @@ -556,13 +556,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) { - usb_priv_speed_t speed; - //esp32-s2 and esp32-s3 only support FS or LS + usb_priv_speed_t speed = USB_PRIV_SPEED_HIGH; switch (hw->hprt_reg.prtspd) { + case 0: + speed = USB_PRIV_SPEED_HIGH; + break; case 1: speed = USB_PRIV_SPEED_FULL; break; - default: + case 2: speed = USB_PRIV_SPEED_LOW; break; } diff --git a/components/hal/include/hal/usb_phy_types.h b/components/hal/include/hal/usb_phy_types.h index 1f5ac431ef..50636a64dd 100644 --- a/components/hal/include/hal/usb_phy_types.h +++ b/components/hal/include/hal/usb_phy_types.h @@ -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 */ @@ -55,6 +55,7 @@ typedef enum { USB_PHY_SPEED_UNDEFINED, USB_PHY_SPEED_LOW, /**< USB Low Speed (1.5 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_t; diff --git a/components/hal/include/hal/usb_types_private.h b/components/hal/include/hal/usb_types_private.h index 5cce6b66af..0808c4b196 100644 --- a/components/hal/include/hal/usb_types_private.h +++ b/components/hal/include/hal/usb_types_private.h @@ -30,6 +30,7 @@ extern "C" * @brief USB speeds supported by the DWC OTG controller */ typedef enum { + USB_PRIV_SPEED_HIGH, USB_PRIV_SPEED_FULL, USB_PRIV_SPEED_LOW, } usb_priv_speed_t; diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index 19e3165197..3e0aecf040 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -12,14 +12,11 @@ #include "freertos/semphr.h" #include "esp_heap_caps.h" #include "esp_intr_alloc.h" +#include "soc/interrupts.h" // For interrupt index #include "esp_err.h" #include "esp_log.h" -#include "esp_rom_gpio.h" #include "hal/usb_dwc_hal.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 "usb_private.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 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. // ----------------------- 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) * @@ -70,12 +61,6 @@ const usb_dwc_hal_fifo_config_t fifo_config_default = { .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 * @@ -98,12 +83,6 @@ const usb_dwc_hal_fifo_config_t fifo_config_bias_rx = { .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) * @@ -126,12 +105,6 @@ const usb_dwc_hal_fifo_config_t fifo_config_bias_ptx = { .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 NUM_BUFFERS 2 @@ -308,7 +281,6 @@ struct port_obj { bool initialized; // FIFO biasing related const usb_dwc_hal_fifo_config_t *fifo_config; - const fifo_mps_limits_t *fifo_mps_limits; // Port callback and context hcd_port_callback_t callback; void *callback_arg; @@ -759,6 +731,16 @@ static bool _internal_pipe_event_notify(pipe_t *pipe, bool from_isr) // ----------------- 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 * @@ -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: { 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->flags.conn_dev_ena = 1; // 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 const usb_dwc_hal_fifo_config_t *fifo_config; - const fifo_mps_limits_t *mps_limits; switch (port_config->fifo_bias) { case HCD_PORT_FIFO_BIAS_BALANCED: fifo_config = &fifo_config_default; - mps_limits = &mps_limits_default; break; case HCD_PORT_FIFO_BIAS_RX: fifo_config = &fifo_config_bias_rx; - mps_limits = &mps_limits_bias_rx; break; case HCD_PORT_FIFO_BIAS_PTX: fifo_config = &fifo_config_bias_ptx; - mps_limits = &mps_limits_bias_ptx; break; default: fifo_config = NULL; - mps_limits = NULL; abort(); 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->last_event = HCD_PORT_EVENT_NONE; port_obj->fifo_config = fifo_config; - port_obj->fifo_mps_limits = mps_limits; port_obj->callback = port_config->callback; port_obj->callback_arg = port_config->callback_arg; 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(); // 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); - usb_priv_speed_t hal_speed = 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; - } + *speed = speed_priv_to_public(usb_dwc_hal_port_get_conn_speed(port->hal)); HCD_EXIT_CRITICAL(); 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; // Get a pointer to the correct FIFO bias constant values const usb_dwc_hal_fifo_config_t *fifo_config; - const fifo_mps_limits_t *mps_limits; switch (bias) { case HCD_PORT_FIFO_BIAS_BALANCED: fifo_config = &fifo_config_default; - mps_limits = &mps_limits_default; break; case HCD_PORT_FIFO_BIAS_RX: fifo_config = &fifo_config_bias_rx; - mps_limits = &mps_limits_bias_rx; break; case HCD_PORT_FIFO_BIAS_PTX: fifo_config = &fifo_config_bias_ptx; - mps_limits = &mps_limits_bias_ptx; break; default: fifo_config = NULL; - mps_limits = NULL; abort(); 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) { usb_dwc_hal_set_fifo_size(port->hal, fifo_config); port->fifo_config = fifo_config; - port->fifo_mps_limits = mps_limits; ret = ESP_OK; } else { ret = ESP_ERR_INVALID_STATE; @@ -1629,10 +1594,14 @@ static bool pipe_args_usb_compliance_verification(const hcd_pipe_config_t *pipe_ 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); - 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 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) int limit; if (USB_EP_DESC_GET_EP_DIR(ep_desc)) { // IN - limit = mps_limits->in_mps; + limit = limit_in_mps; } else { // OUT 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 { - 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) { ep_char->bEndpointAddress = 0; // 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 { ep_char->bEndpointAddress = pipe_config->ep_desc->bEndpointAddress; 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 HCD_CHECK_FROM_CRIT(port->initialized && port->flags.conn_dev_ena, ESP_ERR_INVALID_STATE); 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; 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; } // 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; } // Allocate the pipe resources diff --git a/components/usb/include/usb/usb_types_stack.h b/components/usb/include/usb/usb_types_stack.h index 94ab481ee9..00af897182 100644 --- a/components/usb/include/usb/usb_types_stack.h +++ b/components/usb/include/usb/usb_types_stack.h @@ -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 */ @@ -24,6 +24,7 @@ extern "C" { typedef enum { USB_SPEED_LOW = 0, /**< USB Low Speed (1.5 Mbit/s) */ USB_SPEED_FULL, /**< USB Full Speed (12 Mbit/s) */ + USB_SPEED_HIGH, /**< USB High Speed (480 Mbit/s) */ } usb_speed_t; /** diff --git a/components/usb/usb_phy.c b/components/usb/usb_phy.c index 858c2767d7..492a7e7e22 100644 --- a/components/usb/usb_phy.c +++ b/components/usb/usb_phy.c @@ -141,11 +141,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"); handle->otg_speed = speed; - usb_priv_speed_t hal_speed = 0; - if (speed == USB_PHY_SPEED_LOW) { - hal_speed = USB_PRIV_SPEED_LOW; - } else if (speed == USB_PHY_SPEED_FULL) { - hal_speed = USB_PRIV_SPEED_FULL; + usb_priv_speed_t hal_speed; + switch (speed) { + case USB_PHY_SPEED_LOW: hal_speed = USB_PRIV_SPEED_LOW; break; + case USB_PHY_SPEED_FULL: hal_speed = USB_PRIV_SPEED_FULL; break; + 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); return ESP_OK; From 325205faeee03de68e8782c5f03582477a8cb2de Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Wed, 29 Nov 2023 16:30:04 +0800 Subject: [PATCH 2/3] refactor(usb/host): Make private hal types USB_DWC specific --- components/hal/include/hal/usb_dwc_hal.h | 14 ++--- components/hal/include/hal/usb_dwc_ll.h | 47 ++++------------ .../{usb_types_private.h => usb_dwc_types.h} | 40 +++++++------- components/hal/include/hal/usb_phy_hal.h | 5 +- components/hal/usb_dwc_hal.c | 6 +-- components/hal/usb_phy_hal.c | 4 +- components/usb/hcd_dwc.c | 54 +++++++++---------- components/usb/usb_phy.c | 9 +--- 8 files changed, 71 insertions(+), 108 deletions(-) rename components/hal/include/hal/{usb_types_private.h => usb_dwc_types.h} (59%) diff --git a/components/hal/include/hal/usb_dwc_hal.h b/components/hal/include/hal/usb_dwc_hal.h index 447eb873cb..aee866e7ea 100644 --- a/components/hal/include/hal/usb_dwc_hal.h +++ b/components/hal/include/hal/usb_dwc_hal.h @@ -19,7 +19,7 @@ NOTE: Thread safety is the responsibility fo the HAL user. All USB Host HAL #include #include "soc/usb_dwc_struct.h" #include "hal/usb_dwc_ll.h" -#include "hal/usb_types_private.h" +#include "hal/usb_dwc_types.h" #include "hal/assert.h" #if SOC_USB_OTG_SUPPORTED @@ -104,7 +104,7 @@ typedef enum { typedef struct { union { struct { - usb_priv_xfer_type_t type: 2; /**< The type of endpoint */ + usb_dwc_xfer_type_t type: 2; /**< The type of endpoint */ uint32_t bEndpointAddress: 8; /**< Endpoint address (containing endpoint number and direction) */ uint32_t mps: 11; /**< Maximum Packet Size */ uint32_t dev_addr: 8; /**< Device Address */ @@ -135,9 +135,9 @@ typedef struct { }; uint32_t val; } flags; /**< Flags regarding channel's status and information */ - usb_dwc_host_chan_regs_t *regs; /**< Pointer to the channel's register set */ - usb_dwc_hal_chan_error_t error; /**< The last error that occurred on the channel */ - usb_priv_xfer_type_t type; /**< The transfer type of the channel */ + usb_dwc_host_chan_regs_t *regs; /**< Pointer to the channel's register set */ + usb_dwc_hal_chan_error_t error; /**< The last error that occurred on the channel */ + usb_dwc_xfer_type_t type; /**< The transfer type of the channel */ void *chan_ctx; /**< Context variable for the owner of the channel */ } usb_dwc_hal_chan_t; @@ -470,9 +470,9 @@ static inline bool usb_dwc_hal_port_check_if_connected(usb_dwc_hal_context_t *ha * @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 - * @return usb_priv_speed_t Speed of the connected device + * @return usb_dwc_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_dwc_speed_t usb_dwc_hal_port_get_conn_speed(usb_dwc_hal_context_t *hal) { return usb_dwc_ll_hprt_get_speed(hal->dev); } diff --git a/components/hal/include/hal/usb_dwc_ll.h b/components/hal/include/hal/usb_dwc_ll.h index a3c7757bcf..1f4aef5e7e 100644 --- a/components/hal/include/hal/usb_dwc_ll.h +++ b/components/hal/include/hal/usb_dwc_ll.h @@ -13,7 +13,7 @@ extern "C" { #include #include #include "soc/usb_dwc_struct.h" -#include "hal/usb_types_private.h" +#include "hal/usb_dwc_types.h" #include "hal/misc.h" @@ -446,7 +446,7 @@ static inline void usb_dwc_ll_hcfg_set_fsls_pclk_sel(usb_dwc_dev_t *hw) * @param hw Start address of the DWC_OTG registers * @param speed Speed to initialize the host port at */ -static inline void usb_dwc_ll_hcfg_set_defaults(usb_dwc_dev_t *hw, usb_priv_speed_t speed) +static inline void usb_dwc_ll_hcfg_set_defaults(usb_dwc_dev_t *hw, usb_dwc_speed_t speed) { hw->hcfg_reg.descdma = 1; //Enable scatt/gatt hw->hcfg_reg.fslssupp = 1; //FS/LS support only @@ -455,13 +455,13 @@ static inline void usb_dwc_ll_hcfg_set_defaults(usb_dwc_dev_t *hw, usb_priv_spee Note: It seems like our PHY has an implicit 8 divider applied when in LS mode, so the values of FSLSPclkSel and FrInt have to be adjusted accordingly. */ - hw->hcfg_reg.fslspclksel = (speed == USB_PRIV_SPEED_FULL) ? 1 : 2; //PHY clock on esp32-sx for FS/LS-only + hw->hcfg_reg.fslspclksel = (speed == USB_DWC_SPEED_FULL) ? 1 : 2; //PHY clock on esp32-sx for FS/LS-only hw->hcfg_reg.perschedena = 0; //Disable perio sched } // ----------------------------- HFIR Register --------------------------------- -static inline void usb_dwc_ll_hfir_set_defaults(usb_dwc_dev_t *hw, usb_priv_speed_t speed) +static inline void usb_dwc_ll_hfir_set_defaults(usb_dwc_dev_t *hw, usb_dwc_speed_t speed) { usb_dwc_hfir_reg_t hfir; hfir.val = hw->hfir_reg.val; @@ -471,7 +471,7 @@ static inline void usb_dwc_ll_hfir_set_defaults(usb_dwc_dev_t *hw, usb_priv_spee Note: It seems like our PHY has an implicit 8 divider applied when in LS mode, so the values of FSLSPclkSel and FrInt have to be adjusted accordingly. */ - hfir.frint = (speed == USB_PRIV_SPEED_FULL) ? 48000 : 6000; //esp32-sx targets only support FS or LS + hfir.frint = (speed == USB_DWC_SPEED_FULL) ? 48000 : 6000; //esp32-sx targets only support FS or LS hw->hfir_reg.val = hfir.val; } @@ -554,21 +554,9 @@ static inline uint32_t usb_dwc_ll_hflbaddr_get_base_addr(usb_dwc_dev_t *hw) // ----------------------------- HPRT Register --------------------------------- -static inline usb_priv_speed_t usb_dwc_ll_hprt_get_speed(usb_dwc_dev_t *hw) +static inline usb_dwc_speed_t usb_dwc_ll_hprt_get_speed(usb_dwc_dev_t *hw) { - usb_priv_speed_t speed = USB_PRIV_SPEED_HIGH; - switch (hw->hprt_reg.prtspd) { - case 0: - speed = USB_PRIV_SPEED_HIGH; - break; - case 1: - speed = USB_PRIV_SPEED_FULL; - break; - case 2: - speed = USB_PRIV_SPEED_LOW; - break; - } - return speed; + return (usb_dwc_speed_t)hw->hprt_reg.prtspd; } static inline uint32_t usb_dwc_ll_hprt_get_test_ctl(usb_dwc_dev_t *hw) @@ -727,24 +715,9 @@ static inline void usb_dwc_ll_hcchar_set_dev_addr(volatile usb_dwc_host_chan_reg chan->hcchar_reg.devaddr = addr; } -static inline void usb_dwc_ll_hcchar_set_ep_type(volatile usb_dwc_host_chan_regs_t *chan, usb_priv_xfer_type_t type) +static inline void usb_dwc_ll_hcchar_set_ep_type(volatile usb_dwc_host_chan_regs_t *chan, usb_dwc_xfer_type_t type) { - uint32_t ep_type; - switch (type) { - case USB_PRIV_XFER_TYPE_CTRL: - ep_type = 0; - break; - case USB_PRIV_XFER_TYPE_ISOCHRONOUS: - ep_type = 1; - break; - case USB_PRIV_XFER_TYPE_BULK: - ep_type = 2; - break; - default: //USB_PRIV_XFER_TYPE_INTR - ep_type = 3; - break; - } - chan->hcchar_reg.eptype = ep_type; + chan->hcchar_reg.eptype = (uint32_t)type; } //Indicates whether channel is commuunicating with a LS device connected via a FS hub. Setting this bit to 1 will cause @@ -769,7 +742,7 @@ static inline void usb_dwc_ll_hcchar_set_mps(volatile usb_dwc_host_chan_regs_t * chan->hcchar_reg.mps = mps; } -static inline void usb_dwc_ll_hcchar_init(volatile usb_dwc_host_chan_regs_t *chan, int dev_addr, int ep_num, int mps, usb_priv_xfer_type_t type, bool is_in, bool is_ls) +static inline void usb_dwc_ll_hcchar_init(volatile usb_dwc_host_chan_regs_t *chan, int dev_addr, int ep_num, int mps, usb_dwc_xfer_type_t type, bool is_in, bool is_ls) { //Sets all persistent fields of the channel over its lifetimez usb_dwc_ll_hcchar_set_dev_addr(chan, dev_addr); diff --git a/components/hal/include/hal/usb_types_private.h b/components/hal/include/hal/usb_dwc_types.h similarity index 59% rename from components/hal/include/hal/usb_types_private.h rename to components/hal/include/hal/usb_dwc_types.h index 0808c4b196..0ffa36aa68 100644 --- a/components/hal/include/hal/usb_types_private.h +++ b/components/hal/include/hal/usb_dwc_types.h @@ -1,16 +1,8 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ /* Note: This header file contains USB2.0 related types and macros that can be used by code specific to the DWC_OTG @@ -28,22 +20,26 @@ extern "C" /** * @brief USB speeds supported by the DWC OTG controller + * + * @note usb_dwc_speed_t enum values must match the values of the DWC_OTG prtspd register field */ typedef enum { - USB_PRIV_SPEED_HIGH, - USB_PRIV_SPEED_FULL, - USB_PRIV_SPEED_LOW, -} usb_priv_speed_t; + USB_DWC_SPEED_HIGH = 0, + USB_DWC_SPEED_FULL = 1, + USB_DWC_SPEED_LOW = 2, +} usb_dwc_speed_t; /** * @brief USB transfer types supported by the DWC OTG controller + * + * @note usb_dwc_xfer_type_t enum values must match the values of the DWC_OTG hcchar register field */ typedef enum { - USB_PRIV_XFER_TYPE_CTRL, - USB_PRIV_XFER_TYPE_ISOCHRONOUS, - USB_PRIV_XFER_TYPE_BULK, - USB_PRIV_XFER_TYPE_INTR, -} usb_priv_xfer_type_t; + USB_DWC_XFER_TYPE_CTRL = 0, + USB_DWC_XFER_TYPE_ISOCHRONOUS = 1, + USB_DWC_XFER_TYPE_BULK = 2, + USB_DWC_XFER_TYPE_INTR = 3, +} usb_dwc_xfer_type_t; /** * @brief Enumeration of different possible lengths of the periodic frame list diff --git a/components/hal/include/hal/usb_phy_hal.h b/components/hal/include/hal/usb_phy_hal.h index fe77eb8744..b245d9ff4b 100644 --- a/components/hal/include/hal/usb_phy_hal.h +++ b/components/hal/include/hal/usb_phy_hal.h @@ -6,7 +6,8 @@ #pragma once -#include "usb_types_private.h" +#include +#include "usb_dwc_types.h" #include "usb_phy_types.h" #include "soc/soc_caps.h" #include "soc/usb_wrap_struct.h" @@ -66,7 +67,7 @@ void usb_phy_hal_int_load_conf_host(usb_phy_hal_context_t *hal); * @param hal Context of the HAL layer * @param speed USB speed */ -void usb_phy_hal_int_load_conf_dev(usb_phy_hal_context_t *hal, usb_priv_speed_t speed); +void usb_phy_hal_int_load_conf_dev(usb_phy_hal_context_t *hal, usb_phy_speed_t speed); /** * @brief Enable/Disable test mode for internal PHY to mimick host-device disconnection diff --git a/components/hal/usb_dwc_hal.c b/components/hal/usb_dwc_hal.c index 31a2695c5d..5ece143f52 100644 --- a/components/hal/usb_dwc_hal.c +++ b/components/hal/usb_dwc_hal.c @@ -193,7 +193,7 @@ static inline void debounce_lock_enable(usb_dwc_hal_context_t *hal) void usb_dwc_hal_port_enable(usb_dwc_hal_context_t *hal) { - usb_priv_speed_t speed = usb_dwc_ll_hprt_get_speed(hal->dev); + usb_dwc_speed_t speed = usb_dwc_ll_hprt_get_speed(hal->dev); //Host Configuration usb_dwc_ll_hcfg_set_defaults(hal->dev, speed); //Configure HFIR @@ -238,7 +238,7 @@ bool usb_dwc_hal_chan_alloc(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t *chan void usb_dwc_hal_chan_free(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t *chan_obj) { - if (chan_obj->type == USB_PRIV_XFER_TYPE_INTR || chan_obj->type == USB_PRIV_XFER_TYPE_ISOCHRONOUS) { + if (chan_obj->type == USB_DWC_XFER_TYPE_INTR || chan_obj->type == USB_DWC_XFER_TYPE_ISOCHRONOUS) { //Unschedule this channel for (int i = 0; i < hal->frame_list_len; i++) { hal->periodic_frame_list[i] &= ~(1 << chan_obj->flags.chan_idx); @@ -271,7 +271,7 @@ void usb_dwc_hal_chan_set_ep_char(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t //Save channel type chan_obj->type = ep_char->type; //If this is a periodic endpoint/channel, set its schedule in the frame list - if (ep_char->type == USB_PRIV_XFER_TYPE_ISOCHRONOUS || ep_char->type == USB_PRIV_XFER_TYPE_INTR) { + if (ep_char->type == USB_DWC_XFER_TYPE_ISOCHRONOUS || ep_char->type == USB_DWC_XFER_TYPE_INTR) { HAL_ASSERT((int)ep_char->periodic.interval <= (int)hal->frame_list_len); //Interval cannot exceed the length of the frame list //Find the effective offset in the frame list (in case the phase_offset_frames > interval) int offset = ep_char->periodic.phase_offset_frames % ep_char->periodic.interval; diff --git a/components/hal/usb_phy_hal.c b/components/hal/usb_phy_hal.c index ec24d08aa3..5a0f83bf7a 100644 --- a/components/hal/usb_phy_hal.c +++ b/components/hal/usb_phy_hal.c @@ -42,10 +42,10 @@ void usb_phy_hal_int_load_conf_host(usb_phy_hal_context_t *hal) usb_phy_ll_int_load_conf(hal->wrap_dev, false, true, false, true); } -void usb_phy_hal_int_load_conf_dev(usb_phy_hal_context_t *hal, usb_priv_speed_t speed) +void usb_phy_hal_int_load_conf_dev(usb_phy_hal_context_t *hal, usb_phy_speed_t speed) { // DEVICE - downstream - if (speed == USB_PRIV_SPEED_LOW) { + if (speed == USB_PHY_SPEED_LOW) { // LS: dm_pu = 1 usb_phy_ll_int_load_conf(hal->wrap_dev, false, false, true, false); } else { diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index 3e0aecf040..02947f38e5 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -16,7 +16,7 @@ #include "esp_err.h" #include "esp_log.h" #include "hal/usb_dwc_hal.h" -#include "hal/usb_types_private.h" +#include "hal/usb_dwc_types.h" #include "hcd.h" #include "usb_private.h" #include "usb/usb_types_ch9.h" @@ -373,7 +373,7 @@ static void _buffer_exec(pipe_t *pipe); */ static inline bool _buffer_check_done(pipe_t *pipe) { - if (pipe->ep_char.type != USB_PRIV_XFER_TYPE_CTRL) { + if (pipe->ep_char.type != USB_DWC_XFER_TYPE_CTRL) { return true; } // Only control transfers need to be continued @@ -731,12 +731,12 @@ static bool _internal_pipe_event_notify(pipe_t *pipe, bool from_isr) // ----------------- Interrupt Handlers -------------------- -static usb_speed_t speed_priv_to_public(usb_priv_speed_t priv) +static usb_speed_t get_usb_port_speed(usb_dwc_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; + case USB_DWC_SPEED_LOW: return USB_SPEED_LOW; + case USB_DWC_SPEED_FULL: return USB_SPEED_FULL; + case USB_DWC_SPEED_HIGH: return USB_SPEED_HIGH; default: abort(); } } @@ -766,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: { usb_dwc_hal_port_enable(port->hal); // Initialize remaining host port registers - port->speed = speed_priv_to_public(usb_dwc_hal_port_get_conn_speed(port->hal)); + port->speed = get_usb_port_speed(usb_dwc_hal_port_get_conn_speed(port->hal)); port->state = HCD_PORT_STATE_ENABLED; port->flags.conn_dev_ena = 1; // This was triggered by a command, so no event needs to be propagated. @@ -1407,7 +1407,7 @@ esp_err_t hcd_port_get_speed(hcd_port_handle_t port_hdl, usb_speed_t *speed) HCD_ENTER_CRITICAL(); // 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); - *speed = speed_priv_to_public(usb_dwc_hal_port_get_conn_speed(port->hal)); + *speed = get_usb_port_speed(usb_dwc_hal_port_get_conn_speed(port->hal)); HCD_EXIT_CRITICAL(); return ESP_OK; } @@ -1636,19 +1636,19 @@ static bool pipe_alloc_hcd_support_verification(const usb_ep_desc_t * ep_desc, c static void pipe_set_ep_char(const hcd_pipe_config_t *pipe_config, usb_transfer_type_t type, bool is_default_pipe, int pipe_idx, usb_speed_t port_speed, usb_dwc_hal_ep_char_t *ep_char) { // Initialize EP characteristics - usb_priv_xfer_type_t hal_xfer_type; + usb_dwc_xfer_type_t hal_xfer_type; switch (type) { case USB_TRANSFER_TYPE_CTRL: - hal_xfer_type = USB_PRIV_XFER_TYPE_CTRL; + hal_xfer_type = USB_DWC_XFER_TYPE_CTRL; break; case USB_TRANSFER_TYPE_ISOCHRONOUS: - hal_xfer_type = USB_PRIV_XFER_TYPE_ISOCHRONOUS; + hal_xfer_type = USB_DWC_XFER_TYPE_ISOCHRONOUS; break; case USB_TRANSFER_TYPE_BULK: - hal_xfer_type = USB_PRIV_XFER_TYPE_BULK; + hal_xfer_type = USB_DWC_XFER_TYPE_BULK; break; default: // USB_TRANSFER_TYPE_INTR - hal_xfer_type = USB_PRIV_XFER_TYPE_INTR; + hal_xfer_type = USB_DWC_XFER_TYPE_INTR; break; } ep_char->type = hal_xfer_type; @@ -1749,7 +1749,7 @@ static esp_err_t _pipe_cmd_flush(pipe_t *pipe) // URBs were never executed, Update the actual_num_bytes and status urb->transfer.actual_num_bytes = 0; urb->transfer.status = (canceled) ? USB_TRANSFER_STATUS_CANCELED : USB_TRANSFER_STATUS_NO_DEVICE; - if (pipe->ep_char.type == USB_PRIV_XFER_TYPE_ISOCHRONOUS) { + if (pipe->ep_char.type == USB_DWC_XFER_TYPE_ISOCHRONOUS) { // Update the URB's isoc packet descriptors as well for (int pkt_idx = 0; pkt_idx < urb->transfer.num_isoc_packets; pkt_idx++) { urb->transfer.isoc_packet_desc[pkt_idx].actual_num_bytes = 0; @@ -2198,11 +2198,11 @@ static void _buffer_fill(pipe_t *pipe) int mps = pipe->ep_char.mps; usb_transfer_t *transfer = &urb->transfer; switch (pipe->ep_char.type) { - case USB_PRIV_XFER_TYPE_CTRL: { + case USB_DWC_XFER_TYPE_CTRL: { _buffer_fill_ctrl(buffer_to_fill, transfer); break; } - case USB_PRIV_XFER_TYPE_ISOCHRONOUS: { + case USB_DWC_XFER_TYPE_ISOCHRONOUS: { uint32_t start_idx; if (pipe->multi_buffer_control.buffer_num_to_exec == 0) { // There are no more previously filled buffers to execute. We need to calculate a new start index based on HFNUM and the pipe's schedule @@ -2228,11 +2228,11 @@ static void _buffer_fill(pipe_t *pipe) _buffer_fill_isoc(buffer_to_fill, transfer, is_in, mps, (int)pipe->ep_char.periodic.interval, start_idx); break; } - case USB_PRIV_XFER_TYPE_BULK: { + case USB_DWC_XFER_TYPE_BULK: { _buffer_fill_bulk(buffer_to_fill, transfer, is_in, mps); break; } - case USB_PRIV_XFER_TYPE_INTR: { + case USB_DWC_XFER_TYPE_INTR: { _buffer_fill_intr(buffer_to_fill, transfer, is_in, mps); break; } @@ -2258,7 +2258,7 @@ static void _buffer_exec(pipe_t *pipe) uint32_t start_idx; int desc_list_len; switch (pipe->ep_char.type) { - case USB_PRIV_XFER_TYPE_CTRL: { + case USB_DWC_XFER_TYPE_CTRL: { start_idx = 0; desc_list_len = XFER_LIST_LEN_CTRL; // Set the channel's direction to OUT and PID to 0 respectively for the the setup stage @@ -2266,17 +2266,17 @@ static void _buffer_exec(pipe_t *pipe) usb_dwc_hal_chan_set_pid(pipe->chan_obj, 0); // Setup stage always has a PID of DATA0 break; } - case USB_PRIV_XFER_TYPE_ISOCHRONOUS: { + case USB_DWC_XFER_TYPE_ISOCHRONOUS: { start_idx = buffer_to_exec->flags.isoc.start_idx; desc_list_len = XFER_LIST_LEN_ISOC; break; } - case USB_PRIV_XFER_TYPE_BULK: { + case USB_DWC_XFER_TYPE_BULK: { start_idx = 0; desc_list_len = (buffer_to_exec->flags.bulk.zero_len_packet) ? XFER_LIST_LEN_BULK : 1; break; } - case USB_PRIV_XFER_TYPE_INTR: { + case USB_DWC_XFER_TYPE_INTR: { start_idx = 0; desc_list_len = (buffer_to_exec->flags.intr.zero_len_packet) ? buffer_to_exec->flags.intr.num_qtds + 1 : buffer_to_exec->flags.intr.num_qtds; break; @@ -2297,7 +2297,7 @@ static void _buffer_exec(pipe_t *pipe) static void _buffer_exec_cont(pipe_t *pipe) { // This should only ever be called on control transfers - assert(pipe->ep_char.type == USB_PRIV_XFER_TYPE_CTRL); + assert(pipe->ep_char.type == USB_DWC_XFER_TYPE_CTRL); dma_buffer_block_t *buffer_inflight = pipe->buffers[pipe->multi_buffer_control.rd_idx]; bool next_dir_is_in; int next_pid; @@ -2481,19 +2481,19 @@ static void _buffer_parse(pipe_t *pipe) if (buffer_to_parse->status_flags.pipe_event == HCD_PIPE_EVENT_URB_DONE) { // URB was successful switch (pipe->ep_char.type) { - case USB_PRIV_XFER_TYPE_CTRL: { + case USB_DWC_XFER_TYPE_CTRL: { _buffer_parse_ctrl(buffer_to_parse); break; } - case USB_PRIV_XFER_TYPE_ISOCHRONOUS: { + case USB_DWC_XFER_TYPE_ISOCHRONOUS: { _buffer_parse_isoc(buffer_to_parse, is_in); break; } - case USB_PRIV_XFER_TYPE_BULK: { + case USB_DWC_XFER_TYPE_BULK: { _buffer_parse_bulk(buffer_to_parse); break; } - case USB_PRIV_XFER_TYPE_INTR: { + case USB_DWC_XFER_TYPE_INTR: { _buffer_parse_intr(buffer_to_parse, is_in, mps); break; } diff --git a/components/usb/usb_phy.c b/components/usb/usb_phy.c index 492a7e7e22..6b18161643 100644 --- a/components/usb/usb_phy.c +++ b/components/usb/usb_phy.c @@ -141,14 +141,7 @@ 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"); handle->otg_speed = speed; - usb_priv_speed_t hal_speed; - switch (speed) { - case USB_PHY_SPEED_LOW: hal_speed = USB_PRIV_SPEED_LOW; break; - case USB_PHY_SPEED_FULL: hal_speed = USB_PRIV_SPEED_FULL; break; - 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), speed); return ESP_OK; } From cb4e90ca6ee1366a0f923e811b035a32a4f9d224 Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Wed, 29 Nov 2023 20:11:28 +0800 Subject: [PATCH 3/3] refactor(usb/host): Move FIFO size configuration to HAL layer The logic of calculating FIFO sizes is DWC OTG specific. We move it to the HAL layer to provide better abstraction in the HDC layer. --- components/hal/include/hal/usb_dwc_hal.h | 49 ++++++-- components/hal/include/hal/usb_dwc_ll.h | 61 ++++++++++ components/hal/usb_dwc_hal.c | 58 ++++++++- components/usb/hcd_dwc.c | 143 +++++------------------ 4 files changed, 187 insertions(+), 124 deletions(-) diff --git a/components/hal/include/hal/usb_dwc_hal.h b/components/hal/include/hal/usb_dwc_hal.h index aee866e7ea..57e3776ae0 100644 --- a/components/hal/include/hal/usb_dwc_hal.h +++ b/components/hal/include/hal/usb_dwc_hal.h @@ -28,6 +28,30 @@ NOTE: Thread safety is the responsibility fo the HAL user. All USB Host HAL // ----------------------- Configs ------------------------- +/** + * @brief Possible FIFO biases + */ +typedef enum { + USB_HAL_FIFO_BIAS_DEFAULT, /**< Default (balanced) FIFO sizes */ + USB_HAL_FIFO_BIAS_RX, /**< Bigger RX FIFO for IN transfers */ + USB_HAL_FIFO_BIAS_PTX, /**< Bigger periodic TX FIFO for ISOC OUT transfers */ +} usb_hal_fifo_bias_t; + +/** + * @brief MPS limits based on FIFO configuration + * + * In bytes + * + * The resulting values depend on + * 1. FIFO total size (chip specific) + * 2. Set FIFO bias + */ +typedef struct { + unsigned int in_mps; /**< Maximum packet size of IN packet */ + unsigned int non_periodic_out_mps; /**< Maximum packet size of BULK and CTRL OUT packets */ + unsigned int periodic_out_mps; /**< Maximum packet size of INTR and ISOC OUT packets */ +} usb_hal_fifo_mps_limits_t; + /** * @brief FIFO size configuration structure */ @@ -148,8 +172,10 @@ typedef struct { //Context usb_dwc_dev_t *dev; /**< Pointer to base address of DWC_OTG registers */ //Host Port related - uint32_t *periodic_frame_list; /**< Pointer to scheduling frame list */ - usb_hal_frame_list_len_t frame_list_len; /**< Length of the periodic scheduling frame list */ + uint32_t *periodic_frame_list; /**< Pointer to scheduling frame list */ + usb_hal_frame_list_len_t frame_list_len; /**< Length of the periodic scheduling frame list */ + //FIFO related + const usb_dwc_hal_fifo_config_t *fifo_config; /**< FIFO sizes configuration */ union { struct { uint32_t dbnc_lock_enabled: 1; /**< Debounce lock enabled */ @@ -218,21 +244,28 @@ void usb_dwc_hal_deinit(usb_dwc_hal_context_t *hal); void usb_dwc_hal_core_soft_reset(usb_dwc_hal_context_t *hal); /** - * @brief Set FIFO sizes + * @brief Set FIFO bias * * This function will set the sizes of each of the FIFOs (RX FIFO, Non-periodic TX FIFO, Periodic TX FIFO) and must be - * called at least once before allocating the channel. Based on the type of endpoints (and the endpionts' MPS), there + * called at least once before allocating the channel. Based on the type of endpoints (and the endpoints' MPS), there * may be situations where this function may need to be called again to resize the FIFOs. If resizing FIFOs dynamically, * it is the user's responsibility to ensure there are no active channels when this function is called. * - * @note The totol size of all the FIFOs must be less than or equal to USB_DWC_FIFO_TOTAL_USABLE_LINES * @note After a port reset, the FIFO size registers will reset to their default values, so this function must be called * again post reset. * - * @param hal Context of the HAL layer - * @param fifo_config FIFO configuration + * @param[in] hal Context of the HAL layer + * @param[in] fifo_bias FIFO bias configuration */ -void usb_dwc_hal_set_fifo_size(usb_dwc_hal_context_t *hal, const usb_dwc_hal_fifo_config_t *fifo_config); +void usb_dwc_hal_set_fifo_bias(usb_dwc_hal_context_t *hal, const usb_hal_fifo_bias_t fifo_bias); + +/** + * @brief Get MPS limits + * + * @param[in] hal Context of the HAL layer + * @param[out] mps_limits MPS limits + */ +void usb_dwc_hal_get_mps_limits(usb_dwc_hal_context_t *hal, usb_hal_fifo_mps_limits_t *mps_limits); // ---------------------------------------------------- Host Port ------------------------------------------------------ diff --git a/components/hal/include/hal/usb_dwc_ll.h b/components/hal/include/hal/usb_dwc_ll.h index 1f4aef5e7e..315924a349 100644 --- a/components/hal/include/hal/usb_dwc_ll.h +++ b/components/hal/include/hal/usb_dwc_ll.h @@ -33,6 +33,67 @@ Todo: Check sizes again and express this macro in terms of DWC config options (I ------------------------------ DWC Configuration ------------------------------- ----------------------------------------------------------------------------- */ +/** + * @brief Default FIFO sizes (see 2.1.2.4 for programming guide) + * + * RXFIFO + * - Recommended: ((LPS/4) * 2) + 2 + * - Actual: Whatever leftover size: USB_DWC_FIFO_TOTAL_USABLE_LINES(200) - 48 - 48 = 104 + * - Worst case can accommodate two packets of 204 bytes, or one packet of 408 + * NPTXFIFO + * - Recommended: (LPS/4) * 2 + * - Actual: Assume LPS is 64, and 3 packets: (64/4) * 3 = 48 + * - Worst case can accommodate three packets of 64 bytes or one packet of 192 + * PTXFIFO + * - Recommended: (LPS/4) * 2 + * - Actual: Assume LPS is 64, and 3 packets: (64/4) * 3 = 48 + * - Worst case can accommodate three packets of 64 bytes or one packet of 192 + */ +#define USB_DWC_FIFO_RX_LINES_DEFAULT 104 +#define USB_DWC_FIFO_NPTX_LINES_DEFAULT 48 +#define USB_DWC_FIFO_PTX_LINES_DEFAULT 48 + +/** + * @brief FIFO sizes that bias to giving RX FIFO more capacity + * + * RXFIFO + * - Recommended: ((LPS/4) * 2) + 2 + * - Actual: Whatever leftover size: USB_DWC_FIFO_TOTAL_USABLE_LINES(200) - 32 - 16 = 152 + * - Worst case can accommodate two packets of 300 bytes or one packet of 600 bytes + * NPTXFIFO + * - Recommended: (LPS/4) * 2 + * - Actual: Assume LPS is 64, and 1 packets: (64/4) * 1 = 16 + * - Worst case can accommodate one packet of 64 bytes + * PTXFIFO + * - Recommended: (LPS/4) * 2 + * - Actual: Assume LPS is 64, and 3 packets: (64/4) * 2 = 32 + * - Worst case can accommodate two packets of 64 bytes or one packet of 128 + */ +#define USB_DWC_FIFO_RX_LINES_BIASRX 152 +#define USB_DWC_FIFO_NPTX_LINES_BIASRX 16 +#define USB_DWC_FIFO_PTX_LINES_BIASRX 32 + +/** + * @brief FIFO sizes that bias to giving Periodic TX FIFO more capacity (i.e., ISOC OUT) + * + * RXFIFO + * - Recommended: ((LPS/4) * 2) + 2 + * - Actual: Assume LPS is 64, and 2 packets: ((64/4) * 2) + 2 = 34 + * - Worst case can accommodate two packets of 64 bytes or one packet of 128 + * NPTXFIFO + * - Recommended: (LPS/4) * 2 + * - Actual: Assume LPS is 64, and 1 packets: (64/4) * 1 = 16 + * - Worst case can accommodate one packet of 64 bytes + * PTXFIFO + * - Recommended: (LPS/4) * 2 + * - Actual: Whatever leftover size: USB_DWC_FIFO_TOTAL_USABLE_LINES(200) - 34 - 16 = 150 + * - Worst case can accommodate two packets of 300 bytes or one packet of 600 bytes + */ +#define USB_DWC_FIFO_RX_LINES_BIASTX 34 +#define USB_DWC_FIFO_NPTX_LINES_BIASTX 16 +#define USB_DWC_FIFO_PTX_LINES_BIASTX 150 + + /* * List of relevant DWC configurations. See DWC OTG databook Chapter 3 for more * details. diff --git a/components/hal/usb_dwc_hal.c b/components/hal/usb_dwc_hal.c index 5ece143f52..b9c9baf6db 100644 --- a/components/hal/usb_dwc_hal.c +++ b/components/hal/usb_dwc_hal.c @@ -27,6 +27,35 @@ #define CORE_REG_GHWCFG3 0x00C804B5 #define CORE_REG_GHWCFG4 0xD3F0A030 +// ----------------------- Configs ------------------------- + +/** + * @brief Default FIFO sizes (see 2.1.2.4 for programming guide) + */ +const usb_dwc_hal_fifo_config_t fifo_config_default = { + .rx_fifo_lines = USB_DWC_FIFO_RX_LINES_DEFAULT, + .nptx_fifo_lines = USB_DWC_FIFO_NPTX_LINES_DEFAULT, + .ptx_fifo_lines = USB_DWC_FIFO_PTX_LINES_DEFAULT, +}; + +/** + * @brief FIFO sizes that bias to giving RX FIFO more capacity + */ +const usb_dwc_hal_fifo_config_t fifo_config_bias_rx = { + .rx_fifo_lines = USB_DWC_FIFO_RX_LINES_BIASRX, + .nptx_fifo_lines = USB_DWC_FIFO_NPTX_LINES_BIASRX, + .ptx_fifo_lines = USB_DWC_FIFO_PTX_LINES_BIASRX, +}; + +/** + * @brief FIFO sizes that bias to giving Periodic TX FIFO more capacity (i.e., ISOC OUT) + */ +const usb_dwc_hal_fifo_config_t fifo_config_bias_ptx = { + .rx_fifo_lines = USB_DWC_FIFO_RX_LINES_BIASTX, + .nptx_fifo_lines = USB_DWC_FIFO_NPTX_LINES_BIASTX, + .ptx_fifo_lines = USB_DWC_FIFO_PTX_LINES_BIASTX, +}; + // -------------------- Configurable ----------------------- /** @@ -162,8 +191,23 @@ void usb_dwc_hal_core_soft_reset(usb_dwc_hal_context_t *hal) memset(hal->channels.hdls, 0, sizeof(usb_dwc_hal_chan_t *) * USB_DWC_NUM_HOST_CHAN); } -void usb_dwc_hal_set_fifo_size(usb_dwc_hal_context_t *hal, const usb_dwc_hal_fifo_config_t *fifo_config) +void usb_dwc_hal_set_fifo_bias(usb_dwc_hal_context_t *hal, const usb_hal_fifo_bias_t fifo_bias) { + const usb_dwc_hal_fifo_config_t *fifo_config; + switch (fifo_bias) { + case USB_HAL_FIFO_BIAS_DEFAULT: + fifo_config = &fifo_config_default; + break; + case USB_HAL_FIFO_BIAS_RX: + fifo_config = &fifo_config_bias_rx; + break; + case USB_HAL_FIFO_BIAS_PTX: + fifo_config = &fifo_config_bias_ptx; + break; + default: + abort(); + } + HAL_ASSERT((fifo_config->rx_fifo_lines + fifo_config->nptx_fifo_lines + fifo_config->ptx_fifo_lines) <= USB_DWC_FIFO_TOTAL_USABLE_LINES); //Check that none of the channels are active for (int i = 0; i < USB_DWC_NUM_HOST_CHAN; i++) { @@ -179,9 +223,21 @@ void usb_dwc_hal_set_fifo_size(usb_dwc_hal_context_t *hal, const usb_dwc_hal_fif usb_dwc_ll_grstctl_flush_nptx_fifo(hal->dev); usb_dwc_ll_grstctl_flush_ptx_fifo(hal->dev); usb_dwc_ll_grstctl_flush_rx_fifo(hal->dev); + hal->fifo_config = fifo_config; hal->flags.fifo_sizes_set = 1; } +void usb_dwc_hal_get_mps_limits(usb_dwc_hal_context_t *hal, usb_hal_fifo_mps_limits_t *mps_limits) +{ + HAL_ASSERT(hal && mps_limits); + HAL_ASSERT(hal->flags.fifo_sizes_set); + + const usb_dwc_hal_fifo_config_t *fifo_config = hal->fifo_config; + mps_limits->in_mps = (fifo_config->rx_fifo_lines - 2) * 4; // Two lines are reserved for status quadlets internally by USB_DWC + mps_limits->non_periodic_out_mps = fifo_config->nptx_fifo_lines * 4; + mps_limits->periodic_out_mps = fifo_config->ptx_fifo_lines * 4; +} + // ---------------------------------------------------- Host Port ------------------------------------------------------ static inline void debounce_lock_enable(usb_dwc_hal_context_t *hal) diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index 02947f38e5..41586ea8ee 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -39,72 +39,6 @@ // ----------------------- Configs ------------------------- -/** - * @brief Default FIFO sizes (see 2.1.2.4 for programming guide) - * - * RXFIFO - * - Recommended: ((LPS/4) * 2) + 2 - * - Actual: Whatever leftover size: USB_DWC_FIFO_TOTAL_USABLE_LINES(200) - 48 - 48 = 104 - * - Worst case can accommodate two packets of 204 bytes, or one packet of 408 - * NPTXFIFO - * - Recommended: (LPS/4) * 2 - * - Actual: Assume LPS is 64, and 3 packets: (64/4) * 3 = 48 - * - Worst case can accommodate three packets of 64 bytes or one packet of 192 - * PTXFIFO - * - Recommended: (LPS/4) * 2 - * - Actual: Assume LPS is 64, and 3 packets: (64/4) * 3 = 48 - * - Worst case can accommodate three packets of 64 bytes or one packet of 192 - */ -const usb_dwc_hal_fifo_config_t fifo_config_default = { - .rx_fifo_lines = 104, - .nptx_fifo_lines = 48, - .ptx_fifo_lines = 48, -}; - -/** - * @brief FIFO sizes that bias to giving RX FIFO more capacity - * - * RXFIFO - * - Recommended: ((LPS/4) * 2) + 2 - * - Actual: Whatever leftover size: USB_DWC_FIFO_TOTAL_USABLE_LINES(200) - 32 - 16 = 152 - * - Worst case can accommodate two packets of 300 bytes or one packet of 600 bytes - * NPTXFIFO - * - Recommended: (LPS/4) * 2 - * - Actual: Assume LPS is 64, and 1 packets: (64/4) * 1 = 16 - * - Worst case can accommodate one packet of 64 bytes - * PTXFIFO - * - Recommended: (LPS/4) * 2 - * - Actual: Assume LPS is 64, and 3 packets: (64/4) * 2 = 32 - * - Worst case can accommodate two packets of 64 bytes or one packet of 128 - */ -const usb_dwc_hal_fifo_config_t fifo_config_bias_rx = { - .rx_fifo_lines = 152, - .nptx_fifo_lines = 16, - .ptx_fifo_lines = 32, -}; - -/** - * @brief FIFO sizes that bias to giving Periodic TX FIFO more capacity (i.e., ISOC OUT) - * - * RXFIFO - * - Recommended: ((LPS/4) * 2) + 2 - * - Actual: Assume LPS is 64, and 2 packets: ((64/4) * 2) + 2 = 34 - * - Worst case can accommodate two packets of 64 bytes or one packet of 128 - * NPTXFIFO - * - Recommended: (LPS/4) * 2 - * - Actual: Assume LPS is 64, and 1 packets: (64/4) * 1 = 16 - * - Worst case can accommodate one packet of 64 bytes - * PTXFIFO - * - Recommended: (LPS/4) * 2 - * - Actual: Whatever leftover size: USB_DWC_FIFO_TOTAL_USABLE_LINES(200) - 34 - 16 = 150 - * - Worst case can accommodate two packets of 300 bytes or one packet of 600 bytes - */ -const usb_dwc_hal_fifo_config_t fifo_config_bias_ptx = { - .rx_fifo_lines = 34, - .nptx_fifo_lines = 16, - .ptx_fifo_lines = 150, -}; - #define FRAME_LIST_LEN USB_HAL_FRAME_LIST_LEN_32 #define NUM_BUFFERS 2 @@ -280,7 +214,7 @@ struct port_obj { } flags; bool initialized; // FIFO biasing related - const usb_dwc_hal_fifo_config_t *fifo_config; + usb_hal_fifo_bias_t fifo_bias; // Bias is saved so it can be reconfigured upon reset // Port callback and context hcd_port_callback_t callback; void *callback_arg; @@ -729,7 +663,7 @@ static bool _internal_pipe_event_notify(pipe_t *pipe, bool from_isr) return ret; } -// ----------------- Interrupt Handlers -------------------- +// ----------------- HAL <-> USB helpers -------------------- static usb_speed_t get_usb_port_speed(usb_dwc_speed_t priv) { @@ -741,6 +675,18 @@ static usb_speed_t get_usb_port_speed(usb_dwc_speed_t priv) } } +static usb_hal_fifo_bias_t get_hal_fifo_bias(hcd_port_fifo_bias_t public) +{ + switch (public) { + case HCD_PORT_FIFO_BIAS_BALANCED: return USB_HAL_FIFO_BIAS_DEFAULT; + case HCD_PORT_FIFO_BIAS_RX: return USB_HAL_FIFO_BIAS_RX; + case HCD_PORT_FIFO_BIAS_PTX: return USB_HAL_FIFO_BIAS_PTX; + default: abort(); + } +} + +// ----------------- Interrupt Handlers -------------------- + /** * @brief Handle a HAL port interrupt and obtain the corresponding port event * @@ -1192,7 +1138,7 @@ static esp_err_t _port_cmd_reset(port_t *port) goto bailout; } // Set FIFO sizes based on the selected biasing - usb_dwc_hal_set_fifo_size(port->hal, port->fifo_config); + usb_dwc_hal_set_fifo_bias(port->hal, port->fifo_bias); // We start periodic scheduling only after a RESET command since SOFs only start after a reset usb_dwc_hal_port_set_frame_list(port->hal, port->frame_list, FRAME_LIST_LEN); usb_dwc_hal_port_periodic_enable(port->hal); @@ -1289,24 +1235,6 @@ esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, h HCD_CHECK(port_number > 0 && port_config != NULL && port_hdl != NULL, ESP_ERR_INVALID_ARG); HCD_CHECK(port_number <= NUM_PORTS, ESP_ERR_NOT_FOUND); - // Get a pointer to the correct FIFO bias constant values - const usb_dwc_hal_fifo_config_t *fifo_config; - switch (port_config->fifo_bias) { - case HCD_PORT_FIFO_BIAS_BALANCED: - fifo_config = &fifo_config_default; - break; - case HCD_PORT_FIFO_BIAS_RX: - fifo_config = &fifo_config_bias_rx; - break; - case HCD_PORT_FIFO_BIAS_PTX: - fifo_config = &fifo_config_bias_ptx; - break; - default: - fifo_config = NULL; - abort(); - break; - } - HCD_ENTER_CRITICAL(); HCD_CHECK_FROM_CRIT(s_hcd_obj != NULL && !s_hcd_obj->port_obj->initialized, ESP_ERR_INVALID_STATE); // Port object memory and resources (such as the mutex) already be allocated. Just need to initialize necessary fields only @@ -1315,7 +1243,7 @@ esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, h TAILQ_INIT(&port_obj->pipes_active_tailq); port_obj->state = HCD_PORT_STATE_NOT_POWERED; port_obj->last_event = HCD_PORT_EVENT_NONE; - port_obj->fifo_config = fifo_config; + port_obj->fifo_bias = get_hal_fifo_bias(port_config->fifo_bias); port_obj->callback = port_config->callback; port_obj->callback_arg = port_config->callback_arg; port_obj->context = port_config->context; @@ -1483,31 +1411,16 @@ void *hcd_port_get_context(hcd_port_handle_t port_hdl) esp_err_t hcd_port_set_fifo_bias(hcd_port_handle_t port_hdl, hcd_port_fifo_bias_t bias) { esp_err_t ret; - // Get a pointer to the correct FIFO bias constant values - const usb_dwc_hal_fifo_config_t *fifo_config; - switch (bias) { - case HCD_PORT_FIFO_BIAS_BALANCED: - fifo_config = &fifo_config_default; - break; - case HCD_PORT_FIFO_BIAS_RX: - fifo_config = &fifo_config_bias_rx; - break; - case HCD_PORT_FIFO_BIAS_PTX: - fifo_config = &fifo_config_bias_ptx; - break; - default: - fifo_config = NULL; - abort(); - break; - } + usb_hal_fifo_bias_t hal_bias = get_hal_fifo_bias(bias); + // Configure the new FIFO sizes and store the pointers port_t *port = (port_t *)port_hdl; xSemaphoreTake(port->port_mux, portMAX_DELAY); HCD_ENTER_CRITICAL(); // Check that port is in the correct state to update FIFO sizes 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); - port->fifo_config = fifo_config; + usb_dwc_hal_set_fifo_bias(port->hal, hal_bias); + port->fifo_bias = hal_bias; ret = ESP_OK; } else { ret = ESP_ERR_INVALID_STATE; @@ -1594,13 +1507,13 @@ static bool pipe_args_usb_compliance_verification(const hcd_pipe_config_t *pipe_ return true; } -static bool pipe_alloc_hcd_support_verification(const usb_ep_desc_t * ep_desc, const usb_dwc_hal_fifo_config_t *fifo_config) +static bool pipe_alloc_hcd_support_verification(usb_dwc_hal_context_t *hal, const usb_ep_desc_t * ep_desc) { + assert(hal != NULL); assert(ep_desc != NULL); - 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; + usb_hal_fifo_mps_limits_t mps_limits = {0}; + usb_dwc_hal_get_mps_limits(hal, &mps_limits); const usb_transfer_type_t type = USB_EP_DESC_GET_XFERTYPE(ep_desc); // Check the pipe's interval is not zero @@ -1614,12 +1527,12 @@ static bool pipe_alloc_hcd_support_verification(const usb_ep_desc_t * ep_desc, c // Check if pipe MPS exceeds HCD MPS limits (due to DWC FIFO sizing) int limit; if (USB_EP_DESC_GET_EP_DIR(ep_desc)) { // IN - limit = limit_in_mps; + limit = mps_limits.in_mps; } else { // OUT if (type == USB_TRANSFER_TYPE_CTRL || type == USB_TRANSFER_TYPE_BULK) { - limit = limit_non_periodic_out_mps; + limit = mps_limits.non_periodic_out_mps; } else { - limit = limit_periodic_out_mps; + limit = mps_limits.periodic_out_mps; } } @@ -1829,7 +1742,7 @@ esp_err_t hcd_pipe_alloc(hcd_port_handle_t port_hdl, const hcd_pipe_config_t *pi return ESP_ERR_NOT_SUPPORTED; } // 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, port->fifo_config)) { + if (!is_default && !pipe_alloc_hcd_support_verification(port->hal, pipe_config->ep_desc)) { return ESP_ERR_NOT_SUPPORTED; } // Allocate the pipe resources