diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index c461d9a79..83ebc18cb 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -44,7 +44,7 @@ #if TU_CHECK_MCU(OPT_MCU_GD32VF103) #define DWC2_EP_COUNT(_dwc2) DWC2_EP_MAX #else - #define DWC2_EP_COUNT(_dwc2) ((_dwc2)->ghwcfg2_bm.num_dev_ep + 1) + #define DWC2_EP_COUNT(_dwc2) ({const dwc2_ghwcfg2_t ghwcfg2 = {.value = (_dwc2)->ghwcfg2}; ghwcfg2.num_dev_ep + 1;}) #endif //--------------------------------------------------------------------+ @@ -102,7 +102,8 @@ bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) { TU_ATTR_ALWAYS_INLINE static inline bool dma_device_enabled(const dwc2_regs_t* dwc2) { (void) dwc2; // Internal DMA only - return CFG_TUD_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA; + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; + return CFG_TUD_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA; } static void dma_setup_prepare(uint8_t rhport) { @@ -250,20 +251,15 @@ static void edpt_activate(uint8_t rhport, const tusb_desc_endpoint_t* p_endpoint xfer->interval = p_endpoint_desc->bInterval; // Endpoint control - union { - uint32_t value; - dwc2_depctl_t bm; - } depctl; - depctl.value = 0; - - depctl.bm.mps = xfer->max_size; - depctl.bm.active = 1; - depctl.bm.type = p_endpoint_desc->bmAttributes.xfer; + dwc2_depctl_t depctl = {.value = 0}; + depctl.mps = xfer->max_size; + depctl.active = 1; + depctl.type = p_endpoint_desc->bmAttributes.xfer; if (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) { - depctl.bm.set_data0_iso_even = 1; + depctl.set_data0_iso_even = 1; } if (dir == TUSB_DIR_IN) { - depctl.bm.tx_fifo_num = epnum; + depctl.tx_fifo_num = epnum; } dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum]; @@ -343,31 +339,22 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin } // transfer size: A full OUT transfer (multiple packets, possibly) triggers XFRC. - union { - uint32_t value; - dwc2_ep_tsize_t bm; - } deptsiz; - deptsiz.value = 0; - deptsiz.bm.xfer_size = total_bytes; - deptsiz.bm.packet_count = num_packets; - + dwc2_ep_tsize_t deptsiz = {.value = 0}; + deptsiz.xfer_size = total_bytes; + deptsiz.packet_count = num_packets; dep->tsiz = deptsiz.value; // control - union { - dwc2_depctl_t bm; - uint32_t value; - } depctl; - depctl.value = dep->ctl; - - depctl.bm.clear_nak = 1; - depctl.bm.enable = 1; - if (depctl.bm.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) { - const uint32_t odd_now = (dwc2->dsts_bm.frame_number & 1u); + dwc2_depctl_t depctl = {.value = dep->ctl}; + depctl.clear_nak = 1; + depctl.enable = 1; + if (depctl.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) { + const dwc2_dsts_t dsts = {.value = dwc2->dsts}; + const uint32_t odd_now = dsts.frame_number & 1u; if (odd_now) { - depctl.bm.set_data0_iso_even = 1; + depctl.set_data0_iso_even = 1; } else { - depctl.bm.set_data1_iso_odd = 1; + depctl.set_data1_iso_odd = 1; } } @@ -410,7 +397,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required // when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347) - if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) { + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; + if (ghwcfg2.hs_phy_type == GHWCFG2_HSPHY_ULPI) { dcfg |= DCFG_XCVRDLY; } } else { @@ -671,7 +659,9 @@ static void handle_bus_reset(uint8_t rhport) { dfifo_device_init(rhport); // 5. Reset device address - dwc2->dcfg_bm.address = 0; + dwc2_dcfg_t dcfg = {.value = dwc2->dcfg}; + dcfg.address = 0; + dwc2->dcfg = dcfg.value; // Fixed both control EP0 size to 64 bytes dwc2->epin[0].ctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); @@ -691,8 +681,9 @@ static void handle_bus_reset(uint8_t rhport) { static void handle_enum_done(uint8_t rhport) { dwc2_regs_t *dwc2 = DWC2_REG(rhport); + const dwc2_dsts_t dsts = {.value = dwc2->dsts}; tusb_speed_t speed; - switch (dwc2->dsts_bm.enum_speed) { + switch (dsts.enum_speed) { case DCFG_SPEED_HIGH: speed = TUSB_SPEED_HIGH; break; @@ -737,12 +728,12 @@ static void handle_rxflvl_irq(uint8_t rhport) { const volatile uint32_t* rx_fifo = dwc2->fifo[0]; // Pop control word off FIFO - const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm; - const uint8_t epnum = grxstsp_bm.ep_ch_num; + const dwc2_grxstsp_t grxstsp = {.value = dwc2->grxstsp}; + const uint8_t epnum = grxstsp.ep_ch_num; dwc2_dep_t* epout = &dwc2->epout[epnum]; - switch (grxstsp_bm.packet_status) { + switch (grxstsp.packet_status) { case GRXSTS_PKTSTS_GLOBAL_OUT_NAK: // Global OUT NAK: do nothing break; @@ -764,7 +755,7 @@ static void handle_rxflvl_irq(uint8_t rhport) { case GRXSTS_PKTSTS_RX_DATA: { // Out packet received - const uint16_t byte_count = grxstsp_bm.byte_count; + const uint16_t byte_count = grxstsp.byte_count; xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); if (byte_count) { @@ -778,7 +769,8 @@ static void handle_rxflvl_irq(uint8_t rhport) { // short packet, minus remaining bytes (xfer_size) if (byte_count < xfer->max_size) { - xfer->total_len -= epout->tsiz_bm.xfer_size; + const dwc2_ep_tsize_t tsiz = {.value = epout->tsiz}; + xfer->total_len -= tsiz.xfer_size; if (epnum == 0) { xfer->total_len -= _dcd_data.ep0_pending[TUSB_DIR_OUT]; _dcd_data.ep0_pending[TUSB_DIR_OUT] = 0; @@ -840,11 +832,13 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep // - 64 bytes or // - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL) if (diepint_bm.txfifo_empty && (dwc2->diepempmsk & (1 << epnum))) { - const uint16_t remain_packets = epin->tsiz_bm.packet_count; + dwc2_ep_tsize_t tsiz = {.value = epin->tsiz}; + const uint16_t remain_packets = tsiz.packet_count; // Process every single packet (only whole packets can be written to fifo) for (uint16_t i = 0; i < remain_packets; i++) { - const uint16_t remain_bytes = (uint16_t) epin->tsiz_bm.xfer_size; + tsiz.value = epin->tsiz; + const uint16_t remain_bytes = (uint16_t) tsiz.xfer_size; const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size); // Check if dtxfsts has enough space available @@ -863,7 +857,8 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep } // Turn off TXFE if all bytes are written. - if (epin->tsiz_bm.xfer_size == 0) { + tsiz.value = epin->tsiz; + if (tsiz.xfer_size == 0) { dwc2->diepempmsk &= ~(1 << epnum); } } @@ -894,7 +889,8 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); // determine actual received bytes - const uint16_t remain = epout->tsiz_bm.xfer_size; + const dwc2_ep_tsize_t tsiz = {.value = epout->tsiz}; + const uint16_t remain = tsiz.xfer_size; xfer->total_len -= remain; // this is ZLP, so prepare EP0 for next setup diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c index f80ae9acb..989a833ff 100644 --- a/src/portable/synopsys/dwc2/dwc2_common.c +++ b/src/portable/synopsys/dwc2/dwc2_common.c @@ -88,11 +88,13 @@ static void phy_fs_init(dwc2_regs_t* dwc2) { static void phy_hs_init(dwc2_regs_t* dwc2) { uint32_t gusbcfg = dwc2->gusbcfg; + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; + const dwc2_ghwcfg4_t ghwcfg4 = {.value = dwc2->ghwcfg4}; // De-select FS PHY gusbcfg &= ~GUSBCFG_PHYSEL; - if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) { + if (ghwcfg2.hs_phy_type == GHWCFG2_HSPHY_ULPI) { TU_LOG(DWC2_COMMON_DEBUG, "Highspeed ULPI PHY init\r\n"); // Select ULPI PHY (external) @@ -116,7 +118,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) { gusbcfg &= ~GUSBCFG_ULPI_UTMI_SEL; // Set 16-bit interface if supported - if (dwc2->ghwcfg4_bm.phy_data_width) { + if (ghwcfg4.phy_data_width) { gusbcfg |= GUSBCFG_PHYIF16; // 16 bit } else { gusbcfg &= ~GUSBCFG_PHYIF16; // 8 bit @@ -127,7 +129,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) { dwc2->gusbcfg = gusbcfg; // mcu specific phy init - dwc2_phy_init(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); + dwc2_phy_init(dwc2, ghwcfg2.hs_phy_type); // Reset core after selecting PHY reset_core(dwc2); @@ -136,11 +138,11 @@ static void phy_hs_init(dwc2_regs_t* dwc2) { // - 9 if using 8-bit PHY interface // - 5 if using 16-bit PHY interface gusbcfg &= ~GUSBCFG_TRDT_Msk; - gusbcfg |= (dwc2->ghwcfg4_bm.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos; + gusbcfg |= (ghwcfg4.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos; dwc2->gusbcfg = gusbcfg; // MCU specific PHY update post reset - dwc2_phy_update(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); + dwc2_phy_update(dwc2, ghwcfg2.hs_phy_type); } static bool check_dwc2(dwc2_regs_t* dwc2) { @@ -171,7 +173,7 @@ static bool check_dwc2(dwc2_regs_t* dwc2) { //-------------------------------------------------------------------- bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) { (void)dwc2; - + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; #if CFG_TUD_ENABLED if (role == TUSB_ROLE_DEVICE && !TUD_OPT_HIGH_SPEED) { return false; @@ -183,7 +185,7 @@ bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) { } #endif - return dwc2->ghwcfg2_bm.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED; + return ghwcfg2.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED; } /* dwc2 has several PHYs option diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index 812096759..5ecf9d487 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -184,415 +184,470 @@ enum { //-------------------------------------------------------------------- // Common Register Bitfield //-------------------------------------------------------------------- -typedef struct TU_ATTR_PACKED { - uint32_t ses_req_scs : 1; // 0 Session request success - uint32_t ses_req : 1; // 1 Session request - uint32_t vbval_ov_en : 1; // 2 VBUS valid override enable - uint32_t vbval_ov_val : 1; // 3 VBUS valid override value - uint32_t aval_ov_en : 1; // 4 A-peripheral session valid override enable - uint32_t aval_ov_al : 1; // 5 A-peripheral session valid override value - uint32_t bval_ov_en : 1; // 6 B-peripheral session valid override enable - uint32_t bval_ov_val : 1; // 7 B-peripheral session valid override value - uint32_t hng_scs : 1; // 8 Host negotiation success - uint32_t hnp_rq : 1; // 9 HNP (host negotiation protocol) request - uint32_t host_set_hnp_en : 1; // 10 Host set HNP enable - uint32_t dev_hnp_en : 1; // 11 Device HNP enabled - uint32_t embedded_host_en : 1; // 12 Embedded host enable - uint32_t rsv13_14 : 2; // 13.14 Reserved - uint32_t dbnc_filter_bypass : 1; // 15 Debounce filter bypass - uint32_t cid_status : 1; // 16 Connector ID status - uint32_t dbnc_done : 1; // 17 Debounce done - uint32_t ases_valid : 1; // 18 A-session valid - uint32_t bses_valid : 1; // 19 B-session valid - uint32_t otg_ver : 1; // 20 OTG version 0: v1.3, 1: v2.0 - uint32_t current_mode : 1; // 21 Current mode of operation. Only from v3.00a - uint32_t mult_val_id_bc : 5; // 22..26 Multi-valued input pin ID battery charger - uint32_t chirp_en : 1; // 27 Chirp detection enable - uint32_t rsv28_30 : 3; // 28.30: Reserved - uint32_t test_mode_corr_eusb2 : 1; // 31 Test mode control for eUSB2 PHY +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t ses_req_scs : 1; // 0 Session request success + uint32_t ses_req : 1; // 1 Session request + uint32_t vbval_ov_en : 1; // 2 VBUS valid override enable + uint32_t vbval_ov_val : 1; // 3 VBUS valid override value + uint32_t aval_ov_en : 1; // 4 A-peripheral session valid override enable + uint32_t aval_ov_al : 1; // 5 A-peripheral session valid override value + uint32_t bval_ov_en : 1; // 6 B-peripheral session valid override enable + uint32_t bval_ov_val : 1; // 7 B-peripheral session valid override value + uint32_t hng_scs : 1; // 8 Host negotiation success + uint32_t hnp_rq : 1; // 9 HNP (host negotiation protocol) request + uint32_t host_set_hnp_en : 1; // 10 Host set HNP enable + uint32_t dev_hnp_en : 1; // 11 Device HNP enabled + uint32_t embedded_host_en : 1; // 12 Embedded host enable + uint32_t rsv13_14 : 2; // 13.14 Reserved + uint32_t dbnc_filter_bypass : 1; // 15 Debounce filter bypass + uint32_t cid_status : 1; // 16 Connector ID status + uint32_t dbnc_done : 1; // 17 Debounce done + uint32_t ases_valid : 1; // 18 A-session valid + uint32_t bses_valid : 1; // 19 B-session valid + uint32_t otg_ver : 1; // 20 OTG version 0: v1.3, 1: v2.0 + uint32_t current_mode : 1; // 21 Current mode of operation. Only from v3.00a + uint32_t mult_val_id_bc : 5; // 22..26 Multi-valued input pin ID battery charger + uint32_t chirp_en : 1; // 27 Chirp detection enable + uint32_t rsv28_30 : 3; // 28.30: Reserved + uint32_t test_mode_corr_eusb2 : 1; // 31 Test mode control for eUSB2 PHY + }; } dwc2_gotgctl_t; TU_VERIFY_STATIC(sizeof(dwc2_gotgctl_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t rsv0_1 : 2; // 0..1 Reserved - uint32_t ses_end_det : 1; // 2 Session end detected - uint32_t rsv3_7 : 5; // 3..7 Reserved - uint32_t srs_status_change : 1; // 8 Session request success status change - uint32_t hns_status_change : 1; // 9 Host negotiation success status change - uint32_t rsv10_16 : 7; // 10..16 Reserved - uint32_t hng_det : 1; // 17 Host negotiation detected - uint32_t adev_timeout_change : 1; // 18 A-device timeout change - uint32_t dbnc_done : 1; // 19 Debounce done - uint32_t mult_val_lp_change : 1; // 20 Multi-valued input pin change - uint32_t rsv21_31 :11; // 21..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t rsv0_1 : 2; // 0..1 Reserved + uint32_t ses_end_det : 1; // 2 Session end detected + uint32_t rsv3_7 : 5; // 3..7 Reserved + uint32_t srs_status_change : 1; // 8 Session request success status change + uint32_t hns_status_change : 1; // 9 Host negotiation success status change + uint32_t rsv10_16 : 7; // 10..16 Reserved + uint32_t hng_det : 1; // 17 Host negotiation detected + uint32_t adev_timeout_change : 1; // 18 A-device timeout change + uint32_t dbnc_done : 1; // 19 Debounce done + uint32_t mult_val_lp_change : 1; // 20 Multi-valued input pin change + uint32_t rsv21_31 :11; // 21..31 Reserved + }; } dwc2_gotgint_t; TU_VERIFY_STATIC(sizeof(dwc2_gotgint_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t gintmask : 1; // 0 Global interrupt mask - uint32_t hbst_len : 4; // 1..4 Burst length/type - uint32_t dma_en : 1; // 5 DMA enable - uint32_t rsv6 : 1; // 6 Reserved - uint32_t nptxf_empty_lvl : 1; // 7 Non-periodic Tx FIFO empty level - uint32_t ptxf_empty_lvl : 1; // 8 Periodic Tx FIFO empty level - uint32_t rsv9_20 : 12; // 9.20: Reserved - uint32_t remote_mem_support : 1; // 21 Remote memory support - uint32_t notify_all_dma_write : 1; // 22 Notify all DMA writes - uint32_t ahb_single : 1; // 23 AHB single - uint32_t inv_desc_endian : 1; // 24 Inverse descriptor endian - uint32_t rsv25_31 : 7; // 25..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t gintmask : 1; // 0 Global interrupt mask + uint32_t hbst_len : 4; // 1..4 Burst length/type + uint32_t dma_en : 1; // 5 DMA enable + uint32_t rsv6 : 1; // 6 Reserved + uint32_t nptxf_empty_lvl : 1; // 7 Non-periodic Tx FIFO empty level + uint32_t ptxf_empty_lvl : 1; // 8 Periodic Tx FIFO empty level + uint32_t rsv9_20 : 12; // 9.20: Reserved + uint32_t remote_mem_support : 1; // 21 Remote memory support + uint32_t notify_all_dma_write : 1; // 22 Notify all DMA writes + uint32_t ahb_single : 1; // 23 AHB single + uint32_t inv_desc_endian : 1; // 24 Inverse descriptor endian + uint32_t rsv25_31 : 7; // 25..31 Reserved + }; } dwc2_gahbcfg_t; TU_VERIFY_STATIC(sizeof(dwc2_gahbcfg_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t timeout_cal : 3; /* 0..2 Timeout calibration. - The USB standard timeout value for high-speed operation is 736 to 816 (inclusive) bit times. The USB standard - timeout value for full- speed operation is 16 to 18 (inclusive) bit times. The application must program this field - 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_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 - uint32_t ddr_sel : 1; // 7 ULPI DDR select. 0: Single data rate 8-bit, 1: Double data rate 4-bit - uint32_t srp_capable : 1; // 8 SRP-capable - uint32_t hnp_capable : 1; // 9 HNP-capable - uint32_t turnaround_time : 4; // 10..13 Turnaround time. 9: 8-bit UTMI+, 5: 16-bit UTMI+ - uint32_t rsv14 : 1; // 14 Reserved - uint32_t phy_low_power_clk_sel : 1; /* 15 PHY low-power clock select either 480-MHz or 48-MHz (low-power) PHY mode. - In FS/LS modes, the PHY can usually operate on a 48-MHz clock to save power. This bit is valid only for UTMI+ PHYs. - - 0: 480 Mhz internal PLL: the UTMI interface operates at either 60 MHz (8 bit) or 30 MHz (16-bit) - - 1 48 Mhz external clock: the UTMI interface operates at 48 MHz in FS mode and at either 48 or 6 MHz in LS mode */ - uint32_t otg_i2c_sel : 1; // 16 OTG I2C interface select. 0: UTMI-FS, 1: I2C for OTG signals - uint32_t ulpi_fsls : 1; /* 17 ULPI FS/LS select. 0: ULPI, 1: ULPI FS/LS. - valid only when the FS serial transceiver is selected on the ULPI PHY. */ - uint32_t ulpi_auto_resume : 1; // 18 ULPI Auto-resume - uint32_t ulpi_clk_sus_m : 1; // 19 ULPI Clock SuspendM - uint32_t ulpi_ext_vbus_drv : 1; // 20 ULPI External VBUS Drive - uint32_t ulpi_int_vbus_indicator : 1; // 21 ULPI Internal VBUS Indicator - uint32_t term_sel_dl_pulse : 1; // 22 TermSel DLine pulsing - uint32_t indicator_complement : 1; // 23 Indicator complement - uint32_t indicator_pass_through : 1; // 24 Indicator pass through - uint32_t ulpi_if_protect_disable : 1; // 25 ULPI interface protect disable - uint32_t ic_usb_capable : 1; // 26 IC_USB Capable - uint32_t ic_usb_traf_ctl : 1; // 27 IC_USB Traffic Control - uint32_t tx_end_delay : 1; // 28 TX end delay - uint32_t force_host_mode : 1; // 29 Force host mode - uint32_t force_dev_mode : 1; // 30 Force device mode - uint32_t corrupt_tx_pkt : 1; // 31 Corrupt Tx packet. 0: normal, 1: debug +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t timeout_cal : 3; /* 0..2 Timeout calibration. + The USB standard timeout value for high-speed operation is 736 to 816 (inclusive) bit times. The USB standard + timeout value for full- speed operation is 16 to 18 (inclusive) bit times. The application must program this field + 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_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 + uint32_t ddr_sel : 1; // 7 ULPI DDR select. 0: Single data rate 8-bit, 1: Double data rate 4-bit + uint32_t srp_capable : 1; // 8 SRP-capable + uint32_t hnp_capable : 1; // 9 HNP-capable + uint32_t turnaround_time : 4; // 10..13 Turnaround time. 9: 8-bit UTMI+, 5: 16-bit UTMI+ + uint32_t rsv14 : 1; // 14 Reserved + uint32_t phy_low_power_clk_sel : 1; /* 15 PHY low-power clock select either 480-MHz or 48-MHz (low-power) PHY mode. + In FS/LS modes, the PHY can usually operate on a 48-MHz clock to save power. This bit is valid only for UTMI+ PHYs. + - 0: 480 Mhz internal PLL: the UTMI interface operates at either 60 MHz (8 bit) or 30 MHz (16-bit) + - 1 48 Mhz external clock: the UTMI interface operates at 48 MHz in FS mode and at either 48 or 6 MHz in LS mode */ + uint32_t otg_i2c_sel : 1; // 16 OTG I2C interface select. 0: UTMI-FS, 1: I2C for OTG signals + uint32_t ulpi_fsls : 1; /* 17 ULPI FS/LS select. 0: ULPI, 1: ULPI FS/LS. + valid only when the FS serial transceiver is selected on the ULPI PHY. */ + uint32_t ulpi_auto_resume : 1; // 18 ULPI Auto-resume + uint32_t ulpi_clk_sus_m : 1; // 19 ULPI Clock SuspendM + uint32_t ulpi_ext_vbus_drv : 1; // 20 ULPI External VBUS Drive + uint32_t ulpi_int_vbus_indicator : 1; // 21 ULPI Internal VBUS Indicator + uint32_t term_sel_dl_pulse : 1; // 22 TermSel DLine pulsing + uint32_t indicator_complement : 1; // 23 Indicator complement + uint32_t indicator_pass_through : 1; // 24 Indicator pass through + uint32_t ulpi_if_protect_disable : 1; // 25 ULPI interface protect disable + uint32_t ic_usb_capable : 1; // 26 IC_USB Capable + uint32_t ic_usb_traf_ctl : 1; // 27 IC_USB Traffic Control + uint32_t tx_end_delay : 1; // 28 TX end delay + uint32_t force_host_mode : 1; // 29 Force host mode + uint32_t force_dev_mode : 1; // 30 Force device mode + uint32_t corrupt_tx_pkt : 1; // 31 Corrupt Tx packet. 0: normal, 1: debug + }; } dwc2_gusbcfg_t; TU_VERIFY_STATIC(sizeof(dwc2_gusbcfg_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t core_soft_rst : 1; // 0 Core Soft Reset - uint32_t piufs_soft_rst : 1; // 1 PIU FS Dedicated Controller Soft Reset - uint32_t frame_counter_rst : 1; // 2 Frame Counter Reset (host) - uint32_t intoken_q_flush : 1; // 3 IN Token Queue Flush - uint32_t rx_fifo_flush : 1; // 4 RX FIFO Flush - uint32_t tx_fifo_flush : 1; // 5 TX FIFO Flush - uint32_t tx_fifo_num : 5; // 6..10 TX FIFO Number - uint32_t rsv11_28 :18; // 11..28 Reserved - uint32_t core_soft_rst_done : 1; // 29 Core Soft Reset Done, from v4.20a - uint32_t dma_req : 1; // 30 DMA Request - uint32_t ahb_idle : 1; // 31 AHB Idle +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t core_soft_rst : 1; // 0 Core Soft Reset + uint32_t piufs_soft_rst : 1; // 1 PIU FS Dedicated Controller Soft Reset + uint32_t frame_counter_rst : 1; // 2 Frame Counter Reset (host) + uint32_t intoken_q_flush : 1; // 3 IN Token Queue Flush + uint32_t rx_fifo_flush : 1; // 4 RX FIFO Flush + uint32_t tx_fifo_flush : 1; // 5 TX FIFO Flush + uint32_t tx_fifo_num : 5; // 6..10 TX FIFO Number + uint32_t rsv11_28 :18; // 11..28 Reserved + uint32_t core_soft_rst_done : 1; // 29 Core Soft Reset Done, from v4.20a + uint32_t dma_req : 1; // 30 DMA Request + uint32_t ahb_idle : 1; // 31 AHB Idle + }; } dwc2_grstctl_t; TU_VERIFY_STATIC(sizeof(dwc2_grstctl_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t ep_ch_num : 4; // 0..3 Endpoint/Channel Number - uint32_t byte_count :11; // 4..14 Byte Count - uint32_t dpid : 2; // 15..16 Data PID - uint32_t packet_status : 4; // 17..20 Packet Status - uint32_t frame_number : 4; // 21..24 Frame Number - uint32_t rsv25_31 : 7; // 25..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t ep_ch_num : 4; // 0..3 Endpoint/Channel Number + uint32_t byte_count :11; // 4..14 Byte Count + uint32_t dpid : 2; // 15..16 Data PID + uint32_t packet_status : 4; // 17..20 Packet Status + uint32_t frame_number : 4; // 21..24 Frame Number + uint32_t rsv25_31 : 7; // 25..31 Reserved + }; } dwc2_grxstsp_t; TU_VERIFY_STATIC(sizeof(dwc2_grxstsp_t) == 4, "incorrect size"); -// Hardware Configuration -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 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) - uint32_t num_host_ch : 4; // 14..17 Number of host channel (excluding control) - uint32_t period_channel_support : 1; // 18 Support Periodic OUT Host Channel - uint32_t enable_dynamic_fifo : 1; // 19 Dynamic FIFO Sizing Enabled - uint32_t mul_proc_intrpt : 1; // 20 Multi-Processor Interrupt enabled (OTG_MULTI_PROC_INTRPT) - uint32_t reserved21 : 1; // 21 reserved - uint32_t nptx_q_depth : 2; // 22..23 Non-periodic request queue depth: 0 = 2. 1 = 4, 2 = 8 - uint32_t ptx_q_depth : 2; // 24..25 Host periodic request queue depth: 0 = 2. 1 = 4, 2 = 8 - uint32_t token_q_depth : 5; // 26..30 Device IN token sequence learning queue depth: 0-30 - uint32_t otg_enable_ic_usb : 1; // 31 IC_USB mode specified for mode of operation +typedef union { + uint32_t value; + 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 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) + uint32_t num_host_ch : 4; // 14..17 Number of host channel (excluding control) + uint32_t period_channel_support : 1; // 18 Support Periodic OUT Host Channel + uint32_t enable_dynamic_fifo : 1; // 19 Dynamic FIFO Sizing Enabled + uint32_t mul_proc_intrpt : 1; // 20 Multi-Processor Interrupt enabled (OTG_MULTI_PROC_INTRPT) + uint32_t reserved21 : 1; // 21 reserved + uint32_t nptx_q_depth : 2; // 22..23 Non-periodic request queue depth: 0 = 2. 1 = 4, 2 = 8 + uint32_t ptx_q_depth : 2; // 24..25 Host periodic request queue depth: 0 = 2. 1 = 4, 2 = 8 + uint32_t token_q_depth : 5; // 26..30 Device IN token sequence learning queue depth: 0-30 + uint32_t otg_enable_ic_usb : 1; // 31 IC_USB mode specified for mode of operation + }; } dwc2_ghwcfg2_t; TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg2_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t xfer_size_width : 4; // 0..3 Transfer size counter in bits = 11 + n (max 19 bits) - uint32_t packet_size_width : 3; // 4..6 Packet size counter in bits = 4 + n (max 10 bits) - uint32_t otg_enable : 1; // 7 OTG capable - uint32_t i2c_enable : 1; // 8 I2C interface is available - uint32_t vendor_ctrl_itf : 1; // 9 Vendor control interface is available - uint32_t optional_feature_removed : 1; // 10 remove User ID, GPIO, SOF toggle & counter to save gate count - uint32_t synch_reset : 1; // 11 0: async reset | 1: synch reset - uint32_t otg_adp_support : 1; // 12 ADP logic is present along with HSOTG controller - uint32_t otg_enable_hsic : 1; // 13 1: HSIC-capable with shared UTMI PHY interface | 0: non-HSIC - uint32_t battery_charger_support : 1; // s14 upport battery charger - uint32_t lpm_mode : 1; // 15 LPM mode - uint32_t dfifo_depth : 16; // DFIFO depth - EP_LOC_CNT in terms of 32-bit words -}dwc2_ghwcfg3_t; +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t xfer_size_width : 4; // 0..3 Transfer size counter in bits = 11 + n (max 19 bits) + uint32_t packet_size_width : 3; // 4..6 Packet size counter in bits = 4 + n (max 10 bits) + uint32_t otg_enable : 1; // 7 OTG capable + uint32_t i2c_enable : 1; // 8 I2C interface is available + uint32_t vendor_ctrl_itf : 1; // 9 Vendor control interface is available + uint32_t optional_feature_removed : 1; // 10 remove User ID, GPIO, SOF toggle & counter to save gate count + uint32_t synch_reset : 1; // 11 0: async reset | 1: synch reset + uint32_t otg_adp_support : 1; // 12 ADP logic is present along with HSOTG controller + uint32_t otg_enable_hsic : 1; // 13 1: HSIC-capable with shared UTMI PHY interface | 0: non-HSIC + uint32_t battery_charger_support : 1; // s14 upport battery charger + uint32_t lpm_mode : 1; // 15 LPM mode + uint32_t dfifo_depth : 16; // DFIFO depth - EP_LOC_CNT in terms of 32-bit words + }; +} dwc2_ghwcfg3_t; TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg3_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t num_dev_period_in_ep : 4; // 0..3 Number of Device Periodic IN Endpoints - uint32_t partial_powerdown : 1; // 4 Partial Power Down Enabled - uint32_t ahb_freq_min : 1; // 5 1: minimum of AHB frequency is less than 60 MHz - uint32_t hibernation : 1; // 6 Hibernation feature is enabled - uint32_t extended_hibernation : 1; // 7 Extended Hibernation feature is enabled - uint32_t reserved8 : 1; // 8 Reserved - uint32_t enhanced_lpm_support1 : 1; // 9 Enhanced LPM Support1 - uint32_t service_interval_flow : 1; // 10 Service Interval flow is supported - uint32_t ipg_isoc_support : 1; // 11 Interpacket GAP ISO OUT worst-case is supported - uint32_t acg_support : 1; // 12 Active clock gating is supported - uint32_t enhanced_lpm_support : 1; // 13 Enhanced LPM Support - uint32_t phy_data_width : 2; // 14..15 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable - uint32_t ctrl_ep_num : 4; // 16..19 Number of Device control endpoints in addition to EP0 - uint32_t iddg_filter : 1; // 20 IDDG Filter Enabled - uint32_t vbus_valid_filter : 1; // 21 VBUS Valid Filter Enabled - uint32_t a_valid_filter : 1; // 22 A Valid Filter Enabled - uint32_t b_valid_filter : 1; // 23 B Valid Filter Enabled - uint32_t session_end_filter : 1; // 24 Session End Filter Enabled - uint32_t dedicated_fifos : 1; // 25 Dedicated tx fifo for device IN Endpoint - uint32_t num_dev_in_eps : 4; // 26..29 Number of Device IN Endpoints including EP0 - uint32_t dma_desc_enabled : 1; // scatter/gather DMA configuration enabled - uint32_t dma_desc_dynamic : 1; // Dynamic scatter/gather DMA -}dwc2_ghwcfg4_t; +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t num_dev_period_in_ep : 4; // 0..3 Number of Device Periodic IN Endpoints + uint32_t partial_powerdown : 1; // 4 Partial Power Down Enabled + uint32_t ahb_freq_min : 1; // 5 1: minimum of AHB frequency is less than 60 MHz + uint32_t hibernation : 1; // 6 Hibernation feature is enabled + uint32_t extended_hibernation : 1; // 7 Extended Hibernation feature is enabled + uint32_t reserved8 : 1; // 8 Reserved + uint32_t enhanced_lpm_support1 : 1; // 9 Enhanced LPM Support1 + uint32_t service_interval_flow : 1; // 10 Service Interval flow is supported + uint32_t ipg_isoc_support : 1; // 11 Interpacket GAP ISO OUT worst-case is supported + uint32_t acg_support : 1; // 12 Active clock gating is supported + uint32_t enhanced_lpm_support : 1; // 13 Enhanced LPM Support + uint32_t phy_data_width : 2; // 14..15 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable + uint32_t ctrl_ep_num : 4; // 16..19 Number of Device control endpoints in addition to EP0 + uint32_t iddg_filter : 1; // 20 IDDG Filter Enabled + uint32_t vbus_valid_filter : 1; // 21 VBUS Valid Filter Enabled + uint32_t a_valid_filter : 1; // 22 A Valid Filter Enabled + uint32_t b_valid_filter : 1; // 23 B Valid Filter Enabled + uint32_t session_end_filter : 1; // 24 Session End Filter Enabled + uint32_t dedicated_fifos : 1; // 25 Dedicated tx fifo for device IN Endpoint + uint32_t num_dev_in_eps : 4; // 26..29 Number of Device IN Endpoints including EP0 + uint32_t dma_desc_enabled : 1; // scatter/gather DMA configuration enabled + uint32_t dma_desc_dynamic : 1; // Dynamic scatter/gather DMA + }; +} dwc2_ghwcfg4_t; TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg4_t) == 4, "incorrect size"); -//-------------------------------------------------------------------- -// Host Register Bitfield -//-------------------------------------------------------------------- - -typedef struct TU_ATTR_PACKED { - uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO - uint32_t req_queue_available : 8; // 16..23 Number of spaces available in the NPT transmit request queue for both IN and OU - // 24..31 is top entry in the request queue that is currently being processed by the MAC - uint32_t qtop_terminate : 1; // 24 Last entry for selected channel - uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command - uint32_t qtop_ch_num : 4; // 27..30 Channel number +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO + uint32_t req_queue_available : 8; // 16..23 Number of spaces available in the NPT transmit request queue for both IN and OU + // 24..31 is top entry in the request queue that is currently being processed by the MAC + uint32_t qtop_terminate : 1; // 24 Last entry for selected channel + uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command + uint32_t qtop_ch_num : 4; // 27..30 Channel number + }; } dwc2_hnptxsts_t; TU_VERIFY_STATIC(sizeof(dwc2_hnptxsts_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO - uint32_t req_queue_available : 7; // 16..22 Number of spaces available in the PTX transmit request queue - uint32_t qtop_terminate : 1; // 23 Last entry for selected channel - uint32_t qtop_last_period : 1; // 24 Last entry for selected channel is a periodic entry - uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command - uint32_t qtop_ch_num : 4; // 27..30 Channel number - uint32_t qtop_odd_frame : 1; // 31 Send in odd frame +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO + uint32_t req_queue_available : 7; // 16..22 Number of spaces available in the PTX transmit request queue + uint32_t qtop_terminate : 1; // 23 Last entry for selected channel + uint32_t qtop_last_period : 1; // 24 Last entry for selected channel is a periodic entry + uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command + uint32_t qtop_ch_num : 4; // 27..30 Channel number + uint32_t qtop_odd_frame : 1; // 31 Send in odd frame + }; } dwc2_hptxsts_t; TU_VERIFY_STATIC(sizeof(dwc2_hptxsts_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t conn_status : 1; // 0 Port connect status - uint32_t conn_detected : 1; // 1 Port connect detected - uint32_t enable : 1; // 2 Port enable status - uint32_t enable_change : 1; // 3 Port enable change - uint32_t over_current_active : 1; // 4 Port Over-current active - uint32_t over_current_change : 1; // 5 Port Over-current change - uint32_t resume : 1; // 6 Port resume - uint32_t suspend : 1; // 7 Port suspend - uint32_t reset : 1; // 8 Port reset - uint32_t rsv9 : 1; // 9 Reserved - uint32_t line_status : 2; // 10..11 Line status - uint32_t power : 1; // 12 Port power - uint32_t test_control : 4; // 13..16 Port Test control - uint32_t speed : 2; // 17..18 Port speed - uint32_t rsv19_31 :13; // 19..31 Reserved -}dwc2_hprt_t; +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t conn_status : 1; // 0 Port connect status + uint32_t conn_detected : 1; // 1 Port connect detected + uint32_t enable : 1; // 2 Port enable status + uint32_t enable_change : 1; // 3 Port enable change + uint32_t over_current_active : 1; // 4 Port Over-current active + uint32_t over_current_change : 1; // 5 Port Over-current change + uint32_t resume : 1; // 6 Port resume + uint32_t suspend : 1; // 7 Port suspend + uint32_t reset : 1; // 8 Port reset + uint32_t rsv9 : 1; // 9 Reserved + uint32_t line_status : 2; // 10..11 Line status + uint32_t power : 1; // 12 Port power + uint32_t test_control : 4; // 13..16 Port Test control + uint32_t speed : 2; // 17..18 Port speed + uint32_t rsv19_31 :13; // 19..31 Reserved + }; +} dwc2_hprt_t; TU_VERIFY_STATIC(sizeof(dwc2_hprt_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t ep_size : 11; // 0..10 Maximum packet size - uint32_t ep_num : 4; // 11..14 Endpoint number - uint32_t ep_dir : 1; // 15 Endpoint direction - uint32_t rsv16 : 1; // 16 Reserved - uint32_t low_speed_dev : 1; // 17 Low-speed device - uint32_t ep_type : 2; // 18..19 Endpoint type - uint32_t err_multi_count : 2; // 20..21 Error (splitEn = 1) / Multi (SplitEn = 0) count - uint32_t dev_addr : 7; // 22..28 Device address - uint32_t odd_frame : 1; // 29 Odd frame - uint32_t disable : 1; // 30 Channel disable - uint32_t enable : 1; // 31 Channel enable +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t ep_size : 11; // 0..10 Maximum packet size + uint32_t ep_num : 4; // 11..14 Endpoint number + uint32_t ep_dir : 1; // 15 Endpoint direction + uint32_t rsv16 : 1; // 16 Reserved + uint32_t low_speed_dev : 1; // 17 Low-speed device + uint32_t ep_type : 2; // 18..19 Endpoint type + uint32_t err_multi_count : 2; // 20..21 Error (splitEn = 1) / Multi (SplitEn = 0) count + uint32_t dev_addr : 7; // 22..28 Device address + uint32_t odd_frame : 1; // 29 Odd frame + uint32_t disable : 1; // 30 Channel disable + uint32_t enable : 1; // 31 Channel enable + }; } dwc2_channel_char_t; TU_VERIFY_STATIC(sizeof(dwc2_channel_char_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t hub_port : 7; // 0..6 Hub port number - uint32_t hub_addr : 7; // 7..13 Hub address - uint32_t xact_pos : 2; // 14..15 Transaction position - uint32_t split_compl : 1; // 16 Split completion - uint32_t rsv17_30 : 14; // 17..30 Reserved - uint32_t split_en : 1; // 31 Split enable +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t hub_port : 7; // 0..6 Hub port number + uint32_t hub_addr : 7; // 7..13 Hub address + uint32_t xact_pos : 2; // 14..15 Transaction position + uint32_t split_compl : 1; // 16 Split completion + uint32_t rsv17_30 : 14; // 17..30 Reserved + uint32_t split_en : 1; // 31 Split enable + }; } dwc2_channel_split_t; TU_VERIFY_STATIC(sizeof(dwc2_channel_split_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t xfer_size : 19; // 0..18 Transfer size in bytes - uint32_t packet_count : 10; // 19..28 Number of packets - uint32_t pid : 2; // 29..30 Packet ID - uint32_t do_ping : 1; // 31 Do PING +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t xfer_size : 19; // 0..18 Transfer size in bytes + uint32_t packet_count : 10; // 19..28 Number of packets + uint32_t pid : 2; // 29..30 Packet ID + uint32_t do_ping : 1; // 31 Do PING + }; } dwc2_channel_tsize_t; TU_VERIFY_STATIC(sizeof(dwc2_channel_tsize_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t num : 16; // 0..15 Frame number - uint32_t remainning : 16; // 16..31 Frame remaining +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t num : 16; // 0..15 Frame number + uint32_t remainning : 16; // 16..31 Frame remaining + }; } dwc2_hfnum_t; TU_VERIFY_STATIC(sizeof(dwc2_hfnum_t) == 4, "incorrect size"); // Host Channel typedef struct { - union { - volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics - volatile dwc2_channel_char_t hcchar_bm; - }; - union { - volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control - volatile dwc2_channel_split_t hcsplt_bm; - }; - volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt - volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask - union { - volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size - volatile dwc2_channel_tsize_t hctsiz_bm; - }; - volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address - uint32_t reserved518; // 518 + 20*ch - volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address + volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics + volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control + volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt + volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask + volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size + volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address + uint32_t reserved518; // 518 + 20*ch + volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address } dwc2_channel_t; //-------------------------------------------------------------------- // Device Register Bitfield //-------------------------------------------------------------------- -typedef struct TU_ATTR_PACKED { - uint32_t speed : 2; // 0..1 Speed - uint32_t nzsts_out_handshake : 1; // 2 Non-zero-length status OUT handshake - uint32_t en_32khz_suspsend : 1; // 3 Enable 32-kHz SUSPEND mode - uint32_t address : 7; // 4..10 Device address - uint32_t period_frame_interval : 2; // 11..12 Periodic frame interval - uint32_t en_out_nak : 1; // 13 Enable Device OUT NAK - uint32_t xcvr_delay : 1; // 14 Transceiver delay - uint32_t erratic_int_mask : 1; // 15 Erratic interrupt mask - uint32_t rsv16 : 1; // 16 Reserved - uint32_t ipg_iso_support : 1; // 17 Interpacket gap ISO support - uint32_t epin_mismatch_count : 5; // 18..22 EP IN mismatch count - uint32_t dma_desc : 1; // 23 Enable scatter/gatter DMA descriptor - uint32_t period_schedule_interval : 2; // 24..25 Periodic schedule interval for scatter/gatter DMA - uint32_t resume_valid : 6; // 26..31 Resume valid period +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t speed : 2; // 0..1 Speed + uint32_t nzsts_out_handshake : 1; // 2 Non-zero-length status OUT handshake + uint32_t en_32khz_suspsend : 1; // 3 Enable 32-kHz SUSPEND mode + uint32_t address : 7; // 4..10 Device address + uint32_t period_frame_interval : 2; // 11..12 Periodic frame interval + uint32_t en_out_nak : 1; // 13 Enable Device OUT NAK + uint32_t xcvr_delay : 1; // 14 Transceiver delay + uint32_t erratic_int_mask : 1; // 15 Erratic interrupt mask + uint32_t rsv16 : 1; // 16 Reserved + uint32_t ipg_iso_support : 1; // 17 Interpacket gap ISO support + uint32_t epin_mismatch_count : 5; // 18..22 EP IN mismatch count + uint32_t dma_desc : 1; // 23 Enable scatter/gather DMA descriptor + uint32_t period_schedule_interval : 2; // 24..25 Periodic schedule interval for scatter/gather DMA + uint32_t resume_valid : 6; // 26..31 Resume valid period + }; } dwc2_dcfg_t; TU_VERIFY_STATIC(sizeof(dwc2_dcfg_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t remote_wakeup_signal : 1; // 0 Remote wakeup signal - uint32_t soft_disconnet : 1; // 1 Soft disconnect - uint32_t gnp_in_nak_status : 1; // 2 Global non-periodic NAK IN status - uint32_t gout_nak_status : 1; // 3 Global OUT NAK status - uint32_t test_control : 3; // 4..6 Test control - uint32_t set_gnp_in_nak : 1; // 7 Set global non-periodic IN NAK - uint32_t clear_gnp_in_nak : 1; // 8 Clear global non-periodic IN NAK - uint32_t set_gout_nak : 1; // 9 Set global OUT NAK - uint32_t clear_gout_nak : 1; // 10 Clear global OUT NAK - uint32_t poweron_prog_done : 1; // 11 Power-on programming done - uint32_t rsv12 : 1; // 12 Reserved - uint32_t global_multi_count : 2; // 13..14 Global multi-count - uint32_t ignore_frame_number : 1; // 15 Ignore frame number - uint32_t nak_on_babble : 1; // 16 NAK on babble - uint32_t en_cont_on_bna : 1; // 17 Enable continue on BNA - uint32_t deep_sleep_besl_reject : 1; // 18 Deep sleep BESL reject - uint32_t service_interval : 1; // 19 Service interval for ISO IN endpoint - uint32_t rsv20_31 :12; // 20..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t remote_wakeup_signal : 1; // 0 Remote wakeup signal + uint32_t soft_disconnet : 1; // 1 Soft disconnect + uint32_t gnp_in_nak_status : 1; // 2 Global non-periodic NAK IN status + uint32_t gout_nak_status : 1; // 3 Global OUT NAK status + uint32_t test_control : 3; // 4..6 Test control + uint32_t set_gnp_in_nak : 1; // 7 Set global non-periodic IN NAK + uint32_t clear_gnp_in_nak : 1; // 8 Clear global non-periodic IN NAK + uint32_t set_gout_nak : 1; // 9 Set global OUT NAK + uint32_t clear_gout_nak : 1; // 10 Clear global OUT NAK + uint32_t poweron_prog_done : 1; // 11 Power-on programming done + uint32_t rsv12 : 1; // 12 Reserved + uint32_t global_multi_count : 2; // 13..14 Global multi-count + uint32_t ignore_frame_number : 1; // 15 Ignore frame number + uint32_t nak_on_babble : 1; // 16 NAK on babble + uint32_t en_cont_on_bna : 1; // 17 Enable continue on BNA + uint32_t deep_sleep_besl_reject : 1; // 18 Deep sleep BESL reject + uint32_t service_interval : 1; // 19 Service interval for ISO IN endpoint + uint32_t rsv20_31 :12; // 20..31 Reserved + }; } dwc2_dctl_t; TU_VERIFY_STATIC(sizeof(dwc2_dctl_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t suspend_status : 1; // 0 Suspend status - uint32_t enum_speed : 2; // 1..2 Enumerated speed - uint32_t erratic_err : 1; // 3 Erratic error - uint32_t rsv4_7 : 4; // 4..7 Reserved - uint32_t frame_number : 14; // 8..21 Frame/MicroFrame number - uint32_t line_status : 2; // 22..23 Line status - uint32_t rsv24_31 : 8; // 24..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t suspend_status : 1; // 0 Suspend status + uint32_t enum_speed : 2; // 1..2 Enumerated speed + uint32_t erratic_err : 1; // 3 Erratic error + uint32_t rsv4_7 : 4; // 4..7 Reserved + uint32_t frame_number : 14; // 8..21 Frame/MicroFrame number + uint32_t line_status : 2; // 22..23 Line status + uint32_t rsv24_31 : 8; // 24..31 Reserved + }; } dwc2_dsts_t; TU_VERIFY_STATIC(sizeof(dwc2_dsts_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t xfer_complete : 1; // 0 Transfer complete - uint32_t disabled : 1; // 1 Endpoint disabled - uint32_t ahb_err : 1; // 2 AHB error - uint32_t timeout : 1; // 3 Timeout - uint32_t in_rx_txfe : 1; // 4 IN token received when TxFIFO is empty - uint32_t in_rx_ep_mismatch : 1; // 5 IN token received with EP mismatch - uint32_t in_ep_nak_effective : 1; // 6 IN endpoint NAK effective - uint32_t txfifo_empty : 1; // 7 TX FIFO empty - uint32_t txfifo_underrun : 1; // 8 Tx FIFO under run - uint32_t bna : 1; // 9 Buffer not available - uint32_t rsv10 : 1; // 10 Reserved - uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status - uint32_t babble_err : 1; // 12 Babble error - uint32_t nak : 1; // 13 NAK - uint32_t nyet : 1; // 14 NYET - uint32_t rsv14_31 :17; // 15..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t xfer_complete : 1; // 0 Transfer complete + uint32_t disabled : 1; // 1 Endpoint disabled + uint32_t ahb_err : 1; // 2 AHB error + uint32_t timeout : 1; // 3 Timeout + uint32_t in_rx_txfe : 1; // 4 IN token received when TxFIFO is empty + uint32_t in_rx_ep_mismatch : 1; // 5 IN token received with EP mismatch + uint32_t in_ep_nak_effective : 1; // 6 IN endpoint NAK effective + uint32_t txfifo_empty : 1; // 7 TX FIFO empty + uint32_t txfifo_underrun : 1; // 8 Tx FIFO under run + uint32_t bna : 1; // 9 Buffer not available + uint32_t rsv10 : 1; // 10 Reserved + uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status + uint32_t babble_err : 1; // 12 Babble error + uint32_t nak : 1; // 13 NAK + uint32_t nyet : 1; // 14 NYET + uint32_t rsv14_31 :17; // 15..31 Reserved + }; } dwc2_diepint_t; TU_VERIFY_STATIC(sizeof(dwc2_diepint_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t mps : 11; // 0..10 Maximum packet size, EP0 only use 2 bit - uint32_t next_ep : 4; // 11..14 Next endpoint number - uint32_t active : 1; // 15 Active - const uint32_t dpid_iso_odd : 1; // 16 DATA0/DATA1 for bulk/interrupt, odd frame for isochronous - const uint32_t nak_status : 1; // 17 NAK status - uint32_t type : 2; // 18..19 Endpoint type - uint32_t rsv20 : 1; // 20 Reserved - uint32_t stall : 1; // 21 Stall - uint32_t tx_fifo_num : 4; // 22..25 Tx FIFO number (IN) - uint32_t clear_nak : 1; // 26 Clear NAK - uint32_t set_nak : 1; // 27 Set NAK - uint32_t set_data0_iso_even : 1; // 28 Set DATA0 if bulk/interrupt, even frame for isochronous - uint32_t set_data1_iso_odd : 1; // 29 Set DATA1 if bulk/interrupt, odd frame for isochronous - uint32_t disable : 1; // 30 Disable - uint32_t enable : 1; // 31 Enable +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t mps : 11; // 0..10 Maximum packet size, EP0 only use 2 bits + uint32_t next_ep : 4; // 11..14 Next endpoint number + uint32_t active : 1; // 15 Active + uint32_t dpid_iso_odd : 1; // 16 DATA0/DATA1 for bulk/interrupt, odd frame for isochronous + uint32_t nak_status : 1; // 17 NAK status + uint32_t type : 2; // 18..19 Endpoint type + uint32_t rsv20 : 1; // 20 Reserved + uint32_t stall : 1; // 21 Stall + uint32_t tx_fifo_num : 4; // 22..25 Tx FIFO number (IN) + uint32_t clear_nak : 1; // 26 Clear NAK + uint32_t set_nak : 1; // 27 Set NAK + uint32_t set_data0_iso_even : 1; // 28 Set DATA0 if bulk/interrupt, even frame for isochronous + uint32_t set_data1_iso_odd : 1; // 29 Set DATA1 if bulk/interrupt, odd frame for isochronous + uint32_t disable : 1; // 30 Disable + uint32_t enable : 1; // 31 Enable + }; } dwc2_depctl_t; TU_VERIFY_STATIC(sizeof(dwc2_depctl_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t xfer_complete : 1; // 0 Transfer complete - uint32_t disabled : 1; // 1 Endpoint disabled - uint32_t ahb_err : 1; // 2 AHB error - uint32_t setup_phase_done : 1; // 3 Setup phase done - uint32_t out_rx_ep_disabled : 1; // 4 OUT token received when endpoint disabled - uint32_t status_phase_rx : 1; // 5 Status phase received - uint32_t setup_b2b : 1; // 6 Setup packet back-to-back - uint32_t rsv7 : 1; // 7 Reserved - uint32_t out_packet_err : 1; // 8 OUT packet error - uint32_t bna : 1; // 9 Buffer not available - uint32_t rsv10 : 1; // 10 Reserved - uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status - uint32_t babble_err : 1; // 12 Babble error - uint32_t nak : 1; // 13 NAK - uint32_t nyet : 1; // 14 NYET - uint32_t setup_packet_rx : 1; // 15 Setup packet received (Buffer DMA Mode only) - uint32_t rsv16_31 :16; // 16..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t xfer_complete : 1; // 0 Transfer complete + uint32_t disabled : 1; // 1 Endpoint disabled + uint32_t ahb_err : 1; // 2 AHB error + uint32_t setup_phase_done : 1; // 3 Setup phase done + uint32_t out_rx_ep_disabled : 1; // 4 OUT token received when endpoint disabled + uint32_t status_phase_rx : 1; // 5 Status phase received + uint32_t setup_b2b : 1; // 6 Setup packet back-to-back + uint32_t rsv7 : 1; // 7 Reserved + uint32_t out_packet_err : 1; // 8 OUT packet error + uint32_t bna : 1; // 9 Buffer not available + uint32_t rsv10 : 1; // 10 Reserved + uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status + uint32_t babble_err : 1; // 12 Babble error + uint32_t nak : 1; // 13 NAK + uint32_t nyet : 1; // 14 NYET + uint32_t setup_packet_rx : 1; // 15 Setup packet received (Buffer DMA Mode only) + uint32_t rsv16_31 :16; // 16..31 Reserved + }; } dwc2_doepint_t; TU_VERIFY_STATIC(sizeof(dwc2_doepint_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t xfer_size : 19; // 0..18 Transfer size in bytes - uint32_t packet_count : 10; // 19..28 Number of packets - uint32_t mc_pid : 2; // 29..30 IN: Multi Count, OUT: PID +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t xfer_size : 19; // 0..18 Transfer size in bytes + uint32_t packet_count : 10; // 19..28 Number of packets + uint32_t mc_pid : 2; // 29..30 IN: Multi Count, OUT: PID + }; } dwc2_ep_tsize_t; TU_VERIFY_STATIC(sizeof(dwc2_ep_tsize_t) == 4, "incorrect size"); @@ -601,26 +656,19 @@ typedef struct { union { volatile uint32_t diepctl; volatile uint32_t doepctl; - volatile uint32_t ctl; - volatile dwc2_depctl_t ctl_bm; }; uint32_t rsv04; union { volatile uint32_t intr; - volatile uint32_t diepint; - volatile dwc2_diepint_t diepint_bm; - volatile uint32_t doepint; - volatile dwc2_doepint_t doepint_bm; }; uint32_t rsv0c; union { volatile uint32_t dieptsiz; volatile uint32_t doeptsiz; volatile uint32_t tsiz; - volatile dwc2_ep_tsize_t tsiz_bm; }; union { volatile uint32_t diepdma; @@ -628,7 +676,7 @@ typedef struct { }; volatile uint32_t dtxfsts; uint32_t rsv1c; -}dwc2_dep_t; +} dwc2_dep_t; TU_VERIFY_STATIC(sizeof(dwc2_dep_t) == 0x20, "incorrect size"); @@ -637,156 +685,107 @@ TU_VERIFY_STATIC(sizeof(dwc2_dep_t) == 0x20, "incorrect size"); //-------------------------------------------------------------------- typedef struct { //------------- Core Global -------------// - union { - volatile uint32_t gotgctl; // 000 OTG Control and Status - volatile dwc2_gotgctl_t gotgctl_bm; - }; - union { - volatile uint32_t gotgint; // 004 OTG Interrupt - volatile dwc2_gotgint_t gotgint_bm; - }; - union { - volatile uint32_t gahbcfg; // 008 AHB Configuration - volatile dwc2_gahbcfg_t gahbcfg_bm; - }; - union { - volatile uint32_t gusbcfg; // 00c USB Configuration - volatile dwc2_gusbcfg_t gusbcfg_bm; - }; - union { - volatile uint32_t grstctl; // 010 Reset - volatile dwc2_grstctl_t grstctl_bm; - }; - volatile uint32_t gintsts; // 014 Interrupt - volatile uint32_t gintmsk; // 018 Interrupt Mask - volatile uint32_t grxstsr; // 01c Receive Status Debug Read - union { - volatile uint32_t grxstsp; // 020 Receive Status Read/Pop - volatile dwc2_grxstsp_t grxstsp_bm; - }; - volatile uint32_t grxfsiz; // 024 Receive FIFO Size + volatile uint32_t gotgctl; // 000 OTG Control and Status + volatile uint32_t gotgint; // 004 OTG Interrupt + volatile uint32_t gahbcfg; // 008 AHB Configuration + volatile uint32_t gusbcfg; // 00c USB Configuration + volatile uint32_t grstctl; // 010 Reset + volatile uint32_t gintsts; // 014 Interrupt + volatile uint32_t gintmsk; // 018 Interrupt Mask + volatile uint32_t grxstsr; // 01c Receive Status Debug Read + volatile uint32_t grxstsp; // 020 Receive Status Read/Pop + volatile uint32_t grxfsiz; // 024 Receive FIFO Size union { volatile uint32_t dieptxf0; // 028 EP0 Tx FIFO Size volatile uint32_t gnptxfsiz; // 028 Non-periodic Transmit FIFO Size }; union { volatile uint32_t hnptxsts; // 02c Non-periodic Transmit FIFO/Queue Status - volatile dwc2_hnptxsts_t hnptxsts_bm; volatile uint32_t gnptxsts; }; - volatile uint32_t gi2cctl; // 030 I2C Address - volatile uint32_t gpvndctl; // 034 PHY Vendor Control + volatile uint32_t gi2cctl; // 030 I2C Address + volatile uint32_t gpvndctl; // 034 PHY Vendor Control union { volatile uint32_t ggpio; // 038 General Purpose IO volatile uint32_t stm32_gccfg; // 038 STM32 General Core Configuration }; - volatile uint32_t guid; // 03C User (Application programmable) ID - volatile uint32_t gsnpsid; // 040 Synopsys ID + Release version - volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep) - union { - volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2 - volatile dwc2_ghwcfg2_t ghwcfg2_bm; - }; - union { - volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3 - volatile dwc2_ghwcfg3_t ghwcfg3_bm; - }; + volatile uint32_t guid; // 03C User (Application programmable) ID + volatile uint32_t gsnpsid; // 040 Synopsys ID + Release version + volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep) + volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2 + volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3 union { volatile uint32_t ghwcfg4; // 050 User Hardware Configuration4 volatile dwc2_ghwcfg4_t ghwcfg4_bm; }; - volatile uint32_t glpmcfg; // 054 Core LPM Configuration - volatile uint32_t gpwrdn; // 058 Power Down - volatile uint32_t gdfifocfg; // 05C DFIFO Software Configuration - volatile uint32_t gadpctl; // 060 ADP Timer, Control and Status - uint32_t reserved64[39]; // 064..0FF - volatile uint32_t hptxfsiz; // 100 Host Periodic Tx FIFO Size - volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size - uint32_t reserved140[176]; // 140..3FF + volatile uint32_t glpmcfg; // 054 Core LPM Configuration + volatile uint32_t gpwrdn; // 058 Power Down + volatile uint32_t gdfifocfg; // 05C DFIFO Software Configuration + volatile uint32_t gadpctl; // 060 ADP Timer, Control and Status + uint32_t reserved64[39]; // 064..0FF + volatile uint32_t hptxfsiz; // 100 Host Periodic Tx FIFO Size + volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size + uint32_t reserved140[176]; // 140..3FF - //------------ Host -------------// - volatile uint32_t hcfg; // 400 Host Configuration - volatile uint32_t hfir; // 404 Host Frame Interval - union { - volatile uint32_t hfnum; // 408 Host Frame Number / Frame Remaining - volatile dwc2_hfnum_t hfnum_bm; - }; - uint32_t reserved40c; // 40C - union { - volatile uint32_t hptxsts; // 410 Host Periodic TX FIFO / Queue Status - volatile dwc2_hptxsts_t hptxsts_bm; - }; - volatile uint32_t haint; // 414 Host All Channels Interrupt - 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 -------------// + volatile uint32_t hcfg; // 400 Host Configuration + volatile uint32_t hfir; // 404 Host Frame Interval + volatile uint32_t hfnum; // 408 Host Frame Number / Frame Remaining + uint32_t reserved40c; // 40C + volatile uint32_t hptxsts; // 410 Host Periodic TX FIFO / Queue Status + volatile uint32_t haint; // 414 Host All Channels Interrupt + 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 + volatile uint32_t hprt; // 440 Host Port Control and Status + uint32_t reserved444[47]; // 444..4FF - //------------- Host Channel -------------// - dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15 - uint32_t reserved700[64]; // 700..7FF + //------------- Host Channel -------------// + dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15 + uint32_t reserved700[64]; // 700..7FF - //------------- Device -----------// - union { - volatile uint32_t dcfg; // 800 Device Configuration - volatile dwc2_dcfg_t dcfg_bm; - }; - union { - volatile uint32_t dctl; // 804 Device Control - volatile dwc2_dctl_t dctl_bm; - }; - union { - volatile uint32_t dsts; // 808 Device Status (RO) - volatile dwc2_dsts_t dsts_bm; - }; - uint32_t reserved80c; // 80C - union { - volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask - volatile dwc2_diepint_t diepmsk_bm; - }; - union { - volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask - volatile dwc2_doepint_t doepmsk_bm; - }; - volatile uint32_t daint; // 818 Device All Endpoints Interrupt - volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask - volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1 - volatile uint32_t dtknqr2; // 824 Device IN token sequence learning queue read2 - volatile uint32_t dvbusdis; // 828 Device VBUS Discharge Time - volatile uint32_t dvbuspulse; // 82C Device VBUS Pulsing Time - volatile uint32_t dthrctl; // 830 Device threshold Control - volatile uint32_t diepempmsk; // 834 Device IN Endpoint FIFO Empty Interrupt Mask + //------------- Device -----------// + volatile uint32_t dcfg; // 800 Device Configuration + volatile uint32_t dctl; // 804 Device Control + volatile uint32_t dsts; // 808 Device Status (RO) + uint32_t reserved80c; // 80C + volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask + volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask + volatile uint32_t daint; // 818 Device All Endpoints Interrupt + volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask + volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1 + volatile uint32_t dtknqr2; // 824 Device IN token sequence learning queue read2 + volatile uint32_t dvbusdis; // 828 Device VBUS Discharge Time + volatile uint32_t dvbuspulse; // 82C Device VBUS Pulsing Time + volatile uint32_t dthrctl; // 830 Device threshold Control + volatile uint32_t diepempmsk; // 834 Device IN Endpoint FIFO Empty Interrupt Mask - // Device Each Endpoint (IN/OUT) Interrupt/Mask for generating dedicated EP interrupt line - // require OTG_MULTI_PROC_INTRPT=1 - volatile uint32_t deachint; // 838 Device Each Endpoint Interrupt - volatile uint32_t deachmsk; // 83C Device Each Endpoint Interrupt mask - volatile uint32_t diepeachmsk[16]; // 840..87C Device Each IN Endpoint mask - volatile uint32_t doepeachmsk[16]; // 880..8BF Device Each OUT Endpoint mask - uint32_t reserved8c0[16]; // 8C0..8FF + // Device Each Endpoint (IN/OUT) Interrupt/Mask for generating dedicated EP interrupt line + // require OTG_MULTI_PROC_INTRPT=1 + volatile uint32_t deachint; // 838 Device Each Endpoint Interrupt + volatile uint32_t deachmsk; // 83C Device Each Endpoint Interrupt mask + volatile uint32_t diepeachmsk[16]; // 840..87C Device Each IN Endpoint mask + volatile uint32_t doepeachmsk[16]; // 880..8BF Device Each OUT Endpoint mask + uint32_t reserved8c0[16]; // 8C0..8FF - //------------- Device Endpoint -------------// - union { - dwc2_dep_t ep[2][16]; // 0: IN, 1 OUT - struct { - dwc2_dep_t epin[16]; // 900..AFF IN Endpoints - dwc2_dep_t epout[16]; // B00..CFF OUT Endpoints - }; + //------------- Device Endpoint -------------// + union { + dwc2_dep_t ep[2][16]; // 0: IN, 1 OUT + struct { + dwc2_dep_t epin[16]; // 900..AFF IN Endpoints + dwc2_dep_t epout[16]; // B00..CFF OUT Endpoints }; - uint32_t reservedd00[64]; // D00..DFF + }; + uint32_t reservedd00[64]; // D00..DFF - //------------- Power Clock -------------// - volatile uint32_t pcgcctl; // E00 Power and Clock Gating Characteristic Control - volatile uint32_t pcgcctl1; // E04 Power and Clock Gating Characteristic Control 1 - uint32_t reservede08[126]; // E08..FFF + //------------- Power Clock -------------// + volatile uint32_t pcgcctl; // E00 Power and Clock Gating Characteristic Control + volatile uint32_t pcgcctl1; // E04 Power and Clock Gating Characteristic Control 1 + uint32_t reservede08[126]; // E08..FFF - //------------- FIFOs -------------// - // Word-accessed only using first pointer since it auto shift - volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO + //------------- FIFOs -------------// + // Word-accessed only using first pointer since it auto shift + volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO } dwc2_regs_t; TU_VERIFY_STATIC(offsetof(dwc2_regs_t, hcfg ) == 0x0400, "incorrect size"); diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index b13479b02..af17bb59a 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -44,7 +44,7 @@ #endif #define DWC2_CHANNEL_COUNT_MAX 16 // absolute max channel count -#define DWC2_CHANNEL_COUNT(_dwc2) tu_min8((_dwc2)->ghwcfg2_bm.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX) +#define DWC2_CHANNEL_COUNT(_dwc2) ({const dwc2_ghwcfg2_t ghwcfg2 = {.value = (_dwc2)->ghwcfg2}; tu_min8(ghwcfg2.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX);}) TU_VERIFY_STATIC(CFG_TUH_DWC2_ENDPOINT_MAX <= 255, "currently only use 8-bit for index"); @@ -118,7 +118,8 @@ hcd_data_t _hcd_data; //-------------------------------------------------------------------- TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc2) { tusb_speed_t speed; - switch(dwc2->hprt_bm.speed) { + const dwc2_hprt_t hprt = {.value = dwc2->hprt}; + 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; @@ -133,7 +134,8 @@ TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc TU_ATTR_ALWAYS_INLINE static inline bool dma_host_enabled(const dwc2_regs_t* dwc2) { (void) dwc2; // Internal DMA only - return CFG_TUH_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA; + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; + return CFG_TUH_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA; } #if CFG_TUH_MEM_DCACHE_ENABLE @@ -168,15 +170,18 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) { } // Check if is periodic (interrupt/isochronous) -TU_ATTR_ALWAYS_INLINE static inline bool edpt_is_periodic(uint8_t ep_type) { - return ep_type == HCCHAR_EPTYPE_INTERRUPT || ep_type == HCCHAR_EPTYPE_ISOCHRONOUS; +TU_ATTR_ALWAYS_INLINE static inline bool channel_is_periodic(uint32_t hcchar) { + const dwc2_channel_char_t hcchar_bm = {.value = hcchar}; + return hcchar_bm.ep_type == HCCHAR_EPTYPE_INTERRUPT || hcchar_bm.ep_type == HCCHAR_EPTYPE_ISOCHRONOUS; } TU_ATTR_ALWAYS_INLINE static inline uint8_t req_queue_avail(const dwc2_regs_t* dwc2, bool is_period) { if (is_period) { - return dwc2->hptxsts_bm.req_queue_available; + const dwc2_hptxsts_t hptxsts = {.value = dwc2->hptxsts}; + return hptxsts.req_queue_available; } else { - return dwc2->hnptxsts_bm.req_queue_available; + const dwc2_hnptxsts_t hnptxsts = {.value = dwc2->hnptxsts}; + return hnptxsts.req_queue_available; } } @@ -188,7 +193,7 @@ TU_ATTR_ALWAYS_INLINE static inline void channel_dealloc(dwc2_regs_t* dwc2, uint TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) { // disable also require request queue - TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type))); + TU_ASSERT(req_queue_avail(dwc2, channel_is_periodic(channel->hcchar))); channel->hcintmsk |= HCINT_HALTED; channel->hcchar |= HCCHAR_CHDIS | HCCHAR_CHENA; // must set both CHDIS and CHENA return true; @@ -196,7 +201,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2 // attempt to send IN token to receive data TU_ATTR_ALWAYS_INLINE static inline bool channel_send_in_token(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) { - TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type))); + TU_ASSERT(req_queue_avail(dwc2, channel_is_periodic(channel->hcchar))); channel->hcchar |= HCCHAR_CHENA; return true; } @@ -206,8 +211,8 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_find_enabled(dwc2_regs_t* dw const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2); for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) { if (_hcd_data.xfer[ch_id].allocated) { - const dwc2_channel_char_t hcchar_bm = dwc2->channel[ch_id].hcchar_bm; - if (hcchar_bm.dev_addr == dev_addr && hcchar_bm.ep_num == ep_num && (ep_num == 0 || hcchar_bm.ep_dir == ep_dir)) { + const dwc2_channel_char_t hcchar = {.value = dwc2->channel[ch_id].hcchar}; + if (hcchar.dev_addr == dev_addr && hcchar.ep_num == ep_num && (ep_num == 0 || hcchar.ep_dir == ep_dir)) { return ch_id; } } @@ -304,12 +309,13 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t cal_next_pid(uint8_t pid, uint8_t pa static void dfifo_host_init(uint8_t rhport) { const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport]; dwc2_regs_t* dwc2 = DWC2_REG(rhport); + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per channel const bool is_dma = dma_host_enabled(dwc2); uint16_t dfifo_top = dwc2_controller->ep_fifo_size/4; if (is_dma) { - dfifo_top -= dwc2->ghwcfg2_bm.num_host_ch; + dfifo_top -= ghwcfg2.num_host_ch; } // fixed allocation for now, improve later: @@ -319,7 +325,7 @@ static void dfifo_host_init(uint8_t rhport) { uint32_t ptx_largest = is_highspeed ? TUSB_EPSIZE_ISO_HS_MAX/4 : 256/4; uint16_t nptxfsiz = 2 * nptx_largest; - uint16_t rxfsiz = 2 * (ptx_largest + 2) + dwc2->ghwcfg2_bm.num_host_ch; + uint16_t rxfsiz = 2 * (ptx_largest + 2) + ghwcfg2.num_host_ch; TU_ASSERT(dfifo_top >= (nptxfsiz + rxfsiz),); uint16_t ptxfsiz = dfifo_top - (nptxfsiz + rxfsiz); @@ -509,10 +515,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* // clean up channel after part of transfer is done but the whole urb is not complete static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) { hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; - dwc2_channel_t* channel = &dwc2->channel[ch_id]; + const dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; - edpt->next_pid = channel->hctsiz_bm.pid; // save PID + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; + edpt->next_pid = hctsiz.pid; // save PID /* Since hctsiz.xfersize field reflects the number of bytes transferred via the AHB, not the USB) * For IN: we can use hctsiz.xfersize as remaining bytes. @@ -520,9 +527,10 @@ static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) { * number of packets that have been transferred via the USB. This is always an integral number of packets if the * transfer was halted before its normal completion. */ - const uint16_t remain_packets = channel->hctsiz_bm.packet_count; - const uint16_t total_packets = cal_packet_count(edpt->buflen, channel->hcchar_bm.ep_size); - const uint16_t actual_bytes = (total_packets - remain_packets) * channel->hcchar_bm.ep_size; + const uint16_t remain_packets = hctsiz.packet_count; + const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; + const uint16_t total_packets = cal_packet_count(edpt->buflen, hcchar.ep_size); + const uint16_t actual_bytes = (total_packets - remain_packets) * hcchar.ep_size; xfer->fifo_bytes = 0; xfer->xferred_bytes += actual_bytes; @@ -535,7 +543,7 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) { hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; dwc2_channel_char_t* hcchar_bm = &edpt->hcchar_bm; dwc2_channel_t* channel = &dwc2->channel[ch_id]; - bool const is_period = edpt_is_periodic(hcchar_bm->ep_type); + bool const is_period = channel_is_periodic(hcchar_bm->ep_type); // clear previous state xfer->fifo_bytes = 0; @@ -548,12 +556,15 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) { // hctsiz: zero length packet still count as 1 const uint16_t packet_count = cal_packet_count(edpt->buflen, hcchar_bm->ep_size); - uint32_t hctsiz = (edpt->next_pid << HCTSIZ_PID_Pos) | (packet_count << HCTSIZ_PKTCNT_Pos) | edpt->buflen; + dwc2_channel_tsize_t hctsiz = {.value = 0}; + hctsiz.pid = edpt->next_pid; // next PID is set in transfer complete interrupt + hctsiz.packet_count = packet_count; + hctsiz.xfer_size = edpt->buflen; if (edpt->do_ping && edpt->speed == TUSB_SPEED_HIGH && edpt->next_pid != HCTSIZ_PID_SETUP && hcchar_bm->ep_dir == TUSB_DIR_OUT) { - hctsiz |= HCTSIZ_DOPING; + hctsiz.do_ping = 1; } - channel->hctsiz = hctsiz; + channel->hctsiz = hctsiz.value; edpt->do_ping = 0; // pre-calculate next PID based on packet count, adjusted in transfer complete interrupt if short packet @@ -699,13 +710,16 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; - if (edpt_is_periodic(channel->hcchar_bm.ep_type)){ + if (channel_is_periodic(channel->hcchar)){ + const dwc2_channel_split_t hcsplt = {.value = channel->hcsplt}; // retry immediately for periodic split NYET if we haven't reach max retry - if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) { + if (hcsplt.split_en && hcsplt.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) { xfer->period_split_nyet_count++; xfer->halted_nyet = 0; if (xfer->period_split_nyet_count < HCD_XFER_PERIOD_SPLIT_NYET_MAX) { - channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame + dwc2_channel_char_t hcchar = {.value = channel->hcchar}; + hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame + channel->hcchar = hcchar.value; channel_send_in_token(dwc2, channel); return; } else { @@ -715,7 +729,8 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci } // for periodic, de-allocate channel, enable SOF set frame counter for later transfer - edpt->next_pid = channel->hctsiz_bm.pid; // save PID + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; + edpt->next_pid = hctsiz.pid; // save PID edpt->uframe_countdown = edpt->uframe_interval; dwc2->gintmsk |= GINTSTS_SOF; @@ -756,13 +771,13 @@ static void handle_rxflvl_irq(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); // Pop control word off FIFO - const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm; - const uint8_t ch_id = grxstsp_bm.ep_ch_num; + const dwc2_grxstsp_t grxstsp = {.value= dwc2->grxstsp}; + const uint8_t ch_id = grxstsp.ep_ch_num; - switch (grxstsp_bm.packet_status) { + switch (grxstsp.packet_status) { case GRXSTS_PKTSTS_RX_DATA: { // In packet received, pop this entry --> ACK interrupt - const uint16_t byte_count = grxstsp_bm.byte_count; + const uint16_t byte_count = grxstsp.byte_count; hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,); hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; @@ -796,25 +811,26 @@ static void handle_rxflvl_irq(uint8_t rhport) { // return true if there is still pending data and need more ISR static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) { // Use period txsts for both p/np to get request queue space available (1-bit difference, it is small enough) - volatile dwc2_hptxsts_t* txsts_bm = (volatile dwc2_hptxsts_t*) (is_periodic ? &dwc2->hptxsts : &dwc2->hnptxsts); + const dwc2_hptxsts_t txsts = {.value = (is_periodic ? dwc2->hptxsts : dwc2->hnptxsts)}; const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2); for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) { dwc2_channel_t* channel = &dwc2->channel[ch_id]; + const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; // skip writing to FIFO if channel is expecting halted. - if (!(channel->hcintmsk & HCINT_HALTED) && (channel->hcchar_bm.ep_dir == TUSB_DIR_OUT)) { + if (!(channel->hcintmsk & HCINT_HALTED) && (hcchar.ep_dir == TUSB_DIR_OUT)) { hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; - - const uint16_t remain_packets = channel->hctsiz_bm.packet_count; + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; + const uint16_t remain_packets = hctsiz.packet_count; for (uint16_t i = 0; i < remain_packets; i++) { const uint16_t remain_bytes = edpt->buflen - xfer->fifo_bytes; - const uint16_t xact_bytes = tu_min16(remain_bytes, channel->hcchar_bm.ep_size); + const uint16_t xact_bytes = tu_min16(remain_bytes, hcchar.ep_size); // skip if there is not enough space in FIFO and RequestQueue. // Packet's last word written to FIFO will trigger a request queue - if ((xact_bytes > (txsts_bm->fifo_available << 2)) || (txsts_bm->req_queue_available == 0)) { + if ((xact_bytes > (txsts.fifo_available << 2)) || (txsts.req_queue_available == 0)) { return true; } @@ -831,23 +847,27 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; + const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; + dwc2_channel_split_t hcsplt = {.value = channel->hcsplt}; + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; bool is_done = false; - // if (channel->hcsplt_bm.split_en) { + // if (hcsplt.split_en) { // if (edpt->hcchar_bm.ep_num == 1) { - // TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, channel->hcchar_bm.ep_num, hcint); + // TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, hcsplt.ep_num, hcint); // print_hcint(hcint); // } if (hcint & HCINT_XFER_COMPLETE) { if (edpt->hcchar_bm.ep_num != 0) { - edpt->next_pid = channel->hctsiz_bm.pid; // save pid (already toggled) + edpt->next_pid = hctsiz.pid; // save pid (already toggled) } - const uint16_t remain_packets = channel->hctsiz_bm.packet_count; - if (channel->hcsplt_bm.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) { + const uint16_t remain_packets = hctsiz.packet_count; + if (hcsplt.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) { // Split can only complete 1 transaction (up to 1 packet) at a time, schedule more - channel->hcsplt_bm.split_compl = 0; + hcsplt.split_compl = 0; + channel->hcsplt = hcsplt.value; } else { xfer->result = XFER_RESULT_SUCCESS; } @@ -866,34 +886,38 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h channel_disable(dwc2, channel); } else if (hcint & HCINT_NYET) { // restart complete split - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; xfer->halted_nyet = 1; channel_disable(dwc2, channel); } else if (hcint & HCINT_NAK) { // NAK received, re-enable channel if request queue is available - if (channel->hcsplt_bm.split_en) { - channel->hcsplt_bm.split_compl = 0; // restart with start-split + if (hcsplt.split_en) { + hcsplt.split_compl = 0; // restart with start-split + channel->hcsplt = hcsplt.value; } channel_disable(dwc2, channel); } else if (hcint & HCINT_ACK) { xfer->err_count = 0; - if (channel->hcsplt_bm.split_en) { - if (!channel->hcsplt_bm.split_compl) { + if (hcsplt.split_en) { + if (!hcsplt.split_compl) { // start split is ACK --> do complete split channel->hcintmsk |= HCINT_NYET; - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; channel_send_in_token(dwc2, channel); } else { // do nothing for complete split with DATA, this will trigger XferComplete and handled there } } else { // ACK with data - const uint16_t remain_packets = channel->hctsiz_bm.packet_count; + const uint16_t remain_packets = hctsiz.packet_count; if (remain_packets) { // still more packet to receive, also reset to start split - channel->hcsplt_bm.split_compl = 0; + hcsplt.split_compl = 0; + channel->hcsplt = hcsplt.value; channel_send_in_token(dwc2, channel); } } @@ -922,6 +946,7 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; + dwc2_channel_split_t hcsplt = {.value = channel->hcsplt}; bool is_done = false; if (hcint & HCINT_XFER_COMPLETE) { @@ -933,9 +958,10 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t channel_disable(dwc2, channel); } else if (hcint & HCINT_NYET) { xfer->err_count = 0; - if (channel->hcsplt_bm.split_en) { + if (hcsplt.split_en) { // retry complete split - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; channel->hcchar |= HCCHAR_CHENA; } else { edpt->do_ping = 1; @@ -968,9 +994,10 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t } else if (hcint & HCINT_ACK) { xfer->err_count = 0; channel->hcintmsk &= ~HCINT_ACK; - if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) { + if (hcsplt.split_en && !hcsplt.split_compl) { // start split is ACK --> do complete split - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; channel->hcchar |= HCCHAR_CHENA; } } @@ -989,6 +1016,9 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; + dwc2_channel_char_t hcchar = {.value = channel->hcchar}; + dwc2_channel_split_t hcsplt = {.value = channel->hcsplt}; + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; bool is_done = false; @@ -996,8 +1026,8 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci if (hcint & HCINT_HALTED) { if (hcint & (HCINT_XFER_COMPLETE | HCINT_STALL | HCINT_BABBLE_ERR)) { - const uint16_t remain_bytes = (uint16_t) channel->hctsiz_bm.xfer_size; - const uint16_t remain_packets = channel->hctsiz_bm.packet_count; + const uint16_t remain_bytes = (uint16_t) hctsiz.xfer_size; + const uint16_t remain_packets = hctsiz.packet_count; const uint16_t actual_len = edpt->buflen - remain_bytes; xfer->xferred_bytes += actual_len; @@ -1007,13 +1037,14 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci xfer->result = XFER_RESULT_STALLED; } else if (hcint & HCINT_BABBLE_ERR) { xfer->result = XFER_RESULT_FAILED; - } else if (channel->hcsplt_bm.split_en && remain_packets && actual_len == edpt->hcchar_bm.ep_size) { + } else if (hcsplt.split_en && remain_packets && actual_len == hcchar.ep_size) { // Split can only complete 1 transaction (up to 1 packet) at a time, schedule more is_done = false; edpt->buffer += actual_len; edpt->buflen -= actual_len; - channel->hcsplt_bm.split_compl = 0; + hcsplt.split_compl = 0; + channel->hcsplt = hcsplt.value; channel_xfer_in_retry(dwc2, ch_id, hcint); } else { xfer->result = XFER_RESULT_SUCCESS; @@ -1028,33 +1059,38 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci xfer->result = XFER_RESULT_FAILED; } else { channel->hcintmsk |= HCINT_ACK | HCINT_NAK | HCINT_DATATOGGLE_ERR; - channel->hcsplt_bm.split_compl = 0; + hcsplt.split_compl = 0; + channel->hcsplt = hcsplt.value; channel_xfer_in_retry(dwc2, ch_id, hcint); } } else if (hcint & HCINT_NYET) { // Must handle nyet before nak or ack. Could get a nyet at the same time as either of those on a BULK/CONTROL // OUT that started with a PING. The nyet takes precedence. - if (channel->hcsplt_bm.split_en) { + if (hcsplt.split_en) { // split not yet mean hub has no data, retry complete split - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; channel_xfer_in_retry(dwc2, ch_id, hcint); } } else if (hcint & HCINT_ACK) { xfer->err_count = 0; channel->hcintmsk &= ~HCINT_ACK; - if (channel->hcsplt_bm.split_en) { + if (hcsplt.split_en) { // start split is ACK --> do complete split // TODO: for ISO must use xact_pos to plan complete split based on microframe (up to 187.5 bytes/uframe) - channel->hcsplt_bm.split_compl = 1; - if (edpt_is_periodic(channel->hcchar_bm.ep_type)) { - channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; + if (channel_is_periodic(channel->hcchar)) { + hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame + channel->hcchar = hcchar.value; } channel_send_in_token(dwc2, channel); } } else if (hcint & (HCINT_NAK | HCINT_DATATOGGLE_ERR)) { xfer->err_count = 0; channel->hcintmsk &= ~(HCINT_NAK | HCINT_DATATOGGLE_ERR); - channel->hcsplt_bm.split_compl = 0; // restart with start-split + hcsplt.split_compl = 0; // restart with start-split + channel->hcsplt = hcsplt.value; channel_xfer_in_retry(dwc2, ch_id, hcint); } else if (hcint & HCINT_FARME_OVERRUN) { // retry start-split in next binterval @@ -1069,6 +1105,8 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; + const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; + dwc2_channel_split_t hcsplt = {.value = channel->hcsplt}; bool is_done = false; @@ -1104,16 +1142,18 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc } } } else if (hcint & HCINT_NYET) { - if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl) { + if (hcsplt.split_en && hcsplt.split_compl) { // split not yet mean hub has no data, retry complete split - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; channel->hcchar |= HCCHAR_CHENA; } } else if (hcint & HCINT_ACK) { xfer->err_count = 0; - if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) { + if (hcsplt.split_en && !hcsplt.split_compl) { // start split is ACK --> do complete split - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; channel->hcchar |= HCCHAR_CHENA; } } @@ -1136,7 +1176,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) { dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,); - dwc2_channel_char_t hcchar_bm = channel->hcchar_bm; + dwc2_channel_char_t hcchar = {.value = channel->hcchar}; const uint32_t hcint = channel->hcint; channel->hcint = hcint; // clear interrupt @@ -1144,7 +1184,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) { bool is_done = false; if (is_dma) { #if CFG_TUH_DWC2_DMA_ENABLE - if (hcchar_bm.ep_dir == TUSB_DIR_OUT) { + if (hcchar.ep_dir == TUSB_DIR_OUT) { is_done = handle_channel_out_dma(dwc2, ch_id, hcint); } else { is_done = handle_channel_in_dma(dwc2, ch_id, hcint); @@ -1156,7 +1196,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) { #endif } else { #if CFG_TUH_DWC2_SLAVE_ENABLE - if (hcchar_bm.ep_dir == TUSB_DIR_OUT) { + if (hcchar.ep_dir == TUSB_DIR_OUT) { is_done = handle_channel_out_slave(dwc2, ch_id, hcint); } else { is_done = handle_channel_in_slave(dwc2, ch_id, hcint); @@ -1165,8 +1205,8 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) { } if (is_done) { - const uint8_t ep_addr = tu_edpt_addr(hcchar_bm.ep_num, hcchar_bm.ep_dir); - hcd_event_xfer_complete(hcchar_bm.dev_addr, ep_addr, xfer->xferred_bytes, xfer->result, in_isr); + const uint8_t ep_addr = tu_edpt_addr(hcchar.ep_num, hcchar.ep_dir); + hcd_event_xfer_complete(hcchar.dev_addr, ep_addr, xfer->xferred_bytes, (xfer_result_t)xfer->result, in_isr); channel_dealloc(dwc2, ch_id); } } @@ -1185,7 +1225,7 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) { for(uint8_t ep_id = 0; ep_id < CFG_TUH_DWC2_ENDPOINT_MAX; ep_id++) { hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; - if (edpt->hcchar_bm.enable && edpt_is_periodic(edpt->hcchar_bm.ep_type) && edpt->uframe_countdown > 0) { + if (edpt->hcchar_bm.enable && channel_is_periodic(edpt->hcchar) && edpt->uframe_countdown > 0) { edpt->uframe_countdown -= tu_min32(ucount, edpt->uframe_countdown); if (edpt->uframe_countdown == 0) { if (!edpt_xfer_kickoff(dwc2, ep_id)) { @@ -1204,10 +1244,10 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) { static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) { uint32_t hcfg = dwc2->hcfg & ~HCFG_FSLS_PHYCLK_SEL; - const dwc2_gusbcfg_t gusbcfg_bm = dwc2->gusbcfg_bm; + const dwc2_gusbcfg_t gusbcfg = {.value = dwc2->gusbcfg}; uint32_t phy_clock; - if (gusbcfg_bm.phy_sel) { + if (gusbcfg.phy_sel) { phy_clock = 48; // dedicated FS is 48Mhz if (speed == TUSB_SPEED_LOW) { hcfg |= HCFG_FSLS_PHYCLK_SEL_6MHZ; @@ -1215,11 +1255,11 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) { hcfg |= HCFG_FSLS_PHYCLK_SEL_48MHZ; } } else { - if (gusbcfg_bm.ulpi_utmi_sel) { + if (gusbcfg.ulpi_utmi_sel) { phy_clock = 60; // ULPI 8-bit is 60Mhz } else { // UTMI+ 16-bit is 30Mhz, 8-bit is 60Mhz - phy_clock = gusbcfg_bm.phy_if16 ? 30 : 60; + phy_clock = gusbcfg.phy_if16 ? 30 : 60; // Enable UTMI+ low power mode 48Mhz external clock if not highspeed if (speed == TUSB_SPEED_HIGH) { @@ -1252,7 +1292,7 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) { static void handle_hprt_irq(uint8_t rhport, bool in_isr) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK; - const dwc2_hprt_t hprt_bm = dwc2->hprt_bm; + const dwc2_hprt_t hprt_bm = {.value = hprt}; if (dwc2->hprt & HPRT_CONN_DETECT) { // Port Connect Detect