diff --git a/components/hal/include/hal/usb_dwc_hal.h b/components/hal/include/hal/usb_dwc_hal.h index fb8bba0873..03ab8736da 100644 --- a/components/hal/include/hal/usb_dwc_hal.h +++ b/components/hal/include/hal/usb_dwc_hal.h @@ -31,6 +31,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 */ @@ -151,8 +175,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 */ @@ -221,21 +247,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 15de7a52ac..5c3934e609 100644 --- a/components/hal/include/hal/usb_dwc_ll.h +++ b/components/hal/include/hal/usb_dwc_ll.h @@ -36,6 +36,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