summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/host/usbh.c21
-rw-r--r--src/portable/synopsys/dwc2/dwc2_common.c8
-rw-r--r--src/portable/synopsys/dwc2/dwc2_info.md2
-rwxr-xr-xsrc/portable/synopsys/dwc2/dwc2_info.py6
-rw-r--r--src/portable/synopsys/dwc2/dwc2_type.h20
-rw-r--r--src/portable/synopsys/dwc2/hcd_dwc2.c81
-rw-r--r--src/tusb.h10
7 files changed, 118 insertions, 30 deletions
diff --git a/src/host/usbh.c b/src/host/usbh.c
index b5df29f50..8bf40a607 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -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);
diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c
index a5f1c2b08..d0ad764a5 100644
--- a/src/portable/synopsys/dwc2/dwc2_common.c
+++ b/src/portable/synopsys/dwc2/dwc2_common.c
@@ -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);
diff --git a/src/portable/synopsys/dwc2/dwc2_info.md b/src/portable/synopsys/dwc2/dwc2_info.md
index cfd0c81a8..92293a072 100644
--- a/src/portable/synopsys/dwc2/dwc2_info.md
+++ b/src/portable/synopsys/dwc2/dwc2_info.md
@@ -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 |
diff --git a/src/portable/synopsys/dwc2/dwc2_info.py b/src/portable/synopsys/dwc2/dwc2_info.py
index d1793a005..d97a1192e 100755
--- a/src/portable/synopsys/dwc2/dwc2_info.py
+++ b/src/portable/synopsys/dwc2/dwc2_info.py
@@ -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+",
diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h
index 8fb926a21..d2993bdd9 100644
--- a/src/portable/synopsys/dwc2/dwc2_type.h
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -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
diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c
index 2d4368e94..bb5086631 100644
--- a/src/portable/synopsys/dwc2/hcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/hcd_dwc2.c
@@ -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
diff --git a/src/tusb.h b/src/tusb.h
index 2f30a5739..3ffaafded 100644
--- a/src/tusb.h
+++ b/src/tusb.h
@@ -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
}