fix rusb2 hcd_port_connect_status() using line state, add post root reset delay for stable speed detection

This commit is contained in:
hathach
2026-01-03 23:54:05 +07:00
parent d457ea3d3c
commit b93d463afa
3 changed files with 28 additions and 42 deletions

View File

@ -1405,12 +1405,13 @@ static void remove_device_tree(uint8_t rhport, uint8_t hub_addr, uint8_t hub_por
// NOTE: due to the shared control buffer, we must complete enumerating
// one device before enumerating another one.
//--------------------------------------------------------------------+
enum { // USB 2.0 specs 7.1.7 for timing
ENUM_DEBOUNCING_DELAY_MS = 150, // T(ATTDB) minimum 100 ms for stable connection
ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port
ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset
ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery
ENUM_SET_ADDRESS_RECOVERY_DELAY_MS = 2, // USB 2.0 Spec 9.2.6.3 min is 2 ms
enum { // USB 2.0 specs 7.1.7 for timing
ENUM_DEBOUNCING_DELAY_MS = 150, // T(ATTDB) minimum 100 ms for stable connection
ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port
ENUM_RESET_ROOT_POST_DELAY_MS = 2, // 2 ms delay after root port reset before getting speed/status
ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset
ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery
ENUM_SET_ADDRESS_RECOVERY_DELAY_MS = 2, // USB 2.0 Spec 9.2.6.3 min is 2 ms
};
enum {
@ -1469,6 +1470,7 @@ static bool enum_new_device(hcd_event_t* event) {
hcd_port_reset(dev0_bus->rhport);
tusb_time_delay_ms_api(ENUM_RESET_ROOT_DELAY_MS);
hcd_port_reset_end(dev0_bus->rhport);
tusb_time_delay_ms_api(ENUM_RESET_ROOT_POST_DELAY_MS);
if (!hcd_port_connect_status(dev0_bus->rhport)) {
// device unplugged while delaying

View File

@ -76,12 +76,10 @@ typedef struct TU_ATTR_PACKED {
TU_ATTR_PACKED_END // End of definition of packed structs (used by the CCRX toolchain)
TU_ATTR_BIT_FIELD_ORDER_END
typedef struct
{
bool need_reset; /* The device has not been reset after connection. */
typedef struct {
pipe_state_t pipe[PIPE_COUNT];
uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
} hcd_data_t;
//--------------------------------------------------------------------+
@ -535,13 +533,8 @@ void hcd_int_disable(uint8_t rhport) {
rusb2_int_disable(rhport);
}
uint32_t hcd_frame_number(uint8_t rhport)
{
rusb2_reg_t* rusb = RUSB2_REG(rhport);
/* The device must be reset at least once after connection
* in order to start the frame counter. */
if (_hcd.need_reset) hcd_port_reset(rhport);
uint32_t hcd_frame_number(uint8_t rhport) {
rusb2_reg_t *rusb = RUSB2_REG(rhport);
return rusb->FRMNUM_b.FRNM;
}
@ -550,32 +543,18 @@ uint32_t hcd_frame_number(uint8_t rhport)
*--------------------------------------------------------------------+*/
bool hcd_port_connect_status(uint8_t rhport) {
rusb2_reg_t* rusb = RUSB2_REG(rhport);
return rusb->INTSTS1_b.ATTCH ? true : false;
const uint16_t line_state = rusb->SYSSTS0 & RUSB2_SYSSTS0_LNST_Msk;
return line_state == RUSB2_SYSSTS0_LNST_FS_J || line_state == RUSB2_SYSSTS0_LNST_FS_K;
}
void hcd_port_reset(uint8_t rhport) {
rusb2_reg_t* rusb = RUSB2_REG(rhport);
rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
while (rusb->DCPCTR_b.PBUSY) {}
hcd_int_disable(rhport);
rusb->DVSTCTR0_b.UACT = 0;
if (rusb->DCPCTR_b.SUREQ) {
rusb->DCPCTR_b.SUREQCLR = 1;
}
hcd_int_enable(rhport);
/* Reset should be asserted 10-20ms. */
rusb->DVSTCTR0_b.USBRST = 1;
for (volatile int i = 0; i < 2400000; ++i) {}
rusb->DVSTCTR0_b.USBRST = 0;
rusb->DVSTCTR0_b.UACT = 1;
_hcd.need_reset = false;
}
void hcd_port_reset_end(uint8_t rhport) {
(void) rhport;
rusb2_reg_t *rusb = RUSB2_REG(rhport);
rusb->DVSTCTR0_b.USBRST = 0;
}
tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
@ -584,7 +563,8 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
case RUSB2_DVSTCTR0_RHST_HS: return TUSB_SPEED_HIGH;
case RUSB2_DVSTCTR0_RHST_FS: return TUSB_SPEED_FULL;
case RUSB2_DVSTCTR0_RHST_LS: return TUSB_SPEED_LOW;
default: return TUSB_SPEED_INVALID;
default:
return TUSB_SPEED_INVALID;
}
}
@ -802,7 +782,6 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
if (is1 & RUSB2_INTSTS1_ATTCH_Msk) {
rusb->DVSTCTR0_b.UACT = 1;
_hcd.need_reset = true;
rusb->INTENB1 = (rusb->INTENB1 & ~RUSB2_INTSTS1_ATTCH_Msk) | RUSB2_INTSTS1_DTCH_Msk;
hcd_event_device_attach(rhport, true);
}

View File

@ -1669,15 +1669,20 @@ TU_ATTR_BIT_FIELD_ORDER_END
/*--------------------------------------------------------------------*/
/* Register Bit Utils */
/*--------------------------------------------------------------------*/
#define RUSB2_PIPE_CTR_PID_NAK (0U << RUSB2_PIPE_CTR_PID_Pos) /* NAK response */
#define RUSB2_PIPE_CTR_PID_BUF (1U << RUSB2_PIPE_CTR_PID_Pos) /* BUF response (depends buffer state) */
#define RUSB2_PIPE_CTR_PID_STALL (2U << RUSB2_PIPE_CTR_PID_Pos) /* STALL response */
#define RUSB2_PIPE_CTR_PID_STALL2 (3U << RUSB2_PIPE_CTR_PID_Pos) /* Also STALL response */
#define RUSB2_SYSSTS0_LNST_SE0 (0)
#define RUSB2_SYSSTS0_LNST_FS_J (1u << RUSB2_SYSSTS0_LNST_Pos) /* Full-speed J state */
#define RUSB2_SYSSTS0_LNST_FS_K (2u << RUSB2_SYSSTS0_LNST_Pos) /* Full-speed K state */
#define RUSB2_SYSSTS0_LNST_LS_SE1 (3u << RUSB2_SYSSTS0_LNST_Pos) /* Low-speed SE1 state */
#define RUSB2_DVSTCTR0_RHST_LS (1U << RUSB2_DVSTCTR0_RHST_Pos) /* Low-speed connection */
#define RUSB2_DVSTCTR0_RHST_FS (2U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */
#define RUSB2_DVSTCTR0_RHST_HS (3U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */
#define RUSB2_PIPE_CTR_PID_NAK (0U << RUSB2_PIPE_CTR_PID_Pos) /* NAK response */
#define RUSB2_PIPE_CTR_PID_BUF (1U << RUSB2_PIPE_CTR_PID_Pos) /* BUF response (depends buffer state) */
#define RUSB2_PIPE_CTR_PID_STALL (2U << RUSB2_PIPE_CTR_PID_Pos) /* STALL response */
#define RUSB2_PIPE_CTR_PID_STALL2 (3U << RUSB2_PIPE_CTR_PID_Pos) /* Also STALL response */
#define RUSB2_DEVADD_USBSPD_LS (1U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Low-speed */
#define RUSB2_DEVADD_USBSPD_FS (2U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Full-speed */