Skip to content

Commit 3fd2f53

Browse files
fix(usb/host): Fix reaction on High-Speed NYET packet
In Scatter-Gather DMA mode, the USB-DWC will automatically enable PING protocol if an OUT packet is NACKed by the High-Speed device. The PING bit must be manually reset.
1 parent 13e8541 commit 3fd2f53

File tree

4 files changed

+71
-92
lines changed

4 files changed

+71
-92
lines changed

components/hal/esp32p4/include/hal/usb_dwc_ll.h

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -790,23 +790,33 @@ static inline void usb_dwc_ll_hctsiz_set_qtd_list_len(volatile usb_dwc_host_chan
790790
chan->hctsiz_reg.val = hctsiz.val;
791791
}
792792

793-
static inline void usb_dwc_ll_hctsiz_init(volatile usb_dwc_host_chan_regs_t *chan)
793+
/**
794+
* @brief Perform PING protocol
795+
*
796+
* PING protocol is automatically enabled if High-Speed device responds with NYET in Scatter-Gather DMA mode.
797+
* The application must disable PING for next transfer.
798+
* Relevant only for OUT transfers.
799+
*
800+
* @param[in] chan Channel registers
801+
* @param[in] enable true: Enable PING, false: Disable PING
802+
*/
803+
static inline void usb_dwc_ll_hctsiz_set_dopng(volatile usb_dwc_host_chan_regs_t *chan, bool enable)
794804
{
795-
usb_dwc_hctsiz_reg_t hctsiz;
796-
hctsiz.val = chan->hctsiz_reg.val;
797-
hctsiz.dopng = 0; //Don't do ping
798-
/*
799-
Set SCHED_INFO which occupies xfersize[7:0]
800-
It is always set to 0xFF for full speed and not used in Bulk/Ctrl channels
801-
*/
802-
hctsiz.xfersize |= 0xFF;
803-
chan->hctsiz_reg.val = hctsiz.val;
805+
chan->hctsiz_reg.dopng = (uint32_t)(enable && !chan->hcchar_reg.epdir);
804806
}
805807

808+
/**
809+
* @brief Set scheduling info for Periodic channel
810+
*
811+
* @attention This function must be called for each periodic channel!
812+
* @see USB-OTG databook: Table 5-47
813+
*
814+
* @param[in] chan Channel registers
815+
* @param[in] tokens_per_frame HS: Number of tokens per frame FS: Must be set 8
816+
* @param[in] offset Offset of the channel
817+
*/
806818
static inline void usb_dwc_ll_hctsiz_set_sched_info(volatile usb_dwc_host_chan_regs_t *chan, int tokens_per_frame, int offset)
807819
{
808-
// @see USB-OTG databook: Table 5-47
809-
// This function is relevant only for HS
810820
usb_dwc_hctsiz_reg_t hctsiz;
811821
hctsiz.val = chan->hctsiz_reg.val;
812822
uint8_t sched_info_val;

components/hal/esp32s2/include/hal/usb_dwc_ll.h

Lines changed: 20 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -791,50 +791,33 @@ static inline void usb_dwc_ll_hctsiz_set_qtd_list_len(volatile usb_dwc_host_chan
791791
chan->hctsiz_reg.val = hctsiz.val;
792792
}
793793

794-
static inline void usb_dwc_ll_hctsiz_init(volatile usb_dwc_host_chan_regs_t *chan)
794+
/**
795+
* @brief Perform PING protocol
796+
*
797+
* @note This function is here only for compatibility reasons. PING is not relevant on FS only targets
798+
* @param[in] chan Channel registers
799+
* @param[in] enable true: Enable PING, false: Disable PING
800+
*/
801+
static inline void usb_dwc_ll_hctsiz_set_dopng(volatile usb_dwc_host_chan_regs_t *chan, bool enable)
795802
{
796-
usb_dwc_hctsiz_reg_t hctsiz;
797-
hctsiz.val = chan->hctsiz_reg.val;
798-
hctsiz.dopng = 0; //Don't do ping
799-
/*
800-
Set SCHED_INFO which occupies xfersize[7:0]
801-
It is always set to 0xFF for full speed and not used in Bulk/Ctrl channels
802-
*/
803-
hctsiz.xfersize |= 0xFF;
804-
chan->hctsiz_reg.val = hctsiz.val;
805803
}
806804

805+
/**
806+
* @brief Set scheduling info for Periodic channel
807+
*
808+
* @note ESP32-S2 is Full-Speed only, so SCHED_INFO is always set to 0xFF
809+
* @attention This function must be called for each periodic channel!
810+
* @see USB-OTG databook: Table 5-47
811+
*
812+
* @param[in] chan Channel registers
813+
* @param[in] tokens_per_frame Ignored
814+
* @param[in] offset Ignored
815+
*/
807816
static inline void usb_dwc_ll_hctsiz_set_sched_info(volatile usb_dwc_host_chan_regs_t *chan, int tokens_per_frame, int offset)
808817
{
809-
// @see USB-OTG databook: Table 5-47
810-
// This function is relevant only for HS
811818
usb_dwc_hctsiz_reg_t hctsiz;
812819
hctsiz.val = chan->hctsiz_reg.val;
813-
uint8_t sched_info_val;
814-
switch (tokens_per_frame) {
815-
case 1:
816-
offset %= 8; // If the required offset > 8, we must wrap around to SCHED_INFO size = 8
817-
sched_info_val = 0b00000001;
818-
break;
819-
case 2:
820-
offset %= 4;
821-
sched_info_val = 0b00010001;
822-
break;
823-
case 4:
824-
offset %= 2;
825-
sched_info_val = 0b01010101;
826-
break;
827-
case 8:
828-
offset = 0;
829-
sched_info_val = 0b11111111;
830-
break;
831-
default:
832-
abort();
833-
break;
834-
}
835-
sched_info_val <<= offset;
836-
hctsiz.xfersize &= ~(0xFF);
837-
hctsiz.xfersize |= sched_info_val;
820+
hctsiz.xfersize |= 0xFF;
838821
chan->hctsiz_reg.val = hctsiz.val;
839822
}
840823

components/hal/esp32s3/include/hal/usb_dwc_ll.h

Lines changed: 20 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -791,50 +791,33 @@ static inline void usb_dwc_ll_hctsiz_set_qtd_list_len(volatile usb_dwc_host_chan
791791
chan->hctsiz_reg.val = hctsiz.val;
792792
}
793793

794-
static inline void usb_dwc_ll_hctsiz_init(volatile usb_dwc_host_chan_regs_t *chan)
794+
/**
795+
* @brief Perform PING protocol
796+
*
797+
* @note This function is here only for compatibility reasons. PING is not relevant on FS only targets
798+
* @param[in] chan Channel registers
799+
* @param[in] enable true: Enable PING, false: Disable PING
800+
*/
801+
static inline void usb_dwc_ll_hctsiz_set_dopng(volatile usb_dwc_host_chan_regs_t *chan, bool enable)
795802
{
796-
usb_dwc_hctsiz_reg_t hctsiz;
797-
hctsiz.val = chan->hctsiz_reg.val;
798-
hctsiz.dopng = 0; //Don't do ping
799-
/*
800-
Set SCHED_INFO which occupies xfersize[7:0]
801-
It is always set to 0xFF for full speed and not used in Bulk/Ctrl channels
802-
*/
803-
hctsiz.xfersize |= 0xFF;
804-
chan->hctsiz_reg.val = hctsiz.val;
805803
}
806804

805+
/**
806+
* @brief Set scheduling info for Periodic channel
807+
*
808+
* @note ESP32-S3 is Full-Speed only, so SCHED_INFO is always set to 0xFF
809+
* @attention This function must be called for each periodic channel!
810+
* @see USB-OTG databook: Table 5-47
811+
*
812+
* @param[in] chan Channel registers
813+
* @param[in] tokens_per_frame Ignored
814+
* @param[in] offset Ignored
815+
*/
807816
static inline void usb_dwc_ll_hctsiz_set_sched_info(volatile usb_dwc_host_chan_regs_t *chan, int tokens_per_frame, int offset)
808817
{
809-
// @see USB-OTG databook: Table 5-47
810-
// This function is relevant only for HS
811818
usb_dwc_hctsiz_reg_t hctsiz;
812819
hctsiz.val = chan->hctsiz_reg.val;
813-
uint8_t sched_info_val;
814-
switch (tokens_per_frame) {
815-
case 1:
816-
offset %= 8; // If the required offset > 8, we must wrap around to SCHED_INFO size = 8
817-
sched_info_val = 0b00000001;
818-
break;
819-
case 2:
820-
offset %= 4;
821-
sched_info_val = 0b00010001;
822-
break;
823-
case 4:
824-
offset %= 2;
825-
sched_info_val = 0b01010101;
826-
break;
827-
case 8:
828-
offset = 0;
829-
sched_info_val = 0b11111111;
830-
break;
831-
default:
832-
abort();
833-
break;
834-
}
835-
sched_info_val <<= offset;
836-
hctsiz.xfersize &= ~(0xFF);
837-
hctsiz.xfersize |= sched_info_val;
820+
hctsiz.xfersize |= 0xFF;
838821
chan->hctsiz_reg.val = hctsiz.val;
839822
}
840823

components/hal/usb_dwc_hal.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,6 @@ bool usb_dwc_hal_chan_alloc(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t *chan
312312
usb_dwc_ll_haintmsk_en_chan_intr(hal->dev, 1 << chan_obj->flags.chan_idx);
313313
usb_dwc_ll_hcintmsk_set_intr_mask(chan_obj->regs, CHAN_INTRS_EN_MSK); //Unmask interrupts for this channel
314314
usb_dwc_ll_hctsiz_set_pid(chan_obj->regs, 0); //Set the initial PID to zero
315-
usb_dwc_ll_hctsiz_init(chan_obj->regs); //Set the non changing parts of the HCTSIZ registers (e.g., do_ping and sched info)
316315
return true;
317316
}
318317

@@ -383,8 +382,10 @@ void usb_dwc_hal_chan_set_ep_char(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t
383382
hal->periodic_frame_list[index] |= 1 << chan_obj->flags.chan_idx;
384383
}
385384
// For HS endpoints we must write to sched_info field of HCTSIZ register to schedule microframes
385+
// For FS endpoints sched_info is always 0xFF
386+
// LS endpoints do not support periodic transfers
387+
unsigned int tokens_per_frame = 0;
386388
if (ep_char->periodic.is_hs) {
387-
unsigned int tokens_per_frame;
388389
if (ep_char->periodic.interval >= 8) {
389390
tokens_per_frame = 1; // 1 token every 8 microframes
390391
} else if (ep_char->periodic.interval >= 4) {
@@ -394,21 +395,23 @@ void usb_dwc_hal_chan_set_ep_char(usb_dwc_hal_context_t *hal, usb_dwc_hal_chan_t
394395
} else {
395396
tokens_per_frame = 8; // 1 token every microframe
396397
}
397-
usb_dwc_ll_hctsiz_set_sched_info(chan_obj->regs, tokens_per_frame, ep_char->periodic.offset);
398398
}
399+
usb_dwc_ll_hctsiz_set_sched_info(chan_obj->regs, tokens_per_frame, ep_char->periodic.offset);
399400
}
400401
}
401402

402403
// ------------------- Channel Control ---------------------
403404

404405
void usb_dwc_hal_chan_activate(usb_dwc_hal_chan_t *chan_obj, void *xfer_desc_list, int desc_list_len, int start_idx)
405406
{
406-
//Cannot activate a channel that has already been enabled or is pending error handling
407+
// Cannot activate a channel that has already been enabled or is pending error handling
407408
HAL_ASSERT(!chan_obj->flags.active);
408-
//Set start address of the QTD list and starting QTD index
409+
// Make sure that PING is not enabled from previous transaction
410+
usb_dwc_ll_hctsiz_set_dopng(chan_obj->regs, false);
411+
// Set start address of the QTD list and starting QTD index
409412
usb_dwc_ll_hcdma_set_qtd_list_addr(chan_obj->regs, xfer_desc_list, start_idx);
410413
usb_dwc_ll_hctsiz_set_qtd_list_len(chan_obj->regs, desc_list_len);
411-
usb_dwc_ll_hcchar_enable_chan(chan_obj->regs); //Start the channel
414+
usb_dwc_ll_hcchar_enable_chan(chan_obj->regs); // Start the channel
412415
chan_obj->flags.active = 1;
413416
}
414417

0 commit comments

Comments
 (0)