add tusb_time_millis(), able to reset and enable dwc2 port and get SOF active

This commit is contained in:
hathach 2024-10-21 17:45:40 +07:00
parent f5978876d2
commit 8461525d48
No known key found for this signature in database
GPG Key ID: 26FAB84F615C3C52
8 changed files with 123 additions and 30 deletions

View File

@ -134,3 +134,8 @@ int board_getchar(void) {
char c;
return (sys_read(0, &c, 1) > 0) ? (int) c : (-1);
}
uint32_t tusb_time_millis(void) {
return board_millis();
}

View File

@ -447,9 +447,9 @@ bool tuh_deinit(uint8_t rhport) {
}
bool tuh_task_event_ready(void) {
// Skip if stack is not initialized
if ( !tuh_inited() ) return false;
if (!tuh_inited()) {
return false; // Skip if stack is not initialized
}
return !osal_queue_empty(_usbh_q);
}
@ -1520,10 +1520,17 @@ static bool enum_new_device(hcd_event_t* event) {
_dev0.hub_port = event->connection.hub_port;
if (_dev0.hub_addr == 0) {
// connected/disconnected directly with roothub
// connected directly to roothub
hcd_port_reset(_dev0.rhport);
osal_task_delay(ENUM_RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
// sof of controller may not running while resetting
#if CFG_TUSB_OS == OPT_OS_NONE
// Since we are in middle of rhport reset, frame number is not available for time delay
// need to depend on tusb_time_millis() instead
const uint32_t start_reset = tusb_time_millis();
while ((tusb_time_millis() - start_reset) < ENUM_RESET_DELAY) {}
#else
osal_task_delay(ENUM_RESET_DELAY);
#endif
hcd_port_reset_end(_dev0.rhport);
// wait until device connection is stable TODO non blocking
@ -1548,7 +1555,7 @@ static bool enum_new_device(hcd_event_t* event) {
}
#if CFG_TUH_HUB
else {
// connected/disconnected via external hub
// connected via external hub
// wait until device connection is stable TODO non blocking
osal_task_delay(ENUM_CONTACT_DEBOUNCING_DELAY);

View File

@ -185,6 +185,14 @@ bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, const tusb_rhport_init_t* rh_init
return dwc2->ghwcfg2_bm.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED;
}
/* dwc2 has several PHYs option
* - UTMI+ is internal highspeed PHY, clock can be 30 Mhz (8-bit) or 60 Mhz (16-bit)
* - ULPI is external highspeed PHY, clock is 60Mhz with only 8-bit interface
* - Dedicated FS PHY is internal with clock 48Mhz.
*
* In addition, UTMI+/ULPI can be shared to run at fullspeed mode with 48Mhz
*
*/
bool dwc2_core_init(uint8_t rhport, bool is_highspeed, bool is_dma) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);

View File

@ -7,7 +7,7 @@
| GHWCFG2 | 0x228DDD50 | 0x228F5910 | 0x224DD930 | 0x215FFFD0 | 0x229DCD20 | 0x229ED590 | 0x229ED520 | 0x229ED520 | 0x229FE1D0 | 0x229FE190 | 0x229FE190 | 0x229ED520 | 0x228FE052 | 0x00000000 | 0x228F5930 |
| - op_mode | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | noHNP noSRP | HNP SRP | HNP SRP |
| - arch | DMA internal | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | Slave only | Slave only | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | Slave only | DMA internal |
| - p2p (hub support) | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 |
| - single_point | hub | hub | n/a | hub | n/a | hub | n/a | n/a | hub | hub | hub | n/a | hub | hub | n/a |
| - hs_phy_type | UTMI+ | n/a | n/a | UTMI+/ULPI | n/a | ULPI | n/a | n/a | UTMI+/ULPI | ULPI | ULPI | n/a | UTMI+ | n/a | n/a |
| - fs_phy_type | Dedicated | Dedicated | Dedicated | Shared ULPI | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | n/a | n/a | Dedicated |
| - num_dev_ep | 7 | 6 | 6 | 15 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 0 | 6 |

View File

@ -44,7 +44,7 @@ class GHWCFG2(ctypes.LittleEndianStructure):
_fields_ = [
("op_mode", ctypes.c_uint32, 3),
("arch", ctypes.c_uint32, 2),
("p2p (hub support)", ctypes.c_uint32, 1),
("single_point", ctypes.c_uint32, 1),
("hs_phy_type", ctypes.c_uint32, 2),
("fs_phy_type", ctypes.c_uint32, 2),
("num_dev_ep", ctypes.c_uint32, 4),
@ -119,6 +119,10 @@ GHWCFG2_field = {
1: "DMA external",
2: "DMA internal"
},
'single_point': {
0: "hub",
1: "n/a"
},
'hs_phy_type': {
0: "n/a",
1: "UTMI+",

View File

@ -208,7 +208,7 @@ typedef struct TU_ATTR_PACKED {
based on the speed of enumeration. The number of bit times added per PHY clock are as follows:
- High-speed: PHY clock One 30-MHz = 16 bit times, One 60-MHz = 8 bit times
- Full-speed: PHY clock One 30-MHz = 0.4 bit times, One 60-MHz = 0.2 bit times, One 48-MHz = 0.25 bit times */
uint32_t phy_if : 1; // 3 PHY interface. 0: 8 bits, 1: 16 bits
uint32_t phy_if16 : 1; // 3 PHY interface. 0: 8 bits, 1: 16 bits
uint32_t ulpi_utmi_sel : 1; // 4 ULPI/UTMI select. 0: UTMI+, 1: ULPI
uint32_t fs_intf_sel : 1; // 5 Fullspeed serial interface select. 0: 6-pin, 1: 3-pin
uint32_t phy_sel : 1; // 6 HS/FS PHY selection. 0: HS UTMI+ or ULPI, 1: FS serial transceiver
@ -259,7 +259,7 @@ TU_VERIFY_STATIC(sizeof(dwc2_grstctl_t) == 4, "incorrect size");
typedef struct TU_ATTR_PACKED {
uint32_t op_mode : 3; // 0..2 HNP/SRP Host/Device/OTG mode
uint32_t arch : 2; // 3..4 Slave/External/Internal DMA
uint32_t point2point : 1; // 5 0: support hub and split | 1: no hub, no split
uint32_t single_point : 1; // 5 0: support hub and split | 1: no hub, no split
uint32_t hs_phy_type : 2; // 6..7 0: not supported | 1: UTMI+ | 2: ULPI | 3: UTMI+ and ULPI
uint32_t fs_phy_type : 2; // 8..9 0: not supported | 1: dedicated | 2: UTMI+ | 3: ULPI
uint32_t num_dev_ep : 4; // 10..13 Number of device endpoints (excluding EP0)
@ -407,7 +407,10 @@ typedef struct {
};
volatile uint32_t gotgint; // 004 OTG Interrupt
volatile uint32_t gahbcfg; // 008 AHB Configuration
union {
volatile uint32_t gusbcfg; // 00c USB Configuration
volatile dwc2_gusbcfg_t gusbcfg_bm;
};
volatile uint32_t grstctl; // 010 Reset
volatile uint32_t gintsts; // 014 Interrupt
volatile uint32_t gintmsk; // 018 Interrupt Mask
@ -459,7 +462,10 @@ typedef struct {
volatile uint32_t haintmsk; // 418 Host All Channels Interrupt Mask
volatile uint32_t hflbaddr; // 41C Host Frame List Base Address
uint32_t reserved420[8]; // 420..43F
union {
volatile uint32_t hprt; // 440 Host Port Control and Status
volatile dwc2_hprt_t hprt_bm;
};
uint32_t reserved444[47]; // 444..4FF
//------------- Host Channel -------------//
@ -1490,14 +1496,14 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#define HPRT_CONN_STATUS_Msk (0x1UL << HPRT_CONN_STATUS_Pos) // 0x00000001
#define HPRT_CONN_STATUS HPRT_CONN_STATUS_Msk // Port connect status
#define HPRT_CONN_DETECT_Pos (1U)
#define HPRT_CONN_DETECT_Msk (0x1UL << HPRT_CONN_DETECT_Pos) // 0x00000002
#define HPRT_CONN_DETECT HPRT_CONN_DETECT_Msk // Port connect detected
#define HPRT_CONN_DETECT_Msk (0x1UL << HPRT_CONN_DETECT_Pos) // 0x00000002
#define HPRT_CONN_DETECT HPRT_CONN_DETECT_Msk // Port connect detected
#define HPRT_ENABLE_Pos (2U)
#define HPRT_ENABLE_Msk (0x1UL << HPRT_ENABLE_Pos) // 0x00000004
#define HPRT_ENABLE HPRT_ENABLE_Msk // Port enable
#define HPRT_EN_CHANGE_Pos (3U)
#define HPRT_EN_CHANGE_Msk (0x1UL << HPRT_EN_CHANGE_Pos) // 0x00000008
#define HPRT_EN_CHANGE HPRT_EN_CHANGE_Msk // Port enable/disable change
#define HPRT_ENABLE_CHANGE_Pos (3U)
#define HPRT_ENABLE_CHANGE_Msk (0x1UL << HPRT_ENABLE_CHANGE_Pos) // 0x00000008
#define HPRT_ENABLE_CHANGE HPRT_ENABLE_CHANGE_Msk // Port enable/disable change
#define HPRT_OVER_CURRENT_ACTIVE_Pos (4U)
#define HPRT_OVER_CURRENT_ACTIVE_Msk (0x1UL << HPRT_OVER_CURRENT_ACTIVE_Pos) // 0x00000010
#define HPRT_OVER_CURRENT_ACTIVE HPRT_OVER_CURRENT_ACTIVE_Msk // Port overcurrent active

View File

@ -35,9 +35,20 @@
#include "dwc2_common.h"
enum {
HPRT_W1C_MASK = HPRT_CONN_DETECT | HPRT_ENABLE | HPRT_EN_CHANGE | HPRT_OVER_CURRENT_CHANGE
HPRT_W1C_MASK = HPRT_CONN_DETECT | HPRT_ENABLE | HPRT_ENABLE_CHANGE | HPRT_OVER_CURRENT_CHANGE
};
TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t convert_hprt_speed(uint32_t hprt_speed) {
tusb_speed_t speed;
switch(hprt_speed) {
case HPRT_SPEED_HIGH: speed = TUSB_SPEED_HIGH; break;
case HPRT_SPEED_FULL: speed = TUSB_SPEED_FULL; break;
case HPRT_SPEED_LOW : speed = TUSB_SPEED_LOW ; break;
default: TU_BREAKPOINT(); break;
}
return speed;
}
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
@ -81,6 +92,8 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
}
dwc2->hcfg = hcfg;
// Enable HFIR reload
// force host mode and wait for mode switch
dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FDMOD) | GUSBCFG_FHMOD;
while( (dwc2->gintsts & GINTSTS_CMOD) != GINTSTS_CMODE_HOST) {}
@ -107,8 +120,8 @@ void hcd_int_disable(uint8_t rhport) {
// Get frame number (1ms)
uint32_t hcd_frame_number(uint8_t rhport) {
(void) rhport;
return 0;
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
return dwc2->hfnum & HFNUM_FRNUM_Msk;
}
//--------------------------------------------------------------------+
@ -125,7 +138,9 @@ bool hcd_port_connect_status(uint8_t rhport) {
// Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence.
void hcd_port_reset(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
dwc2->hprt = HPRT_RESET;
uint32_t hprt = dwc2->hprt & ~HPRT_W1C_MASK;
hprt |= HPRT_RESET;
dwc2->hprt = hprt;
}
// Complete bus reset sequence, may be required by some controllers
@ -138,9 +153,9 @@ void hcd_port_reset_end(uint8_t rhport) {
// Get port link speed
tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
(void) rhport;
return TUSB_SPEED_FULL;
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const tusb_speed_t speed = convert_hprt_speed(dwc2->hprt_bm.speed);
return speed;
}
// HCD closes all opened endpoints belong to this device
@ -227,18 +242,62 @@ static void handle_rxflvl_irq(uint8_t rhport) {
*/
TU_ATTR_ALWAYS_INLINE static inline void handle_hprt_irq(uint8_t rhport, bool in_isr) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
uint32_t hprt = dwc2->hprt;
uint32_t hprt = dwc2->hprt & ~HPRT_W1C_MASK;
const dwc2_hprt_t hprt_bm = dwc2->hprt_bm;
if (hprt & HPRT_CONN_DETECT) {
if (dwc2->hprt & HPRT_CONN_DETECT) {
// Port Connect Detect
dwc2->hprt = HPRT_CONN_DETECT; // clear
hprt |= HPRT_CONN_DETECT;
if (hprt & HPRT_CONN_STATUS) {
if (hprt_bm.conn_status) {
hcd_event_device_attach(rhport, in_isr);
} else {
hcd_event_device_remove(rhport, in_isr);
}
}
if (dwc2->hprt & HPRT_ENABLE_CHANGE) {
// Port enable change
hprt |= HPRT_ENABLE_CHANGE;
if (hprt_bm.enable) {
// Port enable
// Config HCFG FS/LS clock and HFIR for SOF interval according to link speed (value is in PHY clock unit)
const tusb_speed_t speed = convert_hprt_speed(hprt_bm.speed);
uint32_t hcfg = dwc2->hcfg & ~HCFG_FSLS_PHYCLK_SEL;
const dwc2_gusbcfg_t gusbcfg_bm = dwc2->gusbcfg_bm;
uint32_t clock = 60;
if (gusbcfg_bm.phy_sel) {
// dedicated FS is 48Mhz
clock = 48;
hcfg |= HCFG_FSLS_PHYCLK_SEL_48MHZ;
} else {
// UTMI+ or ULPI
if (gusbcfg_bm.ulpi_utmi_sel) {
clock = 60; // ULPI 8-bit is 60Mhz
} else if (gusbcfg_bm.phy_if16) {
clock = 30; // UTMI+ 16-bit is 30Mhz
} else {
clock = 60; // UTMI+ 8-bit is 60Mhz
}
hcfg |= HCFG_FSLS_PHYCLK_SEL_30_60MHZ;
}
dwc2->hcfg = hcfg;
uint32_t hfir = dwc2->hfir & ~HFIR_FRIVL_Msk;
if (speed == TUSB_SPEED_HIGH) {
hfir |= 125*clock;
} else {
hfir |= 1000*clock;
}
dwc2->hfir = hfir;
}
}
dwc2->hprt = hprt; // clear interrupt
}
/* Interrupt Hierarchy

View File

@ -127,10 +127,8 @@
//--------------------------------------------------------------------+
// APPLICATION API
// User API
//--------------------------------------------------------------------+
#if CFG_TUH_ENABLED || CFG_TUD_ENABLED
// Internal helper for backward compatible with tusb_init(void)
@ -167,6 +165,12 @@ void tusb_int_handler(uint8_t rhport, bool in_isr);
#endif
//--------------------------------------------------------------------+
// API Implemented by user
//--------------------------------------------------------------------+
// Get current milliseconds, maybe required by some port with no RTOS
uint32_t tusb_time_millis(void);
#ifdef __cplusplus
}