Merge branch 'refactor/cleanup_usb_phy_backport_v5.4' into 'release/v5.4'

fix(usb/host): Fix reaction on High-Speed NYET packet (backport v5.4)

See merge request espressif/esp-idf!36119
This commit is contained in:
morris 2025-01-08 10:22:50 +08:00
commit cfc878a650
4 changed files with 71 additions and 92 deletions

View File

@ -790,23 +790,33 @@ static inline void usb_dwc_ll_hctsiz_set_qtd_list_len(volatile usb_dwc_host_chan
chan->hctsiz_reg.val = hctsiz.val;
}
static inline void usb_dwc_ll_hctsiz_init(volatile usb_dwc_host_chan_regs_t *chan)
/**
* @brief Perform PING protocol
*
* PING protocol is automatically enabled if High-Speed device responds with NYET in Scatter-Gather DMA mode.
* The application must disable PING for next transfer.
* Relevant only for OUT transfers.
*
* @param[in] chan Channel registers
* @param[in] enable true: Enable PING, false: Disable PING
*/
static inline void usb_dwc_ll_hctsiz_set_dopng(volatile usb_dwc_host_chan_regs_t *chan, bool enable)
{
usb_dwc_hctsiz_reg_t hctsiz;
hctsiz.val = chan->hctsiz_reg.val;
hctsiz.dopng = 0; //Don't do ping
/*
Set SCHED_INFO which occupies xfersize[7:0]
It is always set to 0xFF for full speed and not used in Bulk/Ctrl channels
*/
hctsiz.xfersize |= 0xFF;
chan->hctsiz_reg.val = hctsiz.val;
chan->hctsiz_reg.dopng = (uint32_t)(enable && !chan->hcchar_reg.epdir);
}
/**
* @brief Set scheduling info for Periodic channel
*
* @attention This function must be called for each periodic channel!
* @see USB-OTG databook: Table 5-47
*
* @param[in] chan Channel registers
* @param[in] tokens_per_frame HS: Number of tokens per frame FS: Must be set 8
* @param[in] offset Offset of the channel
*/
static inline void usb_dwc_ll_hctsiz_set_sched_info(volatile usb_dwc_host_chan_regs_t *chan, int tokens_per_frame, int offset)
{
// @see USB-OTG databook: Table 5-47
// This function is relevant only for HS
usb_dwc_hctsiz_reg_t hctsiz;
hctsiz.val = chan->hctsiz_reg.val;
uint8_t sched_info_val;

View File

@ -791,50 +791,33 @@ static inline void usb_dwc_ll_hctsiz_set_qtd_list_len(volatile usb_dwc_host_chan
chan->hctsiz_reg.val = hctsiz.val;
}
static inline void usb_dwc_ll_hctsiz_init(volatile usb_dwc_host_chan_regs_t *chan)
/**
* @brief Perform PING protocol
*
* @note This function is here only for compatibility reasons. PING is not relevant on FS only targets
* @param[in] chan Channel registers
* @param[in] enable true: Enable PING, false: Disable PING
*/
static inline void usb_dwc_ll_hctsiz_set_dopng(volatile usb_dwc_host_chan_regs_t *chan, bool enable)
{
usb_dwc_hctsiz_reg_t hctsiz;
hctsiz.val = chan->hctsiz_reg.val;
hctsiz.dopng = 0; //Don't do ping
/*
Set SCHED_INFO which occupies xfersize[7:0]
It is always set to 0xFF for full speed and not used in Bulk/Ctrl channels
*/
hctsiz.xfersize |= 0xFF;
chan->hctsiz_reg.val = hctsiz.val;
}
/**
* @brief Set scheduling info for Periodic channel
*
* @note ESP32-S2 is Full-Speed only, so SCHED_INFO is always set to 0xFF
* @attention This function must be called for each periodic channel!
* @see USB-OTG databook: Table 5-47
*
* @param[in] chan Channel registers
* @param[in] tokens_per_frame Ignored
* @param[in] offset Ignored
*/
static inline void usb_dwc_ll_hctsiz_set_sched_info(volatile usb_dwc_host_chan_regs_t *chan, int tokens_per_frame, int offset)
{
// @see USB-OTG databook: Table 5-47
// This function is relevant only for HS
usb_dwc_hctsiz_reg_t hctsiz;
hctsiz.val = chan->hctsiz_reg.val;
uint8_t sched_info_val;
switch (tokens_per_frame) {
case 1:
offset %= 8; // If the required offset > 8, we must wrap around to SCHED_INFO size = 8
sched_info_val = 0b00000001;
break;
case 2:
offset %= 4;
sched_info_val = 0b00010001;
break;
case 4:
offset %= 2;
sched_info_val = 0b01010101;
break;
case 8:
offset = 0;
sched_info_val = 0b11111111;
break;
default:
abort();
break;
}
sched_info_val <<= offset;
hctsiz.xfersize &= ~(0xFF);
hctsiz.xfersize |= sched_info_val;
hctsiz.xfersize |= 0xFF;
chan->hctsiz_reg.val = hctsiz.val;
}

View File

@ -791,50 +791,33 @@ static inline void usb_dwc_ll_hctsiz_set_qtd_list_len(volatile usb_dwc_host_chan
chan->hctsiz_reg.val = hctsiz.val;
}
static inline void usb_dwc_ll_hctsiz_init(volatile usb_dwc_host_chan_regs_t *chan)
/**
* @brief Perform PING protocol
*
* @note This function is here only for compatibility reasons. PING is not relevant on FS only targets
* @param[in] chan Channel registers
* @param[in] enable true: Enable PING, false: Disable PING
*/
static inline void usb_dwc_ll_hctsiz_set_dopng(volatile usb_dwc_host_chan_regs_t *chan, bool enable)
{
usb_dwc_hctsiz_reg_t hctsiz;
hctsiz.val = chan->hctsiz_reg.val;
hctsiz.dopng = 0; //Don't do ping
/*
Set SCHED_INFO which occupies xfersize[7:0]
It is always set to 0xFF for full speed and not used in Bulk/Ctrl channels
*/
hctsiz.xfersize |= 0xFF;
chan->hctsiz_reg.val = hctsiz.val;
}
/**
* @brief Set scheduling info for Periodic channel
*
* @note ESP32-S3 is Full-Speed only, so SCHED_INFO is always set to 0xFF
* @attention This function must be called for each periodic channel!
* @see USB-OTG databook: Table 5-47
*
* @param[in] chan Channel registers
* @param[in] tokens_per_frame Ignored
* @param[in] offset Ignored
*/
static inline void usb_dwc_ll_hctsiz_set_sched_info(volatile usb_dwc_host_chan_regs_t *chan, int tokens_per_frame, int offset)
{
// @see USB-OTG databook: Table 5-47
// This function is relevant only for HS
usb_dwc_hctsiz_reg_t hctsiz;
hctsiz.val = chan->hctsiz_reg.val;
uint8_t sched_info_val;
switch (tokens_per_frame) {
case 1:
offset %= 8; // If the required offset > 8, we must wrap around to SCHED_INFO size = 8
sched_info_val = 0b00000001;
break;
case 2:
offset %= 4;
sched_info_val = 0b00010001;
break;
case 4:
offset %= 2;
sched_info_val = 0b01010101;
break;
case 8:
offset = 0;
sched_info_val = 0b11111111;
break;
default:
abort();
break;
}
sched_info_val <<= offset;
hctsiz.xfersize &= ~(0xFF);
hctsiz.xfersize |= sched_info_val;
hctsiz.xfersize |= 0xFF;
chan->hctsiz_reg.val = hctsiz.val;
}

View File

@ -312,7 +312,6 @@ bool usb_dwc_hal_chan_alloc(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t *chan
usb_dwc_ll_haintmsk_en_chan_intr(hal->dev, 1 << chan_obj->flags.chan_idx);
usb_dwc_ll_hcintmsk_set_intr_mask(chan_obj->regs, CHAN_INTRS_EN_MSK); //Unmask interrupts for this channel
usb_dwc_ll_hctsiz_set_pid(chan_obj->regs, 0); //Set the initial PID to zero
usb_dwc_ll_hctsiz_init(chan_obj->regs); //Set the non changing parts of the HCTSIZ registers (e.g., do_ping and sched info)
return true;
}
@ -383,8 +382,10 @@ void usb_dwc_hal_chan_set_ep_char(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t
hal->periodic_frame_list[index] |= 1 << chan_obj->flags.chan_idx;
}
// For HS endpoints we must write to sched_info field of HCTSIZ register to schedule microframes
// For FS endpoints sched_info is always 0xFF
// LS endpoints do not support periodic transfers
unsigned int tokens_per_frame = 0;
if (ep_char->periodic.is_hs) {
unsigned int tokens_per_frame;
if (ep_char->periodic.interval >= 8) {
tokens_per_frame = 1; // 1 token every 8 microframes
} else if (ep_char->periodic.interval >= 4) {
@ -394,8 +395,8 @@ void usb_dwc_hal_chan_set_ep_char(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t
} else {
tokens_per_frame = 8; // 1 token every microframe
}
usb_dwc_ll_hctsiz_set_sched_info(chan_obj->regs, tokens_per_frame, ep_char->periodic.offset);
}
usb_dwc_ll_hctsiz_set_sched_info(chan_obj->regs, tokens_per_frame, ep_char->periodic.offset);
}
}
@ -403,12 +404,14 @@ void usb_dwc_hal_chan_set_ep_char(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t
void usb_dwc_hal_chan_activate(usb_dwc_hal_chan_t *chan_obj, void *xfer_desc_list, int desc_list_len, int start_idx)
{
//Cannot activate a channel that has already been enabled or is pending error handling
// Cannot activate a channel that has already been enabled or is pending error handling
HAL_ASSERT(!chan_obj->flags.active);
//Set start address of the QTD list and starting QTD index
// Make sure that PING is not enabled from previous transaction
usb_dwc_ll_hctsiz_set_dopng(chan_obj->regs, false);
// Set start address of the QTD list and starting QTD index
usb_dwc_ll_hcdma_set_qtd_list_addr(chan_obj->regs, xfer_desc_list, start_idx);
usb_dwc_ll_hctsiz_set_qtd_list_len(chan_obj->regs, desc_list_len);
usb_dwc_ll_hcchar_enable_chan(chan_obj->regs); //Start the channel
usb_dwc_ll_hcchar_enable_chan(chan_obj->regs); // Start the channel
chan_obj->flags.active = 1;
}