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.
This commit is contained in:
Tomas Rezucha 2023-11-29 20:11:28 +08:00
parent 325205faee
commit cb4e90ca6e
4 changed files with 187 additions and 124 deletions

View File

@ -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 ------------------------------------------------------

View File

@ -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.

View File

@ -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)

View File

@ -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