summaryrefslogtreecommitdiff
path: root/src/portable
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2024-05-09 15:51:53 +0200
committerHiFiPhile <[email protected]>2024-05-09 15:51:53 +0200
commit36ce6fad8ca997804a569fe575584b45a1b5fc79 (patch)
treef79aa084a42438667b5e26b588a6f794c9ad1608 /src/portable
parentf607a99127cc9e8dfc3f716f977e6c1bfb6f7c2d (diff)
parent74e57499baac36c4cccf76549259905162031e41 (diff)
Merge branch 'master' into vendor_class_zero_length_transfer
Diffstat (limited to 'src/portable')
-rw-r--r--src/portable/analog/max3421/hcd_max3421.c1012
-rw-r--r--src/portable/bridgetek/ft9xx/dcd_ft9xx.c1203
-rw-r--r--src/portable/chipidea/ci_fs/ci_fs_kinetis.h49
-rw-r--r--src/portable/chipidea/ci_fs/ci_fs_mcx.h56
-rw-r--r--src/portable/chipidea/ci_fs/ci_fs_type.h118
-rw-r--r--src/portable/chipidea/ci_fs/dcd_ci_fs.c567
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_imxrt.h101
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h56
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_mcx.h52
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_type.h (renamed from src/portable/nxp/transdimension/common_transdimension.h)100
-rw-r--r--src/portable/chipidea/ci_hs/dcd_ci_hs.c686
-rw-r--r--src/portable/chipidea/ci_hs/hcd_ci_hs.c (renamed from src/portable/nxp/transdimension/hcd_transdimension.c)106
-rw-r--r--src/portable/dialog/da146xx/dcd_da146xx.c365
-rw-r--r--src/portable/ehci/ehci.c1002
-rw-r--r--src/portable/ehci/ehci.h196
-rw-r--r--src/portable/ehci/ehci_api.h (renamed from src/portable/ehci/hcd_ehci.h)14
-rw-r--r--src/portable/espressif/esp32sx/dcd_esp32sx.c163
-rw-r--r--src/portable/mentor/musb/dcd_musb.c908
-rw-r--r--src/portable/mentor/musb/hcd_musb.c891
-rw-r--r--src/portable/mentor/musb/musb_msp432e.h40
-rw-r--r--src/portable/mentor/musb/musb_tm4c.h45
-rw-r--r--src/portable/mentor/musb/musb_type.h2624
-rw-r--r--src/portable/microchip/pic/dcd_pic.c786
-rw-r--r--src/portable/microchip/pic32mz/dcd_pic32mz.c753
-rw-r--r--src/portable/microchip/pic32mz/usbhs_registers.h931
-rw-r--r--src/portable/microchip/samd/dcd_samd.c41
-rw-r--r--src/portable/microchip/samg/dcd_samg.c18
-rw-r--r--src/portable/microchip/samx7x/common_usb_regs.h2108
-rw-r--r--src/portable/microchip/samx7x/dcd_samx7x.c776
-rw-r--r--src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c496
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c883
-rw-r--r--src/portable/nuvoton/nuc120/dcd_nuc120.c37
-rw-r--r--src/portable/nuvoton/nuc121/dcd_nuc121.c103
-rw-r--r--src/portable/nuvoton/nuc505/dcd_nuc505.c33
-rw-r--r--src/portable/nxp/khci/dcd_khci.c274
-rw-r--r--src/portable/nxp/khci/hcd_khci.c641
-rw-r--r--src/portable/nxp/lpc17_40/dcd_lpc17_40.c25
-rw-r--r--src/portable/nxp/lpc17_40/dcd_lpc17_40.h2
-rw-r--r--src/portable/nxp/lpc17_40/hcd_lpc17_40.c5
-rw-r--r--src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c367
-rw-r--r--src/portable/nxp/transdimension/dcd_transdimension.c492
-rw-r--r--src/portable/ohci/ohci.c242
-rw-r--r--src/portable/ohci/ohci.h66
-rw-r--r--src/portable/raspberrypi/pio_usb/dcd_pio_usb.c210
-rw-r--r--src/portable/raspberrypi/pio_usb/hcd_pio_usb.c209
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c769
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c819
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c527
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h153
-rw-r--r--src/portable/renesas/rusb2/dcd_rusb2.c1028
-rw-r--r--src/portable/renesas/rusb2/hcd_rusb2.c844
-rw-r--r--src/portable/renesas/rusb2/rusb2_common.c61
-rw-r--r--src/portable/renesas/rusb2/rusb2_ra.h109
-rw-r--r--src/portable/renesas/rusb2/rusb2_rx.h94
-rw-r--r--src/portable/renesas/rusb2/rusb2_type.h1780
-rw-r--r--src/portable/renesas/usba/dcd_usba.c736
-rw-r--r--src/portable/silabs/efm32/dcd_efm32.c931
-rw-r--r--src/portable/sony/cxd56/dcd_cxd56.c61
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c1359
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h551
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h407
-rw-r--r--src/portable/st/synopsys/dcd_synopsys.c1153
-rw-r--r--src/portable/st/typec/typec_stm32.c372
-rw-r--r--src/portable/sunxi/dcd_sunxi_musb.c1221
-rw-r--r--src/portable/sunxi/musb_def.h643
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c1198
-rw-r--r--src/portable/synopsys/dwc2/dwc2_bcm.h89
-rw-r--r--src/portable/synopsys/dwc2/dwc2_efm32.h89
-rw-r--r--src/portable/synopsys/dwc2/dwc2_esp32.h96
-rw-r--r--src/portable/synopsys/dwc2/dwc2_gd32.h101
-rw-r--r--src/portable/synopsys/dwc2/dwc2_info.md55
-rw-r--r--src/portable/synopsys/dwc2/dwc2_info.py169
-rw-r--r--src/portable/synopsys/dwc2/dwc2_stm32.h261
-rw-r--r--src/portable/synopsys/dwc2/dwc2_type.h1770
-rw-r--r--src/portable/synopsys/dwc2/dwc2_xmc.h88
-rw-r--r--src/portable/template/dcd_template.c19
-rw-r--r--src/portable/template/hcd_template.c163
-rw-r--r--src/portable/ti/msp430x5xx/dcd_msp430x5xx.c167
-rw-r--r--src/portable/valentyusb/eptri/dcd_eptri.c37
-rw-r--r--src/portable/valentyusb/eptri/dcd_eptri.h2
-rw-r--r--src/portable/wch/ch32_usbhs_reg.h349
-rw-r--r--src/portable/wch/dcd_ch32_usbhs.c391
82 files changed, 31513 insertions, 7001 deletions
diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c
new file mode 100644
index 000000000..4dc93d2d8
--- /dev/null
+++ b/src/portable/analog/max3421/hcd_max3421.c
@@ -0,0 +1,1012 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
+
+#include <stdatomic.h>
+#include "host/hcd.h"
+#include "host/usbh.h"
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+// Command format is
+// Reg [7:3] | 0 [2] | Dir [1] | Ack [0]
+
+enum {
+ CMDBYTE_WRITE = 0x02,
+};
+
+enum {
+ RCVVFIFO_ADDR = 1u << 3, // 0x08
+ SNDFIFO_ADDR = 2u << 3, // 0x10
+ SUDFIFO_ADDR = 4u << 3, // 0x20
+ RCVBC_ADDR = 6u << 3, // 0x30
+ SNDBC_ADDR = 7u << 3, // 0x38
+ USBIRQ_ADDR = 13u << 3, // 0x68
+ USBIEN_ADDR = 14u << 3, // 0x70
+ USBCTL_ADDR = 15u << 3, // 0x78
+ CPUCTL_ADDR = 16u << 3, // 0x80
+ PINCTL_ADDR = 17u << 3, // 0x88
+ REVISION_ADDR = 18u << 3, // 0x90
+ // 19 is not used
+ IOPINS1_ADDR = 20u << 3, // 0xA0
+ IOPINS2_ADDR = 21u << 3, // 0xA8
+ GPINIRQ_ADDR = 22u << 3, // 0xB0
+ GPINIEN_ADDR = 23u << 3, // 0xB8
+ GPINPOL_ADDR = 24u << 3, // 0xC0
+ HIRQ_ADDR = 25u << 3, // 0xC8
+ HIEN_ADDR = 26u << 3, // 0xD0
+ MODE_ADDR = 27u << 3, // 0xD8
+ PERADDR_ADDR = 28u << 3, // 0xE0
+ HCTL_ADDR = 29u << 3, // 0xE8
+ HXFR_ADDR = 30u << 3, // 0xF0
+ HRSL_ADDR = 31u << 3, // 0xF8
+};
+
+enum {
+ USBIRQ_OSCOK_IRQ = 1u << 0,
+ USBIRQ_NOVBUS_IRQ = 1u << 5,
+ USBIRQ_VBUS_IRQ = 1u << 6,
+};
+
+enum {
+ USBCTL_PWRDOWN = 1u << 4,
+ USBCTL_CHIPRES = 1u << 5,
+};
+
+enum {
+ CPUCTL_IE = 1u << 0,
+ CPUCTL_PULSEWID0 = 1u << 6,
+ CPUCTL_PULSEWID1 = 1u << 7,
+};
+
+enum {
+ PINCTL_GPXA = 1u << 0,
+ PINCTL_GPXB = 1u << 1,
+ PINCTL_POSINT = 1u << 2,
+ PINCTL_INTLEVEL = 1u << 3,
+ PINCTL_FDUPSPI = 1u << 4,
+};
+
+enum {
+ HIRQ_BUSEVENT_IRQ = 1u << 0,
+ HIRQ_RWU_IRQ = 1u << 1,
+ HIRQ_RCVDAV_IRQ = 1u << 2,
+ HIRQ_SNDBAV_IRQ = 1u << 3,
+ HIRQ_SUSDN_IRQ = 1u << 4,
+ HIRQ_CONDET_IRQ = 1u << 5,
+ HIRQ_FRAME_IRQ = 1u << 6,
+ HIRQ_HXFRDN_IRQ = 1u << 7,
+};
+
+enum {
+ MODE_HOST = 1u << 0,
+ MODE_LOWSPEED = 1u << 1,
+ MODE_HUBPRE = 1u << 2,
+ MODE_SOFKAENAB = 1u << 3,
+ MODE_SEPIRQ = 1u << 4,
+ MODE_DELAYISO = 1u << 5,
+ MODE_DMPULLDN = 1u << 6,
+ MODE_DPPULLDN = 1u << 7,
+};
+
+enum {
+ HCTL_BUSRST = 1u << 0,
+ HCTL_FRMRST = 1u << 1,
+ HCTL_SAMPLEBUS = 1u << 2,
+ HCTL_SIGRSM = 1u << 3,
+ HCTL_RCVTOG0 = 1u << 4,
+ HCTL_RCVTOG1 = 1u << 5,
+ HCTL_SNDTOG0 = 1u << 6,
+ HCTL_SNDTOG1 = 1u << 7,
+};
+
+enum {
+ HXFR_EPNUM_MASK = 0x0f,
+ HXFR_SETUP = 1u << 4,
+ HXFR_OUT_NIN = 1u << 5,
+ HXFR_ISO = 1u << 6,
+ HXFR_HS = 1u << 7,
+};
+
+enum {
+ HRSL_RESULT_MASK = 0x0f,
+ HRSL_RCVTOGRD = 1u << 4,
+ HRSL_SNDTOGRD = 1u << 5,
+ HRSL_KSTATUS = 1u << 6,
+ HRSL_JSTATUS = 1u << 7,
+};
+
+enum {
+ HRSL_SUCCESS = 0,
+ HRSL_BUSY,
+ HRSL_BAD_REQ,
+ HRSL_UNDEF,
+ HRSL_NAK,
+ HRSL_STALL,
+ HRSL_TOG_ERR,
+ HRSL_WRONG_PID,
+ HRSL_BAD_BYTECOUNT,
+ HRSL_PID_ERR,
+ HRSL_PKT_ERR,
+ HRSL_CRC_ERR,
+ HRSL_K_ERR,
+ HRSL_J_ERR,
+ HRSL_TIMEOUT,
+ HRSL_BABBLE,
+};
+
+enum {
+ DEFAULT_HIEN = HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ | HIRQ_HXFRDN_IRQ | HIRQ_RCVDAV_IRQ
+};
+
+enum {
+ MAX_NAK_DEFAULT = 1 // Number of NAK per endpoint per usb frame
+};
+
+enum {
+ EP_STATE_IDLE = 0,
+ EP_STATE_COMPLETE = 1,
+ EP_STATE_ATTEMPT_1 = 2, // pending 1st attempt
+ EP_STATE_ATTEMPT_MAX = 15
+};
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+typedef struct {
+ uint8_t daddr;
+
+ union { ;
+ struct TU_ATTR_PACKED {
+ uint8_t ep_num : 4;
+ uint8_t is_setup : 1;
+ uint8_t is_out : 1;
+ uint8_t is_iso : 1;
+ }hxfr_bm;
+
+ uint8_t hxfr;
+ };
+
+ struct TU_ATTR_PACKED {
+ uint8_t state : 4;
+ uint8_t data_toggle : 1;
+ uint16_t packet_size : 11;
+ };
+
+ uint16_t total_len;
+ uint16_t xferred_len;
+ uint8_t* buf;
+} max3421_ep_t;
+
+TU_VERIFY_STATIC(sizeof(max3421_ep_t) == 12, "size is not correct");
+
+typedef struct {
+ volatile uint16_t frame_count;
+
+ // cached register
+ uint8_t sndbc;
+ uint8_t hirq;
+ uint8_t hien;
+ uint8_t mode;
+ uint8_t peraddr;
+ uint8_t hxfr;
+
+ atomic_flag busy; // busy transferring
+
+#if OSAL_MUTEX_REQUIRED
+ OSAL_MUTEX_DEF(spi_mutexdef);
+ osal_mutex_t spi_mutex;
+#endif
+
+ max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; // [0] is reserved for addr0
+} max3421_data_t;
+
+static max3421_data_t _hcd_data;
+
+// max NAK before giving up in a frame. 0 means infinite NAKs
+static tuh_configure_max3421_t _tuh_cfg = {
+ .max_nak = MAX_NAK_DEFAULT,
+ .cpuctl = 0, // default: INT pulse width = 10.6 us
+ .pinctl = 0, // default: negative edge interrupt
+};
+
+//--------------------------------------------------------------------+
+// API: SPI transfer with MAX3421E
+// - spi_cs_api(), spi_xfer_api(), int_api(): must be implemented by application
+// - reg_read(), reg_write(): is implemented by this driver, can be used by application
+//--------------------------------------------------------------------+
+
+// API to control MAX3421 SPI CS
+extern void tuh_max3421_spi_cs_api(uint8_t rhport, bool active);
+
+// API to transfer data with MAX3421 SPI
+// Either tx_buf or rx_buf can be NULL, which means transfer is write or read only
+extern bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const* tx_buf, uint8_t* rx_buf, size_t xfer_bytes);
+
+// API to enable/disable MAX3421 INTR pin interrupt
+extern void tuh_max3421_int_api(uint8_t rhport, bool enabled);
+
+// API to read MAX3421's register. Implemented by TinyUSB
+uint8_t tuh_max3421_reg_read(uint8_t rhport, uint8_t reg, bool in_isr);
+
+// API to write MAX3421's register. Implemented by TinyUSB
+bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr);
+
+//--------------------------------------------------------------------+
+// SPI Commands and Helper
+//--------------------------------------------------------------------+
+
+#define reg_read tuh_max3421_reg_read
+#define reg_write tuh_max3421_reg_write
+
+static void max3421_spi_lock(uint8_t rhport, bool in_isr) {
+ // disable interrupt and mutex lock (for pre-emptive RTOS) if not in_isr
+ if (!in_isr) {
+ (void) osal_mutex_lock(_hcd_data.spi_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
+ tuh_max3421_int_api(rhport, false);
+ }
+
+ // assert CS
+ tuh_max3421_spi_cs_api(rhport, true);
+}
+
+static void max3421_spi_unlock(uint8_t rhport, bool in_isr) {
+ // de-assert CS
+ tuh_max3421_spi_cs_api(rhport, false);
+
+ // mutex unlock and re-enable interrupt
+ if (!in_isr) {
+ tuh_max3421_int_api(rhport, true);
+ (void) osal_mutex_unlock(_hcd_data.spi_mutex);
+ }
+}
+
+uint8_t tuh_max3421_reg_read(uint8_t rhport, uint8_t reg, bool in_isr) {
+ uint8_t tx_buf[2] = {reg, 0};
+ uint8_t rx_buf[2] = {0, 0};
+
+ max3421_spi_lock(rhport, in_isr);
+ bool ret = tuh_max3421_spi_xfer_api(rhport, tx_buf, rx_buf, 2);
+ max3421_spi_unlock(rhport, in_isr);
+
+ _hcd_data.hirq = rx_buf[0];
+ return ret ? rx_buf[1] : 0;
+}
+
+bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr) {
+ uint8_t tx_buf[2] = {reg | CMDBYTE_WRITE, data};
+ uint8_t rx_buf[2] = {0, 0};
+
+ max3421_spi_lock(rhport, in_isr);
+ bool ret = tuh_max3421_spi_xfer_api(rhport, tx_buf, rx_buf, 2);
+ max3421_spi_unlock(rhport, in_isr);
+
+ // HIRQ register since we are in full-duplex mode
+ _hcd_data.hirq = rx_buf[0];
+
+ return ret;
+}
+
+static void fifo_write(uint8_t rhport, uint8_t reg, uint8_t const * buffer, uint16_t len, bool in_isr) {
+ uint8_t hirq;
+ reg |= CMDBYTE_WRITE;
+
+ max3421_spi_lock(rhport, in_isr);
+
+ tuh_max3421_spi_xfer_api(rhport, &reg, &hirq, 1);
+ _hcd_data.hirq = hirq;
+ tuh_max3421_spi_xfer_api(rhport, buffer, NULL, len);
+
+ max3421_spi_unlock(rhport, in_isr);
+}
+
+static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_isr) {
+ uint8_t hirq;
+ uint8_t const reg = RCVVFIFO_ADDR;
+
+ max3421_spi_lock(rhport, in_isr);
+
+ tuh_max3421_spi_xfer_api(rhport, &reg, &hirq, 1);
+ _hcd_data.hirq = hirq;
+ tuh_max3421_spi_xfer_api(rhport, NULL, buffer, len);
+
+ max3421_spi_unlock(rhport, in_isr);
+}
+
+//------------- register write helper -------------//
+TU_ATTR_ALWAYS_INLINE static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr) {
+ reg_write(rhport, HIRQ_ADDR, data, in_isr);
+ // HIRQ write 1 is clear
+ _hcd_data.hirq &= (uint8_t) ~data;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void hien_write(uint8_t rhport, uint8_t data, bool in_isr) {
+ _hcd_data.hien = data;
+ reg_write(rhport, HIEN_ADDR, data, in_isr);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void mode_write(uint8_t rhport, uint8_t data, bool in_isr) {
+ _hcd_data.mode = data;
+ reg_write(rhport, MODE_ADDR, data, in_isr);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void peraddr_write(uint8_t rhport, uint8_t data, bool in_isr) {
+ if ( _hcd_data.peraddr == data ) return; // no need to change address
+
+ _hcd_data.peraddr = data;
+ reg_write(rhport, PERADDR_ADDR, data, in_isr);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void hxfr_write(uint8_t rhport, uint8_t data, bool in_isr) {
+ _hcd_data.hxfr = data;
+ reg_write(rhport, HXFR_ADDR, data, in_isr);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void sndbc_write(uint8_t rhport, uint8_t data, bool in_isr) {
+ _hcd_data.sndbc = data;
+ reg_write(rhport, SNDBC_ADDR, data, in_isr);
+}
+
+//--------------------------------------------------------------------+
+// Endpoint helper
+//--------------------------------------------------------------------+
+
+static max3421_ep_t* find_ep_not_addr0(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) {
+ uint8_t const is_out = 1-ep_dir;
+ for(size_t i=1; i<CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
+ max3421_ep_t* ep = &_hcd_data.ep[i];
+ // control endpoint is bi-direction (skip check)
+ if (daddr == ep->daddr && ep_num == ep->hxfr_bm.ep_num && (ep_num == 0 || is_out == ep->hxfr_bm.is_out)) {
+ return ep;
+ }
+ }
+
+ return NULL;
+}
+
+// daddr = 0 and ep_num = 0 means find a free (allocate) endpoint
+TU_ATTR_ALWAYS_INLINE static inline max3421_ep_t * allocate_ep(void) {
+ return find_ep_not_addr0(0, 0, 0);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline max3421_ep_t * find_opened_ep(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) {
+ if (daddr == 0 && ep_num == 0) {
+ return &_hcd_data.ep[0];
+ }else{
+ return find_ep_not_addr0(daddr, ep_num, ep_dir);
+ }
+}
+
+// free all endpoints belong to device address
+static void free_ep(uint8_t daddr) {
+ for (size_t i=1; i<CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
+ max3421_ep_t* ep = &_hcd_data.ep[i];
+ if (ep->daddr == daddr) {
+ tu_memclr(ep, sizeof(max3421_ep_t));
+ }
+ }
+}
+
+// Check if endpoint has an queued transfer and not reach max NAK
+TU_ATTR_ALWAYS_INLINE static inline bool is_ep_pending(max3421_ep_t const * ep) {
+ uint8_t const state = ep->state;
+ return ep->packet_size && (state >= EP_STATE_ATTEMPT_1) &&
+ (_tuh_cfg.max_nak == 0 || state < EP_STATE_ATTEMPT_1 + _tuh_cfg.max_nak);
+}
+
+// Find the next pending endpoint using round-robin scheduling, starting from next endpoint.
+// return NULL if not found
+// TODO respect interrupt endpoint's interval
+static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) {
+ size_t const idx = (size_t) (cur_ep - _hcd_data.ep);
+
+ // starting from next endpoint
+ for (size_t i = idx + 1; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
+ max3421_ep_t* ep = &_hcd_data.ep[i];
+ if (is_ep_pending(ep)) {
+ return ep;
+ }
+ }
+
+ // wrap around including current endpoint
+ for (size_t i = 0; i <= idx; i++) {
+ max3421_ep_t* ep = &_hcd_data.ep[i];
+ if (is_ep_pending(ep)) {
+ return ep;
+ }
+ }
+
+ return NULL;
+}
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+// optional hcd configuration, called by tuh_configure()
+bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
+ (void) rhport;
+ TU_VERIFY(cfg_id == TUH_CFGID_MAX3421 && cfg_param != NULL);
+
+ tuh_configure_param_t const* cfg = (tuh_configure_param_t const*) cfg_param;
+ _tuh_cfg = cfg->max3421;
+ return true;
+}
+
+// Initialize controller to host mode
+bool hcd_init(uint8_t rhport) {
+ (void) rhport;
+
+ tuh_max3421_int_api(rhport, false);
+
+ TU_LOG2_INT(sizeof(max3421_ep_t));
+ TU_LOG2_INT(sizeof(max3421_data_t));
+ TU_LOG2_INT(offsetof(max3421_data_t, ep));
+
+ tu_memclr(&_hcd_data, sizeof(_hcd_data));
+ _hcd_data.peraddr = 0xff; // invalid
+
+#if OSAL_MUTEX_REQUIRED
+ _hcd_data.spi_mutex = osal_mutex_create(&_hcd_data.spi_mutexdef);
+#endif
+
+ // NOTE: driver does not seem to work without nRST pin signal
+
+ // full duplex, interrupt negative edge
+ reg_write(rhport, PINCTL_ADDR, _tuh_cfg.pinctl | PINCTL_FDUPSPI, false);
+
+ // v1 is 0x01, v2 is 0x12, v3 is 0x13
+ uint8_t const revision = reg_read(rhport, REVISION_ADDR, false);
+ TU_LOG2_HEX(revision);
+ TU_ASSERT(revision == 0x01 || revision == 0x12 || revision == 0x13, false);
+
+ // reset
+ reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false);
+ reg_write(rhport, USBCTL_ADDR, 0, false);
+ while( !(reg_read(rhport, USBIRQ_ADDR, false) & USBIRQ_OSCOK_IRQ) ) {
+ // wait for oscillator to stabilize
+ }
+
+ // Mode: Host and DP/DM pull down
+ mode_write(rhport, MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST, false);
+
+ // frame reset & bus reset, this will trigger CONDET IRQ if device is already connected
+ reg_write(rhport, HCTL_ADDR, HCTL_BUSRST | HCTL_FRMRST, false);
+
+ // clear all previously pending IRQ
+ hirq_write(rhport, 0xff, false);
+
+ // Enable IRQ
+ hien_write(rhport, DEFAULT_HIEN, false);
+
+ tuh_max3421_int_api(rhport, true);
+
+ // Enable Interrupt pin
+ reg_write(rhport, CPUCTL_ADDR, _tuh_cfg.cpuctl | CPUCTL_IE, false);
+
+ return true;
+}
+
+bool hcd_deinit(uint8_t rhport) {
+ (void) rhport;
+
+ // disable interrupt
+ tuh_max3421_int_api(rhport, false);
+
+ // reset max3421 and power down
+ reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false);
+ reg_write(rhport, USBCTL_ADDR, USBCTL_PWRDOWN, false);
+
+ #if OSAL_MUTEX_REQUIRED
+ osal_mutex_delete(_hcd_data.spi_mutex);
+ _hcd_data.spi_mutex = NULL;
+ #endif
+
+ return true;
+}
+
+// Enable USB interrupt
+// Not actually enable GPIO interrupt, just set variable to prevent handler to process
+void hcd_int_enable (uint8_t rhport) {
+ tuh_max3421_int_api(rhport, true);
+}
+
+// Disable USB interrupt
+// Not actually disable GPIO interrupt, just set variable to prevent handler to process
+void hcd_int_disable(uint8_t rhport) {
+ tuh_max3421_int_api(rhport, false);
+}
+
+// Get frame number (1ms)
+uint32_t hcd_frame_number(uint8_t rhport) {
+ (void) rhport;
+ return (uint32_t ) _hcd_data.frame_count;
+}
+
+//--------------------------------------------------------------------+
+// Port API
+//--------------------------------------------------------------------+
+
+// Get the current connect status of roothub port
+bool hcd_port_connect_status(uint8_t rhport) {
+ (void) rhport;
+ return (_hcd_data.mode & MODE_SOFKAENAB) ? true : false;
+}
+
+// Reset USB bus on the port. Return immediately, bus reset sequence may not be complete.
+// 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) {
+ reg_write(rhport, HCTL_ADDR, HCTL_BUSRST, false);
+}
+
+// Complete bus reset sequence, may be required by some controllers
+void hcd_port_reset_end(uint8_t rhport) {
+ reg_write(rhport, HCTL_ADDR, 0, false);
+}
+
+// Get port link speed
+tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
+ (void) rhport;
+ return (_hcd_data.mode & MODE_LOWSPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
+}
+
+// HCD closes all opened endpoints belong to this device
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
+ (void) rhport;
+ (void) dev_addr;
+}
+
+//--------------------------------------------------------------------+
+// Endpoints API
+//--------------------------------------------------------------------+
+
+// Open an endpoint
+bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * ep_desc) {
+ (void) rhport;
+
+ uint8_t const ep_num = tu_edpt_number(ep_desc->bEndpointAddress);
+ tusb_dir_t const ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress);
+
+ max3421_ep_t * ep;
+ if (daddr == 0 && ep_num == 0) {
+ ep = &_hcd_data.ep[0];
+ }else {
+ ep = allocate_ep();
+ TU_ASSERT(ep);
+ ep->daddr = daddr;
+ ep->hxfr_bm.ep_num = (uint8_t) (ep_num & 0x0f);
+ ep->hxfr_bm.is_out = (ep_dir == TUSB_DIR_OUT) ? 1 : 0;
+ ep->hxfr_bm.is_iso = (TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer) ? 1 : 0;
+ }
+
+ ep->packet_size = (uint16_t) (tu_edpt_packet_size(ep_desc) & 0x7ff);
+
+ return true;
+}
+
+static void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
+ // Page 12: Programming BULK-OUT Transfers
+ // TODO double buffered
+ if (switch_ep) {
+ peraddr_write(rhport, ep->daddr, in_isr);
+
+ uint8_t const hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0);
+ reg_write(rhport, HCTL_ADDR, hctl, in_isr);
+ }
+
+ uint8_t const xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size);
+ TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ,);
+ if (xact_len) {
+ fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr);
+ }
+ sndbc_write(rhport, xact_len, in_isr);
+ hxfr_write(rhport, ep->hxfr, in_isr);
+}
+
+static void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
+ // Page 13: Programming BULK-IN Transfers
+ if (switch_ep) {
+ peraddr_write(rhport, ep->daddr, in_isr);
+
+ uint8_t const hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0);
+ reg_write(rhport, HCTL_ADDR, hctl, in_isr);
+ }
+
+ hxfr_write(rhport, ep->hxfr, in_isr);
+}
+
+static void xact_setup(uint8_t rhport, max3421_ep_t *ep, bool in_isr) {
+ peraddr_write(rhport, ep->daddr, in_isr);
+ fifo_write(rhport, SUDFIFO_ADDR, ep->buf, 8, in_isr);
+ hxfr_write(rhport, HXFR_SETUP, in_isr);
+}
+
+static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
+ if (ep->hxfr_bm.ep_num == 0 ) {
+ // setup
+ if (ep->hxfr_bm.is_setup) {
+ xact_setup(rhport, ep, in_isr);
+ return;
+ }
+
+ // status
+ if (ep->buf == NULL || ep->total_len == 0) {
+ uint8_t const hxfr = (uint8_t) (HXFR_HS | (ep->hxfr & HXFR_OUT_NIN));
+ peraddr_write(rhport, ep->daddr, in_isr);
+ hxfr_write(rhport, hxfr, in_isr);
+ return;
+ }
+ }
+
+ if (ep->hxfr_bm.is_out) {
+ xact_out(rhport, ep, switch_ep, in_isr);
+ }else {
+ xact_in(rhport, ep, switch_ep, in_isr);
+ }
+}
+
+// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) {
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr);
+
+ max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir);
+ TU_VERIFY(ep);
+
+ if (ep_num == 0) {
+ // control transfer can switch direction
+ ep->hxfr_bm.is_out = ep_dir ? 0 : 1;
+ ep->hxfr_bm.is_setup = 0;
+ ep->data_toggle = 1;
+ }
+
+ ep->buf = buffer;
+ ep->total_len = buflen;
+ ep->xferred_len = 0;
+ ep->state = EP_STATE_ATTEMPT_1;
+
+ // carry out transfer if not busy
+ if (!atomic_flag_test_and_set(&_hcd_data.busy)) {
+ xact_generic(rhport, ep, true, false);
+ }
+
+ return true;
+}
+
+// Abort a queued transfer. Note: it can only abort transfer that has not been started
+// Return true if a queued transfer is aborted, false if there is no transfer to abort
+bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+
+ return false;
+}
+
+// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked
+bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]) {
+ (void) rhport;
+
+ max3421_ep_t* ep = find_opened_ep(daddr, 0, 0);
+ TU_ASSERT(ep);
+
+ ep->hxfr_bm.is_out = 1;
+ ep->hxfr_bm.is_setup = 1;
+ ep->buf = (uint8_t*)(uintptr_t) setup_packet;
+ ep->total_len = 8;
+ ep->xferred_len = 0;
+ ep->state = EP_STATE_ATTEMPT_1;
+
+ // carry out transfer if not busy
+ if (!atomic_flag_test_and_set(&_hcd_data.busy)) {
+ xact_setup(rhport, ep, false);
+ }
+
+ return true;
+}
+
+// clear stall, data toggle is also reset to DATA0
+bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+
+ return false;
+}
+
+//--------------------------------------------------------------------+
+// Interrupt Handler
+//--------------------------------------------------------------------+
+
+static void handle_connect_irq(uint8_t rhport, bool in_isr) {
+ uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, in_isr);
+ uint8_t const jk = hrsl & (HRSL_JSTATUS | HRSL_KSTATUS);
+
+ uint8_t new_mode = MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST;
+ TU_LOG2_HEX(jk);
+
+ switch(jk) {
+ case 0x00: // SEO is disconnected
+ case (HRSL_JSTATUS | HRSL_KSTATUS): // SE1 is illegal
+ mode_write(rhport, new_mode, in_isr);
+
+ // port reset anyway, this will help to stable bus signal for next connection
+ reg_write(rhport, HCTL_ADDR, HCTL_BUSRST, in_isr);
+ hcd_event_device_remove(rhport, in_isr);
+ reg_write(rhport, HCTL_ADDR, 0, in_isr);
+ break;
+
+ default: {
+ // Bus Reset also cause CONDET IRQ, skip if we are already connected and doing bus reset
+ if ((_hcd_data.hirq & HIRQ_BUSEVENT_IRQ) && (_hcd_data.mode & MODE_SOFKAENAB)) {
+ break;
+ }
+
+ // Low speed if (LS = 1 and J-state) or (LS = 0 and K-State)
+ // However, since we are always in full speed mode, we can just check J-state
+ if (jk == HRSL_KSTATUS) {
+ new_mode |= MODE_LOWSPEED;
+ TU_LOG3("Low speed\r\n");
+ }else {
+ TU_LOG3("Full speed\r\n");
+ }
+ new_mode |= MODE_SOFKAENAB;
+ mode_write(rhport, new_mode, in_isr);
+
+ // FIXME multiple MAX3421 rootdevice address is not 1
+ uint8_t const daddr = 1;
+ free_ep(daddr);
+
+ hcd_event_device_attach(rhport, in_isr);
+ break;
+ }
+ }
+}
+
+static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl, bool in_isr) {
+ uint8_t const ep_dir = 1-ep->hxfr_bm.is_out;
+ uint8_t const ep_addr = tu_edpt_addr(ep->hxfr_bm.ep_num, ep_dir);
+
+ // save data toggle
+ if (ep_dir) {
+ ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1u : 0u;
+ }else {
+ ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1u : 0u;
+ }
+
+ ep->state = EP_STATE_IDLE;
+ hcd_event_xfer_complete(ep->daddr, ep_addr, ep->xferred_len, result, in_isr);
+
+ // Find next pending endpoint
+ max3421_ep_t * next_ep = find_next_pending_ep(ep);
+ if (next_ep) {
+ xact_generic(rhport, next_ep, true, in_isr);
+ }else {
+ // no more pending
+ atomic_flag_clear(&_hcd_data.busy);
+ }
+}
+
+static void handle_xfer_done(uint8_t rhport, bool in_isr) {
+ uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, in_isr);
+ uint8_t const hresult = hrsl & HRSL_RESULT_MASK;
+
+ uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
+ uint8_t const hxfr_type = _hcd_data.hxfr & 0xf0;
+ uint8_t const ep_dir = ((hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN)) ? 0 : 1;
+
+ max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, ep_dir);
+ TU_VERIFY(ep, );
+
+ xfer_result_t xfer_result;
+ switch(hresult) {
+ case HRSL_SUCCESS:
+ xfer_result = XFER_RESULT_SUCCESS;
+ break;
+
+ case HRSL_STALL:
+ xfer_result = XFER_RESULT_STALLED;
+ break;
+
+ case HRSL_NAK:
+ if (ep_num == 0) {
+ // control endpoint -> retry immediately
+ hxfr_write(rhport, _hcd_data.hxfr, in_isr);
+ } else {
+ if (ep->state < EP_STATE_ATTEMPT_MAX) {
+ ep->state++;
+ }
+
+ max3421_ep_t * next_ep = find_next_pending_ep(ep);
+ if (ep == next_ep) {
+ // this endpoint is only one pending -> retry immediately
+ hxfr_write(rhport, _hcd_data.hxfr, in_isr);
+ } else if (next_ep) {
+ // switch to next pending endpoint TODO could have issue with double buffered if not clear previously out data
+ xact_generic(rhport, next_ep, true, in_isr);
+ } else {
+ // no more pending in this frame -> clear busy
+ atomic_flag_clear(&_hcd_data.busy);
+ }
+ }
+ return;
+
+ case HRSL_BAD_REQ:
+ // occurred when initialized without any pending transfer. Skip for now
+ return;
+
+ default:
+ TU_LOG3("HRSL: %02X\r\n", hrsl);
+ xfer_result = XFER_RESULT_FAILED;
+ break;
+ }
+
+ if (xfer_result != XFER_RESULT_SUCCESS) {
+ xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr);
+ return;
+ }
+
+ if (ep_dir) {
+ // IN transfer: fifo data is already received in RCVDAV IRQ
+
+ // mark control handshake as complete
+ if (hxfr_type & HXFR_HS) {
+ ep->state = EP_STATE_COMPLETE;
+ }
+
+ // short packet or all bytes transferred
+ if (ep->state == EP_STATE_COMPLETE) {
+ xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr);
+ }else {
+ // more to transfer
+ hxfr_write(rhport, _hcd_data.hxfr, in_isr);
+ }
+ } else {
+ // SETUP or OUT transfer
+ uint8_t xact_len;
+
+ if (hxfr_type & HXFR_SETUP) {
+ xact_len = 8;
+ } else if (hxfr_type & HXFR_HS) {
+ xact_len = 0;
+ } else {
+ xact_len = _hcd_data.sndbc;
+ }
+
+ ep->xferred_len += xact_len;
+ ep->buf += xact_len;
+
+ if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) {
+ xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr);
+ } else {
+ // more to transfer
+ xact_out(rhport, ep, false, in_isr);
+ }
+ }
+}
+
+#if CFG_TUSB_DEBUG >= 3
+void print_hirq(uint8_t hirq) {
+ TU_LOG3_HEX(hirq);
+
+ if (hirq & HIRQ_HXFRDN_IRQ) TU_LOG3(" HXFRDN");
+ if (hirq & HIRQ_FRAME_IRQ) TU_LOG3(" FRAME");
+ if (hirq & HIRQ_CONDET_IRQ) TU_LOG3(" CONDET");
+ if (hirq & HIRQ_SUSDN_IRQ) TU_LOG3(" SUSDN");
+ if (hirq & HIRQ_SNDBAV_IRQ) TU_LOG3(" SNDBAV");
+ if (hirq & HIRQ_RCVDAV_IRQ) TU_LOG3(" RCVDAV");
+ if (hirq & HIRQ_RWU_IRQ) TU_LOG3(" RWU");
+ if (hirq & HIRQ_BUSEVENT_IRQ) TU_LOG3(" BUSEVENT");
+
+ TU_LOG3("\r\n");
+}
+#else
+ #define print_hirq(hirq)
+#endif
+
+// Interrupt handler
+void hcd_int_handler(uint8_t rhport, bool in_isr) {
+ uint8_t hirq = reg_read(rhport, HIRQ_ADDR, in_isr) & _hcd_data.hien;
+ if (!hirq) return;
+// print_hirq(hirq);
+
+ if (hirq & HIRQ_FRAME_IRQ) {
+ _hcd_data.frame_count++;
+
+ max3421_ep_t* ep_retry = NULL;
+
+ // reset all endpoints attempt counter
+ for (size_t i = 0; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
+ max3421_ep_t* ep = &_hcd_data.ep[i];
+ if (ep->packet_size && ep->state > EP_STATE_ATTEMPT_1) {
+ ep->state = EP_STATE_ATTEMPT_1;
+
+ if (ep_retry == NULL) {
+ ep_retry = ep;
+ }
+ }
+ }
+
+ // start usb transfer if not busy
+ if (ep_retry != NULL && !atomic_flag_test_and_set(&_hcd_data.busy)) {
+ xact_generic(rhport, ep_retry, true, in_isr);
+ }
+ }
+
+ if (hirq & HIRQ_CONDET_IRQ) {
+ handle_connect_irq(rhport, in_isr);
+ }
+
+ // queue more transfer in handle_xfer_done() can cause hirq to be set again while external IRQ may not catch and/or
+ // not call this handler again. So we need to loop until all IRQ are cleared
+ while (hirq & (HIRQ_RCVDAV_IRQ | HIRQ_HXFRDN_IRQ)) {
+ if (hirq & HIRQ_RCVDAV_IRQ) {
+ uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
+ max3421_ep_t* ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1);
+ uint8_t xact_len = 0;
+
+ // RCVDAV_IRQ can trigger 2 times (dual buffered)
+ while (hirq & HIRQ_RCVDAV_IRQ) {
+ uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, in_isr);
+ xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len);
+ if (xact_len) {
+ fifo_read(rhport, ep->buf, xact_len, in_isr);
+ ep->buf += xact_len;
+ ep->xferred_len += xact_len;
+ }
+
+ // ack RCVDVAV IRQ
+ hirq_write(rhport, HIRQ_RCVDAV_IRQ, in_isr);
+ hirq = reg_read(rhport, HIRQ_ADDR, in_isr);
+ }
+
+ if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) {
+ ep->state = EP_STATE_COMPLETE;
+ }
+ }
+
+ if (hirq & HIRQ_HXFRDN_IRQ) {
+ hirq_write(rhport, HIRQ_HXFRDN_IRQ, in_isr);
+ handle_xfer_done(rhport, in_isr);
+ }
+
+ hirq = reg_read(rhport, HIRQ_ADDR, in_isr);
+ }
+
+ // clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing
+ hirq &= (uint8_t) ~HIRQ_SNDBAV_IRQ;
+ if ( hirq ) {
+ hirq_write(rhport, hirq, in_isr);
+ }
+}
+
+#endif
diff --git a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c
new file mode 100644
index 000000000..f02415904
--- /dev/null
+++ b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c
@@ -0,0 +1,1203 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright 2021 Bridgetek Pte Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/*
+ * Contains code adapted from Bridgetek Pte Ltd via license terms stated
+ * in https://brtchip.com/BRTSourceCodeLicenseAgreement
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && \
+ (CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X)
+
+#include <stdint.h>
+#include <ft900.h>
+#include <registers/ft900_registers.h>
+
+#define USBD_USE_STREAMS
+
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+// Board code will determine the state of VBUS from USB host.
+extern int8_t board_ft9xx_vbus(void);
+extern int board_uart_write(void const *buf, int len);
+
+// Static array to store an incoming SETUP request for processing by tinyusb.
+CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN
+static uint8_t _ft9xx_setup_packet[8];
+
+struct ft9xx_xfer_state
+{
+ volatile uint8_t ready; // OUT Transfer has been received and waiting for transfer.
+ volatile uint8_t valid; // Transfer is pending and total_size, remain_size, and buff_ptr are valid.
+
+ int16_t total_size; // Total transfer size in bytes for this transfer.
+ int16_t remain_size; // Total remaining in transfer.
+ uint8_t *buff_ptr; // Pointer to buffer to transmit from or receive to.
+
+ uint8_t type; // Endpoint type. Of type USBD_ENDPOINT_TYPE from endpoint descriptor.
+ uint8_t dir; // Endpoint direction. TUSB_DIR_OUT or TUSB_DIR_IN. For control endpoint this is the current direction.
+ uint16_t buff_size; // Actual size of buffer RAM used by endpoint.
+ uint16_t size; // Max packet size for endpoint from endpoint descriptor.
+};
+// Endpoint description array for each endpoint.
+static struct ft9xx_xfer_state ep_xfer[USBD_MAX_ENDPOINT_COUNT];
+// USB speed.
+static tusb_speed_t _speed;
+
+// Interrupt handlers.
+void _ft9xx_usbd_ISR(void); // Interrupt handler for USB device.
+void ft9xx_usbd_pm_ISR(void); // Interrupt handler for USB device for power management (called by board).
+
+// Internal functions forward declarations.
+static uint16_t _ft9xx_edpt_xfer_out(uint8_t ep_number, uint8_t *buffer, uint16_t xfer_bytes);
+static uint16_t _ft9xx_edpt_xfer_in(uint8_t ep_number, uint8_t *buffer, uint16_t xfer_bytes);
+static void _ft9xx_reset_edpts(void);
+static inline void _ft9xx_phy_enable(bool en);
+static void _ft9xx_usb_speed(void);
+static void _dcd_ft9xx_attach(void);
+static void _dcd_ft9xx_detach(void) __attribute__((unused));
+static uint16_t _ft9xx_dusb_in(uint8_t ep_number, const uint8_t *buffer, uint16_t length);
+static uint16_t _ft9xx_dusb_out(uint8_t ep_number, uint8_t *buffer, uint16_t length);
+
+// Internal functions.
+
+// Manage an OUT transfer from the host.
+// This can be up-to the maximum packet size of the endpoint.
+// Continuation of a transfer beyond the maximum packet size is performed
+// by the interrupt handler.
+static uint16_t _ft9xx_edpt_xfer_out(uint8_t ep_number, uint8_t *buffer, uint16_t xfer_bytes)
+{
+ //Note: this is called from only the interrupt handler when an OUT transfer is called.
+ uint16_t ep_size = ep_xfer[ep_number].size;
+ (void)ep_size;
+ if (xfer_bytes > ep_size)
+ {
+ xfer_bytes = ep_size;
+ }
+
+ // Wait until the endpoint has finished - it should be complete!
+ //while (!(USBD_EP_SR_REG(ep_number) & MASK_USBD_EPxSR_OPRDY))
+ //;
+
+ // Send the first packet of max packet size
+ xfer_bytes = _ft9xx_dusb_out(ep_number, (uint8_t *)buffer, xfer_bytes);
+ if (ep_number == USBD_EP_0)
+ {
+ // Set flags to indicate data ready.
+ USBD_EP_SR_REG(USBD_EP_0) = (MASK_USBD_EP0SR_OPRDY);
+ }
+ else
+ {
+ USBD_EP_SR_REG(ep_number) = (MASK_USBD_EPxSR_OPRDY);
+ }
+
+ return xfer_bytes;
+}
+
+// Manage an IN transfer to the host.
+// This can be up-to the maximum packet size of the endpoint.
+// Continuation of a transfer beyond the maximum packet size is performed
+// by the interrupt handler.
+static uint16_t _ft9xx_edpt_xfer_in(uint8_t ep_number, uint8_t *buffer, uint16_t xfer_bytes)
+{
+ //Note: this may be called from the interrupt handler or from normal code.
+ uint8_t end = 0;
+ uint16_t ep_size = ep_xfer[ep_number].size;
+ (void)ep_size;
+
+ if ((xfer_bytes == 0) || (xfer_bytes < ep_size))
+ {
+ end = 1;
+ }
+ else
+ {
+ xfer_bytes = ep_size;
+ }
+
+ if (ep_number == USBD_EP_0)
+ {
+ // An IN direction SETUP can be interrupted by an OUT packet.
+ // This will result in a STALL generated by the silicon.
+ while (USBD_EP_SR_REG(USBD_EP_0) & MASK_USBD_EP0SR_STALL)
+ {
+ // Clear the STALL and finish the transaction.
+ USBD_EP_SR_REG(USBD_EP_0) = (MASK_USBD_EP0SR_STALL);
+ }
+ }
+ else
+ {
+ // If there is data to transmit then wait until the IN buffer
+ // for the endpoint is empty.
+ // This does not apply to interrupt endpoints.
+ if (ep_xfer[ep_number].type != TUSB_XFER_INTERRUPT)
+ {
+ uint8_t sr_reg;
+ do
+ {
+ sr_reg = USBD_EP_SR_REG(ep_number);
+ } while (sr_reg & MASK_USBD_EPxSR_INPRDY);
+ }
+ }
+
+ // Do not send a ZLP for interrupt endpoints.
+ if ((ep_xfer[ep_number].type != TUSB_XFER_INTERRUPT) || (xfer_bytes > 0))
+ {
+ xfer_bytes = _ft9xx_dusb_in(ep_number, (uint8_t *)buffer, xfer_bytes);
+ }
+
+ if (ep_number == USBD_EP_0)
+ {
+ if (end)
+ {
+ // Set flags to indicate data ready and transfer complete.
+ USBD_EP_SR_REG(USBD_EP_0) = MASK_USBD_EP0SR_INPRDY | MASK_USBD_EP0SR_DATAEND;
+ }
+ else
+ {
+ // Set flags to indicate data ready.
+ USBD_EP_SR_REG(USBD_EP_0) = (MASK_USBD_EP0SR_INPRDY);
+ }
+ }
+ else
+ {
+ // Set flags to indicate data ready.
+ USBD_EP_SR_REG(ep_number) = (MASK_USBD_EPxSR_INPRDY);
+ }
+
+ return xfer_bytes;
+}
+
+// Reset all non-control endpoints to a default state.
+// Control endpoint is always enabled and ready. All others disabled.
+static void _ft9xx_reset_edpts(void)
+{
+ // Disable all endpoints and remove configuration values.
+ for (int i = 1; i < USBD_MAX_ENDPOINT_COUNT; i++)
+ {
+ // Clear settings.
+ tu_memclr(&ep_xfer[i], sizeof(struct ft9xx_xfer_state));
+ // Disable hardware.
+ USBD_EP_CR_REG(i) = 0;
+ }
+
+ // Enable interrupts from USB device control.
+ USBD_REG(cmie) = MASK_USBD_CMIE_ALL;
+}
+
+// Enable or disable the USB PHY.
+static inline void _ft9xx_phy_enable(bool en)
+{
+ if (en)
+ SYS->PMCFG_L |= MASK_SYS_PMCFG_DEV_PHY_EN;
+ else
+ SYS->PMCFG_L &= ~MASK_SYS_PMCFG_DEV_PHY_EN;
+}
+
+// Safely connect to the USB.
+static void _dcd_ft9xx_attach(void)
+{
+ uint8_t reg;
+
+ CRITICAL_SECTION_BEGIN
+ // Disable device responses.
+ USBD_REG(faddr) = 0;
+
+ // Reset USB Device.
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_DEV_RESET_ALL;
+ // Disable device connect/disconnect/host reset detection.
+ SYS->PMCFG_H = MASK_SYS_PMCFG_DEV_DIS_DEV;
+ SYS->PMCFG_H = MASK_SYS_PMCFG_DEV_CONN_DEV;
+ SYS->PMCFG_L = SYS->PMCFG_L & (~MASK_SYS_PMCFG_DEV_DETECT_EN);
+
+ // Enable Chip USB device clock/PM configuration.
+ sys_enable(sys_device_usb_device);
+ CRITICAL_SECTION_END;
+
+ // Wait a short time to get started.
+ delayms(1);
+
+ CRITICAL_SECTION_BEGIN
+ // Turn off the device enable bit.
+#if BOARD_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED
+ USBD_REG(fctrl) = 0;
+#else // BOARD_TUD_MAX_SPEED == OPT_MODE_FULL_SPEED
+ //Set the full speed only bit if required.
+ USBD_REG(fctrl) = MASK_USBD_FCTRL_MODE_FS_ONLY;
+#endif // BOARD_TUD_MAX_SPEED
+
+ // Clear first reset and suspend interrupts.
+ do
+ {
+ reg = USBD_REG(cmif);
+ USBD_REG(cmif) = reg;
+ } while (reg);
+ // Clear any endpoint interrupts.
+ reg = USBD_REG(epif);
+ USBD_REG(epif) = reg;
+
+ // Disable all interrupts from USB device control before attaching interrupt.
+ USBD_REG(cmie) = 0;
+ CRITICAL_SECTION_END;
+
+ // Enable device connect/disconnect/host reset detection.
+ // Set device detect and remote wakeup enable interrupt enables.
+ SYS->PMCFG_L = SYS->PMCFG_L | MASK_SYS_PMCFG_DEV_DETECT_EN;
+
+#if defined(__FT930__)
+ // Setup VBUS detect
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_USB_VBUS_EN;
+#endif
+}
+
+// Gracefully disconnect from the USB.
+static void _dcd_ft9xx_detach(void)
+{
+ // Disable device connect/disconnect/host reset detection.
+ SYS->PMCFG_L = SYS->PMCFG_L & (~MASK_SYS_PMCFG_DEV_DETECT_EN);
+
+#if defined(__FT930__)
+ // Disable VBUS detection.
+ SYS->MSC0CFG = SYS->MSC0CFG & (~MASK_SYS_MSC0CFG_USB_VBUS_EN);
+#endif
+ CRITICAL_SECTION_BEGIN
+ // Disable interrupts from USB.
+ USBD_REG(epie) = 0;
+ USBD_REG(cmie) = 0;
+ // Turn off the device enable bit.
+ USBD_REG(fctrl) = 0;
+ CRITICAL_SECTION_END;
+
+ delayms(1);
+
+ // Disable USB PHY
+ dcd_disconnect(BOARD_TUD_RHPORT);
+ delayms(1);
+
+ // Disable Chip USB device clock/PM configuration.
+ sys_disable(sys_device_usb_device);
+
+ // Reset USB Device... Needed for Back voltage D+ to be <400mV
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_DEV_RESET_ALL;
+
+ delayms(1);
+ // Set device detect and remote wakeup enable interrupt enables.
+ SYS->PMCFG_L = SYS->PMCFG_L | MASK_SYS_PMCFG_DEV_DETECT_EN;
+
+#if defined(__FT930__)
+ // Setup VBUS detect
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_USB_VBUS_EN;
+#endif
+}
+
+// Determine the speed of the USB to which we are connected.
+// Set the speed of the PHY accordingly.
+// High speed can be disabled through CFG_TUSB_RHPORT0_MODE or CFG_TUD_MAX_SPEED settings.
+static void _ft9xx_usb_speed(void)
+{
+ uint8_t fctrl_val;
+
+ // If USB device function is already enabled then disable it.
+ if (USBD_REG(fctrl) & MASK_USBD_FCTRL_USB_DEV_EN) {
+ USBD_REG(fctrl) = (USBD_REG(fctrl) & (~MASK_USBD_FCTRL_USB_DEV_EN));
+ delayus(200);
+ }
+
+#if BOARD_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED
+
+ /* Detect high or full speed */
+ fctrl_val = MASK_USBD_FCTRL_USB_DEV_EN;
+#if defined(__FT900__)
+ if (!sys_check_ft900_revB())//if 90x series is rev C
+ {
+ fctrl_val |= MASK_USBD_FCTRL_IMP_PERF;
+ }
+#endif
+ USBD_REG(fctrl) = fctrl_val;
+
+#if defined(__FT930__)
+ delayus(200);
+
+ _speed = (SYS->MSC0CFG & MASK_SYS_MSC0CFG_HIGH_SPED_MODE) ?
+ TUSB_SPEED_HIGH : TUSB_SPEED_FULL;
+#else /* __FT930__ */
+ /* Detection by SOF */
+ while (!(USBD_REG(cmif) & MASK_USBD_CMIF_SOFIRQ));
+ USBD_REG(cmif) = MASK_USBD_CMIF_SOFIRQ;
+ delayus(125 + 5);
+ _speed = (USBD_REG(cmif) & MASK_USBD_CMIF_SOFIRQ) ?
+ TUSB_SPEED_HIGH : TUSB_SPEED_FULL;
+ dcd_event_bus_reset(BOARD_TUD_RHPORT, _speed, true);
+
+#endif /* !__FT930__ */
+
+#else // BOARD_TUD_MAX_SPEED == OPT_MODE_FULL_SPEED
+
+ /* User force set to full speed */
+ _speed = TUSB_SPEED_FULL;
+ fctrl_val =
+ MASK_USBD_FCTRL_USB_DEV_EN | MASK_USBD_FCTRL_MODE_FS_ONLY;
+#if defined(__FT900__)
+ if (!sys_check_ft900_revB())//if 90x series is rev C
+ {
+ fctrl_val |= MASK_USBD_FCTRL_IMP_PERF;
+ }
+#endif
+ USBD_REG(fctrl) = fctrl_val;
+ dcd_event_bus_reset(BOARD_TUD_RHPORT, _speed, true);
+ return;
+
+#endif // BOARD_TUD_MAX_SPEED
+}
+
+// Send a buffer to the USB IN FIFO.
+// When the macro USBD_USE_STREAMS is defined this will stream a buffer of data
+// to the FIFO using the most efficient MCU streamout combination.
+// If streaming is disabled then it will send each byte of the buffer in turn
+// to the FIFO. The is no reason to not stream.
+// The total number of bytes sent to the FIFO is returned.
+static uint16_t _ft9xx_dusb_in(uint8_t ep_number, const uint8_t *buffer, uint16_t length)
+{
+ uint16_t bytes_read = 0;
+ uint16_t buff_size = length;
+
+#ifdef USBD_USE_STREAMS
+ volatile uint8_t *data_reg;
+
+ data_reg = (volatile uint8_t *)&(USBD->ep[ep_number].epxfifo);
+ if (buff_size)
+ {
+ if (((uint32_t)buffer) % 4 == 0)
+ {
+ uint16_t aligned = buff_size & (~3);
+ uint16_t left = buff_size & 3;
+
+ if (aligned)
+ {
+ __asm__ volatile("streamout.l %0,%1,%2"
+ :
+ : "r"(data_reg), "r"(buffer), "r"(aligned));
+ buffer += aligned;
+ }
+ if (left)
+ {
+ __asm__ volatile("streamout.b %0,%1,%2"
+ :
+ : "r"(data_reg), "r"(buffer), "r"(left));
+ }
+ }
+ else
+ {
+ __asm__ volatile("streamout.b %0,%1,%2"
+ :
+ : "r"(data_reg), "r"(buffer), "r"(buff_size));
+ }
+ bytes_read = buff_size;
+ }
+#else // USBD_USE_STREAMS
+
+ bytes_read = buff_size;
+ while (buff_size--)
+ {
+ USBD_EP_FIFO_REG(ep_number) = *buffer++;
+ };
+
+#endif // USBD_USE_STREAMS
+
+ return bytes_read;
+}
+
+// Receive a buffer from the USB OUT FIFO.
+// When the macro USBD_USE_STREAMS is defined this will stream from the FIFO
+// to a buffer of data using the most efficient MCU streamin combination.
+// If streaming is disabled then it will receive each byte from the FIFO in turn
+// to the buffer. The is no reason to not stream.
+// The total number of bytes received from the FIFO is returned.
+static uint16_t _ft9xx_dusb_out(uint8_t ep_number, uint8_t *buffer, uint16_t length)
+{
+#ifdef USBD_USE_STREAMS
+ volatile uint8_t *data_reg;
+#endif // USBD_USE_STREAMS
+ uint16_t bytes_read = 0;
+ uint16_t buff_size = length;
+
+ if (length > 0)
+ {
+ if (ep_number == USBD_EP_0)
+ {
+ buff_size = USBD_EP_CNT_REG(USBD_EP_0);
+ }
+ else
+ {
+ if (USBD_EP_SR_REG(ep_number) & (MASK_USBD_EPxSR_OPRDY))
+ {
+ buff_size = USBD_EP_CNT_REG(ep_number);
+ }
+ }
+ }
+
+ // Only read as many bytes as we have space for.
+ if (buff_size > length)
+ buff_size = length;
+
+#ifdef USBD_USE_STREAMS
+ data_reg = (volatile uint8_t *)&(USBD->ep[ep_number].epxfifo);
+ if (buff_size)
+ {
+ if ((uint32_t)buffer % 4 == 0)
+ {
+ uint16_t aligned = buff_size & (~3);
+ uint16_t left = buff_size & 3;
+
+ if (aligned)
+ {
+ __asm__ volatile("streamin.l %0,%1,%2"
+ :
+ : "r"(buffer), "r"(data_reg), "r"(aligned));
+ buffer += aligned;
+ }
+ if (left)
+ {
+ __asm__ volatile("streamin.b %0,%1,%2"
+ :
+ : "r"(buffer), "r"(data_reg), "r"(left));
+ }
+ }
+ else
+ {
+ __asm__ volatile("streamin.b %0,%1,%2"
+ :
+ : "r"(buffer), "r"(data_reg), "r"(buff_size));
+ }
+ bytes_read = buff_size;
+ }
+#else // USBD_USE_STREAMS
+
+ bytes_read = buff_size;
+ while (buff_size--)
+ {
+ *buffer++ = USBD_EP_FIFO_REG(ep_number);
+ }
+
+#endif // USBD_USE_STREAMS
+
+ return bytes_read;
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+
+// Initialize controller to device mode
+void dcd_init(uint8_t rhport)
+{
+ TU_LOG2("FT9xx initialisation\r\n");
+
+ _dcd_ft9xx_attach();
+
+ interrupt_attach(interrupt_usb_device, (int8_t)interrupt_usb_device, _ft9xx_usbd_ISR);
+
+ dcd_connect(rhport);
+}
+
+// Enable device interrupt
+void dcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ TU_LOG3("FT9xx int enable\r\n");
+
+ // Peripheral devices interrupt enable.
+ interrupt_enable_globally();
+}
+
+// Disable device interrupt
+void dcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ TU_LOG3("FT9xx int disable\r\n");
+
+ // Peripheral devices interrupt disable.
+ interrupt_disable_globally();
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ (void)dev_addr;
+
+ // Respond with status. There is no checking that the address is in range.
+ dcd_edpt_xfer(rhport, tu_edpt_addr(USBD_EP_0, TUSB_DIR_IN), NULL, 0);
+
+ // Set the update bit for the address register.
+ dev_addr |= 0x80;
+
+ // Modify the address register within a critical section.
+ CRITICAL_SECTION_BEGIN
+ {
+ USBD_REG(faddr) = dev_addr;
+ }
+ CRITICAL_SECTION_END;
+}
+
+// Invoked when a control transfer's status stage is complete.
+// May help DCD to prepare for next control transfer, this API is optional.
+#if 0 // never called
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
+{
+ (void) rhport;
+
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD )
+ {
+ if (request->bRequest == TUSB_REQ_SET_ADDRESS)
+ {
+ }
+ else if (request->bRequest == TUSB_REQ_SET_CONFIGURATION)
+ {
+ }
+ }
+}
+#endif // 0
+
+// Wake up host
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void)rhport;
+
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_DEV_RMWAKEUP;
+
+ // At least 2 ms of delay needed for RESUME Data K state.
+ delayms(2);
+
+ SYS->MSC0CFG &= ~MASK_SYS_MSC0CFG_DEV_RMWAKEUP;
+
+ // Enable USB PHY and determine current bus speed.
+ dcd_connect(rhport);
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ (void)rhport;
+ TU_LOG2("FT9xx connect\r\n");
+
+ CRITICAL_SECTION_BEGIN
+ // Is device connected?
+ if (board_ft9xx_vbus())
+ {
+ // Clear/disable address register.
+ USBD_REG(faddr) = 0;
+ _ft9xx_phy_enable(true);
+
+ // Determine bus speed and signal speed to tusb.
+ _ft9xx_usb_speed();
+ }
+
+ // Setup the control endpoint only.
+#if CFG_TUD_ENDPOINT0_SIZE == 64
+ USBD_EP_CR_REG(USBD_EP_0) = (USBD_EP0_MAX_SIZE_64 << BIT_USBD_EP0_MAX_SIZE);
+#elif CFG_TUD_ENDPOINT0_SIZE == 32
+ USBD_EP_CR_REG(USBD_EP_0) = (USBD_EP0_MAX_SIZE_32 << BIT_USBD_EP0_MAX_SIZE);
+#elif CFG_TUD_ENDPOINT0_SIZE == 16
+ USBD_EP_CR_REG(USBD_EP_0) = (USBD_EP0_MAX_SIZE_16 << BIT_USBD_EP0_MAX_SIZE);
+#elif CFG_TUD_ENDPOINT0_SIZE == 8
+ USBD_EP_CR_REG(USBD_EP_0) = (USBD_EP0_MAX_SIZE_8 << BIT_USBD_EP0_MAX_SIZE);
+#else
+#error "CFG_TUD_ENDPOINT0_SIZE must be defined with a value of 8, 16, 32 or 64."
+#endif
+ CRITICAL_SECTION_END;
+
+ // Configure the control endpoint.
+ ep_xfer[USBD_EP_0].size = CFG_TUD_ENDPOINT0_SIZE;
+ ep_xfer[USBD_EP_0].type = TUSB_XFER_CONTROL;
+
+ // Enable interrupts on EP0.
+ USBD_REG(epie) = (MASK_USBD_EPIE_EP0IE);
+
+ // Restore default endpoint state.
+ _ft9xx_reset_edpts();
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ (void)rhport;
+ TU_LOG2("FT9xx disconnect\r\n");
+
+ // Disable the USB PHY.
+ _ft9xx_phy_enable(false);
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc)
+{
+ (void)rhport;
+ uint8_t const ep_number = tu_edpt_number(ep_desc->bEndpointAddress);
+ uint8_t const ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress);
+ uint8_t const ep_type = ep_desc->bmAttributes.xfer;
+ uint16_t const ep_size = tu_edpt_packet_size(ep_desc); // Mask size per packet, bits 10..0.
+ uint16_t ep_buff_size;
+ uint8_t ep_reg_size = USBD_EP_MAX_SIZE_8;
+ uint8_t ep_reg_data = 0;
+ int16_t total_ram;
+
+ TU_LOG2("FT9xx endpoint open %d %c\r\n", ep_number, ep_dir?'I':'O');
+
+ // Check that the requested endpoint number is allowable.
+ if (ep_number >= USBD_MAX_ENDPOINT_COUNT)
+ {
+ TU_LOG1("FT9xx endpoint not valid: requested %d max %d\r\n", ep_number, USBD_MAX_ENDPOINT_COUNT);
+ return false;
+ }
+
+ // Calculate the physical size of the endpoint as a power of 2. This may be more than
+ // the requested size.
+ while (ep_size > (8 * (1 << ep_reg_size)))
+ {
+ ep_reg_size++;
+ }
+ if (ep_reg_size > USBD_EP_MAX_SIZE_1024)
+ {
+ TU_LOG1("FT9xx endpoint size not valid: requested %d max 1024\r\n", ep_size);
+ return false;
+ }
+ // Calculate actual amount of buffer RAM used by this endpoint. This may be more than the
+ // requested size.
+ ep_buff_size = 8 << ep_reg_size;
+
+ if (ep_number > 0)
+ {
+ // Set EP cmd parameters...
+ ep_reg_data |= (ep_reg_size << BIT_USBD_EP_MAX_SIZE);
+
+ if (ep_xfer[ep_number].type != USBD_EP_TYPE_DISABLED)
+ {
+ // This could be because an endpoint has been assigned with the same number.
+ // On FT9xx, IN and OUT endpoints may not have the same number. e.g. There
+ // cannot been an 0x81 and 0x01 endpoint.
+ TU_LOG1("FT9xx endpoint %d already assigned\r\n", ep_number);
+ return false;
+ }
+
+ // Check that there is enough buffer RAM to allocate to this new endpoint.
+ // Available buffer RAM depends on the device revision.
+ // The IN and OUT buffer RAM should be the same size.
+ if (ep_dir == USBD_DIR_IN)
+ total_ram = USBD_RAMTOTAL_IN;
+ else
+ total_ram = USBD_RAMTOTAL_OUT;
+ // Work out how much has been allocated to existing endpoints.
+ // The total RAM allocated should always be a positive number as this
+ // algorithm should not let it go below zero.
+ for (int i = 1; i < USBD_MAX_ENDPOINT_COUNT; i++)
+ {
+ if (ep_xfer[i].type != USBD_EP_TYPE_DISABLED)
+ {
+ if (ep_xfer[i].dir == ep_dir)
+ {
+ total_ram -= ep_xfer[i].buff_size;
+ }
+ }
+ }
+
+ if (sys_check_ft900_revB())
+ {
+ // The control endpoint is taken into account as well on RevB silicon.
+ total_ram -= ep_xfer[0].buff_size;
+ }
+
+ // Make sure we have enough space. The corner case is having zero bytes
+ // free which means that total_ram must be signed as zero bytes free is
+ // allowable.
+ if (total_ram < ep_buff_size)
+ {
+ TU_LOG1("FT9xx insufficient buffer RAM for endpoint %d\r\n", ep_number);
+ return false;
+ }
+
+ // Set the type of this endpoint in the control register.
+ if (ep_type == TUSB_XFER_BULK)
+ ep_reg_data |= (USBD_EP_DIS_BULK << BIT_USBD_EP_CONTROL_DIS);
+ else if (ep_type == TUSB_XFER_INTERRUPT)
+ ep_reg_data |= (USBD_EP_DIS_INT << BIT_USBD_EP_CONTROL_DIS);
+ else if (ep_type == TUSB_XFER_ISOCHRONOUS)
+ ep_reg_data |= (USBD_EP_DIS_ISO << BIT_USBD_EP_CONTROL_DIS);
+ // Set the direction of this endpoint in the control register.
+ if (ep_dir == USBD_DIR_IN)
+ ep_reg_data |= MASK_USBD_EPxCR_DIR;
+ // Do not perform double buffering.
+ //if (<double buffering flag> != USBD_DB_OFF)
+ //ep_reg_data |= MASK_USBD_EPxCR_DB;
+ // Set the control register for this endpoint.
+ USBD_EP_CR_REG(ep_number) = ep_reg_data;
+ TU_LOG2("FT9xx endpoint setting %x\r\n", ep_reg_data);
+ }
+ else
+ {
+ // Set the control register for endpoint zero.
+ USBD_EP_CR_REG(USBD_EP_0) = (ep_reg_size << BIT_USBD_EP0_MAX_SIZE);
+ }
+
+ CRITICAL_SECTION_BEGIN
+ // Store the endpoint characteristics for later reference.
+ ep_xfer[ep_number].dir = ep_dir;
+ ep_xfer[ep_number].type = ep_type;
+ ep_xfer[ep_number].size = ep_size;
+ ep_xfer[ep_number].buff_size = ep_buff_size;
+
+ // Clear register transaction continuation and signalling state.
+ ep_xfer[ep_number].ready = 0;
+ ep_xfer[ep_number].valid = 0;
+ ep_xfer[ep_number].buff_ptr = NULL;
+ ep_xfer[ep_number].total_size = 0;
+ ep_xfer[ep_number].remain_size = 0;
+ CRITICAL_SECTION_END
+
+ return true;
+}
+
+// Close all endpoints.
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ (void)rhport;
+ // Reset the endpoint configurations.
+ _ft9xx_reset_edpts();
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+ uint8_t ep_number = tu_edpt_number(ep_addr);
+ uint8_t ep_dir = tu_edpt_dir(ep_addr);
+ uint16_t xfer_bytes;
+ bool status = false;
+
+ // We will attempt to transfer the buffer. If it is less than or equal to the endpoint
+ // maximum packet size then the whole buffer will be transferred. If it is larger then
+ // the interrupt handler will transfer the remainder.
+ // ep_xfer is used to tell the interrupt handler what to do.
+ // ep_xfer can be used at interrupt level to continue transfers.
+ CRITICAL_SECTION_BEGIN
+
+ // Transfer currently in progress.
+ if (ep_xfer[ep_number].valid == 0)
+ {
+ ep_xfer[ep_number].total_size = total_bytes;
+ ep_xfer[ep_number].remain_size = total_bytes;
+ ep_xfer[ep_number].buff_ptr = buffer;
+
+ if (ep_number == USBD_EP_0)
+ {
+ ep_xfer[USBD_EP_0].dir = ep_dir;
+ }
+ else
+ {
+ // Enable the interrupt for this endpoint allowing the interrupt handler to report
+ // continue the transfer and signal completion.
+ USBD_REG(epie) = USBD_REG(epie) | (1 << ep_number);
+ }
+
+ if (ep_dir == TUSB_DIR_IN)
+ {
+ // For IN transfers send the first packet as a starter. Interrupt handler to complete
+ // this if it is larger than one packet.
+ xfer_bytes = _ft9xx_edpt_xfer_in(ep_number, buffer, total_bytes);
+
+ ep_xfer[ep_number].buff_ptr += xfer_bytes;
+ ep_xfer[ep_number].remain_size -= xfer_bytes;
+
+ // Tell the interrupt handler to signal dcd_event_xfer_complete on completion.
+ ep_xfer[ep_number].valid = 1;
+ }
+ else // (dir == TUSB_DIR_OUT)
+ {
+ // For OUT transfers on the control endpoint.
+ // The host may already have performed the first data transfer after the SETUP packet
+ // before the transfer is setup for it.
+ if (ep_xfer[ep_number].ready)
+ {
+ // We have received a data packet on the endpoint without a transfer
+ // being initialised. This can be because the host has sent this packet before
+ // a new transfer has been initiated on the endpoint.
+ // We will now stream the data from the FIFO.
+ ep_xfer[ep_number].ready = 0;
+
+ // Transfer incoming data from an OUT packet to the buffer.
+ xfer_bytes = _ft9xx_edpt_xfer_out(ep_number, buffer, total_bytes);
+
+ // Report completion of the transfer.
+ dcd_event_xfer_complete(BOARD_TUD_RHPORT, ep_number /*| TUSB_DIR_OUT_MASK */, xfer_bytes, XFER_RESULT_SUCCESS, false);
+ }
+ else
+ {
+ // Tell the interrupt handler to wait for the packet to be received and
+ // then report the transfer complete with dcd_event_xfer_complete.
+ ep_xfer[ep_number].valid = 1;
+ }
+ }
+ status = true;
+ }
+ else
+ {
+ // Note: should not arrive here.
+ }
+
+ CRITICAL_SECTION_END
+
+ return status;
+}
+
+// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes)
+{
+ (void)rhport;
+ (void)ep_addr;
+ (void)ff;
+ (void)total_bytes;
+ bool status = false;
+ return status;
+}
+
+// Stall endpoint (non-control endpoint)
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t ep_number = tu_edpt_number(ep_addr);
+ (void)rhport;
+
+ CRITICAL_SECTION_BEGIN
+ if (ep_number == USBD_EP_0)
+ {
+ USBD_EP_CR_REG(USBD_EP_0) = USBD_EP_CR_REG(USBD_EP_0) |
+ MASK_USBD_EP0CR_SDSTL;
+ }
+ else
+ {
+ USBD_EP_CR_REG(ep_number) = USBD_EP_CR_REG(ep_number) |
+ MASK_USBD_EPxCR_SDSTL;
+ USBD_EP_SR_REG(ep_number) = MASK_USBD_EPxSR_CLR_TOGGLE |
+ MASK_USBD_EPxSR_FIFO_FLUSH;
+ }
+ CRITICAL_SECTION_END
+}
+
+// Clear stall (non-control endpoint), data toggle is also reset to DATA0
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t ep_number = tu_edpt_number(ep_addr);
+ (void)rhport;
+
+ if (ep_number > USBD_EP_0)
+ {
+ CRITICAL_SECTION_BEGIN
+ USBD_EP_CR_REG(ep_number) = USBD_EP_CR_REG(ep_number) &
+ (~MASK_USBD_EPxCR_SDSTL);
+ USBD_EP_SR_REG(ep_number) = MASK_USBD_EPxSR_CLR_TOGGLE;
+
+ // Allow transfers to restart.
+ ep_xfer[ep_number].ready = 0;
+ ep_xfer[ep_number].valid = 0;
+ ep_xfer[ep_number].remain_size = 0;
+ CRITICAL_SECTION_END
+ }
+}
+
+// Interrupt handling.
+
+void _ft9xx_usbd_ISR(void)
+{
+ dcd_int_handler(BOARD_TUD_RHPORT);
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+ (void)rhport;
+
+ // Read the Common Interrupt Flag Register.
+ uint8_t cmif = USBD_REG(cmif);
+ // Read the Endpoint Interrupt Flag Register.
+#if defined(__FT930__)
+ // This is 16 bits on FT93x.
+ uint16_t epif = USBD_REG(epif);
+#else
+ // This is 8 bits on FT90x.
+ uint8_t epif = USBD_REG(epif);
+#endif
+
+ if (cmif & MASK_USBD_CMIF_ALL)
+ {
+ // Clear all CMIF bits.
+ USBD_REG(cmif) = MASK_USBD_CMIF_ALL;
+ if (cmif & MASK_USBD_CMIF_PHYIRQ) //Handle PHY interrupt
+ {
+ }
+ if (cmif & MASK_USBD_CMIF_PIDIRQ) //Handle PIDIRQ interrupt
+ {
+ }
+ if (cmif & MASK_USBD_CMIF_CRC16IRQ) //Handle CRC16IRQ interrupt
+ {
+ }
+ if (cmif & MASK_USBD_CMIF_CRC5IRQ) //Handle CRC5 interrupt
+ {
+ }
+ if (cmif & MASK_USBD_CMIF_RSTIRQ) //Handle Reset interrupt
+ {
+ // Reset endpoints to default state.
+ _ft9xx_reset_edpts();
+ dcd_event_bus_reset(BOARD_TUD_RHPORT, _speed, true);
+ }
+ if (cmif & MASK_USBD_CMIF_SUSIRQ) //Handle Suspend interrupt
+ {
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_SUSPEND, true);
+ }
+ if (cmif & MASK_USBD_CMIF_RESIRQ) //Handle Resume interrupt
+ {
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_RESUME, true);
+ }
+ if (cmif & MASK_USBD_CMIF_SOFIRQ) //Handle SOF interrupt
+ {
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_SOF, true);
+ }
+ }
+ // Handle endpoint interrupts.
+ if (epif)
+ {
+ uint16_t xfer_bytes;
+
+ // Check for EP0 interrupts pending.
+ if (epif & MASK_USBD_EPIF_EP0IRQ)
+ {
+ // Clear interrupt register.
+ USBD_REG(epif) = MASK_USBD_EPIF_EP0IRQ;
+ // Test for an incoming SETUP request on the control endpoint.
+ if (USBD_EP_SR_REG(USBD_EP_0) & MASK_USBD_EP0SR_SETUP)
+ {
+ // If protocol STALL, End the STALL signalling.
+ if (USBD_EP_CR_REG(USBD_EP_0) & MASK_USBD_EP0CR_SDSTL)
+ {
+ // STALL end.
+ USBD_EP_CR_REG(USBD_EP_0) = USBD_EP_CR_REG(USBD_EP_0) &
+ (~MASK_USBD_EP0CR_SDSTL);
+ // Clear STALL send.
+ USBD_EP_SR_REG(USBD_EP_0) = MASK_USBD_EP0SR_STALL;
+ }
+
+ // Host has sent a SETUP packet. Receive this into the SETUP packet store.
+ _ft9xx_dusb_out(USBD_EP_0, (uint8_t *)_ft9xx_setup_packet, sizeof(USB_device_request));
+
+ // Send the packet to tinyusb.
+ dcd_event_setup_received(BOARD_TUD_RHPORT, _ft9xx_setup_packet, true);
+
+ // Clear the interrupt that signals a SETUP packet is received.
+ USBD_EP_SR_REG(USBD_EP_0) = (MASK_USBD_EP0SR_SETUP);
+
+ // Any SETUP packet will clear the incoming FIFO.
+ ep_xfer[USBD_EP_0].ready = 0;
+
+ // Allow new DATA and ACK transfers on the control endpoint.
+ ep_xfer[USBD_EP_0].valid = 0;
+ return;
+ }
+ else
+ {
+ // Check for a complete or partially complete transfers on EP0.
+ if (ep_xfer[USBD_EP_0].valid)
+ {
+ xfer_bytes = (uint16_t)ep_xfer[USBD_EP_0].total_size;
+
+ // Transfer incoming data from an OUT packet to the buffer supplied.
+ if (ep_xfer[USBD_EP_0].dir == TUSB_DIR_OUT)
+ {
+ xfer_bytes = _ft9xx_edpt_xfer_out(USBD_EP_0, ep_xfer[USBD_EP_0].buff_ptr, xfer_bytes);
+ }
+ // Now signal completion of data packet.
+ dcd_event_xfer_complete(BOARD_TUD_RHPORT, USBD_EP_0 | (ep_xfer[USBD_EP_0].dir ? TUSB_DIR_IN_MASK : 0),
+ xfer_bytes, XFER_RESULT_SUCCESS, true);
+
+ // Incoming FIFO has been cleared.
+ ep_xfer[USBD_EP_0].ready = 0;
+
+ // Allow new transfers on the control endpoint.
+ ep_xfer[USBD_EP_0].valid = 0;
+ }
+ // No transfer is in flight for EP0.
+ else
+ {
+ // We have received a data packet on the control endpoint without a transfer
+ // being initialised. This can be because the host has sent this packet before
+ // a new transfer has been initiated on the control endpoint.
+ // We will record that there is data in the FIFO for dcd_edpt_xfer to obtain
+ // once the transfer is initiated.
+ ep_xfer[USBD_EP_0].ready = 1;
+ }
+ }
+ }
+ else // !(epif & MASK_USBD_EPIF_EP0IRQ)
+ {
+ // Mask out currently disabled endpoints.
+ epif &= USBD_REG(epie);
+
+ // Handle complete and partially complete transfers for each endpoint.
+ for (uint8_t ep_number = 1; ep_number < USBD_MAX_ENDPOINT_COUNT; ep_number++)
+ {
+ if ((epif & MASK_USBD_EPIF_IRQ(ep_number)) == 0)
+ {
+ // No pending interrupt for this endpoint.
+ continue;
+ }
+
+ if (ep_xfer[ep_number].valid)
+ {
+ xfer_bytes = 0;
+
+ // Clear interrupt register for this endpoint.
+ USBD_REG(epif) = MASK_USBD_EPIF_IRQ(ep_number);
+
+ // Start or continue an OUT transfer.
+ if (ep_xfer[ep_number].dir == TUSB_DIR_OUT)
+ {
+ xfer_bytes = _ft9xx_edpt_xfer_out(ep_number,
+ ep_xfer[ep_number].buff_ptr,
+ (uint16_t)ep_xfer[ep_number].remain_size);
+
+ // Report each OUT packet received to the stack.
+ dcd_event_xfer_complete(BOARD_TUD_RHPORT,
+ ep_number /* | TUSB_DIR_OUT_MASK */,
+ xfer_bytes, XFER_RESULT_SUCCESS, true);
+
+ ep_xfer[ep_number].buff_ptr += xfer_bytes;
+ ep_xfer[ep_number].remain_size -= xfer_bytes;
+ }
+ // continue an IN transfer
+ else // if (ep_xfer[ep_number].dir == TUSB_DIR_IN)
+ {
+ if (ep_xfer[ep_number].remain_size > 0)
+ {
+ xfer_bytes = _ft9xx_edpt_xfer_in(ep_number,
+ ep_xfer[ep_number].buff_ptr,
+ (uint16_t)ep_xfer[ep_number].remain_size);
+
+ ep_xfer[ep_number].buff_ptr += xfer_bytes;
+ ep_xfer[ep_number].remain_size -= xfer_bytes;
+ }
+
+ if (ep_xfer[ep_number].remain_size == 0)
+ {
+ dcd_event_xfer_complete(BOARD_TUD_RHPORT,
+ ep_number | TUSB_DIR_IN_MASK,
+ ep_xfer[ep_number].total_size, XFER_RESULT_SUCCESS, true);
+ }
+ }
+
+ // When the transfer is complete...
+ if (ep_xfer[ep_number].remain_size == 0)
+ {
+ // Finish this transfer and allow new transfers on this endpoint.
+ ep_xfer[ep_number].valid = 0;
+
+ // Disable the interrupt for this endpoint now it is complete.
+ USBD_REG(epie) = USBD_REG(epie) & (~(1 << ep_number));
+ }
+
+ ep_xfer[ep_number].ready = 0;
+ }
+ // No OUT transfer is in flight for this endpoint.
+ else
+ {
+ if (ep_xfer[ep_number].dir == TUSB_DIR_OUT)
+ {
+ // We will record that there is data in the FIFO for dcd_edpt_xfer to obtain
+ // once the transfer is initiated.
+ // Strictly this should not happen for a non-control endpoint. Interrupts
+ // are disabled when there are no transfers setup for an endpoint.
+ ep_xfer[ep_number].ready = 1;
+ }
+ }
+ }
+ }
+ }
+}
+
+// Power management interrupt handler.
+// This handles USB device related power management interrupts only.
+void ft9xx_usbd_pm_ISR(void)
+{
+ uint16_t pmcfg = SYS->PMCFG_H;
+
+ // Main interrupt handler is responible for
+ if (pmcfg & MASK_SYS_PMCFG_DEV_CONN_DEV)
+ {
+ // Signal connection interrupt
+ SYS->PMCFG_H = MASK_SYS_PMCFG_PM_GPIO_IRQ_PEND;
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_RESUME, true);
+ }
+
+ if (pmcfg & MASK_SYS_PMCFG_DEV_DIS_DEV)
+ {
+ // Signal disconnection interrupt
+ SYS->PMCFG_H = MASK_SYS_PMCFG_PM_GPIO_IRQ_PEND;
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_UNPLUGGED, true);
+ }
+
+ if (pmcfg & MASK_SYS_PMCFG_HOST_RST_DEV)
+ {
+ // Signal Host Reset interrupt
+ SYS->PMCFG_H = MASK_SYS_PMCFG_PM_GPIO_IRQ_PEND;
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_BUS_RESET, true);
+ }
+
+ if (pmcfg & MASK_SYS_PMCFG_HOST_RESUME_DEV)
+ {
+ // Signal Host Resume interrupt
+ SYS->PMCFG_H = MASK_SYS_PMCFG_PM_GPIO_IRQ_PEND;
+ if (!(SYS->MSC0CFG & MASK_SYS_MSC0CFG_DEV_RMWAKEUP))
+ {
+ // If we are driving K-state on Device USB port;
+ // We must maintain the 1ms requirement before resuming the phy
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_RESUME, true);
+ }
+ }
+}
+
+#endif
diff --git a/src/portable/chipidea/ci_fs/ci_fs_kinetis.h b/src/portable/chipidea/ci_fs/ci_fs_kinetis.h
new file mode 100644
index 000000000..31e14a546
--- /dev/null
+++ b/src/portable/chipidea/ci_fs/ci_fs_kinetis.h
@@ -0,0 +1,49 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_FS_KINETIS_H
+#define _CI_FS_KINETIS_H
+
+#include "fsl_device_registers.h"
+
+//static const ci_fs_controller_t _ci_controller[] = {
+// {.reg_base = USB0_BASE, .irqnum = USB0_IRQn}
+//};
+
+#define CI_FS_REG(_port) ((ci_fs_regs_t*) USB0_BASE)
+#define CI_REG CI_FS_REG(0)
+
+void dcd_int_enable(uint8_t rhport) {
+ (void) rhport;
+ NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport) {
+ (void) rhport;
+ NVIC_DisableIRQ(USB0_IRQn);
+}
+
+#endif
diff --git a/src/portable/chipidea/ci_fs/ci_fs_mcx.h b/src/portable/chipidea/ci_fs/ci_fs_mcx.h
new file mode 100644
index 000000000..4b93a03a7
--- /dev/null
+++ b/src/portable/chipidea/ci_fs/ci_fs_mcx.h
@@ -0,0 +1,56 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_FS_MCX_H
+#define _CI_FS_MCX_H
+
+#include "fsl_device_registers.h"
+
+#if CFG_TUSB_MCU == OPT_MCU_MCXN9
+ #define CI_FS_REG(_port) ((ci_fs_regs_t*) USBFS0_BASE)
+ #define CIFS_IRQN USB0_FS_IRQn
+
+#elif CFG_TUSB_MCU == OPT_MCU_MCXA15
+ #define CI_FS_REG(_port) ((ci_fs_regs_t*) USB0_BASE)
+ #define CIFS_IRQN USB0_IRQn
+
+#else
+ #error "MCU is not supported"
+#endif
+
+#define CI_REG CI_FS_REG(0)
+
+void dcd_int_enable(uint8_t rhport) {
+ (void) rhport;
+ NVIC_EnableIRQ(CIFS_IRQN);
+}
+
+void dcd_int_disable(uint8_t rhport) {
+ (void) rhport;
+ NVIC_DisableIRQ(CIFS_IRQN);
+}
+
+#endif
diff --git a/src/portable/chipidea/ci_fs/ci_fs_type.h b/src/portable/chipidea/ci_fs/ci_fs_type.h
new file mode 100644
index 000000000..5a5e53fb0
--- /dev/null
+++ b/src/portable/chipidea/ci_fs/ci_fs_type.h
@@ -0,0 +1,118 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_FS_TYPE_H
+#define _CI_FS_TYPE_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+// Note: some MCUs can only access these registers in 8-bit mode
+// align 4 is used to get rid of reserved fields
+#define _va32 volatile TU_ATTR_ALIGNED(4)
+
+typedef struct {
+ _va32 uint8_t PER_ID; // [00] Peripheral ID register
+ _va32 uint8_t ID_COMP; // [04] Peripheral ID complement register
+ _va32 uint8_t REV; // [08] Peripheral revision register
+ _va32 uint8_t ADD_INFO; // [0C] Peripheral additional info register
+ _va32 uint8_t OTG_ISTAT; // [10] OTG Interrupt Status Register
+ _va32 uint8_t OTG_ICTRL; // [14] OTG Interrupt Control Register
+ _va32 uint8_t OTG_STAT; // [18] OTG Status Register
+ _va32 uint8_t OTG_CTRL; // [1C] OTG Control register
+ uint32_t reserved_20[24]; // [20]
+ _va32 uint8_t INT_STAT; // [80] Interrupt status register
+ _va32 uint8_t INT_EN; // [84] Interrupt enable register
+ _va32 uint8_t ERR_STAT; // [88] Error interrupt status register
+ _va32 uint8_t ERR_ENB; // [8C] Error interrupt enable register
+ _va32 uint8_t STAT; // [90] Status register
+ _va32 uint8_t CTL; // [94] Control register
+ _va32 uint8_t ADDR; // [98] Address register
+ _va32 uint8_t BDT_PAGE1; // [9C] BDT page register 1
+ _va32 uint8_t FRM_NUML; // [A0] Frame number register
+ _va32 uint8_t FRM_NUMH; // [A4] Frame number register
+ _va32 uint8_t TOKEN; // [A8] Token register
+ _va32 uint8_t SOF_THLD; // [AC] SOF threshold register
+ _va32 uint8_t BDT_PAGE2; // [B0] BDT page register 2
+ _va32 uint8_t BDT_PAGE3; // [B4] BDT page register 3
+
+ uint32_t reserved_b8; // [B8]
+ uint32_t reserved_bc; // [BC]
+
+ struct {
+ _va32 uint8_t CTL;
+ }EP[16]; // [C0] Endpoint control register
+
+ //----- Following is only found available in NXP Kinetis
+ _va32 uint8_t USBCTRL; // [100] USB Control register,
+ _va32 uint8_t OBSERVE; // [104] USB OTG Observe register,
+ _va32 uint8_t CONTROL; // [108] USB OTG Control register,
+ _va32 uint8_t USBTRC0; // [10C] USB Transceiver Control Register 0,
+ uint32_t reserved_110; // [110]
+ _va32 uint8_t USBFRMADJUST; // [114] Frame Adjust Register,
+
+ //----- Following is only found available in NXP MCX
+ uint32_t reserved_118[3]; // [118]
+ _va32 uint8_t KEEP_ALIVE_CTRL; // [124] Keep Alive Mode Control,
+ _va32 uint8_t KEEP_ALIVE_WKCTRL; // [128] Keep Alive Mode Wakeup Control,
+ _va32 uint8_t MISCCTRL; // [12C] Miscellaneous Control,
+ _va32 uint8_t STALL_IL_DIS; // [130] Peripheral Mode Stall Disable for Endpoints[ 7..0] IN
+ _va32 uint8_t STALL_IH_DIS; // [134] Peripheral Mode Stall Disable for Endpoints[15..8] IN
+ _va32 uint8_t STALL_OL_DIS; // [138] Peripheral Mode Stall Disable for Endpoints[ 7..0] OUT
+ _va32 uint8_t STALL_OH_DIS; // [13C] Peripheral Mode Stall Disable for Endpoints[15..8] OUT
+ _va32 uint8_t CLK_RECOVER_CTRL; // [140] USB Clock Recovery Control,
+ _va32 uint8_t CLK_RECOVER_IRC_EN; // [144] FIRC Oscillator Enable,
+ uint32_t reserved_148[3]; // [148]
+ _va32 uint8_t CLK_RECOVER_INT_EN; // [154] Clock Recovery Combined Interrupt Enable,
+ uint32_t reserved_158; // [158]
+ _va32 uint8_t CLK_RECOVER_INT_STATUS; // [15C] Clock Recovery Separated Interrupt Status,
+} ci_fs_regs_t;
+
+TU_VERIFY_STATIC(sizeof(ci_fs_regs_t) == 0x160, "Size is not correct");
+
+typedef struct
+{
+ uint32_t reg_base;
+ uint32_t irqnum;
+} ci_fs_controller_t;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/chipidea/ci_fs/dcd_ci_fs.c b/src/portable/chipidea/ci_fs/dcd_ci_fs.c
new file mode 100644
index 000000000..02f813ab5
--- /dev/null
+++ b/src/portable/chipidea/ci_fs/dcd_ci_fs.c
@@ -0,0 +1,567 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Koji Kitayama
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_CHIPIDEA_FS)
+
+#include "device/dcd.h"
+#include "ci_fs_type.h"
+
+#if defined(TUP_USBIP_CHIPIDEA_FS_KINETIS)
+ #include "ci_fs_kinetis.h"
+#elif defined(TUP_USBIP_CHIPIDEA_FS_MCX)
+ #include "ci_fs_mcx.h"
+#else
+ #error "MCU is not supported"
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+ TOK_PID_OUT = 0x1u,
+ TOK_PID_IN = 0x9u,
+ TOK_PID_SETUP = 0xDu,
+};
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t head;
+ struct {
+ union {
+ struct {
+ uint16_t : 2;
+ __IO uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ __IO uint16_t own : 1;
+ uint16_t : 8;
+ };
+ struct {
+ uint16_t : 2;
+ uint16_t bdt_stall : 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ uint16_t : 10;
+ };
+ };
+ __IO uint16_t bc : 10;
+ uint16_t : 6;
+ };
+ };
+ uint8_t *addr;
+}buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" );
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t state;
+ struct {
+ uint32_t max_packet_size :11;
+ uint32_t : 5;
+ uint32_t odd : 1;
+ uint32_t :15;
+ };
+ };
+ uint16_t length;
+ uint16_t remaining;
+}endpoint_state_t;
+
+TU_VERIFY_STATIC( sizeof(endpoint_state_t) == 8, "size is not correct" );
+
+typedef struct
+{
+ union {
+ /* [#EP][OUT,IN][EVEN,ODD] */
+ buffer_descriptor_t bdt[16][2][2];
+ uint16_t bda[512];
+ };
+ TU_ATTR_ALIGNED(4) union {
+ endpoint_state_t endpoint[16][2];
+ endpoint_state_t endpoint_unified[16 * 2];
+ };
+ uint8_t setup_packet[8];
+ uint8_t addr;
+}dcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+// BDT(Buffer Descriptor Table) must be 256-byte aligned
+CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
+
+TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
+
+static void prepare_next_setup_packet(uint8_t rhport)
+{
+ const unsigned out_odd = _dcd.endpoint[0][0].odd;
+ const unsigned in_odd = _dcd.endpoint[0][1].odd;
+ TU_ASSERT(0 == _dcd.bdt[0][0][out_odd].own, );
+
+ _dcd.bdt[0][0][out_odd].data = 0;
+ _dcd.bdt[0][0][out_odd ^ 1].data = 1;
+ _dcd.bdt[0][1][in_odd].data = 1;
+ _dcd.bdt[0][1][in_odd ^ 1].data = 0;
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT),
+ _dcd.setup_packet, sizeof(_dcd.setup_packet));
+}
+
+static void process_stall(uint8_t rhport)
+{
+ for (int i = 0; i < 16; ++i) {
+ uint32_t const ep_ctl = CI_REG->EP[i].CTL;
+
+ if (ep_ctl & USB_ENDPT_EPSTALL_MASK) {
+ // prepare next setup if endpoint0
+ if ( i == 0 ) prepare_next_setup_packet(rhport);
+
+ // clear stall bit
+ CI_REG->EP[i].CTL = ep_ctl & ~USB_ENDPT_EPSTALL_MASK;
+ }
+ }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+ const unsigned s = CI_REG->STAT;
+ CI_REG->INT_STAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
+
+ uint8_t const epnum = (s >> USB_STAT_ENDP_SHIFT);
+ uint8_t const dir = (s & USB_STAT_TX_MASK) >> USB_STAT_TX_SHIFT;
+ unsigned const odd = (s & USB_STAT_ODD_MASK) ? 1 : 0;
+
+ buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s];
+ endpoint_state_t *ep = &_dcd.endpoint_unified[s >> 3];
+
+ /* fetch pid before discarded by the next steps */
+ const unsigned pid = bd->tok_pid;
+
+ /* reset values for a next transfer */
+ bd->bdt_stall = 0;
+ bd->dts = 1;
+ bd->ninc = 0;
+ bd->keep = 0;
+ /* update the odd variable to prepare for the next transfer */
+ ep->odd = odd ^ 1;
+ if (pid == TOK_PID_SETUP) {
+ dcd_event_setup_received(rhport, bd->addr, true);
+ CI_REG->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
+ return;
+ }
+
+ const unsigned bc = bd->bc;
+ const unsigned remaining = ep->remaining - bc;
+ if (remaining && bc == ep->max_packet_size) {
+ /* continue the transferring consecutive data */
+ ep->remaining = remaining;
+ const int next_remaining = remaining - ep->max_packet_size;
+ if (next_remaining > 0) {
+ /* prepare to the after next transfer */
+ bd->addr += ep->max_packet_size * 2;
+ bd->bc = next_remaining > ep->max_packet_size ? ep->max_packet_size: next_remaining;
+ __DSB();
+ bd->own = 1; /* the own bit must set after addr */
+ }
+ return;
+ }
+ const unsigned length = ep->length;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(epnum, dir),
+ length - remaining, XFER_RESULT_SUCCESS, true);
+ if (0 == epnum && 0 == length) {
+ /* After completion a ZLP of control transfer,
+ * it prepares for the next steup transfer. */
+ if (_dcd.addr) {
+ /* When the transfer was the SetAddress,
+ * the device address should be updated here. */
+ CI_REG->ADDR = _dcd.addr;
+ _dcd.addr = 0;
+ }
+ prepare_next_setup_packet(rhport);
+ }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+ CI_REG->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+ CI_REG->CTL |= USB_CTL_ODDRST_MASK;
+ CI_REG->ADDR = 0;
+ CI_REG->INT_EN = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK | USB_INTEN_SLEEPEN_MASK |
+ USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
+
+ CI_REG->EP[0].CTL = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+ for (unsigned i = 1; i < 16; ++i) {
+ CI_REG->EP[i].CTL = 0;
+ }
+ buffer_descriptor_t *bd = _dcd.bdt[0][0];
+ for (unsigned i = 0; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+ bd->head = 0;
+ }
+ const endpoint_state_t ep0 = {
+ .max_packet_size = CFG_TUD_ENDPOINT0_SIZE,
+ .odd = 0,
+ .length = 0,
+ .remaining = 0,
+ };
+ _dcd.endpoint[0][0] = ep0;
+ _dcd.endpoint[0][1] = ep0;
+ tu_memclr(_dcd.endpoint[1], sizeof(_dcd.endpoint) - sizeof(_dcd.endpoint[0]));
+ _dcd.addr = 0;
+ prepare_next_setup_packet(rhport);
+ CI_REG->CTL &= ~USB_CTL_ODDRST_MASK;
+ dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+}
+
+static void process_bus_sleep(uint8_t rhport)
+{
+ // Enable resume & disable suspend interrupt
+ const unsigned inten = CI_REG->INT_EN;
+
+ CI_REG->INT_EN = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK;
+ CI_REG->USBTRC0 |= USB_USBTRC0_USBRESMEN_MASK;
+ CI_REG->USBCTRL |= USB_USBCTRL_SUSP_MASK;
+
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+}
+
+static void process_bus_resume(uint8_t rhport)
+{
+ // Enable suspend & disable resume interrupt
+ const unsigned inten = CI_REG->INT_EN;
+
+ CI_REG->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; // will also clear USB_USBTRC0_USB_RESUME_INT_MASK
+ CI_REG->USBTRC0 &= ~USB_USBTRC0_USBRESMEN_MASK;
+ CI_REG->INT_EN = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
+
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+ (void) rhport;
+
+ // save crystal-less setting (if available)
+ #if defined(FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED) && FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED == 1
+ uint32_t clk_recover_irc_en = CI_REG->CLK_RECOVER_IRC_EN;
+ uint32_t clk_recover_ctrl = CI_REG->CLK_RECOVER_CTRL;
+ #endif
+
+ CI_REG->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
+ while (CI_REG->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+
+ // restore crystal-less setting (if available)
+ #if defined(FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED) && FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED == 1
+ CI_REG->CLK_RECOVER_IRC_EN = clk_recover_irc_en;
+ CI_REG->CLK_RECOVER_CTRL |= clk_recover_ctrl;
+ #endif
+
+ tu_memclr(&_dcd, sizeof(_dcd));
+ CI_REG->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */
+ CI_REG->BDT_PAGE1 = (uint8_t)((uintptr_t)_dcd.bdt >> 8);
+ CI_REG->BDT_PAGE2 = (uint8_t)((uintptr_t)_dcd.bdt >> 16);
+ CI_REG->BDT_PAGE3 = (uint8_t)((uintptr_t)_dcd.bdt >> 24);
+
+ CI_REG->INT_EN = USB_INTEN_USBRSTEN_MASK;
+
+ dcd_connect(rhport);
+ // NVIC_ClearPendingIRQ(CIFS_IRQN);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ _dcd.addr = dev_addr & 0x7F;
+ /* Response with status first before changing device address */
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void) rhport;
+
+ CI_REG->CTL |= USB_CTL_RESUME_MASK;
+
+ unsigned cnt = SystemCoreClock / 1000;
+ while (cnt--) __NOP();
+
+ CI_REG->CTL &= ~USB_CTL_RESUME_MASK;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ (void) rhport;
+ CI_REG->USBCTRL = 0;
+ CI_REG->CONTROL |= USB_CONTROL_DPPULLUPNONOTG_MASK;
+ CI_REG->CTL |= USB_CTL_USBENSOFEN_MASK;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ (void) rhport;
+ CI_REG->CTL = 0;
+ CI_REG->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void) rhport;
+
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ const unsigned odd = ep->odd;
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+
+ /* No support for control transfer */
+ TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL));
+
+ ep->max_packet_size = tu_edpt_packet_size(ep_desc);
+ unsigned val = USB_ENDPT_EPCTLDIS_MASK;
+ val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? USB_ENDPT_EPHSHK_MASK: 0;
+ val |= dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+ CI_REG->EP[epn].CTL |= val;
+
+ if (xfer != TUSB_XFER_ISOCHRONOUS) {
+ bd[odd].dts = 1;
+ bd[odd].data = 0;
+ bd[odd ^ 1].dts = 1;
+ bd[odd ^ 1].data = 1;
+ }
+
+ return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ dcd_int_disable(rhport);
+
+ for (unsigned i = 1; i < 16; ++i) {
+ CI_REG->EP[i].CTL = 0;
+ }
+
+ dcd_int_enable(rhport);
+
+ buffer_descriptor_t *bd = _dcd.bdt[1][0];
+ for (unsigned i = 2; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+ bd->head = 0;
+ }
+
+ endpoint_state_t *ep = &_dcd.endpoint[1][0];
+ for (unsigned i = 2; i < sizeof(_dcd.endpoint)/sizeof(*ep); ++i, ++ep) {
+ /* Clear except the odd */
+ ep->max_packet_size = 0;
+ ep->length = 0;
+ ep->remaining = 0;
+ }
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+ const unsigned msk = dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+
+ dcd_int_disable(rhport);
+
+ CI_REG->EP[epn].CTL &= ~msk;
+ ep->max_packet_size = 0;
+ ep->length = 0;
+ ep->remaining = 0;
+ bd[0].head = 0;
+ bd[1].head = 0;
+
+ dcd_int_enable(rhport);
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd];
+ TU_ASSERT(0 == bd->own);
+
+ dcd_int_disable(rhport);
+
+ ep->length = total_bytes;
+ ep->remaining = total_bytes;
+
+ const unsigned mps = ep->max_packet_size;
+ if (total_bytes > mps) {
+ buffer_descriptor_t *next = ep->odd ? bd - 1: bd + 1;
+ /* When total_bytes is greater than the max packet size,
+ * it prepares to the next transfer to avoid NAK in advance. */
+ next->bc = total_bytes >= 2 * mps ? mps: total_bytes - mps;
+ next->addr = buffer + mps;
+ next->own = 1;
+ }
+ bd->bc = total_bytes >= mps ? mps: total_bytes;
+ bd->addr = buffer;
+ __DSB();
+ bd->own = 1; /* This bit must be set last */
+
+ dcd_int_enable(rhport);
+
+ return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ const unsigned epn = tu_edpt_number(ep_addr);
+
+ if (0 == epn) {
+ CI_REG->EP[epn].CTL |= USB_ENDPT_EPSTALL_MASK;
+ } else {
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned odd = _dcd.endpoint[epn][dir].odd;
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][odd];
+ TU_ASSERT(0 == bd->own,);
+
+ dcd_int_disable(rhport);
+
+ bd->bdt_stall = 1;
+ __DSB();
+ bd->own = 1; /* This bit must be set last */
+
+ dcd_int_enable(rhport);
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ TU_VERIFY(epn,);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned odd = _dcd.endpoint[epn][dir].odd;
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+ TU_VERIFY(bd[odd].own,);
+
+ dcd_int_disable(rhport);
+
+ bd[odd].own = 0;
+ __DSB();
+
+ // clear stall
+ bd[odd].bdt_stall = 0;
+
+ // Reset data toggle
+ bd[odd ].data = 0;
+ bd[odd ^ 1].data = 1;
+
+ // We already cleared this in ISR, but just clear it here to be safe
+ const uint32_t ep_ctl = CI_REG->EP[epn].CTL;
+ if (ep_ctl & USB_ENDPT_EPSTALL_MASK) {
+ CI_REG->EP[epn].CTL = ep_ctl & ~USB_ENDPT_EPSTALL_MASK;
+ }
+
+ dcd_int_enable(rhport);
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void dcd_int_handler(uint8_t rhport)
+{
+ uint32_t is = CI_REG->INT_STAT;
+ uint32_t msk = CI_REG->INT_EN;
+
+ // clear non-enabled interrupts
+ CI_REG->INT_STAT = is & ~msk;
+ is &= msk;
+
+ if (is & USB_ISTAT_ERROR_MASK) {
+ /* TODO: */
+ uint32_t es = CI_REG->ERR_STAT;
+ CI_REG->ERR_STAT = es;
+ CI_REG->INT_STAT = is; /* discard any pending events */
+ }
+
+ if (is & USB_ISTAT_USBRST_MASK) {
+ CI_REG->INT_STAT = is; /* discard any pending events */
+ process_bus_reset(rhport);
+ }
+
+ if (is & USB_ISTAT_SLEEP_MASK) {
+ // TU_LOG2("Suspend: "); TU_LOG2_HEX(is);
+
+ // Note Host usually has extra delay after bus reset (without SOF), which could falsely
+ // detected as Sleep event. Though usbd has debouncing logic so we are good
+ CI_REG->INT_STAT = USB_ISTAT_SLEEP_MASK;
+ process_bus_sleep(rhport);
+ }
+
+#if 0 // ISTAT_RESUME never trigger, probably for host mode ?
+ if (is & USB_ISTAT_RESUME_MASK) {
+ // TU_LOG2("ISTAT Resume: "); TU_LOG2_HEX(is);
+ KHCI->ISTAT = USB_ISTAT_RESUME_MASK;
+ process_bus_resume(rhport);
+ }
+#endif
+
+ if (CI_REG->USBTRC0 & USB_USBTRC0_USB_RESUME_INT_MASK) {
+ // TU_LOG2("USBTRC0 Resume: "); TU_LOG2_HEX(is); TU_LOG2_HEX(KHCI->USBTRC0);
+ process_bus_resume(rhport);
+ }
+
+ if (is & USB_ISTAT_SOFTOK_MASK) {
+ CI_REG->INT_STAT = USB_ISTAT_SOFTOK_MASK;
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
+
+ if (is & USB_ISTAT_STALL_MASK) {
+ CI_REG->INT_STAT = USB_ISTAT_STALL_MASK;
+ process_stall(rhport);
+ }
+
+ if (is & USB_ISTAT_TOKDNE_MASK) {
+ process_tokdne(rhport);
+ }
+}
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/ci_hs_imxrt.h b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
new file mode 100644
index 000000000..c59c107ff
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
@@ -0,0 +1,101 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_HS_IMXRT_H_
+#define _CI_HS_IMXRT_H_
+
+#include "fsl_device_registers.h"
+
+#if !defined(USB1_BASE) && defined(USB_OTG1_BASE)
+#define USB1_BASE USB_OTG1_BASE
+#endif
+
+#if !defined(USB2_BASE) && defined(USB_OTG2_BASE)
+#define USB2_BASE USB_OTG2_BASE
+#endif
+
+// RT1040 calls its only USB USB_OTG (no 1)
+#if defined(MIMXRT1042_SERIES)
+#define USB_OTG1_IRQn USB_OTG_IRQn
+#endif
+
+static const ci_hs_controller_t _ci_controller[] =
+{
+ // RT1010 and RT1020 only has 1 USB controller
+ #if FSL_FEATURE_SOC_USBHS_COUNT == 1
+ { .reg_base = USB_BASE , .irqnum = USB_OTG1_IRQn }
+ #else
+ { .reg_base = USB1_BASE, .irqnum = USB_OTG1_IRQn},
+ { .reg_base = USB2_BASE, .irqnum = USB_OTG2_IRQn}
+ #endif
+};
+
+#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
+
+//------------- DCD -------------//
+#define CI_DCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_DCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+//------------- HCD -------------//
+#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+//------------- DCache -------------//
+TU_ATTR_ALWAYS_INLINE static inline bool imxrt_is_cache_mem(uintptr_t addr) {
+ return !(0x20000000 <= addr && addr < 0x20100000);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool imxrt_dcache_clean(void const* addr, uint32_t data_size) {
+ const uintptr_t addr32 = (uintptr_t) addr;
+ if (imxrt_is_cache_mem(addr32)) {
+ TU_ASSERT(tu_is_aligned32(addr32));
+ SCB_CleanDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size);
+ }
+ return true;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool imxrt_dcache_invalidate(void const* addr, uint32_t data_size) {
+ const uintptr_t addr32 = (uintptr_t) addr;
+ if (imxrt_is_cache_mem(addr32)) {
+ // Invalidating does not push cached changes back to RAM so we need to be
+ // *very* careful when we do it. If we're not aligned, then we risk resetting
+ // values back to their RAM state.
+ TU_ASSERT(tu_is_aligned32(addr32));
+ SCB_InvalidateDCache_by_Addr((void*) addr32, (int32_t) data_size);
+ }
+ return true;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool imxrt_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
+ const uintptr_t addr32 = (uintptr_t) addr;
+ if (imxrt_is_cache_mem(addr32)) {
+ TU_ASSERT(tu_is_aligned32(addr32));
+ SCB_CleanInvalidateDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size);
+ }
+ return true;
+}
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h b/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h
new file mode 100644
index 000000000..178eec419
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h
@@ -0,0 +1,56 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_HS_LPC18_43_H_
+#define _CI_HS_LPC18_43_H_
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+// LPCOpen for 18xx & 43xx
+#include "chip.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+static const ci_hs_controller_t _ci_controller[] =
+{
+ { .reg_base = LPC_USB0_BASE, .irqnum = USB0_IRQn },
+ { .reg_base = LPC_USB1_BASE, .irqnum = USB1_IRQn }
+};
+
+#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
+
+#define CI_DCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_DCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/ci_hs_mcx.h b/src/portable/chipidea/ci_hs/ci_hs_mcx.h
new file mode 100644
index 000000000..f940f4a9d
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_mcx.h
@@ -0,0 +1,52 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_HS_MCX_H_
+#define _CI_HS_MCX_H_
+
+#include "fsl_device_registers.h"
+
+// NOTE: MCX N9 has 2 different USB Controller
+// - USB0 is KHCI FullSpeed
+// - USB1 is ChipIdea HighSpeed, therefore rhport = 1 is actually index 0
+
+static const ci_hs_controller_t _ci_controller[] = {
+ {.reg_base = USBHS1__USBC_BASE, .irqnum = USB1_HS_IRQn}
+};
+
+TU_ATTR_ALWAYS_INLINE static inline ci_hs_regs_t* CI_HS_REG(uint8_t port) {
+ (void) port;
+ return ((ci_hs_regs_t*) _ci_controller[0].reg_base);
+}
+
+#define CI_DCD_INT_ENABLE(_p) do { (void) _p; NVIC_EnableIRQ (_ci_controller[0].irqnum); } while (0)
+#define CI_DCD_INT_DISABLE(_p) do { (void) _p; NVIC_DisableIRQ(_ci_controller[0].irqnum); } while (0)
+
+#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+
+#endif
diff --git a/src/portable/nxp/transdimension/common_transdimension.h b/src/portable/chipidea/ci_hs/ci_hs_type.h
index 7b94dac34..2f3aa3694 100644
--- a/src/portable/nxp/transdimension/common_transdimension.h
+++ b/src/portable/chipidea/ci_hs/ci_hs_type.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2021, Ha Thach (tinyusb.org)
@@ -24,20 +24,28 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef COMMON_TRANSDIMENSION_H_
-#define COMMON_TRANSDIMENSION_H_
+#ifndef CI_HS_TYPE_H_
+#define CI_HS_TYPE_H_
#ifdef __cplusplus
extern "C" {
#endif
+// DCCPARAMS
+enum {
+ DCCPARAMS_DEN_MASK = 0x1Fu, ///< DEN bit 4:0
+};
+
// USBCMD
enum {
USBCMD_RUN_STOP = TU_BIT(0),
USBCMD_RESET = TU_BIT(1),
USBCMD_SETUP_TRIPWIRE = TU_BIT(13),
- USBCMD_ADD_QTD_TRIPWIRE = TU_BIT(14) ///< This bit is used as a semaphore to ensure the to proper addition of a new dTD to an active (primed) endpoint’s linked list. This bit is set and cleared by software during the process of adding a new dTD
-// Interrupt Threshold bit 23:16
+ USBCMD_ADD_QTD_TRIPWIRE = TU_BIT(14), // This bit is used as a semaphore to ensure the to proper addition of a
+ // new dTD to an active (primed) endpoint’s linked list. This bit is set and
+ // cleared by software during the process of adding a new dTD
+
+ USBCMD_INTR_THRESHOLD_MASK = 0x00FF0000u, // Interrupt Threshold bit 23:16
};
// PORTSC1
@@ -72,6 +80,7 @@ enum {
// USBMode
enum {
+ USBMOD_CM_MASK = TU_BIT(0) | TU_BIT(1),
USBMODE_CM_DEVICE = 2,
USBMODE_CM_HOST = 3,
@@ -85,52 +94,59 @@ enum {
typedef struct
{
//------------- ID + HW Parameter Registers-------------//
- __I uint32_t TU_RESERVED[64]; ///< For iMX RT10xx, but not used by LPC18XX/LPC43XX
+ volatile uint32_t TU_RESERVED[64]; ///< For iMX RT10xx, but not used by LPC18XX/LPC43XX
//------------- Capability Registers-------------//
- __I uint8_t CAPLENGTH; ///< Capability Registers Length
- __I uint8_t TU_RESERVED[1];
- __I uint16_t HCIVERSION; ///< Host Controller Interface Version
+ volatile uint8_t CAPLENGTH; ///< Capability Registers Length
+ volatile uint8_t TU_RESERVED[1];
+ volatile uint16_t HCIVERSION; ///< Host Controller Interface Version
- __I uint32_t HCSPARAMS; ///< Host Controller Structural Parameters
- __I uint32_t HCCPARAMS; ///< Host Controller Capability Parameters
- __I uint32_t TU_RESERVED[5];
+ volatile uint32_t HCSPARAMS; ///< Host Controller Structural Parameters
+ volatile uint32_t HCCPARAMS; ///< Host Controller Capability Parameters
+ volatile uint32_t TU_RESERVED[5];
- __I uint16_t DCIVERSION; ///< Device Controller Interface Version
- __I uint8_t TU_RESERVED[2];
+ volatile uint16_t DCIVERSION; ///< Device Controller Interface Version
+ volatile uint8_t TU_RESERVED[2];
- __I uint32_t DCCPARAMS; ///< Device Controller Capability Parameters
- __I uint32_t TU_RESERVED[6];
+ volatile uint32_t DCCPARAMS; ///< Device Controller Capability Parameters
+ volatile uint32_t TU_RESERVED[6];
//------------- Operational Registers -------------//
- __IO uint32_t USBCMD; ///< USB Command Register
- __IO uint32_t USBSTS; ///< USB Status Register
- __IO uint32_t USBINTR; ///< Interrupt Enable Register
- __IO uint32_t FRINDEX; ///< USB Frame Index
- __I uint32_t TU_RESERVED;
- __IO uint32_t DEVICEADDR; ///< Device Address
- __IO uint32_t ENDPTLISTADDR; ///< Endpoint List Address
- __I uint32_t TU_RESERVED;
- __IO uint32_t BURSTSIZE; ///< Programmable Burst Size
- __IO uint32_t TXFILLTUNING; ///< TX FIFO Fill Tuning
- uint32_t TU_RESERVED[4];
- __IO uint32_t ENDPTNAK; ///< Endpoint NAK
- __IO uint32_t ENDPTNAKEN; ///< Endpoint NAK Enable
- __I uint32_t TU_RESERVED;
- __IO uint32_t PORTSC1; ///< Port Status & Control
- __I uint32_t TU_RESERVED[7];
- __IO uint32_t OTGSC; ///< On-The-Go Status & control
- __IO uint32_t USBMODE; ///< USB Device Mode
- __IO uint32_t ENDPTSETUPSTAT; ///< Endpoint Setup Status
- __IO uint32_t ENDPTPRIME; ///< Endpoint Prime
- __IO uint32_t ENDPTFLUSH; ///< Endpoint Flush
- __I uint32_t ENDPTSTAT; ///< Endpoint Status
- __IO uint32_t ENDPTCOMPLETE; ///< Endpoint Complete
- __IO uint32_t ENDPTCTRL[8]; ///< Endpoint Control 0 - 7
-} dcd_registers_t;
+ volatile uint32_t USBCMD; ///< USB Command Register
+ volatile uint32_t USBSTS; ///< USB Status Register
+ volatile uint32_t USBINTR; ///< Interrupt Enable Register
+ volatile uint32_t FRINDEX; ///< USB Frame Index
+ volatile uint32_t TU_RESERVED;
+ volatile uint32_t DEVICEADDR; ///< Device Address
+ volatile uint32_t ENDPTLISTADDR; ///< Endpoint List Address
+ volatile uint32_t TU_RESERVED;
+ volatile uint32_t BURSTSIZE; ///< Programmable Burst Size
+ volatile uint32_t TXFILLTUNING; ///< TX FIFO Fill Tuning
+ uint32_t TU_RESERVED[4];
+ volatile uint32_t ENDPTNAK; ///< Endpoint NAK
+ volatile uint32_t ENDPTNAKEN; ///< Endpoint NAK Enable
+ volatile uint32_t TU_RESERVED;
+ volatile uint32_t PORTSC1; ///< Port Status & Control
+ volatile uint32_t TU_RESERVED[7];
+ volatile uint32_t OTGSC; ///< On-The-Go Status & control
+ volatile uint32_t USBMODE; ///< USB Device Mode
+ volatile uint32_t ENDPTSETUPSTAT; ///< Endpoint Setup Status
+ volatile uint32_t ENDPTPRIME; ///< Endpoint Prime
+ volatile uint32_t ENDPTFLUSH; ///< Endpoint Flush
+ volatile uint32_t ENDPTSTAT; ///< Endpoint Status
+ volatile uint32_t ENDPTCOMPLETE; ///< Endpoint Complete
+ volatile uint32_t ENDPTCTRL[8]; ///< Endpoint Control 0 - 7
+} ci_hs_regs_t;
+
+
+typedef struct
+{
+ uint32_t reg_base;
+ uint32_t irqnum;
+}ci_hs_controller_t;
#ifdef __cplusplus
}
#endif
-#endif /* COMMON_TRANSDIMENSION_H_ */
+#endif /* CI_HS_TYPE_H_ */
diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
new file mode 100644
index 000000000..f9ec666e5
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
@@ -0,0 +1,686 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_CHIPIDEA_HS)
+
+#include "device/dcd.h"
+#include "ci_hs_type.h"
+
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX
+ #include "ci_hs_imxrt.h"
+
+ void dcd_dcache_clean(void const* addr, uint32_t data_size) {
+ imxrt_dcache_clean(addr, data_size);
+ }
+
+ void dcd_dcache_invalidate(void const* addr, uint32_t data_size) {
+ imxrt_dcache_invalidate(addr, data_size);
+ }
+
+ void dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
+ imxrt_dcache_clean_invalidate(addr, data_size);
+ }
+
+#else
+
+#if TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
+ #include "ci_hs_lpc18_43.h"
+
+#elif TU_CHECK_MCU(OPT_MCU_MCXN9)
+ // MCX N9 only port 1 use this controller
+ #include "ci_hs_mcx.h"
+#else
+ #error "Unsupported MCUs"
+#endif
+
+ TU_ATTR_WEAK void dcd_dcache_clean(void const* addr, uint32_t data_size) {
+ (void) addr; (void) data_size;
+ }
+
+ TU_ATTR_WEAK void dcd_dcache_invalidate(void const* addr, uint32_t data_size) {
+ (void) addr; (void) data_size;
+ }
+
+ TU_ATTR_WEAK void dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
+ (void) addr; (void) data_size;
+ }
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+// ENDPTCTRL
+enum {
+ ENDPTCTRL_STALL = TU_BIT(0),
+ ENDPTCTRL_TOGGLE_INHIBIT = TU_BIT(5), // used for test only
+ ENDPTCTRL_TOGGLE_RESET = TU_BIT(6),
+ ENDPTCTRL_ENABLE = TU_BIT(7)
+};
+
+enum {
+ ENDPTCTRL_TYPE_POS = 2, // Endpoint type is 2-bit field
+};
+
+// USBSTS, USBINTR
+enum {
+ INTR_USB = TU_BIT(0),
+ INTR_ERROR = TU_BIT(1),
+ INTR_PORT_CHANGE = TU_BIT(2),
+ INTR_RESET = TU_BIT(6),
+ INTR_SOF = TU_BIT(7),
+ INTR_SUSPEND = TU_BIT(8),
+ INTR_NAK = TU_BIT(16)
+};
+
+// Queue Transfer Descriptor
+typedef struct
+{
+ // Word 0: Next QTD Pointer
+ uint32_t next; ///< Next link pointer This field contains the physical memory address of the next dTD to be processed
+
+ // Word 1: qTQ Token
+ uint32_t : 3 ;
+ volatile uint32_t xact_err : 1 ;
+ uint32_t : 1 ;
+ volatile uint32_t buffer_err : 1 ;
+ volatile uint32_t halted : 1 ;
+ volatile uint32_t active : 1 ;
+ uint32_t : 2 ;
+ uint32_t iso_mult_override : 2 ; ///< This field can be used for transmit ISOs to override the MULT field in the dQH. This field must be zero for all packet types that are not transmit-ISO.
+ uint32_t : 3 ;
+ uint32_t int_on_complete : 1 ;
+ volatile uint32_t total_bytes : 15 ;
+ uint32_t : 1 ;
+
+ // Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page
+ uint32_t buffer[5]; ///< buffer1 has frame_n for TODO Isochronous
+
+ //--------------------------------------------------------------------+
+ // TD is 32 bytes aligned but occupies only 28 bytes
+ // Therefore there are 4 bytes padding that we can use.
+ //--------------------------------------------------------------------+
+ uint16_t expected_bytes;
+ uint8_t reserved[2];
+} dcd_qtd_t;
+
+TU_VERIFY_STATIC( sizeof(dcd_qtd_t) == 32, "size is not correct");
+
+// Queue Head
+typedef struct
+{
+ // Word 0: Capabilities and Characteristics
+ uint32_t : 15 ; ///< Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated by the USB variable length protocol where N is computed using Max_packet_length and the Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: Isochronous endpoints must set MULT = 01, 10, or 11 as needed.
+ uint32_t int_on_setup : 1 ; ///< Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is set in response to a setup being received.
+ uint32_t max_packet_size : 11 ; ///< Endpoint's wMaxPacketSize
+ uint32_t : 2 ;
+ uint32_t zero_length_termination : 1 ; ///< This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on transfers that are equal in length to a multiple Max_packet_length.
+ uint32_t iso_mult : 2 ; ///<
+
+ // Word 1: Current qTD Pointer
+ volatile uint32_t qtd_addr;
+
+ // Word 2-9: Transfer Overlay
+ volatile dcd_qtd_t qtd_overlay;
+
+ // Word 10-11: Setup request (control OUT only)
+ volatile tusb_control_request_t setup_request;
+
+ //--------------------------------------------------------------------+
+ // QHD is 64 bytes aligned but occupies only 48 bytes
+ // Therefore there are 16 bytes padding that we can use.
+ //--------------------------------------------------------------------+
+ tu_fifo_t * ff;
+ uint8_t reserved[12];
+} dcd_qhd_t;
+
+TU_VERIFY_STATIC( sizeof(dcd_qhd_t) == 64, "size is not correct");
+
+//--------------------------------------------------------------------+
+// Variables
+//--------------------------------------------------------------------+
+
+#define QTD_NEXT_INVALID 0x01
+
+typedef struct {
+ // Must be at 2K alignment
+ // Each endpoint with direction (IN/OUT) occupies a queue head
+ // for portability, TinyUSB only queue 1 TD for each Qhd
+ dcd_qhd_t qhd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64);
+ dcd_qtd_t qtd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32);
+}dcd_data_t;
+
+CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(2048)
+static dcd_data_t _dcd_data;
+
+//--------------------------------------------------------------------+
+// Prototypes and Helper Functions
+//--------------------------------------------------------------------+
+
+TU_ATTR_ALWAYS_INLINE
+static inline uint8_t ci_ep_count(ci_hs_regs_t const* dcd_reg)
+{
+ return dcd_reg->DCCPARAMS & DCCPARAMS_DEN_MASK;
+}
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+/// follows LPC43xx User Manual 23.10.3
+static void bus_reset(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ // The reset value for all endpoint types is the control endpoint. If one endpoint
+ // direction is enabled and the paired endpoint of opposite direction is disabled, then the
+ // endpoint type of the unused direction must be changed from the control type to any other
+ // type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
+ // for the data PID tracking on the active endpoint.
+ uint8_t const ep_count = ci_ep_count(dcd_reg);
+ for( uint8_t i=1; i < ep_count; i++)
+ {
+ dcd_reg->ENDPTCTRL[i] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS));
+ }
+
+ //------------- Clear All Registers -------------//
+ dcd_reg->ENDPTNAK = dcd_reg->ENDPTNAK;
+ dcd_reg->ENDPTNAKEN = 0;
+ dcd_reg->USBSTS = dcd_reg->USBSTS;
+ dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;
+ dcd_reg->ENDPTCOMPLETE = dcd_reg->ENDPTCOMPLETE;
+
+ while (dcd_reg->ENDPTPRIME) {}
+ dcd_reg->ENDPTFLUSH = 0xFFFFFFFF;
+ while (dcd_reg->ENDPTFLUSH) {}
+
+ // read reset bit in portsc
+
+ //------------- Queue Head & Queue TD -------------//
+ tu_memclr(&_dcd_data, sizeof(dcd_data_t));
+
+ //------------- Set up Control Endpoints (0 OUT, 1 IN) -------------//
+ _dcd_data.qhd[0][0].zero_length_termination = _dcd_data.qhd[0][1].zero_length_termination = 1;
+ _dcd_data.qhd[0][0].max_packet_size = _dcd_data.qhd[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
+ _dcd_data.qhd[0][0].qtd_overlay.next = _dcd_data.qhd[0][1].qtd_overlay.next = QTD_NEXT_INVALID;
+
+ _dcd_data.qhd[0][0].int_on_setup = 1; // OUT only
+
+ dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
+}
+
+void dcd_init(uint8_t rhport)
+{
+ tu_memclr(&_dcd_data, sizeof(dcd_data_t));
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ TU_ASSERT(ci_ep_count(dcd_reg) <= TUP_DCD_ENDPOINT_MAX, );
+
+ // Reset controller
+ dcd_reg->USBCMD |= USBCMD_RESET;
+ while( dcd_reg->USBCMD & USBCMD_RESET ) {}
+
+ // Set mode to device, must be set immediately after reset
+ uint32_t usbmode = dcd_reg->USBMODE & ~USBMOD_CM_MASK;
+ usbmode |= USBMODE_CM_DEVICE;
+ dcd_reg->USBMODE = usbmode;
+
+ dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION;
+
+#if !TUD_OPT_HIGH_SPEED
+ dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED;
+#endif
+
+ dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
+
+ dcd_reg->ENDPTLISTADDR = (uint32_t) _dcd_data.qhd; // Endpoint List Address has to be 2K alignment
+ dcd_reg->USBSTS = dcd_reg->USBSTS;
+ dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_SUSPEND;
+
+ uint32_t usbcmd = dcd_reg->USBCMD;
+ usbcmd &= ~USBCMD_INTR_THRESHOLD_MASK; // Interrupt Threshold Interval = 0
+ usbcmd |= USBCMD_RUN_STOP; // run
+
+ dcd_reg->USBCMD = usbcmd;
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ CI_DCD_INT_ENABLE(rhport);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ CI_DCD_INT_DISABLE(rhport);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ // Response with status first before changing device address
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->PORTSC1 |= PORTSC1_FORCE_PORT_RESUME;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->USBCMD |= USBCMD_RUN_STOP;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->USBCMD &= ~USBCMD_RUN_STOP;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+//--------------------------------------------------------------------+
+// HELPER
+//--------------------------------------------------------------------+
+
+static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes)
+{
+ // Force the CPU to flush the buffer. We increase the size by 31 because the call aligns the
+ // address to 32-byte boundaries. Buffer must be word aligned
+ dcd_dcache_clean_invalidate((uint32_t*) tu_align((uint32_t) data_ptr, 4), total_bytes + 31);
+
+ tu_memclr(p_qtd, sizeof(dcd_qtd_t));
+
+ p_qtd->next = QTD_NEXT_INVALID;
+ p_qtd->active = 1;
+ p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
+ p_qtd->int_on_complete = true;
+
+ if (data_ptr != NULL)
+ {
+ p_qtd->buffer[0] = (uint32_t) data_ptr;
+
+ uint32_t const bufend = p_qtd->buffer[0] + total_bytes;
+ for(uint8_t i=1; i<5; i++)
+ {
+ uint32_t const next_page = tu_align4k( p_qtd->buffer[i-1] ) + 4096;
+ if ( bufend <= next_page ) break;
+
+ p_qtd->buffer[i] = next_page;
+
+ // TODO page[1] FRAME_N for ISO transfer
+ }
+ }
+}
+
+//--------------------------------------------------------------------+
+// DCD Endpoint Port
+//--------------------------------------------------------------------+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0);
+
+ // flush to abort any primed buffer
+ dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ // data toggle also need to be reset
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << ( dir ? 16 : 0 );
+ dcd_reg->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << ( dir ? 16 : 0));
+}
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+{
+ uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+ uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ // Must not exceed max endpoint number
+ TU_ASSERT(epnum < ci_ep_count(dcd_reg));
+
+ //------------- Prepare Queue Head -------------//
+ dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
+ tu_memclr(p_qhd, sizeof(dcd_qhd_t));
+
+ p_qhd->zero_length_termination = 1;
+ p_qhd->max_packet_size = tu_edpt_packet_size(p_endpoint_desc);
+ if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS)
+ {
+ p_qhd->iso_mult = 1;
+ }
+
+ p_qhd->qtd_overlay.next = QTD_NEXT_INVALID;
+
+ dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
+
+ // Enable EP Control
+ uint32_t const epctrl = (p_endpoint_desc->bmAttributes.xfer << ENDPTCTRL_TYPE_POS) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET;
+
+ if ( dir == TUSB_DIR_OUT )
+ {
+ dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0xFFFF0000u) | epctrl;
+ }else
+ {
+ dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0x0000FFFFu) | (epctrl << 16);
+ }
+
+ return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ // Disable all non-control endpoints
+ uint8_t const ep_count = ci_ep_count(dcd_reg);
+ for (uint8_t epnum = 1; epnum < ep_count; epnum++)
+ {
+ _dcd_data.qhd[epnum][TUSB_DIR_OUT].qtd_overlay.halted = 1;
+ _dcd_data.qhd[epnum][TUSB_DIR_IN ].qtd_overlay.halted = 1;
+
+ dcd_reg->ENDPTFLUSH = TU_BIT(epnum) | TU_BIT(epnum+16);
+ dcd_reg->ENDPTCTRL[epnum] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS));
+ }
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ _dcd_data.qhd[epnum][dir].qtd_overlay.halted = 1;
+
+ // Flush EP
+ uint32_t const flush_mask = TU_BIT(epnum + (dir ? 16 : 0));
+ dcd_reg->ENDPTFLUSH = flush_mask;
+ while(dcd_reg->ENDPTFLUSH & flush_mask);
+
+ // Clear EP enable
+ dcd_reg->ENDPTCTRL[epnum] &=~(ENDPTCTRL_ENABLE << (dir ? 16 : 0));
+}
+
+static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
+
+ p_qhd->qtd_overlay.halted = false; // clear any previous error
+ p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd
+
+ // flush cache
+ dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
+
+ if ( epnum == 0 )
+ {
+ // follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism
+ // wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out
+ while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {}
+ }
+
+ // start transfer
+ dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0));
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
+
+ // Prepare qtd
+ qtd_init(p_qtd, buffer, total_bytes);
+
+ // Start qhd transfer
+ p_qhd->ff = NULL;
+ qhd_start_xfer(rhport, epnum, dir);
+
+ return true;
+}
+
+// fifo has to be aligned to 4k boundary
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
+
+ tu_fifo_buffer_info_t fifo_info;
+
+ if (dir)
+ {
+ tu_fifo_get_read_info(ff, &fifo_info);
+ } else
+ {
+ tu_fifo_get_write_info(ff, &fifo_info);
+ }
+
+ if ( fifo_info.len_lin >= total_bytes )
+ {
+ // Linear length is enough for this transfer
+ qtd_init(p_qtd, fifo_info.ptr_lin, total_bytes);
+ }
+ else
+ {
+ // linear part is not enough
+
+ // prepare TD up to linear length
+ qtd_init(p_qtd, fifo_info.ptr_lin, fifo_info.len_lin);
+
+ if ( !tu_offset4k((uint32_t) fifo_info.ptr_wrap) && !tu_offset4k(tu_fifo_depth(ff)) )
+ {
+ // If buffer is aligned to 4K & buffer size is multiple of 4K
+ // We can make use of buffer page array to also combine the linear + wrapped length
+ p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
+
+ for(uint8_t i = 1, page = 0; i < 5; i++)
+ {
+ // pick up buffer array where linear ends
+ if (p_qtd->buffer[i] == 0)
+ {
+ p_qtd->buffer[i] = (uint32_t) fifo_info.ptr_wrap + 4096 * page;
+ page++;
+ }
+ }
+
+ dcd_dcache_clean_invalidate((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), total_bytes - fifo_info.len_wrap + 31);
+ }
+ else
+ {
+ // TODO we may need to carry the wrapped length after the linear part complete
+ // for now only transfer up to linear part
+ }
+ }
+
+ // Start qhd transfer
+ p_qhd->ff = ff;
+ qhd_start_xfer(rhport, epnum, dir);
+
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+
+static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir)
+{
+ dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
+
+ uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED :
+ ( p_qtd->xact_err || p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS;
+
+ if ( result != XFER_RESULT_SUCCESS )
+ {
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ // flush to abort error buffer
+ dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
+ }
+
+ uint16_t const xferred_bytes = p_qtd->expected_bytes - p_qtd->total_bytes;
+
+ if (p_qhd->ff)
+ {
+ if (dir == TUSB_DIR_IN)
+ {
+ tu_fifo_advance_read_pointer(p_qhd->ff, xferred_bytes);
+ } else
+ {
+ tu_fifo_advance_write_pointer(p_qhd->ff, xferred_bytes);
+ }
+ }
+
+ // only number of bytes in the IOC qtd
+ dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), xferred_bytes, result, true);
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ uint32_t const int_enable = dcd_reg->USBINTR;
+ uint32_t const int_status = dcd_reg->USBSTS & int_enable;
+ dcd_reg->USBSTS = int_status; // Acknowledge handled interrupt
+
+ // disabled interrupt sources
+ if (int_status == 0) return;
+
+ // Set if the port controller enters the full or high-speed operational state.
+ // either from Bus Reset or Suspended state
+ if (int_status & INTR_PORT_CHANGE)
+ {
+ // TU_LOG2("PortChange %08lx\r\n", dcd_reg->PORTSC1);
+
+ // Reset interrupt is not enabled, we manually check if Port Change is due
+ // to connection / disconnection
+ if ( dcd_reg->USBSTS & INTR_RESET )
+ {
+ dcd_reg->USBSTS = INTR_RESET;
+
+ if (dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS)
+ {
+ uint32_t const speed = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS;
+ bus_reset(rhport);
+ dcd_event_bus_reset(rhport, (tusb_speed_t) speed, true);
+ }else
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+ }
+ }
+ else
+ {
+ // Triggered by resuming from suspended state
+ if ( !(dcd_reg->PORTSC1 & PORTSC1_SUSPEND) )
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+ }
+ }
+ }
+
+ if (int_status & INTR_SUSPEND)
+ {
+ // TU_LOG2("Suspend %08lx\r\n", dcd_reg->PORTSC1);
+
+ if (dcd_reg->PORTSC1 & PORTSC1_SUSPEND)
+ {
+ // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
+ // Skip suspend event if we are not addressed
+ if ((dcd_reg->DEVICEADDR >> 25) & 0x0f)
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+ }
+ }
+ }
+
+ if (int_status & INTR_USB)
+ {
+ // Make sure we read the latest version of _dcd_data.
+ dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
+
+ uint32_t const edpt_complete = dcd_reg->ENDPTCOMPLETE;
+ dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge
+
+ // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set
+ // nothing to do, we will submit xfer as error to usbd
+ // if (int_status & INTR_ERROR) { }
+
+ if ( edpt_complete )
+ {
+ for(uint8_t epnum = 0; epnum < TUP_DCD_ENDPOINT_MAX; epnum++)
+ {
+ if ( tu_bit_test(edpt_complete, epnum) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_OUT);
+ if ( tu_bit_test(edpt_complete, epnum+16) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_IN);
+ }
+ }
+
+ // Set up Received
+ // 23.10.10.2 Operational model for setup transfers
+ // Must be after normal transfer complete since it is possible to have both previous control status + new setup
+ // in the same frame and we should handle previous status first.
+ if (dcd_reg->ENDPTSETUPSTAT) {
+ dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;
+ dcd_event_setup_received(rhport, (uint8_t *) (uintptr_t) &_dcd_data.qhd[0][0].setup_request, true);
+ }
+ }
+
+ if (int_status & INTR_SOF)
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
+}
+
+#endif
diff --git a/src/portable/nxp/transdimension/hcd_transdimension.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
index db447ef23..462cbd301 100644
--- a/src/portable/nxp/transdimension/hcd_transdimension.c
+++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -26,100 +26,82 @@
#include "tusb_option.h"
-// NXP Trans-Dimension USB IP implement EHCI for host functionality
+// Chipidea Highspeed USB IP implement EHCI for host functionality
-#if TUSB_OPT_HOST_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX)
+#if CFG_TUH_ENABLED && defined(TUP_USBIP_EHCI)
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
- #include "fsl_device_registers.h"
-#else
- // LPCOpen for 18xx & 43xx
- #include "chip.h"
-#endif
-
#include "common/tusb_common.h"
-#include "common_transdimension.h"
-#include "portable/ehci/hcd_ehci.h"
+#include "host/hcd.h"
+#include "portable/ehci/ehci_api.h"
+#include "ci_hs_type.h"
-//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF
-//--------------------------------------------------------------------+
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX
+
+#include "ci_hs_imxrt.h"
+
+bool hcd_dcache_clean(void const* addr, uint32_t data_size) {
+ return imxrt_dcache_clean(addr, data_size);
+}
+
+bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) {
+ return imxrt_dcache_invalidate(addr, data_size);
+}
+
+bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
+ return imxrt_dcache_clean_invalidate(addr, data_size);
+}
-// TODO can be merged with dcd_controller_t
-typedef struct
-{
- uint32_t regs_base; // registers base
- const IRQn_Type irqnum; // IRQ number
-}hcd_controller_t;
+#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
- static const hcd_controller_t _hcd_controller[] =
- {
- // RT1010 and RT1020 only has 1 USB controller
- #if FSL_FEATURE_SOC_USBHS_COUNT == 1
- { .regs_base = USB_BASE , .irqnum = USB_OTG1_IRQn }
- #else
- { .regs_base = USB1_BASE, .irqnum = USB_OTG1_IRQn },
- { .regs_base = USB2_BASE, .irqnum = USB_OTG2_IRQn }
- #endif
- };
+#include "ci_hs_lpc18_43.h"
#else
- static const hcd_controller_t _hcd_controller[] =
- {
- { .regs_base = LPC_USB0_BASE, .irqnum = USB0_IRQn },
- { .regs_base = LPC_USB1_BASE, .irqnum = USB1_IRQn }
- };
+#error "Unsupported MCUs"
#endif
//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
-bool hcd_init(uint8_t rhport)
-{
- dcd_registers_t* dcd_reg = (dcd_registers_t*) _hcd_controller[rhport].regs_base;
+bool hcd_init(uint8_t rhport) {
+ ci_hs_regs_t *hcd_reg = CI_HS_REG(rhport);
// Reset controller
- dcd_reg->USBCMD |= USBCMD_RESET;
- while( dcd_reg->USBCMD & USBCMD_RESET ) {}
+ hcd_reg->USBCMD |= USBCMD_RESET;
+ while ( hcd_reg->USBCMD & USBCMD_RESET ) {}
// Set mode to device, must be set immediately after reset
#if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX
// LPC18XX/43XX need to set VBUS Power Select to HIGH
// RHPORT1 is fullspeed only (need external PHY for Highspeed)
- dcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT;
- if (rhport == 1) dcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
+ hcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT;
+ if ( rhport == 1 ) hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
#else
- dcd_reg->USBMODE = USBMODE_CM_HOST;
+ hcd_reg->USBMODE = USBMODE_CM_HOST;
#endif
// FIXME force full speed, still have issue with Highspeed enumeration
- dcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
+ // probably due to physical connection bouncing when plug/unplug
+ // 1. Have issue when plug/unplug devices, maybe the port is not reset properly
+ // 2. Also does not seems to detect disconnection
+ hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
- return hcd_ehci_init(rhport);
+ return ehci_init(rhport, (uint32_t) &hcd_reg->CAPLENGTH, (uint32_t) &hcd_reg->USBCMD);
}
-void hcd_int_enable(uint8_t rhport)
-{
- NVIC_EnableIRQ(_hcd_controller[rhport].irqnum);
+void hcd_int_enable(uint8_t rhport) {
+ CI_HCD_INT_ENABLE(rhport);
}
-void hcd_int_disable(uint8_t rhport)
-{
- NVIC_DisableIRQ(_hcd_controller[rhport].irqnum);
-}
-
-uint32_t hcd_ehci_register_addr(uint8_t rhport)
-{
- dcd_registers_t* hcd_reg = (dcd_registers_t*) _hcd_controller[rhport].regs_base;
-
- // EHCI USBCMD has same address within dcd_register_t
- return (uint32_t) &hcd_reg->USBCMD;
+void hcd_int_disable(uint8_t rhport) {
+ CI_HCD_INT_DISABLE(rhport);
}
#endif
diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c
index 59f728d08..d1e85c2df 100644
--- a/src/portable/dialog/da146xx/dcd_da146xx.c
+++ b/src/portable/dialog/da146xx/dcd_da146xx.c
@@ -26,9 +26,9 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_DA1469X
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_DA1469X
-#include "DA1469xAB.h"
+#include "mcu/mcu.h"
#include "device/dcd.h"
@@ -60,10 +60,17 @@
#define EP_MAX 4
+// Node functional states
#define NFSR_NODE_RESET 0
#define NFSR_NODE_RESUME 1
#define NFSR_NODE_OPERATIONAL 2
#define NFSR_NODE_SUSPEND 3
+// Those two following states are added to allow going out of sleep mode
+// using frame interrupt. On remove wakeup RESUME state must be kept for
+// at least 1ms. It is accomplished by using FRAME interrupt that goes
+// through those two fake states before entering OPERATIONAL state.
+#define NFSR_NODE_WAKING (0x10 | (NFSR_NODE_RESUME))
+#define NFSR_NODE_WAKING2 (0x20 | (NFSR_NODE_RESUME))
static TU_ATTR_ALIGNED(4) uint8_t _setup_packet[8];
@@ -133,7 +140,7 @@ typedef struct
__IOM uint32_t USB_RXC2_REG; /*!< (@ 0x000000DC) Receive Command Register 2 */
__IOM uint32_t USB_RXC3_REG; /*!< (@ 0x000000FC) Receive Command Register 3 */
};
-} EPx_REGS;
+} volatile EPx_REGS;
#define EP_REGS(first_ep_reg) (EPx_REGS*)(&USB->first_ep_reg)
@@ -193,8 +200,14 @@ typedef struct
#define REG_CLR_BIT(reg, field) USB->reg &= ~USB_ ## reg ## _ ## field ## _Msk
#define REG_SET_VAL(reg, field, val) USB->reg = (USB->reg & ~USB_ ## reg ## _ ## field ## _Msk) | (val << USB_ ## reg ## _ ## field ## _Pos)
+static EPx_REGS * const ep_regs[EP_MAX] = {
+ EP_REGS(USB_EPC0_REG),
+ EP_REGS(USB_EPC1_REG),
+ EP_REGS(USB_EPC3_REG),
+ EP_REGS(USB_EPC5_REG),
+};
+
typedef struct {
- EPx_REGS * regs;
uint8_t * buffer;
// Total length of current transfer
uint16_t total_len;
@@ -217,22 +230,24 @@ typedef struct {
static struct
{
bool vbus_present;
- bool in_reset;
+ bool init_called;
+ uint8_t nfsr;
xfer_ctl_t xfer_status[EP_MAX][2];
// Endpoints that use DMA, one for each direction
uint8_t dma_ep[2];
} _dcd =
{
.vbus_present = false,
- .xfer_status =
- {
- { { .regs = EP_REGS(USB_EPC0_REG) }, { .regs = EP_REGS(USB_EPC0_REG) } },
- { { .regs = EP_REGS(USB_EPC1_REG) }, { .regs = EP_REGS(USB_EPC1_REG) } },
- { { .regs = EP_REGS(USB_EPC3_REG) }, { .regs = EP_REGS(USB_EPC3_REG) } },
- { { .regs = EP_REGS(USB_EPC5_REG) }, { .regs = EP_REGS(USB_EPC5_REG) } },
- }
+ .init_called = false,
};
+// Converts xfer pointer to epnum (0,1,2,3) regardless of xfer direction
+#define XFER_EPNUM(xfer) ((xfer - &_dcd.xfer_status[0][0]) >> 1)
+// Converts xfer pointer to EPx_REGS pointer (returns same pointer for IN and OUT with same endpoint number)
+#define XFER_REGS(xfer) ep_regs[XFER_EPNUM(xfer)]
+// Converts epnum (0,1,2,3) to EPx_REGS pointer
+#define EPNUM_REGS(epnum) ep_regs[epnum]
+
// Two endpoint 0 descriptor definition for unified dcd_edpt_open()
static const tusb_desc_endpoint_t ep0OUT_desc =
{
@@ -241,7 +256,7 @@ static const tusb_desc_endpoint_t ep0OUT_desc =
.bEndpointAddress = 0x00,
.bmAttributes = { .xfer = TUSB_XFER_CONTROL },
- .wMaxPacketSize = { .size = CFG_TUD_ENDPOINT0_SIZE },
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
.bInterval = 0
};
@@ -252,45 +267,27 @@ static const tusb_desc_endpoint_t ep0IN_desc =
.bEndpointAddress = 0x80,
.bmAttributes = { .xfer = TUSB_XFER_CONTROL },
- .wMaxPacketSize = { .size = CFG_TUD_ENDPOINT0_SIZE },
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
.bInterval = 0
};
#define XFER_CTL_BASE(_ep, _dir) &_dcd.xfer_status[_ep][_dir]
-// Function could be called when VBUS change was detected.
-void tusb_vbus_changed(bool present)
+static void set_nfsr(uint8_t val)
{
- if (present != _dcd.vbus_present)
- {
- _dcd.vbus_present = present;
- if (present)
- {
- USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk;
- USB->USB_NFSR_REG = 0;
- USB->USB_FAR_REG = 0x80;
- USB->USB_NFSR_REG = NFSR_NODE_RESET;
- USB->USB_TXMSK_REG = 0;
- USB->USB_RXMSK_REG = 0;
-
- USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk |
- USB_USB_MAMSK_REG_USB_M_ALT_Msk |
- USB_USB_MAMSK_REG_USB_M_WARN_Msk;
- USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk;
- }
- else
- {
- USB->USB_MCTRL_REG = 0;
- }
- }
+ _dcd.nfsr = val;
+ // Write only lower 2 bits to register, higher bits are used
+ // to count down till OPERATIONAL state can be entered when
+ // remote wakeup activated.
+ USB->USB_NFSR_REG = val & 3;
}
static void fill_tx_fifo(xfer_ctl_t * xfer)
{
int left_to_send;
uint8_t const *src;
- EPx_REGS *regs = xfer->regs;
uint8_t const epnum = tu_edpt_number(xfer->ep_addr);
+ EPx_REGS *regs = EPNUM_REGS(epnum);
src = &xfer->buffer[xfer->transferred];
left_to_send = xfer->total_len - xfer->transferred;
@@ -318,7 +315,7 @@ static void fill_tx_fifo(xfer_ctl_t * xfer)
}
else
{
- xfer->regs->txc &= ~USB_USB_TXC1_REG_USB_TFWL_Msk;
+ regs->txc &= ~USB_USB_TXC1_REG_USB_TFWL_Msk;
USB->USB_FWMSK_REG &= ~(1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_TXWARN31_Pos));
// Whole packet already in fifo, no need to refill it later. Mark last.
regs->txc |= USB_USB_TXC1_REG_USB_LAST_Msk;
@@ -359,30 +356,31 @@ static void start_rx_packet(xfer_ctl_t *xfer)
uint8_t const epnum = tu_edpt_number(xfer->ep_addr);
uint16_t remaining = xfer->total_len - xfer->transferred;
uint16_t size = tu_min16(remaining, xfer->max_packet_size);
+ EPx_REGS *regs = XFER_REGS(xfer);
xfer->last_packet_size = 0;
if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE)
{
if (try_allocate_dma(epnum, TUSB_DIR_OUT))
{
- start_rx_dma(&xfer->regs->rxd, xfer->buffer + xfer->transferred, size);
+ start_rx_dma(&regs->rxd, xfer->buffer + xfer->transferred, size);
}
else
{
// Other endpoint is using DMA in that direction, fall back to interrupts.
- // For endpoint size greater then FIFO size enable FIFO level warning interrupt
- // when FIFO has less then 17 bytes free.
- xfer->regs->rxc |= USB_USB_RXC1_REG_USB_RFWL_Msk;
+ // For endpoint size greater than FIFO size enable FIFO level warning interrupt
+ // when FIFO has less than 17 bytes free.
+ regs->rxc |= USB_USB_RXC1_REG_USB_RFWL_Msk;
USB->USB_FWMSK_REG |= 1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_RXWARN31_Pos);
}
}
else if (epnum != 0)
{
// If max_packet_size would fit in FIFO no need for FIFO level warning interrupt.
- xfer->regs->rxc &= ~USB_USB_RXC1_REG_USB_RFWL_Msk;
+ regs->rxc &= ~USB_USB_RXC1_REG_USB_RFWL_Msk;
USB->USB_FWMSK_REG &= ~(1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_RXWARN31_Pos));
}
- xfer->regs->rxc |= USB_USB_RXC1_REG_USB_RX_EN_Msk;
+ regs->rxc |= USB_USB_RXC1_REG_USB_RX_EN_Msk;
}
static void start_tx_dma(void *src, volatile void *dst, uint16_t size)
@@ -401,13 +399,13 @@ static void start_tx_packet(xfer_ctl_t *xfer)
uint8_t const epnum = tu_edpt_number(xfer->ep_addr);
uint16_t remaining = xfer->total_len - xfer->transferred;
uint16_t size = tu_min16(remaining, xfer->max_packet_size);
- EPx_REGS *regs = xfer->regs;
+ EPx_REGS *regs = EPNUM_REGS(epnum);
xfer->last_packet_size = 0;
regs->txc = USB_USB_TXC1_REG_USB_FLUSH_Msk;
regs->txc = USB_USB_TXC1_REG_USB_IGN_ISOMSK_Msk;
- if (xfer->data1) xfer->regs->txc |= USB_USB_TXC1_REG_USB_TOGGLE_TX_Msk;
+ if (xfer->data1) regs->txc |= USB_USB_TXC1_REG_USB_TOGGLE_TX_Msk;
if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE && try_allocate_dma(epnum, TUSB_DIR_IN))
{
@@ -422,9 +420,9 @@ static void start_tx_packet(xfer_ctl_t *xfer)
regs->txc |= USB_USB_TXC1_REG_USB_TX_EN_Msk;
}
-static void read_rx_fifo(xfer_ctl_t *xfer, uint16_t bytes_in_fifo)
+static uint16_t read_rx_fifo(xfer_ctl_t *xfer, uint16_t bytes_in_fifo)
{
- EPx_REGS *regs = xfer->regs;
+ EPx_REGS *regs = XFER_REGS(xfer);
uint16_t remaining = xfer->total_len - xfer->transferred - xfer->last_packet_size;
uint16_t receive_this_time = bytes_in_fifo;
@@ -435,6 +433,8 @@ static void read_rx_fifo(xfer_ctl_t *xfer, uint16_t bytes_in_fifo)
for (int i = 0; i < receive_this_time; ++i) buf[i] = regs->rxd;
xfer->last_packet_size += receive_this_time;
+
+ return bytes_in_fifo - receive_this_time;
}
static void handle_ep0_rx(void)
@@ -494,7 +494,7 @@ static void handle_ep0_tx(void)
{
uint32_t txs0;
xfer_ctl_t *xfer = XFER_CTL_BASE(0, TUSB_DIR_IN);
- EPx_REGS *regs = xfer->regs;
+ EPx_REGS *regs = XFER_REGS(xfer);
txs0 = regs->USB_TXS0_REG;
@@ -528,7 +528,7 @@ static void handle_epx_rx_ev(uint8_t ep)
int fifo_bytes;
xfer_ctl_t *xfer = XFER_CTL_BASE(ep, TUSB_DIR_OUT);
- EPx_REGS *regs = xfer->regs;
+ EPx_REGS *regs = EPNUM_REGS(ep);
do
{
@@ -564,7 +564,7 @@ static void handle_epx_rx_ev(uint8_t ep)
// FIFO maybe empty if DMA read it before or it's final iteration and function already read all that was to read.
if (fifo_bytes > 0)
{
- read_rx_fifo(xfer, fifo_bytes);
+ fifo_bytes = read_rx_fifo(xfer, fifo_bytes);
}
if (GET_BIT(rxs, USB_USB_RXS1_REG_USB_RX_LAST))
{
@@ -579,6 +579,13 @@ static void handle_epx_rx_ev(uint8_t ep)
xfer->transferred += xfer->last_packet_size;
if (xfer->total_len == xfer->transferred || xfer->last_packet_size < xfer->max_packet_size || xfer->iso)
{
+ if (fifo_bytes)
+ {
+ // There are extra bytes in the FIFO just flush them
+ regs->rxc |= USB_USB_RXC1_REG_USB_FLUSH_Msk;
+ fifo_bytes = 0;
+ }
+
dcd_event_xfer_complete(0, xfer->ep_addr, xfer->transferred, XFER_RESULT_SUCCESS, true);
}
else
@@ -607,7 +614,7 @@ static void handle_epx_tx_ev(xfer_ctl_t *xfer)
{
uint8_t const epnum = tu_edpt_number(xfer->ep_addr);
uint32_t txs;
- EPx_REGS *regs = xfer->regs;
+ EPx_REGS *regs = EPNUM_REGS(epnum);
txs = regs->txs;
@@ -634,10 +641,17 @@ static void handle_epx_tx_ev(xfer_ctl_t *xfer)
return;
}
}
+ else if (regs->epc_in & USB_USB_EPC1_REG_USB_STALL_Msk)
+ {
+ // TX_DONE also indicates that STALL packet was just sent, there is
+ // no point to put anything into transmit FIFO. It could result in
+ // empty packet being scheduled.
+ return;
+ }
}
if (txs & USB_USB_TXS1_REG_USB_TX_URUN_Msk)
{
- TU_LOG1("EP %d FIFO underrun\n", epnum);
+ TU_LOG1("EP %d FIFO underrun\r\n", epnum);
}
// Start next or repeated packet.
start_tx_packet(xfer);
@@ -653,60 +667,90 @@ static void handle_tx_ev(void)
handle_epx_tx_ev(XFER_CTL_BASE(3, TUSB_DIR_IN));
}
+static uint32_t check_reset_end(uint32_t alt_ev)
+{
+ if (_dcd.nfsr == NFSR_NODE_RESET)
+ {
+ if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_RESET))
+ {
+ // Could be still in reset, but since USB_M_RESET is disabled it can
+ // be also old reset state that was not cleared yet.
+ // If (after reading USB_ALTEV_REG register again) bit is cleared
+ // reset state just ended.
+ // Keep non-reset bits combined from two previous ALTEV read and
+ // one from the next line.
+ alt_ev = (alt_ev & ~USB_USB_ALTEV_REG_USB_RESET_Msk) | USB->USB_ALTEV_REG;
+ }
+ if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_RESET) == 0)
+ {
+ USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
+ USB_USB_ALTEV_REG_USB_SD3_Msk;
+ set_nfsr(NFSR_NODE_OPERATIONAL);
+ dcd_edpt_open(0, &ep0OUT_desc);
+ dcd_edpt_open(0, &ep0IN_desc);
+ }
+ }
+ return alt_ev;
+}
+
static void handle_bus_reset(void)
{
+ uint32_t alt_ev;
+
USB->USB_NFSR_REG = 0;
USB->USB_FAR_REG = 0x80;
USB->USB_ALTMSK_REG = 0;
USB->USB_NFSR_REG = NFSR_NODE_RESET;
USB->USB_TXMSK_REG = 0;
USB->USB_RXMSK_REG = 0;
- (void)USB->USB_ALTEV_REG;
- _dcd.in_reset = true;
+ set_nfsr(NFSR_NODE_RESET);
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
USB->USB_DMA_CTRL_REG = 0;
USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk |
-#if USE_SOF
USB_USB_MAMSK_REG_USB_M_FRAME_Msk |
-#endif
USB_USB_MAMSK_REG_USB_M_WARN_Msk |
USB_USB_MAMSK_REG_USB_M_ALT_Msk;
- USB->USB_NFSR_REG = NFSR_NODE_OPERATIONAL;
- USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_SD3_Msk |
- USB_USB_ALTMSK_REG_USB_M_RESUME_Msk;
- // There is no information about end of reset state
- // USB_FRAME event will be used to enable reset detection again
- REG_SET_BIT(USB_MAEV_REG, USB_FRAME);
- dcd_edpt_open (0, &ep0OUT_desc);
- dcd_edpt_open (0, &ep0IN_desc);
+ USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESUME_Msk;
+ alt_ev = USB->USB_ALTEV_REG;
+ check_reset_end(alt_ev);
}
static void handle_alt_ev(void)
{
uint32_t alt_ev = USB->USB_ALTEV_REG;
- if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_RESET))
+ alt_ev = check_reset_end(alt_ev);
+ if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_RESET) && _dcd.nfsr != NFSR_NODE_RESET)
{
handle_bus_reset();
}
- else
+ else if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_RESUME))
{
- if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_RESUME))
+ if (USB->USB_NFSR_REG == NFSR_NODE_SUSPEND)
{
- USB->USB_NFSR_REG = NFSR_NODE_OPERATIONAL;
- USB->USB_ALTMSK_REG &= ~USB_USB_ALTMSK_REG_USB_M_RESUME_Msk;
- USB->USB_ALTMSK_REG |= USB_USB_ALTMSK_REG_USB_M_SD3_Msk;
+ set_nfsr(NFSR_NODE_OPERATIONAL);
+ USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
+ USB_USB_ALTMSK_REG_USB_M_SD3_Msk;
+ // Re-enable reception of endpoint with pending transfer
+ for (int epnum = 1; epnum <= 3; ++epnum)
+ {
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
+ if (xfer->total_len > xfer->transferred)
+ {
+ start_rx_packet(xfer);
+ }
+ }
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
}
- if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_SD3))
- {
- USB->USB_NFSR_REG = NFSR_NODE_SUSPEND;
- USB->USB_ALTMSK_REG |= USB_USB_ALTMSK_REG_USB_M_RESUME_Msk;
- USB->USB_ALTMSK_REG &= ~USB_USB_ALTMSK_REG_USB_M_SD3_Msk | USB_USB_ALTMSK_REG_USB_M_SD5_Msk;
- dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
- }
+ }
+ else if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_SD3))
+ {
+ set_nfsr(NFSR_NODE_SUSPEND);
+ USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
+ USB_USB_ALTMSK_REG_USB_M_RESUME_Msk;
+ dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
}
}
@@ -762,10 +806,13 @@ static void handle_ep0_nak(void)
*------------------------------------------------------------------*/
void dcd_init(uint8_t rhport)
{
- USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk;
- tusb_vbus_changed((CRG_TOP->ANA_STATUS_REG & CRG_TOP_ANA_STATUS_REG_VBUS_AVAILABLE_Msk) != 0);
+ (void) rhport;
- dcd_connect(rhport);
+ _dcd.init_called = true;
+ if (_dcd.vbus_present)
+ {
+ dcd_connect(rhport);
+ }
}
void dcd_int_enable(uint8_t rhport)
@@ -795,16 +842,37 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
void dcd_remote_wakeup(uint8_t rhport)
{
(void)rhport;
+ if (_dcd.nfsr == NFSR_NODE_SUSPEND)
+ {
+ // Enter fake state that will use FRAME interrupt to wait before going operational.
+ set_nfsr(NFSR_NODE_WAKING);
+ USB->USB_MAMSK_REG |= USB_USB_MAMSK_REG_USB_M_FRAME_Msk;
+ }
}
void dcd_connect(uint8_t rhport)
{
(void)rhport;
- REG_SET_BIT(USB_MCTRL_REG, USB_NAT);
+ if (GET_BIT(USB->USB_MCTRL_REG, USB_USB_MCTRL_REG_USB_NAT) == 0)
+ {
+ USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk;
+ USB->USB_NFSR_REG = 0;
+ USB->USB_FAR_REG = 0x80;
+ USB->USB_TXMSK_REG = 0;
+ USB->USB_RXMSK_REG = 0;
+
+ USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk |
+ USB_USB_MAMSK_REG_USB_M_ALT_Msk |
+ USB_USB_MAMSK_REG_USB_M_WARN_Msk;
+ USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
+ USB_USB_ALTEV_REG_USB_SD3_Msk;
+
+ USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk | USB_USB_MCTRL_REG_USB_NAT_Msk;
- // Select chosen DMA to be triggered by USB.
- DMA->DMA_REQ_MUX_REG = (DMA->DMA_REQ_MUX_REG & ~DA146XX_DMA_USB_MUX_MASK) | DA146XX_DMA_USB_MUX;
+ // Select chosen DMA to be triggered by USB.
+ DMA->DMA_REQ_MUX_REG = (DMA->DMA_REQ_MUX_REG & ~DA146XX_DMA_USB_MUX_MASK) | DA146XX_DMA_USB_MUX;
+ }
}
void dcd_disconnect(uint8_t rhport)
@@ -814,6 +882,38 @@ void dcd_disconnect(uint8_t rhport)
REG_CLR_BIT(USB_MCTRL_REG, USB_NAT);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
+{
+ return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
+}
+
+void tusb_vbus_changed(bool present)
+{
+ if (present && !_dcd.vbus_present)
+ {
+ _dcd.vbus_present = true;
+ // If power event happened before USB started, delay dcd_connect
+ // until dcd_init is called.
+ if (_dcd.init_called)
+ {
+ dcd_connect(0);
+ }
+ }
+ else if (!present && _dcd.vbus_present)
+ {
+ _dcd.vbus_present = false;
+ USB->USB_MCTRL_REG = 0;
+ dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, is_in_isr());
+ }
+}
/*------------------------------------------------------------------*/
/* DCD Endpoint port
@@ -826,11 +926,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+ EPx_REGS *regs = EPNUM_REGS(epnum);
uint8_t iso_mask = 0;
TU_ASSERT(epnum < EP_MAX);
- xfer->max_packet_size = desc_edpt->wMaxPacketSize.size;
+ xfer->max_packet_size = tu_edpt_packet_size(desc_edpt);
xfer->ep_addr = desc_edpt->bEndpointAddress;
xfer->data1 = 0;
xfer->iso = 0;
@@ -850,14 +951,14 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
{
if (dir == TUSB_DIR_OUT)
{
- xfer->regs->epc_out = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
- USB->USB_RXMSK_REG |= 0x101 << (epnum - 1);
+ regs->epc_out = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
+ USB->USB_RXMSK_REG |= 0x11 << (epnum - 1);
REG_SET_BIT(USB_MAMSK_REG, USB_M_RX_EV);
}
else
{
- xfer->regs->epc_in = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
- USB->USB_TXMSK_REG |= 0x101 << (epnum - 1);
+ regs->epc_in = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
+ USB->USB_TXMSK_REG |= 0x11 << (epnum - 1);
REG_SET_BIT(USB_MAMSK_REG, USB_M_TX_EV);
}
}
@@ -865,10 +966,22 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+
+ for (int epnum = 1; epnum < EP_MAX; ++epnum)
+ {
+ dcd_edpt_close(0, epnum | TUSB_DIR_OUT);
+ dcd_edpt_close(0, epnum | TUSB_DIR_IN);
+ }
+}
+
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
+ EPx_REGS *regs = EPNUM_REGS(epnum);
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
(void)rhport;
@@ -884,9 +997,9 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
if (dir == TUSB_DIR_OUT)
{
- xfer->regs->rxc = USB_USB_RXC1_REG_USB_FLUSH_Msk;
- xfer->regs->epc_out = 0;
- USB->USB_RXMSK_REG &= ~(0x101 << (epnum - 1));
+ regs->rxc = USB_USB_RXC1_REG_USB_FLUSH_Msk;
+ regs->epc_out = 0;
+ USB->USB_RXMSK_REG &= ~(0x11 << (epnum - 1));
// Release DMA if needed
if (_dcd.dma_ep[TUSB_DIR_OUT] == epnum)
{
@@ -896,9 +1009,9 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
}
else
{
- xfer->regs->txc = USB_USB_TXC1_REG_USB_FLUSH_Msk;
- xfer->regs->epc_in = 0;
- USB->USB_TXMSK_REG &= ~(0x101 << (epnum - 1));
+ regs->txc = USB_USB_TXC1_REG_USB_FLUSH_Msk;
+ regs->epc_in = 0;
+ USB->USB_TXMSK_REG &= ~(0x11 << (epnum - 1));
// Release DMA if needed
if (_dcd.dma_ep[TUSB_DIR_IN] == epnum)
{
@@ -907,6 +1020,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
}
}
}
+ tu_memclr(xfer, sizeof(*xfer));
}
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
@@ -942,6 +1056,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
(void)rhport;
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+ EPx_REGS *regs = EPNUM_REGS(epnum);
xfer->stall = 1;
if (epnum == 0)
@@ -950,11 +1065,11 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
REG_SET_BIT(USB_EPC0_REG, USB_STALL);
if (dir == TUSB_DIR_OUT)
{
- xfer->regs->USB_RXC0_REG = USB_USB_RXC0_REG_USB_RX_EN_Msk;
+ regs->USB_RXC0_REG = USB_USB_RXC0_REG_USB_RX_EN_Msk;
}
else
{
- if (xfer->regs->USB_RXC0_REG & USB_USB_RXC0_REG_USB_RX_EN_Msk)
+ if (regs->USB_RXC0_REG & USB_USB_RXC0_REG_USB_RX_EN_Msk)
{
// If RX is also enabled TX will not be stalled since RX has
// higher priority. Enable NAK interrupt to handle stall.
@@ -962,7 +1077,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
}
else
{
- xfer->regs->USB_TXC0_REG |= USB_USB_TXC0_REG_USB_TX_EN_Msk;
+ regs->USB_TXC0_REG |= USB_USB_TXC0_REG_USB_TX_EN_Msk;
}
}
}
@@ -970,13 +1085,13 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
if (dir == TUSB_DIR_OUT)
{
- xfer->regs->epc_out |= USB_USB_EPC1_REG_USB_STALL_Msk;
- xfer->regs->rxc |= USB_USB_RXC1_REG_USB_RX_EN_Msk;
+ regs->epc_out |= USB_USB_EPC1_REG_USB_STALL_Msk;
+ regs->rxc |= USB_USB_RXC1_REG_USB_RX_EN_Msk;
}
else
{
- xfer->regs->epc_in |= USB_USB_EPC1_REG_USB_STALL_Msk;
- xfer->regs->txc |= USB_USB_TXC1_REG_USB_TX_EN_Msk | USB_USB_TXC1_REG_USB_LAST_Msk;
+ regs->epc_in |= USB_USB_EPC1_REG_USB_STALL_Msk;
+ regs->txc |= USB_USB_TXC1_REG_USB_TX_EN_Msk | USB_USB_TXC1_REG_USB_LAST_Msk;
}
}
}
@@ -989,6 +1104,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
(void)rhport;
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+ EPx_REGS *regs = EPNUM_REGS(epnum);
// Clear stall is called in response to Clear Feature ENDPOINT_HALT, reset toggle
xfer->data1 = 0;
@@ -996,11 +1112,11 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
if (dir == TUSB_DIR_OUT)
{
- xfer->regs->epc_out &= ~USB_USB_EPC1_REG_USB_STALL_Msk;
+ regs->epc_out &= ~USB_USB_EPC1_REG_USB_STALL_Msk;
}
else
{
- xfer->regs->epc_in &= ~USB_USB_EPC1_REG_USB_STALL_Msk;
+ regs->epc_in &= ~USB_USB_EPC1_REG_USB_STALL_Msk;
}
if (epnum == 0)
{
@@ -1014,7 +1130,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
void dcd_int_handler(uint8_t rhport)
{
- uint32_t int_status = USB->USB_MAEV_REG;
+ uint32_t int_status = USB->USB_MAEV_REG & USB->USB_MAMSK_REG;
(void)rhport;
@@ -1056,19 +1172,38 @@ void dcd_int_handler(uint8_t rhport)
if (GET_BIT(int_status, USB_USB_MAEV_REG_USB_FRAME))
{
- if (_dcd.in_reset)
+ if (_dcd.nfsr == NFSR_NODE_RESET)
{
- // Enable reset detection
- _dcd.in_reset = false;
- (void)USB->USB_ALTEV_REG;
+ // During reset FRAME interrupt is enabled to periodically
+ // check when reset state ends.
+ // FRAME interrupt is generated every 1ms without host sending
+ // actual SOF.
+ check_reset_end(USB_USB_ALTEV_REG_USB_RESET_Msk);
}
+ else if (_dcd.nfsr == NFSR_NODE_WAKING)
+ {
+ // No need to call set_nfsr, just set state
+ _dcd.nfsr = NFSR_NODE_WAKING2;
+ }
+ else if (_dcd.nfsr == NFSR_NODE_WAKING2)
+ {
+ // No need to call set_nfsr, just set state
+ _dcd.nfsr = NFSR_NODE_RESUME;
+ }
+ else if (_dcd.nfsr == NFSR_NODE_RESUME)
+ {
+ set_nfsr(NFSR_NODE_OPERATIONAL);
+ }
+ else
+ {
#if USE_SOF
- dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+ dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
#else
- // SOF was used to re-enable reset detection
- // No need to keep it enabled
- USB->USB_MAMSK_REG &= ~USB_USB_MAMSK_REG_USB_M_FRAME_Msk;
+ // FRAME interrupt was used to re-enable reset detection or remote
+ // wakeup no need to keep it enabled when USE_SOF is off.
+ USB->USB_MAMSK_REG &= ~USB_USB_MAMSK_REG_USB_M_FRAME_Msk;
#endif
+ }
}
if (GET_BIT(int_status, USB_USB_MAEV_REG_USB_TX_EV))
diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c
index bcba360bb..01bbf62bf 100644
--- a/src/portable/ehci/ehci.c
+++ b/src/portable/ehci/ehci.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -24,11 +24,9 @@
* This file is part of the TinyUSB stack.
*/
-#include "common/tusb_common.h"
+#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || \
- CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX )
+#if CFG_TUH_ENABLED && defined(TUP_USBIP_EHCI)
//--------------------------------------------------------------------+
// INCLUDE
@@ -36,89 +34,143 @@
#include "osal/osal.h"
#include "host/hcd.h"
-#include "host/usbh_hcd.h"
-#include "hcd_ehci.h"
+#include "ehci_api.h"
#include "ehci.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
+// Debug level of EHCI
+#define EHCI_DBG 2
+
+// Framelist size as small as possible to save SRAM
+#ifdef TUP_USBIP_CHIPIDEA_HS
+ // NXP Transdimension: 8 elements
+ #define FRAMELIST_SIZE_BIT_VALUE 7u
+ #define FRAMELIST_SIZE_USBCMD_VALUE (((FRAMELIST_SIZE_BIT_VALUE & 3) << EHCI_USBCMD_FRAMELIST_SIZE_SHIFT) | \
+ ((FRAMELIST_SIZE_BIT_VALUE >> 2) << EHCI_USBCMD_CHIPIDEA_FRAMELIST_SIZE_MSB_SHIFT))
+#else
+ // STD EHCI: 256 elements
+ #define FRAMELIST_SIZE_BIT_VALUE 2u
+ #define FRAMELIST_SIZE_USBCMD_VALUE ((FRAMELIST_SIZE_BIT_VALUE & 3) << EHCI_USBCMD_POS_FRAMELIST_SIZE)
+#endif
+
+#define FRAMELIST_SIZE (1024 >> FRAMELIST_SIZE_BIT_VALUE)
+
+// Total queue head pool. TODO should be user configurable and more optimize memory usage in the future
+#define QHD_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX + CFG_TUH_HUB)
+#define QTD_MAX QHD_MAX
+
typedef struct
{
- ehci_link_t period_framelist[EHCI_FRAMELIST_SIZE];
+ ehci_link_t period_framelist[FRAMELIST_SIZE];
- // for NXP ECHI, only implement 1 ms & 2 ms & 4 ms, 8 ms (framelist)
+ // TODO only implement 1 ms & 2 ms & 4 ms, 8 ms (framelist)
// [0] : 1ms, [1] : 2ms, [2] : 4ms, [3] : 8 ms
+ // TODO better implementation without dummy head to save SRAM
ehci_qhd_t period_head_arr[4];
// Note control qhd of dev0 is used as head of async list
struct {
ehci_qhd_t qhd;
ehci_qtd_t qtd;
- }control[CFG_TUSB_HOST_DEVICE_MAX+1];
+ }control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
- ehci_qhd_t qhd_pool[HCD_MAX_ENDPOINT];
- ehci_qtd_t qtd_pool[HCD_MAX_XFER] TU_ATTR_ALIGNED(32);
+ ehci_qhd_t qhd_pool[QHD_MAX];
+ ehci_qtd_t qtd_pool[QTD_MAX] TU_ATTR_ALIGNED(32);
- ehci_registers_t* regs;
+ ehci_registers_t* regs; // operational register
+ ehci_cap_registers_t* cap_regs; // capability register
volatile uint32_t uframe_number;
}ehci_data_t;
-//--------------------------------------------------------------------+
-// INTERNAL OBJECT & FUNCTION DECLARATION
-//--------------------------------------------------------------------+
+
// Periodic frame list must be 4K alignment
-CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4096) static ehci_data_t ehci_data;
+CFG_TUH_MEM_SECTION TU_ATTR_ALIGNED(4096) static ehci_data_t ehci_data;
//--------------------------------------------------------------------+
-// PROTOTYPE
+// Debug
//--------------------------------------------------------------------+
-static inline ehci_link_t* get_period_head(uint8_t rhport, uint8_t interval_ms)
-{
- (void) rhport;
- return (ehci_link_t*) &ehci_data.period_head_arr[ tu_log2( tu_min8(EHCI_FRAMELIST_SIZE, interval_ms) ) ];
-}
+#if 0 && CFG_TUSB_DEBUG >= (EHCI_DBG + 1)
+static inline void print_portsc(ehci_registers_t* regs) {
+ TU_LOG_HEX(EHCI_DBG, regs->portsc);
+ TU_LOG(EHCI_DBG, " Connect Status : %u\r\n", regs->portsc_bm.current_connect_status);
+ TU_LOG(EHCI_DBG, " Connect Change : %u\r\n", regs->portsc_bm.connect_status_change);
+ TU_LOG(EHCI_DBG, " Enabled : %u\r\n", regs->portsc_bm.port_enabled);
+ TU_LOG(EHCI_DBG, " Enabled Change : %u\r\n", regs->portsc_bm.port_enable_change);
-static inline ehci_qhd_t* qhd_control(uint8_t dev_addr)
-{
- return &ehci_data.control[dev_addr].qhd;
+ TU_LOG(EHCI_DBG, " OverCurr Change: %u\r\n", regs->portsc_bm.over_current_change);
+ TU_LOG(EHCI_DBG, " Force Resume : %u\r\n", regs->portsc_bm.force_port_resume);
+ TU_LOG(EHCI_DBG, " Suspend : %u\r\n", regs->portsc_bm.suspend);
+ TU_LOG(EHCI_DBG, " Reset : %u\r\n", regs->portsc_bm.port_reset);
+ TU_LOG(EHCI_DBG, " Power : %u\r\n", regs->portsc_bm.port_power);
}
-static inline ehci_qhd_t* qhd_async_head(uint8_t rhport)
-{
- (void) rhport;
- // control qhd of dev0 is used as async head
- return qhd_control(0);
+static inline void print_intr(uint32_t intr) {
+ TU_LOG_HEX(EHCI_DBG, intr);
+ TU_LOG(EHCI_DBG, " USB Interrupt : %u\r\n", (intr & EHCI_INT_MASK_USB) ? 1 : 0);
+ TU_LOG(EHCI_DBG, " USB Error : %u\r\n", (intr & EHCI_INT_MASK_ERROR) ? 1 : 0);
+ TU_LOG(EHCI_DBG, " Port Change Detect : %u\r\n", (intr & EHCI_INT_MASK_PORT_CHANGE) ? 1 : 0);
+ TU_LOG(EHCI_DBG, " Frame List Rollover: %u\r\n", (intr & EHCI_INT_MASK_FRAMELIST_ROLLOVER) ? 1 : 0);
+ TU_LOG(EHCI_DBG, " Host System Error : %u\r\n", (intr & EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR) ? 1 : 0);
+ TU_LOG(EHCI_DBG, " Async Advance : %u\r\n", (intr & EHCI_INT_MASK_ASYNC_ADVANCE) ? 1 : 0);
+// TU_LOG(EHCI_DBG, " Interrupt on Async: %u\r\n", (intr & EHCI_INT_MASK_NXP_ASYNC));
+// TU_LOG(EHCI_DBG, " Periodic Schedule : %u\r\n", (intr & EHCI_INT_MASK_NXP_PERIODIC));
}
-static inline ehci_qtd_t* qtd_control(uint8_t dev_addr)
-{
- return &ehci_data.control[dev_addr].qtd;
-}
+#else
+#define print_portsc(_reg)
+#endif
+//--------------------------------------------------------------------+
+// PROTOTYPE
+//--------------------------------------------------------------------+
-static inline ehci_qhd_t* qhd_next (ehci_qhd_t const * p_qhd);
-static inline ehci_qhd_t* qhd_find_free (void);
-static inline ehci_qhd_t* qhd_get_from_addr (uint8_t dev_addr, uint8_t ep_addr);
+// weak dcache for non-cacheable MCU
+TU_ATTR_WEAK bool hcd_dcache_clean(void const* addr, uint32_t data_size) { (void) addr; (void) data_size; return true; }
+TU_ATTR_WEAK bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) { (void) addr; (void) data_size; return true; }
+TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) { (void) addr; (void) data_size; return true; }
-// determine if a queue head has bus-related error
-static inline bool qhd_has_xact_error (ehci_qhd_t * p_qhd)
-{
- return (p_qhd->qtd_overlay.buffer_err || p_qhd->qtd_overlay.babble_err || p_qhd->qtd_overlay.xact_err);
- //p_qhd->qtd_overlay.non_hs_period_missed_uframe || p_qhd->qtd_overlay.pingstate_err TODO split transaction error
-}
+TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_control(uint8_t dev_addr);
+TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_next (ehci_qhd_t const * p_qhd);
+TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_find_free (void);
+static ehci_qhd_t* qhd_get_from_addr (uint8_t dev_addr, uint8_t ep_addr);
+static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
+static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd);
+static void qhd_remove_qtd(ehci_qhd_t *qhd);
-static void qhd_init (ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
+TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t* qtd_control(uint8_t dev_addr);
+TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t* qtd_find_free (void);
+static void qtd_init (ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes);
-static inline ehci_qtd_t* qtd_find_free (void);
-static inline ehci_qtd_t* qtd_next (ehci_qtd_t const * p_qtd);
-static inline void qtd_insert_to_qhd (ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new);
-static inline void qtd_remove_1st_from_qhd (ehci_qhd_t *p_qhd);
-static void qtd_init (ehci_qtd_t* p_qtd, void* buffer, uint16_t total_bytes);
+TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_get_period_head(uint8_t rhport, uint32_t interval_ms);
+TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* list_get_async_head(uint8_t rhport);
+TU_ATTR_ALWAYS_INLINE static inline void list_insert (ehci_link_t *current, ehci_link_t *new, uint8_t new_type);
+TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_next (ehci_link_t const *p_link);
+static void list_remove_qhd_by_daddr(ehci_link_t* list_head, uint8_t dev_addr);
-static inline void list_insert (ehci_link_t *current, ehci_link_t *new, uint8_t new_type);
-static inline ehci_link_t* list_next (ehci_link_t *p_link_pointer);
+static void ehci_disable_schedule(ehci_registers_t* regs, bool is_period) {
+ // maybe have a timeout for status
+ if (is_period) {
+ regs->command_bm.periodic_enable = 0;
+ while(regs->status_bm.periodic_status) {}
+ } else {
+ regs->command_bm.async_enable = 0;
+ while(regs->status_bm.async_status) {} // should have a timeout
+ }
+}
+
+static void ehci_enable_schedule(ehci_registers_t* regs, bool is_period) {
+ // maybe have a timeout for status
+ if (is_period) {
+ regs->command_bm.periodic_enable = 1;
+ while ( 0 == regs->status_bm.periodic_status ) {}
+ } else {
+ regs->command_bm.async_enable = 1;
+ while( 0 == regs->status_bm.async_status ) {}
+ }
+}
//--------------------------------------------------------------------+
// HCD API
@@ -136,26 +188,38 @@ void hcd_port_reset(uint8_t rhport)
ehci_registers_t* regs = ehci_data.regs;
-// regs->portsc_bm.port_enabled = 0; // disable port before reset
-// regs->portsc_bm.port_reset = 1;
+ // skip if already in reset
+ if (regs->portsc_bm.port_reset) {
+ return;
+ }
- uint32_t portsc = regs->portsc;
+ // mask out Write-1-to-Clear bits
+ uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_W1C;
+ // EHCI Table 2-16 PortSC
+ // when software writes Port Reset bit to a one, it must also write a zero to the Port Enable bit.
portsc &= ~(EHCI_PORTSC_MASK_PORT_EANBLED);
portsc |= EHCI_PORTSC_MASK_PORT_RESET;
regs->portsc = portsc;
}
-#if 0
void hcd_port_reset_end(uint8_t rhport)
{
(void) rhport;
-
ehci_registers_t* regs = ehci_data.regs;
- regs->portsc_bm.port_reset = 0;
+
+ // skip if reset is already complete
+ if (!regs->portsc_bm.port_reset) {
+ return;
+ }
+
+ // mask out all change bits since they are Write 1 to clear
+ uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_W1C;
+ portsc &= ~EHCI_PORTSC_MASK_PORT_RESET;
+
+ regs->portsc = portsc;
}
-#endif
bool hcd_port_connect_status(uint8_t rhport)
{
@@ -169,133 +233,126 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport)
return (tusb_speed_t) ehci_data.regs->portsc_bm.nxp_port_speed; // NXP specific port speed
}
-static void list_remove_qhd_by_addr(ehci_link_t* list_head, uint8_t dev_addr)
-{
- for(ehci_link_t* prev = list_head;
- !prev->terminate && (tu_align32(prev->address) != (uint32_t) list_head);
- prev = list_next(prev) )
- {
- // TODO check type for ISO iTD and siTD
- ehci_qhd_t* qhd = (ehci_qhd_t*) list_next(prev);
- if ( qhd->dev_addr == dev_addr )
- {
- // TODO deactive all TD, wait for QHD to inactive before removal
- prev->address = qhd->next.address;
-
- // EHCI 4.8.2 link the removed qhd to async head (which always reachable by Host Controller)
- qhd->next.address = ((uint32_t) list_head) | (EHCI_QTYPE_QHD << 1);
-
- if ( qhd->int_smask )
- {
- // period list queue element is guarantee to be free in the next frame (1 ms)
- qhd->used = 0;
- }else
- {
- // async list use async advance handshake
- // mark as removing, will completely re-usable when async advance isr occurs
- qhd->removing = 1;
- }
- }
- }
-}
-
// Close all opened endpoint belong to this device
-void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+void hcd_device_close(uint8_t rhport, uint8_t daddr)
{
// skip dev0
- if (dev_addr == 0) return;
+ if (daddr == 0) {
+ return;
+ }
// Remove from async list
- list_remove_qhd_by_addr( (ehci_link_t*) qhd_async_head(rhport), dev_addr );
+ list_remove_qhd_by_daddr((ehci_link_t *) list_get_async_head(rhport), daddr);
// Remove from all interval period list
- for(uint8_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++)
- {
- list_remove_qhd_by_addr( (ehci_link_t*) &ehci_data.period_head_arr[i], dev_addr);
+ for(uint8_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++) {
+ list_remove_qhd_by_daddr((ehci_link_t *) &ehci_data.period_head_arr[i], daddr);
}
// Async doorbell (EHCI 4.8.2 for operational details)
ehci_data.regs->command_bm.async_adv_doorbell = 1;
}
-// EHCI controller init
-bool hcd_ehci_init(uint8_t rhport)
-{
- tu_memclr(&ehci_data, sizeof(ehci_data_t));
-
- ehci_data.regs = (ehci_registers_t* ) hcd_ehci_register_addr(rhport);
-
- ehci_registers_t* regs = ehci_data.regs;
-
- //------------- CTRLDSSEGMENT Register (skip) -------------//
- //------------- USB INT Register -------------//
- regs->inten = 0; // 1. disable all the interrupt
- regs->status = EHCI_INT_MASK_ALL; // 2. clear all status
-
- regs->inten = EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE | EHCI_INT_MASK_ASYNC_ADVANCE |
- EHCI_INT_MASK_NXP_PERIODIC | EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_FRAMELIST_ROLLOVER;
-
- //------------- Asynchronous List -------------//
- ehci_qhd_t * const async_head = qhd_async_head(rhport);
- tu_memclr(async_head, sizeof(ehci_qhd_t));
-
- async_head->next.address = (uint32_t) async_head; // circular list, next is itself
- async_head->next.type = EHCI_QTYPE_QHD;
- async_head->head_list_flag = 1;
- async_head->qtd_overlay.halted = 1; // inactive most of time
- async_head->qtd_overlay.next.terminate = 1; // TODO removed if verified
-
- regs->async_list_addr = (uint32_t) async_head;
+static void init_periodic_list(uint8_t rhport) {
+ (void) rhport;
- //------------- Periodic List -------------//
// Build the polling interval tree with 1 ms, 2 ms, 4 ms and 8 ms (framesize) only
- for(uint32_t i=0; i<4; i++)
- {
- ehci_data.period_head_arr[i].int_smask = 1; // queue head in period list must have smask non-zero
+ for ( uint32_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++ ) {
+ ehci_data.period_head_arr[i].int_smask = 1; // queue head in period list must have smask non-zero
ehci_data.period_head_arr[i].qtd_overlay.halted = 1; // dummy node, always inactive
}
- ehci_link_t * const framelist = ehci_data.period_framelist;
- ehci_link_t * const period_1ms = get_period_head(rhport, 1);
+ // TODO EHCI_FRAMELIST_SIZE with other size than 8
// all links --> period_head_arr[0] (1ms)
// 0, 2, 4, 6 etc --> period_head_arr[1] (2ms)
// 1, 5 --> period_head_arr[2] (4ms)
// 3 --> period_head_arr[3] (8ms)
- // TODO EHCI_FRAMELIST_SIZE with other size than 8
- for(uint32_t i=0; i<EHCI_FRAMELIST_SIZE; i++)
- {
- framelist[i].address = (uint32_t) period_1ms;
- framelist[i].type = EHCI_QTYPE_QHD;
+ ehci_link_t * const framelist = ehci_data.period_framelist;
+ ehci_link_t * const head_1ms = (ehci_link_t *) &ehci_data.period_head_arr[0];
+ ehci_link_t * const head_2ms = (ehci_link_t *) &ehci_data.period_head_arr[1];
+ ehci_link_t * const head_4ms = (ehci_link_t *) &ehci_data.period_head_arr[2];
+ ehci_link_t * const head_8ms = (ehci_link_t *) &ehci_data.period_head_arr[3];
+
+ for (uint32_t i = 0; i < FRAMELIST_SIZE; i++) {
+ framelist[i].address = (uint32_t) head_1ms;
+ framelist[i].type = EHCI_QTYPE_QHD;
}
- for(uint32_t i=0; i<EHCI_FRAMELIST_SIZE; i+=2)
- {
- list_insert(framelist + i, get_period_head(rhport, 2), EHCI_QTYPE_QHD);
+ for (uint32_t i = 0; i < FRAMELIST_SIZE; i += 2) {
+ list_insert(framelist + i, head_2ms, EHCI_QTYPE_QHD);
}
- for(uint32_t i=1; i<EHCI_FRAMELIST_SIZE; i+=4)
- {
- list_insert(framelist + i, get_period_head(rhport, 4), EHCI_QTYPE_QHD);
+ for (uint32_t i = 1; i < FRAMELIST_SIZE; i += 4) {
+ list_insert(framelist + i, head_4ms, EHCI_QTYPE_QHD);
}
- list_insert(framelist+3, get_period_head(rhport, 8), EHCI_QTYPE_QHD);
+ list_insert(framelist + 3, head_8ms, EHCI_QTYPE_QHD);
- period_1ms->terminate = 1;
+ head_1ms->terminate = 1;
+}
- regs->periodic_list_base = (uint32_t) framelist;
+bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
+{
+ tu_memclr(&ehci_data, sizeof(ehci_data_t));
+
+ ehci_data.regs = (ehci_registers_t*) operatial_reg;
+ ehci_data.cap_regs = (ehci_cap_registers_t*) capability_reg;
+
+ ehci_registers_t* regs = ehci_data.regs;
+
+ // EHCI 4.1 Host Controller Initialization
+
+ //------------- CTRLDSSEGMENT Register (skip) -------------//
+
+ //------------- USB INT Register -------------//
+
+ // disable all the interrupt
+ regs->inten = 0;
+
+ // clear all status except port change since device maybe connected before this driver is initialized
+ regs->status = (EHCI_INT_MASK_ALL & ~EHCI_INT_MASK_PORT_CHANGE);
+
+ // Enable interrupts
+ regs->inten = EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE |
+ EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_FRAMELIST_ROLLOVER;
+
+ //------------- Asynchronous List -------------//
+ ehci_qhd_t * const async_head = list_get_async_head(rhport);
+ tu_memclr(async_head, sizeof(ehci_qhd_t));
+
+ async_head->next.address = (uint32_t) async_head; // circular list, next is itself
+ async_head->next.type = EHCI_QTYPE_QHD;
+ async_head->head_list_flag = 1;
+ async_head->qtd_overlay.halted = 1; // inactive most of time
+ async_head->qtd_overlay.next.terminate = 1; // TODO removed if verified
+
+ regs->async_list_addr = (uint32_t) async_head;
+
+ //------------- Periodic List -------------//
+ init_periodic_list(rhport);
+ regs->periodic_list_base = (uint32_t) ehci_data.period_framelist;
+
+ hcd_dcache_clean(&ehci_data, sizeof(ehci_data_t));
//------------- TT Control (NXP only) -------------//
regs->nxp_tt_control = 0;
//------------- USB CMD Register -------------//
- regs->command |= TU_BIT(EHCI_USBCMD_POS_RUN_STOP) | TU_BIT(EHCI_USBCMD_POS_ASYNC_ENABLE)
- | TU_BIT(EHCI_USBCMD_POS_PERIOD_ENABLE) // TODO enable period list only there is int/iso endpoint
- | ((EHCI_CFG_FRAMELIST_SIZE_BITS & TU_BIN8(011)) << EHCI_USBCMD_POS_FRAMELIST_SZIE)
- | ((EHCI_CFG_FRAMELIST_SIZE_BITS >> 2) << EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB);
+ regs->command |= EHCI_USBCMD_RUN_STOP | EHCI_USBCMD_PERIOD_SCHEDULE_ENABLE | EHCI_USBCMD_ASYNC_SCHEDULE_ENABLE |
+ FRAMELIST_SIZE_USBCMD_VALUE;
//------------- ConfigFlag Register (skip) -------------//
- regs->portsc_bm.port_power = 1; // enable port power
+
+ // enable port power bit in portsc. The function of this bit depends on the value of the Port
+ // Power Control (PPC) field in the HCSPARAMS register.
+ if (ehci_data.cap_regs->hcsparams_bm.port_power_control) {
+ // mask out all change bits since they are Write 1 to clear
+ uint32_t portsc = (regs->portsc & ~EHCI_PORTSC_MASK_W1C);
+ portsc |= EHCI_PORTSC_MASK_PORT_POWER;
+
+ regs->portsc = portsc;
+ }
return true;
}
@@ -326,15 +383,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
TU_ASSERT (ep_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
//------------- Prepare Queue Head -------------//
- ehci_qhd_t * p_qhd;
-
- if ( ep_desc->bEndpointAddress == 0 )
- {
- p_qhd = qhd_control(dev_addr);
- }else
- {
- p_qhd = qhd_find_free();
- }
+ ehci_qhd_t *p_qhd = (ep_desc->bEndpointAddress == 0) ? qhd_control(dev_addr) : qhd_find_free();
TU_ASSERT(p_qhd);
qhd_init(p_qhd, dev_addr, ep_desc);
@@ -349,11 +398,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
{
case TUSB_XFER_CONTROL:
case TUSB_XFER_BULK:
- list_head = (ehci_link_t*) qhd_async_head(rhport);
+ list_head = (ehci_link_t*) list_get_async_head(rhport);
break;
case TUSB_XFER_INTERRUPT:
- list_head = get_period_head(rhport, p_qhd->interval_ms);
+ list_head = list_get_period_head(rhport, p_qhd->interval_ms);
break;
case TUSB_XFER_ISOCHRONOUS:
@@ -362,12 +411,13 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
default: break;
}
-
TU_ASSERT(list_head);
- // TODO might need to disable async/period list
list_insert(list_head, (ehci_link_t*) p_qhd, EHCI_QTYPE_QHD);
+ hcd_dcache_clean(p_qhd, sizeof(ehci_qhd_t));
+ hcd_dcache_clean(list_head, sizeof(ehci_qhd_t));
+
return true;
}
@@ -378,17 +428,18 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
ehci_qhd_t* qhd = &ehci_data.control[dev_addr].qhd;
ehci_qtd_t* td = &ehci_data.control[dev_addr].qtd;
- qtd_init(td, (void*) setup_packet, 8);
- td->pid = EHCI_PID_SETUP;
- td->int_on_complete = 1;
- td->next.terminate = 1;
+ qtd_init(td, setup_packet, 8);
+ td->pid = EHCI_PID_SETUP;
- // sw region
- qhd->p_qtd_list_head = td;
- qhd->p_qtd_list_tail = td;
+ hcd_dcache_clean(setup_packet, 8);
- // attach TD
- qhd->qtd_overlay.next.address = (uint32_t) td;
+ // Control endpoint never be stalled. Skip reset Data Toggle since it is fixed per stage
+ if (qhd->qtd_overlay.halted) {
+ qhd->qtd_overlay.halted = false;
+ }
+
+ // attach TD to QHD -> start transferring
+ qhd_attach_qtd(qhd, td);
return true;
}
@@ -400,63 +451,84 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
- if ( epnum == 0 )
- {
- ehci_qhd_t* qhd = qhd_control(dev_addr);
- ehci_qtd_t* qtd = qtd_control(dev_addr);
+ ehci_qhd_t* qhd = qhd_get_from_addr(dev_addr, ep_addr);
+ ehci_qtd_t* qtd;
+ if (epnum == 0) {
+ // Control endpoint never be stalled. Skip reset Data Toggle since it is fixed per stage
+ if (qhd->qtd_overlay.halted) {
+ qhd->qtd_overlay.halted = false;
+ }
+
+ qtd = qtd_control(dev_addr);
qtd_init(qtd, buffer, buflen);
- // first first data toggle is always 1 (data & setup stage)
+ // first data toggle is always 1 (data & setup stage)
qtd->data_toggle = 1;
qtd->pid = dir ? EHCI_PID_IN : EHCI_PID_OUT;
- qtd->int_on_complete = 1;
- qtd->next.terminate = 1;
+ } else {
+ // skip if endpoint is halted
+ TU_VERIFY(!qhd->qtd_overlay.halted);
- // sw region
- qhd->p_qtd_list_head = qtd;
- qhd->p_qtd_list_tail = qtd;
+ qtd = qtd_find_free();
+ TU_ASSERT(qtd);
- // attach TD
- qhd->qtd_overlay.next.address = (uint32_t) qtd;
- }else
- {
- ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);
- ehci_qtd_t *p_qtd = qtd_find_free();
- TU_ASSERT(p_qtd);
+ qtd_init(qtd, buffer, buflen);
+ qtd->pid = qhd->pid;
+ }
- qtd_init(p_qtd, buffer, buflen);
- p_qtd->pid = p_qhd->pid;
+ // IN transfer: invalidate buffer, OUT transfer: clean buffer
+ if (dir) {
+ hcd_dcache_invalidate(buffer, buflen);
+ }else {
+ hcd_dcache_clean(buffer, buflen);
+ }
- // Insert TD to QH
- qtd_insert_to_qhd(p_qhd, p_qtd);
+ // attach TD to QHD -> start transferring
+ qhd_attach_qtd(qhd, qtd);
- p_qhd->p_qtd_list_tail->int_on_complete = 1;
+ return true;
+}
+
+bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+
+ // TODO ISO not supported yet
+ ehci_qhd_t* qhd = qhd_get_from_addr(dev_addr, ep_addr);
+ ehci_qtd_t * volatile qtd = qhd->attached_qtd;
+ TU_VERIFY(qtd != NULL); // no queued transfer
+
+ hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
+ TU_VERIFY(qtd->active); // transfer is already complete
+
+ // HC is still processing, disable HC list schedule before making changes
+ bool const is_period = (qhd->interval_ms > 0);
+
+ ehci_disable_schedule(ehci_data.regs, is_period);
+
+ // check active bit again just in case HC has just processed the TD
+ bool const still_active = qtd->active;
+ if (still_active) {
+ // remove TD from QH overlay
+ qhd->qtd_overlay.next.terminate = 1;
+ hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
- // attach head QTD to QHD start transferring
- p_qhd->qtd_overlay.next.address = (uint32_t) p_qhd->p_qtd_list_head;
+ // remove TD from QH software list
+ qhd_remove_qtd(qhd);
}
- return true;
-}
+ ehci_enable_schedule(ehci_data.regs, is_period);
-bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
-{
- ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);
- return !p_qhd->qtd_overlay.halted && (p_qhd->p_qtd_list_head != NULL);
+ return still_active; // true if removed an active transfer
}
-bool hcd_edpt_stalled(uint8_t dev_addr, uint8_t ep_addr)
-{
- ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);
- return p_qhd->qtd_overlay.halted && !qhd_has_xact_error(p_qhd);
-}
+bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport;
+ ehci_qhd_t *qhd = qhd_get_from_addr(daddr, ep_addr);
+ qhd->qtd_overlay.halted = 0;
+ qhd->qtd_overlay.data_toggle = 0;
+ hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
-bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
-{
- ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);
- p_qhd->qtd_overlay.halted = 0;
- // TODO reset data toggle ?
return true;
}
@@ -467,335 +539,299 @@ bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
// async_advance is handshake between usb stack & ehci controller.
// This isr mean it is safe to modify previously removed queue head from async list.
// In tinyusb, queue head is only removed when device is unplugged.
-static void async_advance_isr(uint8_t rhport)
+TU_ATTR_ALWAYS_INLINE static inline
+void async_advance_isr(uint8_t rhport)
{
(void) rhport;
- ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
- for(uint32_t i = 0; i < HCD_MAX_ENDPOINT; i++)
- {
- if ( qhd_pool[i].removing )
- {
+ ehci_qhd_t *qhd_pool = ehci_data.qhd_pool;
+ for (uint32_t i = 0; i < QHD_MAX; i++) {
+ if (qhd_pool[i].removing) {
qhd_pool[i].removing = 0;
- qhd_pool[i].used = 0;
+ qhd_pool[i].used = 0;
}
}
}
-static void port_connect_status_change_isr(uint8_t hostid)
-{
+TU_ATTR_ALWAYS_INLINE static inline
+void port_connect_status_change_isr(uint8_t rhport) {
// NOTE There is an sequence plug->unplug->…..-> plug if device is powering with pre-plugged device
- if (ehci_data.regs->portsc_bm.current_connect_status)
- {
- hcd_port_reset(hostid);
- hcd_event_device_attach(hostid, true);
- }else // device unplugged
+ if ( ehci_data.regs->portsc_bm.current_connect_status ) {
+ hcd_port_reset(rhport);
+ hcd_event_device_attach(rhport, true);
+ } else // device unplugged
{
- hcd_event_device_remove(hostid, true);
+ hcd_event_device_remove(rhport, true);
}
}
-static void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd)
-{
- // free all TDs from the head td to the first active TD
- while(p_qhd->p_qtd_list_head != NULL && !p_qhd->p_qtd_list_head->active)
- {
- ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) p_qhd->p_qtd_list_head;
- bool const is_ioc = (qtd->int_on_complete != 0);
- uint8_t const ep_addr = tu_edpt_addr(p_qhd->ep_number, qtd->pid == EHCI_PID_IN ? 1 : 0);
-
- p_qhd->total_xferred_bytes += qtd->expected_bytes - qtd->total_bytes;
+// Check queue head for potential transfer complete (successful or error)
+TU_ATTR_ALWAYS_INLINE static inline
+void qhd_xfer_complete_isr(ehci_qhd_t * qhd) {
+ hcd_dcache_invalidate(qhd, sizeof(ehci_qhd_t)); // HC may have updated the overlay
+ volatile ehci_qtd_t *qtd_overlay = &qhd->qtd_overlay;
- // TD need to be freed and removed from qhd, before invoking callback
- qtd->used = 0; // free QTD
- qtd_remove_1st_from_qhd(p_qhd);
-
- if (is_ioc)
- {
- hcd_event_xfer_complete(p_qhd->dev_addr, ep_addr, p_qhd->total_xferred_bytes, XFER_RESULT_SUCCESS, true);
- p_qhd->total_xferred_bytes = 0;
- }
- }
-}
+ // process non-active (completed) QHD with attached (scheduled) TD
+ if ( !qtd_overlay->active && qhd->attached_qtd != NULL ) {
+ xfer_result_t xfer_result;
-static void async_list_xfer_complete_isr(ehci_qhd_t * const async_head)
-{
- ehci_qhd_t *p_qhd = async_head;
- do
- {
- if ( !p_qhd->qtd_overlay.halted ) // halted or error is processed in error isr
- {
- qhd_xfer_complete_isr(p_qhd);
+ if ( qtd_overlay->halted ) {
+ if (qtd_overlay->xact_err || qtd_overlay->err_count == 0 || qtd_overlay->buffer_err || qtd_overlay->babble_err) {
+ // Error count = 0 often occurs when device disconnected, or other bus-related error
+ // clear halted bit if not caused by STALL to allow more transfer
+ xfer_result = XFER_RESULT_FAILED;
+ qtd_overlay->halted = false;
+ TU_LOG3(" QHD xfer err count: %d\r\n", qtd_overlay->err_count);
+ // TU_BREAKPOINT(); // TODO skip unplugged device
+ }else {
+ // no error bits are set, endpoint is halted due to STALL
+ xfer_result = XFER_RESULT_STALLED;
+ }
+ } else {
+ xfer_result = XFER_RESULT_SUCCESS;
}
- p_qhd = qhd_next(p_qhd);
- }while(p_qhd != async_head); // async list traversal, stop if loop around
-}
-static void period_list_xfer_complete_isr(uint8_t hostid, uint8_t interval_ms)
-{
- uint16_t max_loop = 0;
- uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1);
- ehci_link_t next_item = * get_period_head(hostid, interval_ms);
+ ehci_qtd_t * volatile qtd = qhd->attached_qtd;
+ hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t)); // HC may have written back TD
- // TODO abstract max loop guard for period
- while( !next_item.terminate &&
- !(interval_ms > 1 && period_1ms_addr == tu_align32(next_item.address)) &&
- max_loop < (HCD_MAX_ENDPOINT + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUSB_HOST_DEVICE_MAX)
- {
- switch ( next_item.type )
- {
- case EHCI_QTYPE_QHD:
- {
- ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) tu_align32(next_item.address);
- if ( !p_qhd_int->qtd_overlay.halted )
- {
- qhd_xfer_complete_isr(p_qhd_int);
- }
- }
- break;
+ uint8_t const dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
+ uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
- case EHCI_QTYPE_ITD: // TODO support hs/fs ISO
- case EHCI_QTYPE_SITD:
- case EHCI_QTYPE_FSTN:
-
- default: break;
+ // invalidate dcache if IN transfer with data
+ if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
+ hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
}
- next_item = *list_next(&next_item);
- max_loop++;
+ // remove and free TD before invoking callback
+ qhd_remove_qtd(qhd);
+
+ // notify usbh
+ uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
+ hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, xfer_result, true);
}
}
-static void qhd_xfer_error_isr(ehci_qhd_t * p_qhd)
+TU_ATTR_ALWAYS_INLINE static inline
+void proccess_async_xfer_isr(ehci_qhd_t * const list_head)
{
- if ( (p_qhd->dev_addr != 0 && p_qhd->qtd_overlay.halted) || // addr0 cannot be protocol STALL
- qhd_has_xact_error(p_qhd) )
- {
- // current qhd has error in transaction
- xfer_result_t error_event;
-
- // no error bits are set, endpoint is halted due to STALL
- error_event = qhd_has_xact_error(p_qhd) ? XFER_RESULT_FAILED : XFER_RESULT_STALLED;
-
- p_qhd->total_xferred_bytes += p_qhd->p_qtd_list_head->expected_bytes - p_qhd->p_qtd_list_head->total_bytes;
-
-// if ( XFER_RESULT_FAILED == error_event ) TU_BREAKPOINT(); // TODO skip unplugged device
-
- p_qhd->p_qtd_list_head->used = 0; // free QTD
- qtd_remove_1st_from_qhd(p_qhd);
+ ehci_qhd_t *qhd = list_head;
- if ( 0 == p_qhd->ep_number )
- {
- // control cannot be halted --> clear all qtd list
- p_qhd->p_qtd_list_head = NULL;
- p_qhd->p_qtd_list_tail = NULL;
-
- p_qhd->qtd_overlay.next.terminate = 1;
- p_qhd->qtd_overlay.alternate.terminate = 1;
- p_qhd->qtd_overlay.halted = 0;
-
- ehci_qtd_t *p_setup = qtd_control(p_qhd->dev_addr);
- p_setup->used = 0;
- }
-
- // call USBH callback
- hcd_event_xfer_complete(p_qhd->dev_addr, tu_edpt_addr(p_qhd->ep_number, p_qhd->pid == EHCI_PID_IN ? 1 : 0), p_qhd->total_xferred_bytes, error_event, true);
-
- p_qhd->total_xferred_bytes = 0;
- }
+ do {
+ qhd_xfer_complete_isr(qhd);
+ qhd = qhd_next(qhd);
+ } while ( qhd != list_head ); // async list traversal, stop if loop around
}
-static void xfer_error_isr(uint8_t hostid)
+TU_ATTR_ALWAYS_INLINE static inline
+void process_period_xfer_isr(uint8_t rhport, uint32_t interval_ms)
{
- //------------- async list -------------//
- ehci_qhd_t * const async_head = qhd_async_head(hostid);
- ehci_qhd_t *p_qhd = async_head;
- do
- {
- qhd_xfer_error_isr( p_qhd );
- p_qhd = qhd_next(p_qhd);
- }while(p_qhd != async_head); // async list traversal, stop if loop around
+ uint32_t const period_1ms_addr = (uint32_t) list_get_period_head(rhport, 1u);
+ ehci_link_t next_link = *list_get_period_head(rhport, interval_ms);
- //------------- TODO refractor period list -------------//
- uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1);
- for (uint8_t interval_ms=1; interval_ms <= EHCI_FRAMELIST_SIZE; interval_ms *= 2)
- {
- ehci_link_t next_item = * get_period_head(hostid, interval_ms);
+ while (!next_link.terminate) {
+ if (interval_ms > 1 && period_1ms_addr == tu_align32(next_link.address)) {
+ // 1ms period list is end of list for all larger interval
+ break;
+ }
- // TODO abstract max loop guard for period
- while( !next_item.terminate &&
- !(interval_ms > 1 && period_1ms_addr == tu_align32(next_item.address)) )
- {
- switch ( next_item.type )
- {
- case EHCI_QTYPE_QHD:
- {
- ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) tu_align32(next_item.address);
- qhd_xfer_error_isr(p_qhd_int);
- }
- break;
+ uintptr_t const entry_addr = tu_align32(next_link.address);
- // TODO support hs/fs ISO
- case EHCI_QTYPE_ITD:
- case EHCI_QTYPE_SITD:
- case EHCI_QTYPE_FSTN:
- default: break;
+ switch (next_link.type) {
+ case EHCI_QTYPE_QHD: {
+ ehci_qhd_t *qhd = (ehci_qhd_t *) entry_addr;
+ qhd_xfer_complete_isr(qhd);
}
+ break;
- next_item = *list_next(&next_item);
+ // TODO support hs/fs ISO
+ case EHCI_QTYPE_ITD:
+ case EHCI_QTYPE_SITD:
+ case EHCI_QTYPE_FSTN:
+ default:
+ break;
}
+
+ next_link = *list_next(&next_link);
}
}
//------------- Host Controller Driver's Interrupt Handler -------------//
-void hcd_int_handler(uint8_t rhport)
-{
+void hcd_int_handler(uint8_t rhport, bool in_isr) {
+ (void) in_isr;
ehci_registers_t* regs = ehci_data.regs;
+ uint32_t const int_status = regs->status;
- uint32_t int_status = regs->status;
- int_status &= regs->inten;
-
- regs->status |= int_status; // Acknowledge handled interrupt
-
- if (int_status == 0) return;
+ if (int_status & EHCI_INT_MASK_HC_HALTED) {
+ // something seriously wrong, maybe forget to flush/invalidate cache
+ TU_BREAKPOINT();
+ TU_LOG1(" HC halted\r\n");
+ return;
+ }
- if (int_status & EHCI_INT_MASK_FRAMELIST_ROLLOVER)
- {
- ehci_data.uframe_number += (EHCI_FRAMELIST_SIZE << 3);
+ if (int_status & EHCI_INT_MASK_FRAMELIST_ROLLOVER) {
+ ehci_data.uframe_number += (FRAMELIST_SIZE << 3);
+ regs->status = EHCI_INT_MASK_FRAMELIST_ROLLOVER; // Acknowledge
}
- if (int_status & EHCI_INT_MASK_PORT_CHANGE)
- {
- uint32_t port_status = regs->portsc & EHCI_PORTSC_MASK_ALL;
+ if (int_status & EHCI_INT_MASK_PORT_CHANGE) {
+ // Including: Force port resume, over-current change, enable/disable change and connect status change.
+ uint32_t const port_status = regs->portsc & EHCI_PORTSC_MASK_W1C;
+ // print_portsc(regs);
- if (regs->portsc_bm.connect_status_change)
- {
+ if (regs->portsc_bm.connect_status_change) {
port_connect_status_change_isr(rhport);
}
regs->portsc |= port_status; // Acknowledge change bits in portsc
+ regs->status = EHCI_INT_MASK_PORT_CHANGE; // Acknowledge
}
- if (int_status & EHCI_INT_MASK_ERROR)
- {
- xfer_error_isr(rhport);
- }
+ // A USB transfer is completed (OK or error)
+ uint32_t const usb_int = int_status & (EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR);
+ if (usb_int) {
+ proccess_async_xfer_isr(list_get_async_head(rhport));
- //------------- some QTD/SITD/ITD with IOC set is completed -------------//
- if (int_status & EHCI_INT_MASK_NXP_ASYNC)
- {
- async_list_xfer_complete_isr( qhd_async_head(rhport) );
- }
-
- if (int_status & EHCI_INT_MASK_NXP_PERIODIC)
- {
- for (uint8_t i=1; i <= EHCI_FRAMELIST_SIZE; i *= 2)
- {
- period_list_xfer_complete_isr( rhport, i );
+ for ( uint32_t i = 1; i <= FRAMELIST_SIZE; i *= 2 ) {
+ process_period_xfer_isr(rhport, i);
}
+
+ regs->status = usb_int; // Acknowledge
}
//------------- There is some removed async previously -------------//
- if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) // need to place after EHCI_INT_MASK_NXP_ASYNC
- {
+ // need to place after EHCI_INT_MASK_NXP_ASYNC
+ if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) {
async_advance_isr(rhport);
+ regs->status = EHCI_INT_MASK_ASYNC_ADVANCE; // Acknowledge
}
}
//--------------------------------------------------------------------+
-// HELPER
+// List Managing Helper
//--------------------------------------------------------------------+
+// Get head of periodic list
+TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_get_period_head(uint8_t rhport, uint32_t interval_ms) {
+ (void) rhport;
+ return (ehci_link_t*) &ehci_data.period_head_arr[ tu_log2( tu_min32(FRAMELIST_SIZE, interval_ms) ) ];
+}
-//------------- queue head helper -------------//
-static inline ehci_qhd_t* qhd_find_free (void)
-{
- for (uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
- {
- if ( !ehci_data.qhd_pool[i].used ) return &ehci_data.qhd_pool[i];
- }
+// Get head of async list
+TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* list_get_async_head(uint8_t rhport) {
+ (void) rhport;
+ return qhd_control(0); // control qhd of dev0 is used as async head
+}
- return NULL;
+TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_next(ehci_link_t const *p_link) {
+ return (ehci_link_t*) tu_align32(p_link->address);
}
-static inline ehci_qhd_t* qhd_next(ehci_qhd_t const * p_qhd)
+TU_ATTR_ALWAYS_INLINE static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type)
{
- return (ehci_qhd_t*) tu_align32(p_qhd->next.address);
+ new->address = current->address;
+ current->address = ((uint32_t) new) | (new_type << 1);
}
-static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
-{
- ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
+// Remove all queue head belong to this device address
+static void list_remove_qhd_by_daddr(ehci_link_t* list_head, uint8_t dev_addr) {
+ ehci_link_t* prev = list_head;
- for(uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
- {
- if ( (qhd_pool[i].dev_addr == dev_addr) &&
- ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) )
- {
- return &qhd_pool[i];
+ while (prev && !prev->terminate) {
+ ehci_qhd_t* qhd = (ehci_qhd_t*) (uintptr_t) list_next(prev);
+
+ // done if loop back to head
+ if ( (uintptr_t) qhd == (uintptr_t) list_head) {
+ break;
+ }
+
+ if ( qhd->dev_addr == dev_addr ) {
+ // TODO deactivate all TD, wait for QHD to inactive before removal
+ prev->address = qhd->next.address;
+
+ // EHCI 4.8.2 link the removed qhd's next to async head (which always reachable by Host Controller)
+ qhd->next.address = ((uint32_t) list_head) | (EHCI_QTYPE_QHD << 1);
+
+ if ( qhd->int_smask )
+ {
+ // period list queue element is guarantee to be free in the next frame (1 ms)
+ qhd->used = 0;
+ }else
+ {
+ // async list use async advance handshake
+ // mark as removing, will completely re-usable when async advance isr occurs
+ qhd->removing = 1;
+ }
+
+ hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
+ hcd_dcache_clean(prev, sizeof(ehci_qhd_t));
+ }else {
+ prev = list_next(prev);
}
}
+}
- return NULL;
+
+//--------------------------------------------------------------------+
+// Queue Header helper
+//--------------------------------------------------------------------+
+
+// Get queue head for control transfer (always available)
+TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_control(uint8_t dev_addr) {
+ return &ehci_data.control[dev_addr].qhd;
}
-//------------- TD helper -------------//
-static inline ehci_qtd_t* qtd_find_free(void)
-{
- for (uint32_t i=0; i<HCD_MAX_XFER; i++)
- {
- if ( !ehci_data.qtd_pool[i].used ) return &ehci_data.qtd_pool[i];
+// Find a free queue head
+TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t *qhd_find_free(void) {
+ for ( uint32_t i = 0; i < QHD_MAX; i++ ) {
+ if ( !ehci_data.qhd_pool[i].used ) return &ehci_data.qhd_pool[i];
}
-
return NULL;
}
-static inline ehci_qtd_t* qtd_next(ehci_qtd_t const * p_qtd )
-{
- return (ehci_qtd_t*) tu_align32(p_qtd->next.address);
+// Next queue head link
+TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t *qhd_next(ehci_qhd_t const *p_qhd) {
+ return (ehci_qhd_t *) tu_align32(p_qhd->next.address);
}
-static inline void qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd)
-{
- if (p_qhd->p_qtd_list_head == p_qhd->p_qtd_list_tail) // last TD --> make it NULL
- {
- p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = NULL;
- }else
- {
- p_qhd->p_qtd_list_head = qtd_next( p_qhd->p_qtd_list_head );
+// Get queue head from device + endpoint address
+static ehci_qhd_t *qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr) {
+ if ( 0 == tu_edpt_number(ep_addr) ) {
+ return qhd_control(dev_addr);
}
-}
-static inline void qtd_insert_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new)
-{
- if (p_qhd->p_qtd_list_head == NULL) // empty list
- {
- p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = p_qtd_new;
- }else
- {
- p_qhd->p_qtd_list_tail->next.address = (uint32_t) p_qtd_new;
- p_qhd->p_qtd_list_tail = p_qtd_new;
+ ehci_qhd_t *qhd_pool = ehci_data.qhd_pool;
+
+ for ( uint32_t i = 0; i < QHD_MAX; i++ ) {
+ if ( (qhd_pool[i].dev_addr == dev_addr) &&
+ ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) ) {
+ return &qhd_pool[i];
+ }
}
+
+ return NULL;
}
+// Init queue head with endpoint descriptor
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
{
// address 0 is used as async head, which always on the list --> cannot be cleared (ehci halted otherwise)
- if (dev_addr != 0)
- {
+ if (dev_addr != 0) {
tu_memclr(p_qhd, sizeof(ehci_qhd_t));
}
+ hcd_devtree_info_t devtree_info;
+ hcd_devtree_get_info(dev_addr, &devtree_info);
+
uint8_t const xfer_type = ep_desc->bmAttributes.xfer;
uint8_t const interval = ep_desc->bInterval;
p_qhd->dev_addr = dev_addr;
p_qhd->fl_inactive_next_xact = 0;
p_qhd->ep_number = tu_edpt_number(ep_desc->bEndpointAddress);
- p_qhd->ep_speed = _usbh_devices[dev_addr].speed;
+ p_qhd->ep_speed = devtree_info.speed;
p_qhd->data_toggle_control= (xfer_type == TUSB_XFER_CONTROL) ? 1 : 0;
p_qhd->head_list_flag = (dev_addr == 0) ? 1 : 0; // addr0's endpoint is the static asyn list head
- p_qhd->max_packet_size = ep_desc->wMaxPacketSize.size;
+ p_qhd->max_packet_size = tu_edpt_packet_size(ep_desc);
p_qhd->fl_ctrl_ep_flag = ((xfer_type == TUSB_XFER_CONTROL) && (p_qhd->ep_speed != TUSB_SPEED_HIGH)) ? 1 : 0;
p_qhd->nak_reload = 0;
@@ -806,7 +842,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
if (TUSB_SPEED_HIGH == p_qhd->ep_speed)
{
TU_ASSERT( interval <= 16, );
- if ( interval < 4) // sub milisecond interval
+ if ( interval < 4) // sub millisecond interval
{
p_qhd->interval_ms = 0;
p_qhd->int_smask = (interval == 1) ? TU_BIN8(11111111) :
@@ -829,58 +865,84 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
p_qhd->int_smask = p_qhd->fl_int_cmask = 0;
}
- p_qhd->fl_hub_addr = _usbh_devices[dev_addr].hub_addr;
- p_qhd->fl_hub_port = _usbh_devices[dev_addr].hub_port;
- p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet
+ p_qhd->fl_hub_addr = devtree_info.hub_addr;
+ p_qhd->fl_hub_port = devtree_info.hub_port;
+ p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet
//------------- HCD Management Data -------------//
- p_qhd->used = 1;
- p_qhd->removing = 0;
- p_qhd->p_qtd_list_head = NULL;
- p_qhd->p_qtd_list_tail = NULL;
+ p_qhd->used = 1;
+ p_qhd->removing = 0;
+ p_qhd->attached_qtd = NULL;
p_qhd->pid = tu_edpt_dir(ep_desc->bEndpointAddress) ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint
//------------- active, but no TD list -------------//
p_qhd->qtd_overlay.halted = 0;
p_qhd->qtd_overlay.next.terminate = 1;
p_qhd->qtd_overlay.alternate.terminate = 1;
+
if (TUSB_XFER_BULK == xfer_type && p_qhd->ep_speed == TUSB_SPEED_HIGH && p_qhd->pid == EHCI_PID_OUT)
{
p_qhd->qtd_overlay.ping_err = 1; // do PING for Highspeed Bulk OUT, EHCI section 4.11
}
}
-static void qtd_init(ehci_qtd_t* p_qtd, void* buffer, uint16_t total_bytes)
-{
- tu_memclr(p_qtd, sizeof(ehci_qtd_t));
+// Attach a TD to queue head
+static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd) {
+ qhd->attached_qtd = qtd;
+ qhd->attached_buffer = qtd->buffer[0];
- p_qtd->used = 1;
+ // clean and invalidate cache before physically write
+ hcd_dcache_clean_invalidate(qtd, sizeof(ehci_qtd_t));
- p_qtd->next.terminate = 1; // init to null
- p_qtd->alternate.terminate = 1; // not used, always set to terminated
- p_qtd->active = 1;
- p_qtd->err_count = 3; // TODO 3 consecutive errors tolerance
- p_qtd->data_toggle = 0;
- p_qtd->total_bytes = total_bytes;
- p_qtd->expected_bytes = total_bytes;
+ qhd->qtd_overlay.next.address = (uint32_t) qtd;
+ hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
+}
- p_qtd->buffer[0] = (uint32_t) buffer;
- for(uint8_t i=1; i<5; i++)
- {
- p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096;
- }
+// Remove an attached TD from queue head
+static void qhd_remove_qtd(ehci_qhd_t *qhd) {
+ ehci_qtd_t * volatile qtd = qhd->attached_qtd;
+
+ qhd->attached_qtd = NULL;
+ qhd->attached_buffer = 0;
+ hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
+
+ qtd->used = 0; // free QTD
+ hcd_dcache_clean(qtd, sizeof(ehci_qtd_t));
}
-//------------- List Managing Helper -------------//
-static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type)
-{
- new->address = current->address;
- current->address = ((uint32_t) new) | (new_type << 1);
+//--------------------------------------------------------------------+
+// Queue TD helper
+//--------------------------------------------------------------------+
+
+// Get TD for control transfer (always available)
+TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t* qtd_control(uint8_t dev_addr) {
+ return &ehci_data.control[dev_addr].qtd;
}
-static inline ehci_link_t* list_next(ehci_link_t *p_link_pointer)
-{
- return (ehci_link_t*) tu_align32(p_link_pointer->address);
+TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t *qtd_find_free(void) {
+ for (uint32_t i = 0; i < QTD_MAX; i++) {
+ if (!ehci_data.qtd_pool[i].used) return &ehci_data.qtd_pool[i];
+ }
+ return NULL;
+}
+
+static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes) {
+ tu_memclr(qtd, sizeof(ehci_qtd_t));
+ qtd->used = 1;
+
+ qtd->next.terminate = 1; // init to null
+ qtd->alternate.terminate = 1; // not used, always set to terminated
+ qtd->active = 1;
+ qtd->err_count = 3; // TODO 3 consecutive errors tolerance
+ qtd->data_toggle = 0;
+ qtd->int_on_complete = 1;
+ qtd->total_bytes = total_bytes;
+ qtd->expected_bytes = total_bytes;
+
+ qtd->buffer[0] = (uint32_t) buffer;
+ for(uint8_t i=1; i<5; i++) {
+ qtd->buffer[i] |= tu_align4k(qtd->buffer[i - 1] ) + 4096;
+ }
}
#endif
diff --git a/src/portable/ehci/ehci.h b/src/portable/ehci/ehci.h
index 874195a0c..457adc1d3 100644
--- a/src/portable/ehci/ehci.h
+++ b/src/portable/ehci/ehci.h
@@ -46,8 +46,6 @@
//--------------------------------------------------------------------+
// EHCI CONFIGURATION & CONSTANTS
//--------------------------------------------------------------------+
-#define EHCI_CFG_FRAMELIST_SIZE_BITS 7 /// Framelist Size (NXP specific) (0:1024) - (1:512) - (2:256) - (3:128) - (4:64) - (5:32) - (6:16) - (7:8)
-#define EHCI_FRAMELIST_SIZE (1024 >> EHCI_CFG_FRAMELIST_SIZE_BITS)
// TODO merge OHCI with EHCI
enum {
@@ -55,9 +53,6 @@ enum {
EHCI_MAX_SITD = 16
};
-//------------- Validation -------------//
-TU_VERIFY_STATIC(EHCI_CFG_FRAMELIST_SIZE_BITS <= 7, "incorrect value");
-
//--------------------------------------------------------------------+
// EHCI Data Structure
//--------------------------------------------------------------------+
@@ -86,6 +81,8 @@ typedef union {
};
}ehci_link_t;
+TU_VERIFY_STATIC( sizeof(ehci_link_t) == 4, "size is not correct" );
+
/// Queue Element Transfer Descriptor
/// Qtd is used to declare overlay in ehci_qhd_t -> cannot be declared with TU_ATTR_ALIGNED(32)
typedef struct
@@ -106,8 +103,8 @@ typedef struct
// Word 2: qTQ Token
volatile uint32_t ping_err : 1 ; ///< For Highspeed: 0 Out, 1 Ping. Full/Slow used as error indicator
- volatile uint32_t non_hs_split_state : 1 ; ///< Used by HC to track the state of slipt transaction
- volatile uint32_t non_hs_missed_uframe : 1 ; ///< HC misses a complete slip transaction
+ volatile uint32_t non_hs_split_state : 1 ; ///< Used by HC to track the state of split transaction
+ volatile uint32_t non_hs_missed_uframe : 1 ; ///< HC misses a complete split transaction
volatile uint32_t xact_err : 1 ; ///< Error (Timeout, CRC, Bad PID ... )
volatile uint32_t babble_err : 1 ; ///< Babble detected, also set Halted bit to 1
volatile uint32_t buffer_err : 1 ; ///< Data overrun/underrun error
@@ -119,7 +116,7 @@ typedef struct
volatile uint32_t current_page : 3 ; ///< Index into the qTD buffer pointer list
uint32_t int_on_complete : 1 ; ///< Interrupt on complete
volatile uint32_t total_bytes : 15 ; ///< Transfer bytes, decreased during transaction
- volatile uint32_t data_toggle : 1 ; ///< Data Toogle bit
+ volatile uint32_t data_toggle : 1 ; ///< Data Toggle bit
/// Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page
@@ -165,13 +162,14 @@ typedef struct TU_ATTR_ALIGNED(32)
uint8_t used;
uint8_t removing; // removed from asyn list, waiting for async advance
uint8_t pid;
- uint8_t interval_ms; // polling interval in frames (or milisecond)
+ uint8_t interval_ms; // polling interval in frames (or millisecond)
- uint16_t total_xferred_bytes; // number of bytes xferred until a qtd with ioc bit set
- uint8_t reserved2[2];
+ uint8_t TU_RESERVED[4];
- ehci_qtd_t * volatile p_qtd_list_head; // head of the scheduled TD list
- ehci_qtd_t * volatile p_qtd_list_tail; // tail of the scheduled TD list
+ // Attached TD management, note usbh will only queue 1 TD per QHD.
+ // buffer for dcache invalidate since td's buffer is modified by HC and finding initial buffer address is not trivial
+ uint32_t attached_buffer;
+ ehci_qtd_t * volatile attached_qtd;
} ehci_qhd_t;
TU_VERIFY_STATIC( sizeof(ehci_qhd_t) == 64, "size is not correct" );
@@ -230,7 +228,7 @@ typedef struct TU_ATTR_ALIGNED(32)
uint16_t reserved ; ///< reserved
// Word 3: siTD Transfer Status and Control
- // Status [7:0] TODO indentical to qTD Token'status --> refractor later
+ // Status [7:0] TODO identical to qTD Token'status --> refactor later
volatile uint32_t : 1 ; // reserved
volatile uint32_t split_state : 1 ;
volatile uint32_t missed_uframe : 1 ;
@@ -250,14 +248,6 @@ typedef struct TU_ATTR_ALIGNED(32)
/// Word 4-5: Buffer Pointer List
uint32_t buffer[2]; // buffer[1] TP: Transaction Position - T-Count: Transaction Count
-// union{
-// uint32_t BufferPointer1;
-// struct {
-// volatile uint32_t TCount : 3;
-// volatile uint32_t TPosition : 2;
-// };
-// };
-
/*---------- Word 6 ----------*/
ehci_link_t back;
@@ -272,53 +262,63 @@ TU_VERIFY_STATIC( sizeof(ehci_sitd_t) == 32, "size is not correct" );
//--------------------------------------------------------------------+
// EHCI Operational Register
//--------------------------------------------------------------------+
-enum ehci_interrupt_mask_{
+enum {
+ // Bit 0-5 has maskable in interrupt enabled register
EHCI_INT_MASK_USB = TU_BIT(0),
EHCI_INT_MASK_ERROR = TU_BIT(1),
EHCI_INT_MASK_PORT_CHANGE = TU_BIT(2),
-
EHCI_INT_MASK_FRAMELIST_ROLLOVER = TU_BIT(3),
EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR = TU_BIT(4),
EHCI_INT_MASK_ASYNC_ADVANCE = TU_BIT(5),
+
EHCI_INT_MASK_NXP_SOF = TU_BIT(7),
- EHCI_INT_MASK_NXP_ASYNC = TU_BIT(18),
- EHCI_INT_MASK_NXP_PERIODIC = TU_BIT(19),
+ EHCI_INT_MASK_HC_HALTED = TU_BIT(12),
+ EHCI_INT_MASK_RECLAIMATION = TU_BIT(13),
+ EHCI_INT_MASK_PERIODIC_SCHED_STATUS = TU_BIT(14),
+ EHCI_INT_MASK_ASYNC_SCHED_STATUS = TU_BIT(15),
EHCI_INT_MASK_ALL =
EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE |
EHCI_INT_MASK_FRAMELIST_ROLLOVER | EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR |
- EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_SOF |
- EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_NXP_PERIODIC
+ EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_SOF
};
-enum ehci_usbcmd_pos_ {
- EHCI_USBCMD_POS_RUN_STOP = 0,
- EHCI_USBCMD_POS_FRAMELIST_SZIE = 2,
- EHCI_USBCMD_POS_PERIOD_ENABLE = 4,
- EHCI_USBCMD_POS_ASYNC_ENABLE = 5,
- EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB = 15,
- EHCI_USBCMD_POS_INTERRUPT_THRESHOLD = 16
+enum {
+ EHCI_USBCMD_FRAMELIST_SIZE_SHIFT = 2, // [2..3]
+ EHCI_USBCMD_CHIPIDEA_FRAMELIST_SIZE_MSB_SHIFT = 15,
+ EHCI_USBCMD_INTERRUPT_THRESHOLD_SHIFT = 16
+};
+
+enum {
+ EHCI_USBCMD_RUN_STOP = TU_BIT(0), // [0..0] 1 = Run, 0 = Stop
+ EHCI_USBCMD_HCRESET = TU_BIT(1), // [1..1] SW write 1 to reset HC, clear by HC when complete
+ EHCI_USBCMD_PERIOD_SCHEDULE_ENABLE = TU_BIT(4), // [4..4] Enable periodic schedule
+ EHCI_USBCMD_ASYNC_SCHEDULE_ENABLE = TU_BIT(5), // [5..5] Enable async schedule
+ EHCI_USBCMD_INTR_ON_ASYNC_ADVANCE_DOORBELL = TU_BIT(6), // [6..6] Tell HC to interrupt next time it advances async list. Clear by HC
};
-enum ehci_portsc_change_mask_{
+enum {
EHCI_PORTSC_MASK_CURRENT_CONNECT_STATUS = TU_BIT(0),
EHCI_PORTSC_MASK_CONNECT_STATUS_CHANGE = TU_BIT(1),
EHCI_PORTSC_MASK_PORT_EANBLED = TU_BIT(2),
- EHCI_PORTSC_MASK_PORT_ENABLE_CHAGNE = TU_BIT(3),
+ EHCI_PORTSC_MASK_PORT_ENABLE_CHANGE = TU_BIT(3),
EHCI_PORTSC_MASK_OVER_CURRENT_CHANGE = TU_BIT(5),
+ EHCI_PORTSC_MASK_FORCE_RESUME = TU_BIT(6),
+ EHCI_PORTSC_MASK_PORT_SUSPEND = TU_BIT(7),
EHCI_PORTSC_MASK_PORT_RESET = TU_BIT(8),
+ EHCI_PORTSC_MASK_PORT_POWER = TU_BIT(12),
- EHCI_PORTSC_MASK_ALL =
- EHCI_PORTSC_MASK_CONNECT_STATUS_CHANGE |
- EHCI_PORTSC_MASK_PORT_ENABLE_CHAGNE |
- EHCI_PORTSC_MASK_OVER_CURRENT_CHANGE
+ EHCI_PORTSC_MASK_W1C =
+ EHCI_PORTSC_MASK_CONNECT_STATUS_CHANGE |
+ EHCI_PORTSC_MASK_PORT_ENABLE_CHANGE |
+ EHCI_PORTSC_MASK_OVER_CURRENT_CHANGE
};
typedef volatile struct
{
union {
- uint32_t command;
+ uint32_t command; // 0x00
struct {
uint32_t run_stop : 1 ; ///< 1=Run. 0=Stop
@@ -338,7 +338,7 @@ typedef volatile struct
};
union {
- uint32_t status;
+ uint32_t status; // 0x04
struct {
uint32_t usb : 1 ; ///< qTD with IOC is retired
@@ -355,14 +355,14 @@ typedef volatile struct
uint32_t periodic_status : 1 ; ///< Periodic schedule status
uint32_t async_status : 1 ; ///< Async schedule status
uint32_t : 2 ;
- uint32_t nxp_int_async : 1 ; ///< NXP customized: This bit is set by the Host Controller when the cause of an interrupt is a completion of a USB transaction where the Transfer Descriptor (TD) has an interrupt on complete (IOC) bit set andthe TD was from the asynchronous schedule. This bit is also set by the Host when a short packet is detected andthe packet is on the asynchronous schedule.
- uint32_t nxp_int_period : 1 ; ///< NXP customized: This bit is set by the Host Controller when the cause of an interrupt is a completion of a USB transaction where the Transfer Descriptor (TD) has an interrupt on complete (IOC) bit set andthe TD was from the periodic schedule.
+ uint32_t nxp_int_async : 1 ; ///< NXP customized: This bit is set by the Host Controller when the cause of an interrupt is a completion of a USB transaction where the Transfer Descriptor (TD) has an interrupt on complete (IOC) bit set and the TD was from the asynchronous schedule. This bit is also set by the Host when a short packet is detected and the packet is on the asynchronous schedule.
+ uint32_t nxp_int_period : 1 ; ///< NXP customized: This bit is set by the Host Controller when the cause of an interrupt is a completion of a USB transaction where the Transfer Descriptor (TD) has an interrupt on complete (IOC) bit set and the TD was from the periodic schedule.
uint32_t : 12 ;
}status_bm;
};
union{
- uint32_t inten;
+ uint32_t inten; // 0x08
struct {
uint32_t usb : 1 ;
@@ -380,43 +380,87 @@ typedef volatile struct
}inten_bm;
};
- uint32_t frame_index ; ///< Micro frame counter
- uint32_t ctrl_ds_seg ; ///< Control Data Structure Segment
- uint32_t periodic_list_base ; ///< Beginning address of perodic frame list
- uint32_t async_list_addr ; ///< Address of next async QHD to be executed
+ uint32_t frame_index ; ///< 0x0C Micro frame counter
+ uint32_t ctrl_ds_seg ; ///< 0x10 Control Data Structure Segment
+ uint32_t periodic_list_base ; ///< 0x14 Beginning address of perodic frame list
+ uint32_t async_list_addr ; ///< 0x18 Address of next async QHD to be executed
uint32_t nxp_tt_control ; ///< nxp embedded transaction translator (reserved by EHCI specs)
uint32_t reserved[8] ;
- uint32_t config_flag ; ///< not used by NXP
+ uint32_t config_flag ; ///< 0x40 not used by NXP
union {
- uint32_t portsc ; ///< port status and control
- struct {
- uint32_t current_connect_status : 1; ///< 0: No device, 1: Device is present on port
- uint32_t connect_status_change : 1; ///< Change in Current Connect Status
- uint32_t port_enabled : 1; ///< Ports can only be enabled by HC as a part of the reset and enable. SW can write 0 to disable
- uint32_t port_enable_change : 1; ///< Port Enabled has changed
- uint32_t over_current_active : 1; ///< Port has an over-current condition
- uint32_t over_current_change : 1; ///< Change to Over-current Active
- uint32_t force_port_resume : 1; ///< Resume detected/driven on port. This functionality defined for manipulating this bit depends on the value of the Suspend bit.
- uint32_t suspend : 1; ///< Port in suspend state
- uint32_t port_reset : 1; ///< 1=Port is in Reset. 0=Port is not in Reset
- uint32_t nxp_highspeed_status : 1; ///< NXP customized: 0=connected to the port is not in High-speed mode, 1=connected to the port is in High-speed mode
- uint32_t line_status : 2; ///< D+/D- state: 00: SE0, 10: J-state, 01: K-state
- uint32_t port_power : 1; ///< 0= power off, 1= power on
- uint32_t port_owner : 1; ///< not used by NXP
- uint32_t port_indicator_control : 2; ///< 00b: off, 01b: Amber, 10b: green, 11b: undefined
- uint32_t port_test_control : 4; ///< Port test mode, not used by tinyusb
- uint32_t wake_on_connect_enable : 1; ///< Enables device connects as wake-up events
- uint32_t wake_on_disconnect_enable : 1; ///< Enables device disconnects as wake-up events
- uint32_t wake_on_over_current_enable : 1; ///< Enables over-current conditions as wake-up events
- uint32_t nxp_phy_clock_disable : 1; ///< NXP customized: the PHY can be put into Low Power Suspend – Clock Disable when the downstream device has been put into suspend mode or when no downstream device is connected. Low power suspend is completely under the control of software. 0: enable PHY clock, 1: disable PHY clock
- uint32_t nxp_port_force_fullspeed : 1; ///< NXP customized: Writing this bit to a 1 will force the port to only connect at Full Speed. It disables the chirp sequence that allowsthe port to identify itself as High Speed. This is useful for testing FS configurations with a HS host, hub or device.
- uint32_t : 1;
- uint32_t nxp_port_speed : 2; ///< NXP customized: This register field indicates the speed atwhich the port is operating. For HS mode operation in the host controllerand HS/FS operation in the device controller the port routing steers data to the Protocol engine. For FS and LS mode operation in the host controller, the port routing steers data to the Protocol Engine w/ Embedded Transaction Translator. 0x0: Fullspeed, 0x1: Lowspeed, 0x2: Highspeed
+ // mixed with RW and R/WC bits, care should be taken when writing to this register
+ uint32_t portsc ; ///< 0x44 port status and control
+ const struct {
+ uint32_t current_connect_status : 1; ///< 00: 0: No device, 1: Device is present on port
+ uint32_t connect_status_change : 1; ///< 01: [R/WC] Change in Current Connect Status
+ uint32_t port_enabled : 1; ///< 02: Ports can only be enabled by HC as a part of the reset and enable. SW can write 0 to disable
+ uint32_t port_enable_change : 1; ///< 03: [R/WC] Port Enabled has changed
+ uint32_t over_current_active : 1; ///< 04: Port has an over-current condition
+ uint32_t over_current_change : 1; ///< 05: [R/WC] Change to Over-current Active
+ uint32_t force_port_resume : 1; ///< 06: Resume detected/driven on port. This functionality defined for manipulating this bit depends on the value of the Suspend bit.
+ uint32_t suspend : 1; ///< 07: Port in suspend state
+ uint32_t port_reset : 1; ///< 08: 1=Port is in Reset. 0=Port is not in Reset
+ uint32_t nxp_highspeed_status : 1; ///< 09: NXP customized: 0=connected to the port is not in High-speed mode, 1=connected to the port is in High-speed mode
+ uint32_t line_status : 2; ///< 10-11: D+/D- state: 00: SE0, 10: J-state, 01: K-state
+ uint32_t port_power : 1; ///< 12: 0= power off, 1= power on
+ uint32_t port_owner : 1; ///< 13: not used by NXP
+ uint32_t port_indicator_control : 2; ///< 14-15: 00b: off, 01b: Amber, 10b: green, 11b: undefined
+ uint32_t port_test_control : 4; ///< 16-19: Port test mode, not used by tinyusb
+ uint32_t wake_on_connect_enable : 1; ///< 20: Enables device connects as wake-up events
+ uint32_t wake_on_disconnect_enable : 1; ///< 21: Enables device disconnects as wake-up events
+ uint32_t wake_on_over_current_enable : 1; ///< 22: Enables over-current conditions as wake-up events
+ uint32_t nxp_phy_clock_disable : 1; ///< 23: NXP customized: the PHY can be put into Low Power Suspend – Clock Disable when the downstream device has been put into suspend mode or when no downstream device is connected. Low power suspend is completely under the control of software. 0: enable PHY clock, 1: disable PHY clock
+ uint32_t nxp_port_force_fullspeed : 1; ///< 24: NXP customized: Writing this bit to a 1 will force the port to only connect at Full Speed. It disables the chirp sequence that allowsthe port to identify itself as High Speed. This is useful for testing FS configurations with a HS host, hub or device.
+ uint32_t TU_RESERVED : 1; ///< 25
+ uint32_t nxp_port_speed : 2; ///< 26-27: NXP customized: This register field indicates the speed atwhich the port is operating. For HS mode operation in the host controllerand HS/FS operation in the device controller the port routing steers data to the Protocol engine. For FS and LS mode operation in the host controller, the port routing steers data to the Protocol Engine w/ Embedded Transaction Translator. 0x0: Fullspeed, 0x1: Lowspeed, 0x2: Highspeed
uint32_t TU_RESERVED : 4;
}portsc_bm;
};
-}ehci_registers_t;
+} ehci_registers_t;
+
+//--------------------------------------------------------------------+
+// Capability Registers
+//--------------------------------------------------------------------+
+typedef volatile struct {
+ uint8_t caplength; // 0x00
+ uint8_t TU_RESERVED; // 0x01
+ uint16_t hciversion; // 0x02
+
+ union {
+ uint32_t hcsparams; // 0x04
+ struct {
+ uint32_t num_ports : 4; // [00:03]
+ uint32_t port_power_control : 1; // [04]
+ uint32_t TU_RESERVED : 2; // [05:06]
+ uint32_t port_route_rule : 1; // [07]
+ uint32_t n_pcc : 4; // [08:11] Number of Ports per Companion Controller
+ uint32_t n_cc : 4; // [12:15] Number of Companion Controllers
+ uint32_t port_ind : 1; // [16] Port Indicators
+ uint32_t TU_RESERVED : 3; // [17:19]
+ uint32_t n_ptt : 4; // [20:23] ChipIdea: Number of Ports per Transaction Translator
+ uint32_t n_tt : 4; // [24:27] ChipIdea: Number of Transaction Translators
+ uint32_t TU_RESERVED : 4; // [28:31]
+ } hcsparams_bm;
+ };
+
+ union {
+ uint32_t hccparams; // 0x08
+ struct {
+ uint32_t addr_64bit : 1; // [00] 64-bit Addressing Capability
+ uint32_t programmable_frame_list_flag : 1; // [01] Programmable Frame List Flag
+ uint32_t async_park_cap : 1; // [02] Asynchronous Schedule Park Capability
+ uint32_t TU_RESERVED : 1; // [03]
+ uint32_t iso_schedule_threshold : 4; // [4:7] Isochronous Scheduling Threshold
+ uint32_t eecp : 8; // [8:15] EHCI Extended Capabilities Pointer
+ uint32_t TU_RESERVED : 16;// [16:31]
+ } hccparams_bm;
+ };
+
+ uint32_t hcsp_portroute; // 0x0C HCSP Port Route Register
+} ehci_cap_registers_t;
+
+TU_VERIFY_STATIC(sizeof(ehci_cap_registers_t) == 16, "size is not correct");
#ifdef __cplusplus
}
diff --git a/src/portable/ehci/hcd_ehci.h b/src/portable/ehci/ehci_api.h
index 480d11eda..12e0a73d7 100644
--- a/src/portable/ehci/hcd_ehci.h
+++ b/src/portable/ehci/ehci_api.h
@@ -24,27 +24,19 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_HCD_EHCI_H_
-#define _TUSB_HCD_EHCI_H_
+#ifndef _TUSB_EHCI_API_H_
+#define _TUSB_EHCI_API_H_
#ifdef __cplusplus
extern "C" {
#endif
-
-//--------------------------------------------------------------------+
-// API Implemented by HCD
-//--------------------------------------------------------------------+
-
-// Get operational address i.e EHCI Command register
-uint32_t hcd_ehci_register_addr(uint8_t rhport);
-
//--------------------------------------------------------------------+
// API Implemented by EHCI
//--------------------------------------------------------------------+
// Initialize EHCI driver
-extern bool hcd_ehci_init (uint8_t rhport);
+bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg);
#ifdef __cplusplus
}
diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c
index d728487c2..bfc0baa56 100644
--- a/src/portable/espressif/esp32sx/dcd_esp32sx.c
+++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c
@@ -28,23 +28,28 @@
#include "tusb_option.h"
-#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && TUSB_OPT_DEVICE_ENABLED)
+#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && CFG_TUD_ENABLED)
// Espressif
-#include "driver/periph_ctrl.h"
-#include "freertos/xtensa_api.h"
+#include "xtensa_api.h"
#include "esp_intr_alloc.h"
#include "esp_log.h"
-#include "driver/gpio.h"
#include "soc/dport_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/usb_periph.h"
+#include "soc/usb_reg.h"
+#include "soc/usb_struct.h"
+#include "soc/periph_defs.h" // for interrupt source
#include "device/dcd.h"
-// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
-// We disable SOF for now until needed later on
-#define USE_SOF 0
+#ifndef USB_OUT_EP_NUM
+#define USB_OUT_EP_NUM ((int) (sizeof(USB0.out_ep_reg) / sizeof(USB0.out_ep_reg[0])))
+#endif
+
+#ifndef USB_IN_EP_NUM
+#define USB_IN_EP_NUM ((int) (sizeof(USB0.in_ep_reg) / sizeof(USB0.in_ep_reg[0])))
+#endif
// Max number of bi-directional endpoints including EP0
// Note: ESP32S2 specs say there are only up to 5 IN active endpoints include EP0
@@ -64,6 +69,7 @@ typedef struct {
uint16_t queued_len;
uint16_t max_size;
bool short_packet;
+ uint8_t interval;
} xfer_ctl_t;
static const char *TAG = "TUSB:DCD";
@@ -92,11 +98,12 @@ static void bus_reset(void)
USB0.out_ep_reg[ep_num].doepctl |= USB_DO_SNAK0_M; // DOEPCTL0_SNAK
}
- USB0.dcfg &= ~USB_DEVADDR_M; // reset address
+ // clear device address
+ USB0.dcfg &= ~USB_DEVADDR_M;
- USB0.daintmsk |= USB_OUTEPMSK0_M | USB_INEPMSK0_M;
- USB0.doepmsk |= USB_SETUPMSK_M | USB_XFERCOMPLMSK;
- USB0.diepmsk |= USB_TIMEOUTMSK_M | USB_DI_XFERCOMPLMSK_M /*| USB_INTKNTXFEMPMSK_M*/;
+ USB0.daintmsk = USB_OUTEPMSK0_M | USB_INEPMSK0_M;
+ USB0.doepmsk = USB_SETUPMSK_M | USB_XFERCOMPLMSK;
+ USB0.diepmsk = USB_TIMEOUTMSK_M | USB_DI_XFERCOMPLMSK_M /*| USB_INTKNTXFEMPMSK_M*/;
// "USB Data FIFOs" section in reference manual
// Peripheral FIFO architecture
@@ -193,9 +200,6 @@ void dcd_init(uint8_t rhport)
USB0.gintsts = ~0U; //clear pending ints
USB0.gintmsk = USB_OTGINTMSK_M |
USB_MODEMISMSK_M |
- #if USE_SOF
- USB_SOFMSK_M |
- #endif
USB_RXFLVIMSK_M |
USB_ERLYSUSPMSK_M |
USB_USBSUSPMSK_M |
@@ -220,8 +224,17 @@ void dcd_remote_wakeup(uint8_t rhport)
{
(void)rhport;
- // TODO must manually clear this bit after 1-15 ms
- // USB0.DCTL |= USB_RMTWKUPSIG_M;
+ // set remote wakeup
+ USB0.dctl |= USB_RMTWKUPSIG_M;
+
+ // enable SOF to detect bus resume
+ USB0.gintsts = USB_SOF_M;
+ USB0.gintmsk |= USB_SOFMSK_M;
+
+ // Per specs: remote wakeup signal bit must be clear within 1-15ms
+ vTaskDelay(pdMS_TO_TICKS(1));
+
+ USB0.dctl &= ~USB_RMTWKUPSIG_M;
}
// connect by enabling internal pull-up resistor on D+/D-
@@ -238,6 +251,14 @@ void dcd_disconnect(uint8_t rhport)
USB0.dctl |= USB_SFTDISCON_M;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
@@ -253,16 +274,17 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
- TU_ASSERT(desc_edpt->wMaxPacketSize.size <= 64);
TU_ASSERT(epnum < EP_MAX);
xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
- xfer->max_size = desc_edpt->wMaxPacketSize.size;
+ xfer->max_size = tu_edpt_packet_size(desc_edpt);
+ xfer->interval = desc_edpt->bInterval;
if (dir == TUSB_DIR_OUT) {
- out_ep[epnum].doepctl |= USB_USBACTEP0_M |
- desc_edpt->bmAttributes.xfer << USB_EPTYPE0_S |
- desc_edpt->wMaxPacketSize.size << USB_MPS0_S;
+ out_ep[epnum].doepctl |= USB_USBACTEP1_M |
+ desc_edpt->bmAttributes.xfer << USB_EPTYPE1_S |
+ (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_DO_SETD0PID1_M : 0) |
+ xfer->max_size << USB_MPS1_S;
USB0.daintmsk |= (1 << (16 + epnum));
} else {
// "USB Data FIFOs" section in reference manual
@@ -296,7 +318,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
fifo_num << USB_D_TXFNUM1_S |
desc_edpt->bmAttributes.xfer << USB_D_EPTYPE1_S |
(desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? (1 << USB_DI_SETD0PID1_S) : 0) |
- desc_edpt->wMaxPacketSize.size << 0;
+ xfer->max_size << 0;
USB0.daintmsk |= (1 << (0 + epnum));
@@ -312,65 +334,40 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
return true;
}
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+void dcd_edpt_close_all(uint8_t rhport)
{
- (void)rhport;
+ (void) rhport;
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
+ usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = buffer;
- // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
- xfer->total_len = total_bytes;
- xfer->queued_len = 0;
- xfer->short_packet = false;
+ // Disable non-control interrupt
+ USB0.daintmsk = USB_OUTEPMSK0_M | USB_INEPMSK0_M;
- uint16_t num_packets = (total_bytes / xfer->max_size);
- uint8_t short_packet_size = total_bytes % xfer->max_size;
+ for(uint8_t n = 1; n < EP_MAX; n++)
+ {
+ // disable OUT endpoint
+ out_ep[n].doepctl = 0;
+ xfer_status[n][TUSB_DIR_OUT].max_size = 0;
- // Zero-size packet is special case.
- if (short_packet_size > 0 || (total_bytes == 0)) {
- num_packets++;
+ // disable IN endpoint
+ in_ep[n].diepctl = 0;
+ xfer_status[n][TUSB_DIR_IN].max_size = 0;
}
- ESP_LOGV(TAG, "Transfer <-> EP%i, %s, pkgs: %i, bytes: %i",
- epnum, ((dir == TUSB_DIR_IN) ? "USB0.HOST (in)" : "HOST->DEV (out)"),
- num_packets, total_bytes);
-
- // IN and OUT endpoint xfers are interrupt-driven, we just schedule them
- // here.
- if (dir == TUSB_DIR_IN) {
- // A full IN transfer (multiple packets, possibly) triggers XFRC.
- USB0.in_ep_reg[epnum].dieptsiz = (num_packets << USB_D_PKTCNT0_S) | total_bytes;
- USB0.in_ep_reg[epnum].diepctl |= USB_D_EPENA1_M | USB_D_CNAK1_M; // Enable | CNAK
-
- // Enable fifo empty interrupt only if there are something to put in the fifo.
- if(total_bytes != 0) {
- USB0.dtknqr4_fifoemptymsk |= (1 << epnum);
- }
- } else {
- // Each complete packet for OUT xfers triggers XFRC.
- USB0.out_ep_reg[epnum].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
- USB0.out_ep_reg[epnum].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
- }
- return true;
+ _allocated_fifos = 1;
}
-#if 0 // TODO support dcd_edpt_xfer_fifo API
-bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
(void)rhport;
- // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
- TU_ASSERT(ff->item_size == 1);
-
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = NULL;
- xfer->ff = ff;
+ xfer->buffer = buffer;
+ // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
xfer->total_len = total_bytes;
xfer->queued_len = 0;
xfer->short_packet = false;
@@ -394,6 +391,13 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
USB0.in_ep_reg[epnum].dieptsiz = (num_packets << USB_D_PKTCNT0_S) | total_bytes;
USB0.in_ep_reg[epnum].diepctl |= USB_D_EPENA1_M | USB_D_CNAK1_M; // Enable | CNAK
+ // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame
+ if ((USB0.in_ep_reg[epnum].diepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) {
+ // Take odd/even bit from frame counter.
+ uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S));
+ USB0.in_ep_reg[epnum].diepctl |= (odd_frame_now ? USB_DI_SETD0PID1 : USB_DI_SETD1PID1);
+ }
+
// Enable fifo empty interrupt only if there are something to put in the fifo.
if(total_bytes != 0) {
USB0.dtknqr4_fifoemptymsk |= (1 << epnum);
@@ -402,9 +406,22 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
// Each complete packet for OUT xfers triggers XFRC.
USB0.out_ep_reg[epnum].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
USB0.out_ep_reg[epnum].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
+
+ // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame
+ if ((USB0.out_ep_reg[epnum].doepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) {
+ // Take odd/even bit from frame counter.
+ uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S));
+ USB0.out_ep_reg[epnum].doepctl |= (odd_frame_now ? USB_DO_SETD0PID1 : USB_DO_SETD1PID1);
+ }
}
return true;
}
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+ (void)rhport;
+}
#endif
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
@@ -734,7 +751,7 @@ static void handle_epin_ints(void)
// XFER Timeout
if (USB0.in_ep_reg[n].diepint & USB_D_TIMEOUT0_M) {
- // Clear interrupt or enpoint will hang.
+ // Clear interrupt or endpoint will hang.
USB0.in_ep_reg[n].diepint = USB_D_TIMEOUT0_M;
// Maybe retry?
}
@@ -748,8 +765,8 @@ static void _dcd_int_handler(void* arg)
(void) arg;
uint8_t const rhport = 0;
- const uint32_t int_status = USB0.gintsts;
- //const uint32_t int_msk = USB0.gintmsk;
+ const uint32_t int_msk = USB0.gintmsk;
+ const uint32_t int_status = USB0.gintsts & int_msk;
if (int_status & USB_USBRST_M) {
// start of reset
@@ -802,12 +819,15 @@ static void _dcd_int_handler(void* arg)
USB0.gotgint = otg_int;
}
-#if USE_SOF
if (int_status & USB_SOF_M) {
USB0.gintsts = USB_SOF_M;
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); // do nothing actually
+
+ // Disable SOF interrupt since currently only used for remote wakeup detection
+ USB0.gintmsk &= ~USB_SOFMSK_M;
+
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
}
-#endif
+
if (int_status & USB_RXFLVI_M) {
// RXFLVL bit is read-only
@@ -864,4 +884,3 @@ void dcd_int_disable (uint8_t rhport)
}
#endif // #if OPT_MCU_ESP32S2 || OPT_MCU_ESP32S3
-
diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c
new file mode 100644
index 000000000..a817c5d6e
--- /dev/null
+++ b/src/portable/mentor/musb/dcd_musb.c
@@ -0,0 +1,908 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && \
+ TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+
+#if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED)
+/* GCC warns that an address may be unaligned, even though
+ * the target CPU has the capability for unaligned memory access. */
+_Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");
+#endif
+
+#include "device/dcd.h"
+
+#if TU_CHECK_MCU(OPT_MCU_MSP432E4)
+ #include "musb_msp432e.h"
+
+#elif TU_CHECK_MCU(OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+ #include "musb_tm4c.h"
+
+ // HACK generalize later
+ #include "musb_type.h"
+ #define FIFO0_WORD FIFO0
+ #define FIFO1_WORD FIFO1
+
+#else
+ #error "Unsupported MCUs"
+#endif
+
+/*------------------------------------------------------------------
+ * MACRO TYPEDEF CONSTANT ENUM DECLARATION
+ *------------------------------------------------------------------*/
+#define REQUEST_TYPE_INVALID (0xFFu)
+
+typedef struct {
+ uint_fast16_t beg; /* offset of including first element */
+ uint_fast16_t end; /* offset of excluding the last element */
+} free_block_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint16_t TXMAXP;
+ uint8_t TXCSRL;
+ uint8_t TXCSRH;
+ uint16_t RXMAXP;
+ uint8_t RXCSRL;
+ uint8_t RXCSRH;
+ uint16_t RXCOUNT;
+ uint16_t RESERVED[3];
+} hw_endpoint_t;
+
+typedef union {
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+} hw_fifo_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ void *buf; /* the start address of a transfer data buffer */
+ uint16_t length; /* the number of bytes in the buffer */
+ uint16_t remaining; /* the number of bytes remaining in the buffer */
+} pipe_state_t;
+
+typedef struct
+{
+ tusb_control_request_t setup_packet;
+ uint16_t remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */
+ int8_t status_out;
+ pipe_state_t pipe0;
+ pipe_state_t pipe[2][7]; /* pipe[direction][endpoint number - 1] */
+ uint16_t pipe_buf_is_fifo[2]; /* Bitmap. Each bit means whether 1:TU_FIFO or 0:POD. */
+} dcd_data_t;
+
+/*------------------------------------------------------------------
+ * INTERNAL OBJECT & FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+static dcd_data_t _dcd;
+
+
+static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
+{
+ free_block_t *cur = beg;
+ for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ;
+ return cur;
+}
+
+static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size)
+{
+ free_block_t *p = find_containing_block(blks, blks + num, addr);
+ TU_ASSERT(p != blks + num, -2);
+ if (p->beg == addr) {
+ /* Shrink block */
+ p->beg = addr + size;
+ if (p->beg != p->end) return 0;
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ } else {
+ /* Split into 2 blocks */
+ free_block_t tmp = {
+ .beg = addr + size,
+ .end = p->end
+ };
+ p->end = addr;
+ if (p->beg == p->end) {
+ if (tmp.beg != tmp.end) {
+ *p = tmp;
+ return 0;
+ }
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ }
+ if (tmp.beg == tmp.end) return 0;
+ blks[num] = tmp;
+ return 1;
+ }
+}
+
+static inline unsigned free_block_size(free_block_t const *blk)
+{
+ return blk->end - blk->beg;
+}
+
+#if 0
+static inline void print_block_list(free_block_t const *blk, unsigned num)
+{
+ TU_LOG1("*************\r\n");
+ for (unsigned i = 0; i < num; ++i) {
+ TU_LOG1(" Blk%u %u %u\r\n", i, blk->beg, blk->end);
+ ++blk;
+ }
+}
+#else
+#define print_block_list(a,b)
+#endif
+
+static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
+{
+ free_block_t free_blocks[2 * (TUP_DCD_ENDPOINT_MAX - 1)];
+ unsigned num_blocks = 1;
+
+ /* Initialize free memory block list */
+ free_blocks[0].beg = 64 / 8;
+ free_blocks[0].end = (4 << 10) / 8; /* 4KiB / 8 bytes */
+ for (int i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
+ uint_fast16_t addr;
+ int num;
+ USB0->EPIDX = i;
+ addr = USB0->TXFIFOADD;
+ if (addr) {
+ unsigned sz = USB0->TXFIFOSZ;
+ unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ print_block_list(free_blocks, num_blocks);
+ }
+ addr = USB0->RXFIFOADD;
+ if (addr) {
+ unsigned sz = USB0->RXFIFOSZ;
+ unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ print_block_list(free_blocks, num_blocks);
+ }
+ }
+ print_block_list(free_blocks, num_blocks);
+
+ /* Find the best fit memory block */
+ uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3;
+ free_block_t const *min = NULL;
+ uint_fast16_t min_sz = 0xFFFFu;
+ free_block_t const *end = &free_blocks[num_blocks];
+ for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) {
+ uint_fast16_t sz = free_block_size(cur);
+ if (sz < size_in_8byte_unit) continue;
+ if (size_in_8byte_unit == sz) return cur->beg;
+ if (sz < min_sz) min = cur;
+ }
+ TU_ASSERT(min, 0);
+ return min->beg;
+}
+
+static inline volatile hw_endpoint_t* edpt_regs(unsigned epnum_minus1)
+{
+ volatile hw_endpoint_t *regs = (volatile hw_endpoint_t*)((uintptr_t)&USB0->TXMAXP1);
+ return regs + epnum_minus1;
+}
+
+static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 4) {
+ reg->u32 = *(uint32_t const *)addr;
+ addr += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ reg->u16 = *(uint16_t const *)addr;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ reg->u8 = *(uint8_t const *)addr;
+ }
+}
+
+static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 4) {
+ *(uint32_t *)addr = reg->u32;
+ addr += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ *(uint16_t *)addr = reg->u16;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ *(uint8_t *)addr = reg->u8;
+ }
+}
+
+static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigned len, unsigned dir)
+{
+ static const struct {
+ void (*tu_fifo_get_info)(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
+ void (*tu_fifo_advance)(tu_fifo_t *f, uint16_t n);
+ void (*pipe_read_write)(void *buf, volatile void *fifo, unsigned len);
+ } ops[] = {
+ /* OUT */ {tu_fifo_get_write_info,tu_fifo_advance_write_pointer,pipe_read_packet},
+ /* IN */ {tu_fifo_get_read_info, tu_fifo_advance_read_pointer, pipe_write_packet},
+ };
+ tu_fifo_buffer_info_t info;
+ ops[dir].tu_fifo_get_info(f, &info);
+ unsigned total_len = len;
+ len = TU_MIN(total_len, info.len_lin);
+ ops[dir].pipe_read_write(info.ptr_lin, fifo, len);
+ unsigned rem = total_len - len;
+ if (rem) {
+ len = TU_MIN(rem, info.len_wrap);
+ ops[dir].pipe_read_write(info.ptr_wrap, fifo, len);
+ rem -= len;
+ }
+ ops[dir].tu_fifo_advance(f, total_len - rem);
+}
+
+static void process_setup_packet(uint8_t rhport)
+{
+ uint32_t *p = (void*)&_dcd.setup_packet;
+ p[0] = USB0->FIFO0_WORD;
+ p[1] = USB0->FIFO0_WORD;
+
+ _dcd.pipe0.buf = NULL;
+ _dcd.pipe0.length = 0;
+ _dcd.pipe0.remaining = 0;
+ dcd_event_setup_received(rhport, (const uint8_t*)(uintptr_t)&_dcd.setup_packet, true);
+
+ const unsigned len = _dcd.setup_packet.wLength;
+ _dcd.remaining_ctrl = len;
+ const unsigned dir_in = tu_edpt_dir(_dcd.setup_packet.bmRequestType);
+ /* Clear RX FIFO and reverse the transaction direction */
+ if (len && dir_in) USB0->CSRL0 = USB_CSRL0_RXRDYC;
+}
+
+static bool handle_xfer_in(uint_fast8_t ep_addr)
+{
+ unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
+ const unsigned rem = pipe->remaining;
+
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+
+ volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1);
+ const unsigned mps = regs->TXMAXP;
+ const unsigned len = TU_MIN(mps, rem);
+ void *buf = pipe->buf;
+ // TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem);
+ if (len) {
+ if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
+ pipe_read_write_packet_ff(buf, &USB0->FIFO1_WORD + epnum_minus1, len, TUSB_DIR_IN);
+ } else {
+ pipe_write_packet(buf, &USB0->FIFO1_WORD + epnum_minus1, len);
+ pipe->buf = buf + len;
+ }
+ pipe->remaining = rem - len;
+ }
+ regs->TXCSRL = USB_TXCSRL1_TXRDY;
+ // TU_LOG1(" TXCSRL%d = %x %d\r\n", epnum_minus1 + 1, regs->TXCSRL, rem - len);
+ return false;
+}
+
+static bool handle_xfer_out(uint_fast8_t ep_addr)
+{
+ unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
+ volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1);
+ // TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, regs->RXCSRL);
+
+ TU_ASSERT(regs->RXCSRL & USB_RXCSRL1_RXRDY);
+
+ const unsigned mps = regs->RXMAXP;
+ const unsigned rem = pipe->remaining;
+ const unsigned vld = regs->RXCOUNT;
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
+ pipe_read_write_packet_ff(buf, &USB0->FIFO1_WORD + epnum_minus1, len, TUSB_DIR_OUT);
+ } else {
+ pipe_read_packet(buf, &USB0->FIFO1_WORD + epnum_minus1, len);
+ pipe->buf = buf + len;
+ }
+ pipe->remaining = rem - len;
+ }
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return NULL != buf;
+ }
+ regs->RXCSRL = 0; /* Clear RXRDY bit */
+ return false;
+}
+
+static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+
+ unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ unsigned dir_in = tu_edpt_dir(ep_addr);
+
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][epnum_minus1];
+ pipe->buf = buffer;
+ pipe->length = total_bytes;
+ pipe->remaining = total_bytes;
+
+ if (dir_in) {
+ handle_xfer_in(ep_addr);
+ } else {
+ volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1);
+ if (regs->RXCSRL & USB_RXCSRL1_RXRDY) regs->RXCSRL = 0;
+ }
+ return true;
+}
+
+static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+ TU_ASSERT(total_bytes <= 64); /* Current implementation supports for only up to 64 bytes. */
+
+ const unsigned req = _dcd.setup_packet.bmRequestType;
+ TU_ASSERT(req != REQUEST_TYPE_INVALID || total_bytes == 0);
+
+ if (req == REQUEST_TYPE_INVALID || _dcd.status_out) {
+ /* STATUS OUT stage.
+ * MUSB controller automatically handles STATUS OUT packets without
+ * software helps. We do not have to do anything. And STATUS stage
+ * may have already finished and received the next setup packet
+ * without calling this function, so we have no choice but to
+ * invoke the callback function of status packet here. */
+ // TU_LOG1(" STATUS OUT USB0->CSRL0 = %x\r\n", USB0->CSRL0);
+ _dcd.status_out = 0;
+ if (req == REQUEST_TYPE_INVALID) {
+ dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false);
+ } else {
+ /* The next setup packet has already been received, it aborts
+ * invoking callback function to avoid confusing TUSB stack. */
+ TU_LOG1("Drop CONTROL_STAGE_ACK\r\n");
+ }
+ return true;
+ }
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ if (tu_edpt_dir(req) == dir_in) { /* DATA stage */
+ TU_ASSERT(total_bytes <= _dcd.remaining_ctrl);
+ const unsigned rem = _dcd.remaining_ctrl;
+ const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes);
+ if (dir_in) {
+ pipe_write_packet(buffer, &USB0->FIFO0_WORD, len);
+
+ _dcd.pipe0.buf = buffer + len;
+ _dcd.pipe0.length = len;
+ _dcd.pipe0.remaining = 0;
+
+ _dcd.remaining_ctrl = rem - len;
+ if ((len < 64) || (rem == len)) {
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; /* Change to STATUS/SETUP stage */
+ _dcd.status_out = 1;
+ /* Flush TX FIFO and reverse the transaction direction. */
+ USB0->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_DATAEND;
+ } else {
+ USB0->CSRL0 = USB_CSRL0_TXRDY; /* Flush TX FIFO to return ACK. */
+ }
+ // TU_LOG1(" IN USB0->CSRL0 = %x\r\n", USB0->CSRL0);
+ } else {
+ // TU_LOG1(" OUT USB0->CSRL0 = %x\r\n", USB0->CSRL0);
+ _dcd.pipe0.buf = buffer;
+ _dcd.pipe0.length = len;
+ _dcd.pipe0.remaining = len;
+ USB0->CSRL0 = USB_CSRL0_RXRDYC; /* Clear RX FIFO to return ACK. */
+ }
+ } else if (dir_in) {
+ // TU_LOG1(" STATUS IN USB0->CSRL0 = %x\r\n", USB0->CSRL0);
+ _dcd.pipe0.buf = NULL;
+ _dcd.pipe0.length = 0;
+ _dcd.pipe0.remaining = 0;
+ /* Clear RX FIFO and reverse the transaction direction */
+ USB0->CSRL0 = USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND;
+ }
+ return true;
+}
+
+static void process_ep0(uint8_t rhport)
+{
+ uint_fast8_t csrl = USB0->CSRL0;
+
+ // TU_LOG1(" EP0 USB0->CSRL0 = %x\r\n", csrl);
+
+ if (csrl & USB_CSRL0_STALLED) {
+ /* Returned STALL packet to HOST. */
+ USB0->CSRL0 = 0; /* Clear STALL */
+ return;
+ }
+
+ unsigned req = _dcd.setup_packet.bmRequestType;
+ if (csrl & USB_CSRL0_SETEND) {
+ TU_LOG1(" ABORT by the next packets\r\n");
+ USB0->CSRL0 = USB_CSRL0_SETENDC;
+ if (req != REQUEST_TYPE_INVALID && _dcd.pipe0.buf) {
+ /* DATA stage was aborted by receiving STATUS or SETUP packet. */
+ _dcd.pipe0.buf = NULL;
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ dcd_event_xfer_complete(rhport,
+ req & TUSB_DIR_IN_MASK,
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+ req = REQUEST_TYPE_INVALID;
+ if (!(csrl & USB_CSRL0_RXRDY)) return; /* Received SETUP packet */
+ }
+
+ if (csrl & USB_CSRL0_RXRDY) {
+ /* Received SETUP or DATA OUT packet */
+ if (req == REQUEST_TYPE_INVALID) {
+ /* SETUP */
+ TU_ASSERT(sizeof(tusb_control_request_t) == USB0->COUNT0,);
+ process_setup_packet(rhport);
+ return;
+ }
+ if (_dcd.pipe0.buf) {
+ /* DATA OUT */
+ const unsigned vld = USB0->COUNT0;
+ const unsigned rem = _dcd.pipe0.remaining;
+ const unsigned len = TU_MIN(TU_MIN(rem, 64), vld);
+ pipe_read_packet(_dcd.pipe0.buf, &USB0->FIFO0_WORD, len);
+
+ _dcd.pipe0.remaining = rem - len;
+ _dcd.remaining_ctrl -= len;
+
+ _dcd.pipe0.buf = NULL;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(0, TUSB_DIR_OUT),
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+ return;
+ }
+
+ /* When CSRL0 is zero, it means that completion of sending a any length packet
+ * or receiving a zero length packet. */
+ if (req != REQUEST_TYPE_INVALID && !tu_edpt_dir(req)) {
+ /* STATUS IN */
+ if (*(const uint16_t*)(uintptr_t)&_dcd.setup_packet == 0x0500) {
+ /* The address must be changed on completion of the control transfer. */
+ USB0->FADDR = (uint8_t)_dcd.setup_packet.wValue;
+ }
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(0, TUSB_DIR_IN),
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ return;
+ }
+ if (_dcd.pipe0.buf) {
+ /* DATA IN */
+ _dcd.pipe0.buf = NULL;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(0, TUSB_DIR_IN),
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_edpt_n(uint8_t rhport, uint_fast8_t ep_addr)
+{
+ bool completed;
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned epn_minus1 = tu_edpt_number(ep_addr) - 1;
+
+ volatile hw_endpoint_t *regs = edpt_regs(epn_minus1);
+ if (dir_in) {
+ // TU_LOG1(" TXCSRL%d = %x\r\n", epn_minus1 + 1, regs->TXCSRL);
+ if (regs->TXCSRL & USB_TXCSRL1_STALLED) {
+ regs->TXCSRL &= ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_UNDRN);
+ return;
+ }
+ completed = handle_xfer_in(ep_addr);
+ } else {
+ // TU_LOG1(" RXCSRL%d = %x\r\n", epn_minus1 + 1, regs->RXCSRL);
+ if (regs->RXCSRL & USB_RXCSRL1_STALLED) {
+ regs->RXCSRL &= ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_OVER);
+ return;
+ }
+ completed = handle_xfer_out(ep_addr);
+ }
+
+ if (completed) {
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][tu_edpt_number(ep_addr) - 1];
+ dcd_event_xfer_complete(rhport, ep_addr,
+ pipe->length - pipe->remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+ /* When bmRequestType is REQUEST_TYPE_INVALID(0xFF),
+ * a control transfer state is SETUP or STATUS stage. */
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ _dcd.status_out = 0;
+ /* When pipe0.buf has not NULL, DATA stage works in progress. */
+ _dcd.pipe0.buf = NULL;
+
+ USB0->TXIE = 1; /* Enable only EP0 */
+ USB0->RXIE = 0;
+
+ /* Clear FIFO settings */
+ for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
+ USB0->EPIDX = i;
+ USB0->TXFIFOSZ = 0;
+ USB0->TXFIFOADD = 0;
+ USB0->RXFIFOSZ = 0;
+ USB0->RXFIFOADD = 0;
+ }
+ dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+}
+
+/*------------------------------------------------------------------
+ * Device API
+ *------------------------------------------------------------------*/
+
+void dcd_init(uint8_t rhport)
+{
+ (void)rhport;
+ USB0->IE |= USB_IE_SUSPND;
+ NVIC_ClearPendingIRQ(USB0_IRQn);
+
+ dcd_connect(rhport);
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_DisableIRQ(USB0_IRQn);
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ (void)dev_addr;
+ _dcd.pipe0.buf = NULL;
+ _dcd.pipe0.length = 0;
+ _dcd.pipe0.remaining = 0;
+ /* Clear RX FIFO to return ACK. */
+ USB0->CSRL0 = USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND;
+}
+
+// Wake up host
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void)rhport;
+ USB0->POWER |= USB_POWER_RESUME;
+
+ unsigned cnt = SystemCoreClock / 1000;
+ while (cnt--) __NOP();
+
+ USB0->POWER &= ~USB_POWER_RESUME;
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ (void)rhport;
+ USB0->POWER |= USB_POWER_SOFTCONN;
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ (void)rhport;
+ USB0->POWER &= ~USB_POWER_SOFTCONN;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void) rhport;
+
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ const unsigned mps = tu_edpt_packet_size(ep_desc);
+
+ TU_ASSERT(epn < TUP_DCD_ENDPOINT_MAX);
+
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+
+ volatile hw_endpoint_t *regs = edpt_regs(epn - 1);
+ if (dir_in) {
+ regs->TXMAXP = mps;
+ regs->TXCSRH = (xfer == TUSB_XFER_ISOCHRONOUS) ? USB_TXCSRH1_ISO : 0;
+ if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ USB0->TXIE |= TU_BIT(epn);
+ } else {
+ regs->RXMAXP = mps;
+ regs->RXCSRH = (xfer == TUSB_XFER_ISOCHRONOUS) ? USB_RXCSRH1_ISO : 0;
+ if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ USB0->RXIE |= TU_BIT(epn);
+ }
+
+ /* Setup FIFO */
+ int size_in_log2_minus3 = 28 - TU_MIN(28, __CLZ((uint32_t)mps));
+ if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3;
+ unsigned addr = find_free_memory(size_in_log2_minus3);
+ TU_ASSERT(addr);
+
+ USB0->EPIDX = epn;
+ if (dir_in) {
+ USB0->TXFIFOADD = addr;
+ USB0->TXFIFOSZ = size_in_log2_minus3;
+ } else {
+ USB0->RXFIFOADD = addr;
+ USB0->RXFIFOSZ = size_in_log2_minus3;
+ }
+
+ return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ (void) rhport;
+ volatile hw_endpoint_t *regs = (volatile hw_endpoint_t *)(uintptr_t)&USB0->TXMAXP1;
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ USB0->TXIE = 1; /* Enable only EP0 */
+ USB0->RXIE = 0;
+ for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
+ regs->TXMAXP = 0;
+ regs->TXCSRH = 0;
+ if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+
+ regs->RXMAXP = 0;
+ regs->RXCSRH = 0;
+ if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+
+ USB0->EPIDX = i;
+ USB0->TXFIFOSZ = 0;
+ USB0->TXFIFOADD = 0;
+ USB0->RXFIFOSZ = 0;
+ USB0->RXFIFOADD = 0;
+ }
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ unsigned const dir_in = tu_edpt_dir(ep_addr);
+
+ hw_endpoint_t volatile *regs = edpt_regs(epn - 1);
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ if (dir_in) {
+ USB0->TXIE &= ~TU_BIT(epn);
+ regs->TXMAXP = 0;
+ regs->TXCSRH = 0;
+ if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+
+ USB0->EPIDX = epn;
+ USB0->TXFIFOSZ = 0;
+ USB0->TXFIFOADD = 0;
+ } else {
+ USB0->RXIE &= ~TU_BIT(epn);
+ regs->RXMAXP = 0;
+ regs->RXCSRH = 0;
+ if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+
+ USB0->EPIDX = epn;
+ USB0->RXFIFOSZ = 0;
+ USB0->RXFIFOADD = 0;
+ }
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+ bool ret;
+ // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes);
+ unsigned const epnum = tu_edpt_number(ep_addr);
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ if (epnum) {
+ _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] &= ~TU_BIT(epnum - 1);
+ ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes);
+ } else
+ ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes);
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ return ret;
+}
+
+// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+ (void)rhport;
+ bool ret;
+ // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes);
+ unsigned const epnum = tu_edpt_number(ep_addr);
+ TU_ASSERT(epnum);
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] |= TU_BIT(epnum - 1);
+ ret = edpt_n_xfer(rhport, ep_addr, (uint8_t*)ff, total_bytes);
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ return ret;
+}
+
+// Stall endpoint
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ if (0 == epn) {
+ if (!ep_addr) { /* Ignore EP80 */
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ _dcd.pipe0.buf = NULL;
+ USB0->CSRL0 = USB_CSRL0_STALL;
+ }
+ } else {
+ volatile hw_endpoint_t *regs = edpt_regs(epn - 1);
+ if (tu_edpt_dir(ep_addr)) { /* IN */
+ regs->TXCSRL = USB_TXCSRL1_STALL;
+ } else { /* OUT */
+ TU_ASSERT(!(regs->RXCSRL & USB_RXCSRL1_RXRDY),);
+ regs->RXCSRL = USB_RXCSRL1_STALL;
+ }
+ }
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ hw_endpoint_t volatile *regs = edpt_regs(epn - 1);
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ if (tu_edpt_dir(ep_addr)) { /* IN */
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ } else { /* OUT */
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ }
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+/*-------------------------------------------------------------------
+ * ISR
+ *-------------------------------------------------------------------*/
+void dcd_int_handler(uint8_t rhport)
+{
+ uint_fast8_t is, txis, rxis;
+
+ is = USB0->IS; /* read and clear interrupt status */
+ txis = USB0->TXIS; /* read and clear interrupt status */
+ rxis = USB0->RXIS; /* read and clear interrupt status */
+ // TU_LOG1("D%2x T%2x R%2x\r\n", is, txis, rxis);
+
+ is &= USB0->IE; /* Clear disabled interrupts */
+ if (is & USB_IS_DISCON) {
+ }
+ if (is & USB_IS_SOF) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
+ if (is & USB_IS_RESET) {
+ process_bus_reset(rhport);
+ }
+ if (is & USB_IS_RESUME) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+ }
+ if (is & USB_IS_SUSPEND) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+ }
+
+ txis &= USB0->TXIE; /* Clear disabled interrupts */
+ if (txis & USB_TXIE_EP0) {
+ process_ep0(rhport);
+ txis &= ~TU_BIT(0);
+ }
+ while (txis) {
+ unsigned const num = __builtin_ctz(txis);
+ process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_IN));
+ txis &= ~TU_BIT(num);
+ }
+ rxis &= USB0->RXIE; /* Clear disabled interrupts */
+ while (rxis) {
+ unsigned const num = __builtin_ctz(rxis);
+ process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_OUT));
+ rxis &= ~TU_BIT(num);
+ }
+}
+
+#endif
diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c
new file mode 100644
index 000000000..5312c2812
--- /dev/null
+++ b/src/portable/mentor/musb/hcd_musb.c
@@ -0,0 +1,891 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && \
+ TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+
+#if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED)
+/* GCC warns that an address may be unaligned, even though
+ * the target CPU has the capability for unaligned memory access. */
+_Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");
+#endif
+
+#include "host/hcd.h"
+
+#if TU_CHECK_MCU(OPT_MCU_MSP432E4)
+ #include "musb_msp432e.h"
+
+#elif TU_CHECK_MCU(OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+ #include "musb_tm4c.h"
+
+ // HACK generalize later
+ #include "musb_type.h"
+ #define FIFO0_WORD FIFO0
+
+#else
+ #error "Unsupported MCUs"
+#endif
+
+#ifndef HCD_ATTR_ENDPOINT_MAX
+# define HCD_ATTR_ENDPOINT_MAX 8
+#endif
+
+/*------------------------------------------------------------------
+ * MACRO TYPEDEF CONSTANT ENUM DECLARATION
+ *------------------------------------------------------------------*/
+#define REQUEST_TYPE_INVALID (0xFFu)
+
+typedef struct {
+ uint_fast16_t beg; /* offset of including first element */
+ uint_fast16_t end; /* offset of excluding the last element */
+} free_block_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint8_t TXFUNCADDR;
+ uint8_t RESERVED0;
+ uint8_t TXHUBADDR;
+ uint8_t TXHUBPORT;
+ uint8_t RXFUNCADDR;
+ uint8_t RESERVED1;
+ uint8_t RXHUBADDR;
+ uint8_t RXHUBPORT;
+} hw_addr_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint16_t TXMAXP;
+ uint8_t TXCSRL;
+ uint8_t TXCSRH;
+ uint16_t RXMAXP;
+ uint8_t RXCSRL;
+ uint8_t RXCSRH;
+ uint16_t RXCOUNT;
+ uint8_t TXTYPE;
+ uint8_t TXINTERVAL;
+ uint8_t RXTYPE;
+ uint8_t RXINTERVAL;
+ uint16_t RESERVED;
+} hw_endpoint_t;
+
+typedef union {
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+} hw_fifo_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ void *buf; /* the start address of a transfer data buffer */
+ uint16_t length; /* the number of bytes in the buffer */
+ uint16_t remaining; /* the number of bytes remaining in the buffer */
+} pipe_state_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ uint8_t dev;
+ uint8_t ep;
+} pipe_addr_t;
+
+typedef struct
+{
+ bool need_reset; /* The device has not been reset after connection. */
+ uint8_t bmRequestType;
+ uint8_t ctl_mps[7]; /* EP0 max packet size for each device */
+ pipe_state_t pipe0;
+ pipe_state_t pipe[7][2]; /* pipe[pipe number - 1][direction 0:RX 1:TX] */
+ pipe_addr_t addr[7][2]; /* addr[pipe number - 1][direction 0:RX 1:TX] */
+} hcd_data_t;
+
+/*------------------------------------------------------------------
+ * INTERNAL OBJECT & FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+static hcd_data_t _hcd;
+
+static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
+{
+ free_block_t *cur = beg;
+ for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ;
+ return cur;
+}
+
+static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size)
+{
+ free_block_t *p = find_containing_block(blks, blks + num, addr);
+ TU_ASSERT(p != blks + num, -2);
+ if (p->beg == addr) {
+ /* Shrink block */
+ p->beg = addr + size;
+ if (p->beg != p->end) return 0;
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ } else {
+ /* Split into 2 blocks */
+ free_block_t tmp = {
+ .beg = addr + size,
+ .end = p->end
+ };
+ p->end = addr;
+ if (p->beg == p->end) {
+ if (tmp.beg != tmp.end) {
+ *p = tmp;
+ return 0;
+ }
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ }
+ if (tmp.beg == tmp.end) return 0;
+ blks[num] = tmp;
+ return 1;
+ }
+}
+
+static inline unsigned free_block_size(free_block_t const *blk)
+{
+ return blk->end - blk->beg;
+}
+
+static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
+{
+ free_block_t free_blocks[2 * (HCD_ATTR_ENDPOINT_MAX - 1)];
+ unsigned num_blocks = 1;
+
+ /* Initialize free memory block list */
+ free_blocks[0].beg = 64 / 8;
+ free_blocks[0].end = (4 << 10) / 8; /* 4KiB / 8 bytes */
+ for (int i = 1; i < HCD_ATTR_ENDPOINT_MAX; ++i) {
+ uint_fast16_t addr;
+ int num;
+ USB0->EPIDX = i;
+ addr = USB0->TXFIFOADD;
+ if (addr) {
+ unsigned sz = USB0->TXFIFOSZ;
+ unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ }
+ addr = USB0->RXFIFOADD;
+ if (addr) {
+ unsigned sz = USB0->RXFIFOSZ;
+ unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ }
+ }
+
+ /* Find the best fit memory block */
+ uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3;
+ free_block_t const *min = NULL;
+ uint_fast16_t min_sz = 0xFFFFu;
+ free_block_t const *end = &free_blocks[num_blocks];
+ for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) {
+ uint_fast16_t sz = free_block_size(cur);
+ if (sz < size_in_8byte_unit) continue;
+ if (size_in_8byte_unit == sz) return cur->beg;
+ if (sz < min_sz) min = cur;
+ }
+ TU_ASSERT(min, 0);
+ return min->beg;
+}
+
+static inline volatile hw_endpoint_t* edpt_regs(unsigned epnum_minus1)
+{
+ volatile hw_endpoint_t *regs = (volatile hw_endpoint_t*)((uintptr_t)&USB0->TXMAXP1);
+ return regs + epnum_minus1;
+}
+
+static unsigned find_pipe(uint_fast8_t dev_addr, uint_fast8_t ep_addr)
+{
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ pipe_addr_t const *p = &_hcd.addr[0][dir_tx];
+ for (unsigned i = 0; i < sizeof(_hcd.addr)/sizeof(_hcd.addr[0]); ++i, p += 2) {
+ if ((dev_addr == p->dev) && (ep_addr == p->ep))
+ return i + 1;
+ }
+ return 0;
+}
+
+static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 4) {
+ reg->u32 = *(uint32_t const *)addr;
+ addr += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ reg->u16 = *(uint16_t const *)addr;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ reg->u8 = *(uint8_t const *)addr;
+ }
+}
+
+static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 4) {
+ *(uint32_t *)addr = reg->u32;
+ addr += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ *(uint16_t *)addr = reg->u16;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ *(uint8_t *)addr = reg->u8;
+ }
+}
+
+static bool edpt0_xfer_out(void)
+{
+ pipe_state_t *pipe = &_hcd.pipe0;
+ unsigned const rem = pipe->remaining;
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+ unsigned const dev_addr = USB0->TXFUNCADDR0;
+ unsigned const mps = _hcd.ctl_mps[dev_addr];
+ unsigned const len = TU_MIN(rem, mps);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, &USB0->FIFO0_WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ pipe->remaining = rem - len;
+ USB0->CSRL0 = USB_CSRL0_TXRDY;
+ return false;
+}
+
+static bool edpt0_xfer_in(void)
+{
+ pipe_state_t *pipe = &_hcd.pipe0;
+ unsigned const rem = pipe->remaining;
+ unsigned const dev_addr = USB0->TXFUNCADDR0;
+ unsigned const mps = _hcd.ctl_mps[dev_addr];
+ unsigned const vld = USB0->COUNT0;
+ unsigned const len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_read_packet(buf, &USB0->FIFO0_WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ pipe->remaining = rem - len;
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return true;
+ }
+ USB0->CSRL0 = USB_CSRL0_REQPKT;
+ return false;
+}
+
+static bool edpt0_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ (void)rhport;
+
+ unsigned const req = _hcd.bmRequestType;
+ TU_ASSERT(req != REQUEST_TYPE_INVALID);
+ TU_ASSERT(dev_addr < sizeof(_hcd.ctl_mps));
+
+ USB0->TXFUNCADDR0 = dev_addr;
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ if (tu_edpt_dir(req) == dir_in) { /* DATA stage */
+ TU_ASSERT(buffer);
+ _hcd.pipe0.buf = buffer;
+ _hcd.pipe0.length = buflen;
+ _hcd.pipe0.remaining = buflen;
+ if (dir_in)
+ USB0->CSRL0 = USB_CSRL0_REQPKT;
+ else
+ edpt0_xfer_out();
+ } else { /* STATUS stage */
+ _hcd.pipe0.buf = NULL;
+ _hcd.pipe0.length = 0;
+ _hcd.pipe0.remaining = 0;
+ USB0->CSRL0 = USB_CSRL0_STATUS | (dir_in ? USB_CSRL0_REQPKT: USB_CSRL0_TXRDY);
+ }
+ return true;
+}
+
+static bool pipe_xfer_out(uint_fast8_t pipenum)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][1];
+ unsigned const rem = pipe->remaining;
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+ hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
+ unsigned const mps = regs->TXMAXP;
+ unsigned const len = TU_MIN(rem, mps);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, &USB0->FIFO0_WORD + pipenum, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ pipe->remaining = rem - len;
+ regs->TXCSRL = USB_TXCSRL1_TXRDY;
+ return false;
+}
+
+static bool pipe_xfer_in(uint_fast8_t pipenum)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][0];
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+
+ TU_ASSERT(regs->RXCSRL & USB_RXCSRL1_RXRDY);
+
+ const unsigned mps = regs->RXMAXP;
+ const unsigned rem = pipe->remaining;
+ const unsigned vld = regs->RXCOUNT;
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_read_packet(buf, &USB0->FIFO0_WORD + pipenum, len);
+ pipe->buf = buf + len;
+ pipe->remaining = rem - len;
+ }
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return NULL != buf;
+ }
+ regs->RXCSRL = USB_RXCSRL1_REQPKT;
+ return false;
+}
+
+static bool edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ (void)rhport;
+ unsigned const pipenum = find_pipe(dev_addr, ep_addr);
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][dir_tx];
+ pipe->buf = buffer;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ if (dir_tx) {
+ pipe_xfer_out(pipenum);
+ } else {
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+ regs->RXCSRL = USB_RXCSRL1_REQPKT;
+ }
+ return true;
+}
+
+static void process_ep0(uint8_t rhport)
+{
+ (void)rhport;
+
+ uint_fast8_t csrl = USB0->CSRL0;
+ // TU_LOG1(" EP0 CSRL = %x\r\n", csrl);
+
+ unsigned const dev_addr = USB0->TXFUNCADDR0;
+ unsigned const req = _hcd.bmRequestType;
+ if (csrl & (USB_CSRL0_ERROR | USB_CSRL0_NAKTO | USB_CSRL0_STALLED)) {
+ /* No response / NAK timed out / Stall received */
+ if (csrl & (USB_CSRL0_RXRDY | USB_CSRL0_TXRDY))
+ USB0->CSRH0 = USB_CSRH0_FLUSH;
+ USB0->CSRL0 = 0;
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ uint8_t result = (csrl & USB_CSRL0_STALLED) ? XFER_RESULT_STALLED: XFER_RESULT_FAILED;
+ if (REQUEST_TYPE_INVALID == req) { /* SETUP */
+ uint8_t const ep_addr = tu_edpt_addr(0, TUSB_DIR_OUT);
+ hcd_event_xfer_complete(dev_addr, ep_addr,
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ result, true);
+ } else if (csrl & USB_CSRL0_STATUS) { /* STATUS */
+ uint8_t const ep_addr = tu_edpt_dir(req) ?
+ tu_edpt_addr(0, TUSB_DIR_OUT): tu_edpt_addr(0, TUSB_DIR_IN);
+ hcd_event_xfer_complete(dev_addr, ep_addr,
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ result, true);
+ } else { /* DATA */
+ uint8_t const ep_addr = tu_edpt_dir(req) ?
+ tu_edpt_addr(0, TUSB_DIR_IN): tu_edpt_addr(0, TUSB_DIR_OUT);
+ hcd_event_xfer_complete(dev_addr, ep_addr,
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ result, true);
+ }
+ return;
+ }
+ if (csrl & USB_CSRL0_STATUS) {
+ /* STATUS IN */
+ TU_ASSERT(USB_CSRL0_RXRDY == (csrl & USB_CSRL0_RXRDY),);
+ TU_ASSERT(0 == USB0->COUNT0,);
+ USB0->CSRH0 = USB_CSRH0_FLUSH;
+ USB0->CSRL0 = 0;
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_IN),
+ 0, XFER_RESULT_SUCCESS, true);
+ return;
+ }
+ if (csrl & USB_CSRL0_RXRDY) {
+ /* DATA IN */
+ TU_ASSERT(REQUEST_TYPE_INVALID != req,);
+ TU_ASSERT(_hcd.pipe0.buf,);
+ if (edpt0_xfer_in()) {
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_IN),
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+ return;
+ }
+
+ /* When CSRL0 is zero, it means that completion of sending a any length packet. */
+ if (!_hcd.pipe0.buf) {
+ /* STATUS OUT */
+ TU_ASSERT(REQUEST_TYPE_INVALID != req,);
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ /* EP address is the reverse direction of DATA stage */
+ uint8_t const ep_addr = tu_edpt_dir(req) ?
+ tu_edpt_addr(0, TUSB_DIR_OUT): tu_edpt_addr(0, TUSB_DIR_IN);
+ hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true);
+ return;
+ }
+ if (REQUEST_TYPE_INVALID == req) {
+ /* SETUP */
+ _hcd.bmRequestType = *(uint8_t*)_hcd.pipe0.buf;
+ _hcd.pipe0.buf = NULL;
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_OUT),
+ 8, XFER_RESULT_SUCCESS, true);
+ return;
+ }
+
+ /* DATA OUT */
+ if (edpt0_xfer_out()) {
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_OUT),
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_pipe_tx(uint8_t rhport, uint_fast8_t pipenum)
+{
+ (void)rhport;
+ bool completed;
+ uint8_t result;
+
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+ unsigned const csrl = regs->TXCSRL;
+ // TU_LOG1(" TXCSRL%d = %x\r\n", pipenum, csrl);
+ if (csrl & (USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR)) {
+ if (csrl & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = (csrl & ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR)) | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = csrl & ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR);
+ completed = true;
+ result = (csrl & USB_TXCSRL1_STALLED) ? XFER_RESULT_STALLED: XFER_RESULT_FAILED;
+ } else {
+ completed = pipe_xfer_out(pipenum);
+ result = XFER_RESULT_SUCCESS;
+ }
+ if (completed) {
+ pipe_addr_t *addr = &_hcd.addr[pipenum - 1][1];
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][1];
+ hcd_event_xfer_complete(addr->dev, addr->ep,
+ pipe->length - pipe->remaining,
+ result, true);
+ }
+}
+
+static void process_pipe_rx(uint8_t rhport, uint_fast8_t pipenum)
+{
+ (void)rhport;
+ bool completed;
+ uint8_t result;
+
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+ unsigned const csrl = regs->RXCSRL;
+ // TU_LOG1(" RXCSRL%d = %x\r\n", pipenum, csrl);
+ if (csrl & (USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR)) {
+ if (csrl & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = (csrl & ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR)) | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = csrl & ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR);
+ completed = true;
+ result = (csrl & USB_RXCSRL1_STALLED) ? XFER_RESULT_STALLED: XFER_RESULT_FAILED;
+ } else {
+ completed = pipe_xfer_in(pipenum);
+ result = XFER_RESULT_SUCCESS;
+ }
+ if (completed) {
+ pipe_addr_t *addr = &_hcd.addr[pipenum - 1][0];
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][0];
+ hcd_event_xfer_complete(addr->dev, addr->ep,
+ pipe->length - pipe->remaining,
+ result, true);
+ }
+}
+
+/*------------------------------------------------------------------
+ * Host API
+ *------------------------------------------------------------------*/
+
+bool hcd_init(uint8_t rhport)
+{
+ (void)rhport;
+
+ NVIC_ClearPendingIRQ(USB0_IRQn);
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ USB0->DEVCTL |= USB_DEVCTL_SESSION;
+ USB0->IE = USB_IE_DISCON | USB_IE_CONN | USB_IE_BABBLE | USB_IE_RESUME;
+ return true;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_DisableIRQ(USB0_IRQn);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void)rhport;
+ /* The device must be reset at least once after connection
+ * in order to start the frame counter. */
+ if (_hcd.need_reset) hcd_port_reset(rhport);
+ return USB0->FRAME;
+}
+
+//--------------------------------------------------------------------+
+// Port API
+//--------------------------------------------------------------------+
+
+bool hcd_port_connect_status(uint8_t rhport)
+{
+ (void)rhport;
+ unsigned devctl = USB0->DEVCTL;
+ if (!(devctl & USB_DEVCTL_HOST)) return false;
+ if (devctl & (USB_DEVCTL_LSDEV | USB_DEVCTL_FSDEV)) return true;
+ return false;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+ (void)rhport;
+ USB0->POWER |= USB_POWER_HSENAB | USB_POWER_RESET;
+ unsigned cnt = SystemCoreClock / 1000 * 20;
+ while (cnt--) __NOP();
+ USB0->POWER &= ~USB_POWER_RESET;
+ _hcd.need_reset = false;
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+ (void)rhport;
+ unsigned devctl = USB0->DEVCTL;
+ if (devctl & USB_DEVCTL_LSDEV) return TUSB_SPEED_LOW;
+ if (!(devctl & USB_DEVCTL_FSDEV)) return TUSB_SPEED_INVALID;
+ if (USB0->POWER & USB_POWER_HSMODE) return TUSB_SPEED_HIGH;
+ return TUSB_SPEED_FULL;
+}
+
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ if (sizeof(_hcd.ctl_mps) <= dev_addr) return;
+
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ _hcd.ctl_mps[dev_addr] = 0;
+ if (!dev_addr) return;
+
+ pipe_addr_t *p = &_hcd.addr[0][0];
+ for (unsigned i = 0; i < sizeof(_hcd.addr)/sizeof(_hcd.addr[0]); ++i) {
+ for (unsigned j = 0; j < 2; ++j, ++p) {
+ if (dev_addr != p->dev) continue;
+ hw_addr_t volatile *fadr = (hw_addr_t volatile*)&USB0->TXFUNCADDR0 + i + 1;
+ hw_endpoint_t volatile *regs = edpt_regs(i);
+ USB0->EPIDX = i + 1;
+ if (j) {
+ USB0->TXIE &= ~TU_BIT(i + 1);
+ if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ regs->TXMAXP = 0;
+ regs->TXTYPE = 0;
+ regs->TXINTERVAL = 0;
+ fadr->TXFUNCADDR = 0;
+ fadr->TXHUBADDR = 0;
+ fadr->TXHUBPORT = 0;
+ USB0->TXFIFOADD = 0;
+ USB0->TXFIFOSZ = 0;
+ } else {
+ USB0->RXIE &= ~TU_BIT(i + 1);
+ if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ regs->RXMAXP = 0;
+ regs->RXTYPE = 0;
+ regs->RXINTERVAL = 0;
+ fadr->RXFUNCADDR = 0;
+ fadr->RXHUBADDR = 0;
+ fadr->RXHUBPORT = 0;
+ USB0->RXFIFOADD = 0;
+ USB0->RXFIFOSZ = 0;
+ }
+ p->dev = 0;
+ p->ep = 0;
+ pipe_state_t *pipe = &_hcd.pipe[i][j];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+ }
+ }
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+//--------------------------------------------------------------------+
+// Endpoints API
+//--------------------------------------------------------------------+
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ (void)rhport;
+ pipe_write_packet((void*)(uintptr_t)setup_packet, &USB0->FIFO0_WORD, 8);
+ _hcd.pipe0.buf = (void*)(uintptr_t)setup_packet;
+ _hcd.pipe0.length = 8;
+ _hcd.pipe0.remaining = 0;
+
+ hcd_devtree_info_t devtree;
+ hcd_devtree_get_info(dev_addr, &devtree);
+ switch (devtree.speed) {
+ default: return false;
+ case TUSB_SPEED_LOW: USB0->TYPE0 = USB_TYPE0_SPEED_LOW; break;
+ case TUSB_SPEED_FULL: USB0->TYPE0 = USB_TYPE0_SPEED_FULL; break;
+ case TUSB_SPEED_HIGH: USB0->TYPE0 = USB_TYPE0_SPEED_HIGH; break;
+ }
+ USB0->TXHUBADDR0 = devtree.hub_addr;
+ USB0->TXHUBPORT0 = devtree.hub_port;
+ USB0->TXFUNCADDR0 = dev_addr;
+ USB0->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_SETUP;
+ return true;
+}
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void)rhport;
+ if (sizeof(_hcd.ctl_mps) <= dev_addr) return false;
+ unsigned const ep_addr = ep_desc->bEndpointAddress;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ if (0 == epn) {
+ _hcd.ctl_mps[dev_addr] = ep_desc->wMaxPacketSize;
+ return true;
+ }
+
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ /* Find a free pipe */
+ unsigned pipenum = 0;
+ pipe_addr_t *p = &_hcd.addr[0][dir_tx];
+ for (unsigned i = 0; i < sizeof(_hcd.addr)/sizeof(_hcd.addr[0]); ++i, p += 2) {
+ if (0 == p->ep) {
+ p->dev = dev_addr;
+ p->ep = ep_addr;
+ pipenum = i + 1;
+ break;
+ }
+ }
+ if (!pipenum) return false;
+
+ unsigned const xfer = ep_desc->bmAttributes.xfer;
+ unsigned const mps = tu_edpt_packet_size(ep_desc);
+
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][dir_tx];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+
+ uint8_t pipe_type = 0;
+ hcd_devtree_info_t devtree;
+ hcd_devtree_get_info(dev_addr, &devtree);
+ switch (devtree.speed) {
+ default: return false;
+ case TUSB_SPEED_LOW: pipe_type |= USB_TXTYPE1_SPEED_LOW; break;
+ case TUSB_SPEED_FULL: pipe_type |= USB_TXTYPE1_SPEED_FULL; break;
+ case TUSB_SPEED_HIGH: pipe_type |= USB_TXTYPE1_SPEED_HIGH; break;
+ }
+ switch (xfer) {
+ default: return false;
+ case TUSB_XFER_BULK: pipe_type |= USB_TXTYPE1_PROTO_BULK; break;
+ case TUSB_XFER_INTERRUPT: pipe_type |= USB_TXTYPE1_PROTO_INT; break;
+ case TUSB_XFER_ISOCHRONOUS: pipe_type |= USB_TXTYPE1_PROTO_ISOC; break;
+ }
+
+ hw_addr_t volatile *fadr = (hw_addr_t volatile*)&USB0->TXFUNCADDR0 + pipenum;
+ hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
+ if (dir_tx) {
+ fadr->TXFUNCADDR = dev_addr;
+ fadr->TXHUBADDR = devtree.hub_addr;
+ fadr->TXHUBPORT = devtree.hub_port;
+ regs->TXMAXP = mps;
+ regs->TXTYPE = pipe_type | epn;
+ regs->TXINTERVAL = ep_desc->bInterval;
+ if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ USB0->TXIE |= TU_BIT(pipenum);
+ } else {
+ fadr->RXFUNCADDR = dev_addr;
+ fadr->RXHUBADDR = devtree.hub_addr;
+ fadr->RXHUBPORT = devtree.hub_port;
+ regs->RXMAXP = mps;
+ regs->RXTYPE = pipe_type | epn;
+ regs->RXINTERVAL = ep_desc->bInterval;
+ if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ USB0->RXIE |= TU_BIT(pipenum);
+ }
+
+ /* Setup FIFO */
+ int size_in_log2_minus3 = 28 - TU_MIN(28, __CLZ((uint32_t)mps));
+ if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3;
+ unsigned addr = find_free_memory(size_in_log2_minus3);
+ TU_ASSERT(addr);
+
+ USB0->EPIDX = pipenum;
+ if (dir_tx) {
+ USB0->TXFIFOADD = addr;
+ USB0->TXFIFOSZ = size_in_log2_minus3;
+ } else {
+ USB0->RXFIFOADD = addr;
+ USB0->RXFIFOSZ = size_in_log2_minus3;
+ }
+ return true;
+}
+
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ (void)rhport;
+ bool ret = false;
+ if (0 == tu_edpt_number(ep_addr)) {
+ ret = edpt0_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
+ } else {
+ ret = edpt_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
+ }
+ return ret;
+}
+
+bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+ // TODO not implemented yet
+ return false;
+}
+
+// clear stall, data toggle is also reset to DATA0
+bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ unsigned const pipenum = find_pipe(dev_addr, ep_addr);
+ if (!pipenum) return false;
+ hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ if (dir_tx)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ return true;
+}
+
+/*-------------------------------------------------------------------
+ * ISR
+ *-------------------------------------------------------------------*/
+void hcd_int_handler(uint8_t rhport, bool in_isr)
+{
+ (void) in_isr;
+
+ uint_fast8_t is, txis, rxis;
+
+ is = USB0->IS; /* read and clear interrupt status */
+ txis = USB0->TXIS; /* read and clear interrupt status */
+ rxis = USB0->RXIS; /* read and clear interrupt status */
+ // TU_LOG1("D%2x T%2x R%2x\r\n", is, txis, rxis);
+
+ is &= USB0->IE; /* Clear disabled interrupts */
+ if (is & USB_IS_RESUME) {
+ }
+ if (is & USB_IS_CONN) {
+ _hcd.need_reset = true;
+ hcd_event_device_attach(rhport, true);
+ }
+ if (is & USB_IS_DISCON) {
+ hcd_event_device_remove(rhport, true);
+ }
+ if (is & USB_IS_BABBLE) {
+ }
+ txis &= USB0->TXIE; /* Clear disabled interrupts */
+ if (txis & USB_TXIE_EP0) {
+ process_ep0(rhport);
+ txis &= ~TU_BIT(0);
+ }
+ while (txis) {
+ unsigned const num = __builtin_ctz(txis);
+ process_pipe_tx(rhport, num);
+ txis &= ~TU_BIT(num);
+ }
+ rxis &= USB0->RXIE; /* Clear disabled interrupts */
+ while (rxis) {
+ unsigned const num = __builtin_ctz(rxis);
+ process_pipe_rx(rhport, num);
+ rxis &= ~TU_BIT(num);
+ }
+}
+
+#endif
diff --git a/src/portable/mentor/musb/musb_msp432e.h b/src/portable/mentor/musb/musb_msp432e.h
new file mode 100644
index 000000000..fce21de88
--- /dev/null
+++ b/src/portable/mentor/musb/musb_msp432e.h
@@ -0,0 +1,40 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_MUSB_MSP432E_H_
+#define _TUSB_MUSB_MSP432E_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "msp.h"
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/mentor/musb/musb_tm4c.h b/src/portable/mentor/musb/musb_tm4c.h
new file mode 100644
index 000000000..65a1751b0
--- /dev/null
+++ b/src/portable/mentor/musb/musb_tm4c.h
@@ -0,0 +1,45 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_MUSB_TM4C_H_
+#define _TUSB_MUSB_TM4C_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_TM4C123
+ #include "TM4C123.h"
+//#elif CFG_TUSB_MCU == OPT_MCU_TM4C129
+#else
+ #error "Unsupported MCUs"
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/mentor/musb/musb_type.h b/src/portable/mentor/musb/musb_type.h
new file mode 100644
index 000000000..8f83305a5
--- /dev/null
+++ b/src/portable/mentor/musb/musb_type.h
@@ -0,0 +1,2624 @@
+/******************************************************************************
+*
+* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the
+* distribution.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*******************************************************************************/
+
+#ifndef _TUSB_MUSB_TYPE_H_
+#define _TUSB_MUSB_TYPE_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FADDR register.
+//
+//*****************************************************************************
+#define USB_FADDR_M 0x0000007F // Function Address
+#define USB_FADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_POWER register.
+//
+//*****************************************************************************
+#define USB_POWER_ISOUP 0x00000080 // Isochronous Update
+#define USB_POWER_SOFTCONN 0x00000040 // Soft Connect/Disconnect
+#define USB_POWER_HSENAB 0x00000020 // High Speed Enable
+#define USB_POWER_HSMODE 0x00000010 // High Speed Enable
+#define USB_POWER_RESET 0x00000008 // RESET Signaling
+#define USB_POWER_RESUME 0x00000004 // RESUME Signaling
+#define USB_POWER_SUSPEND 0x00000002 // SUSPEND Mode
+#define USB_POWER_PWRDNPHY 0x00000001 // Power Down PHY
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXIS register.
+//
+//*****************************************************************************
+#define USB_TXIS_EP7 0x00000080 // TX Endpoint 7 Interrupt
+#define USB_TXIS_EP6 0x00000040 // TX Endpoint 6 Interrupt
+#define USB_TXIS_EP5 0x00000020 // TX Endpoint 5 Interrupt
+#define USB_TXIS_EP4 0x00000010 // TX Endpoint 4 Interrupt
+#define USB_TXIS_EP3 0x00000008 // TX Endpoint 3 Interrupt
+#define USB_TXIS_EP2 0x00000004 // TX Endpoint 2 Interrupt
+#define USB_TXIS_EP1 0x00000002 // TX Endpoint 1 Interrupt
+#define USB_TXIS_EP0 0x00000001 // TX and RX Endpoint 0 Interrupt
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXIS register.
+//
+//*****************************************************************************
+#define USB_RXIS_EP7 0x00000080 // RX Endpoint 7 Interrupt
+#define USB_RXIS_EP6 0x00000040 // RX Endpoint 6 Interrupt
+#define USB_RXIS_EP5 0x00000020 // RX Endpoint 5 Interrupt
+#define USB_RXIS_EP4 0x00000010 // RX Endpoint 4 Interrupt
+#define USB_RXIS_EP3 0x00000008 // RX Endpoint 3 Interrupt
+#define USB_RXIS_EP2 0x00000004 // RX Endpoint 2 Interrupt
+#define USB_RXIS_EP1 0x00000002 // RX Endpoint 1 Interrupt
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXIE register.
+//
+//*****************************************************************************
+#define USB_TXIE_EP7 0x00000080 // TX Endpoint 7 Interrupt Enable
+#define USB_TXIE_EP6 0x00000040 // TX Endpoint 6 Interrupt Enable
+#define USB_TXIE_EP5 0x00000020 // TX Endpoint 5 Interrupt Enable
+#define USB_TXIE_EP4 0x00000010 // TX Endpoint 4 Interrupt Enable
+#define USB_TXIE_EP3 0x00000008 // TX Endpoint 3 Interrupt Enable
+#define USB_TXIE_EP2 0x00000004 // TX Endpoint 2 Interrupt Enable
+#define USB_TXIE_EP1 0x00000002 // TX Endpoint 1 Interrupt Enable
+#define USB_TXIE_EP0 0x00000001 // TX and RX Endpoint 0 Interrupt
+ // Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXIE register.
+//
+//*****************************************************************************
+#define USB_RXIE_EP7 0x00000080 // RX Endpoint 7 Interrupt Enable
+#define USB_RXIE_EP6 0x00000040 // RX Endpoint 6 Interrupt Enable
+#define USB_RXIE_EP5 0x00000020 // RX Endpoint 5 Interrupt Enable
+#define USB_RXIE_EP4 0x00000010 // RX Endpoint 4 Interrupt Enable
+#define USB_RXIE_EP3 0x00000008 // RX Endpoint 3 Interrupt Enable
+#define USB_RXIE_EP2 0x00000004 // RX Endpoint 2 Interrupt Enable
+#define USB_RXIE_EP1 0x00000002 // RX Endpoint 1 Interrupt Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_IS register.
+//
+//*****************************************************************************
+#define USB_IS_VBUSERR 0x00000080 // VBUS Error (OTG only)
+#define USB_IS_SESREQ 0x00000040 // SESSION REQUEST (OTG only)
+#define USB_IS_DISCON 0x00000020 // Session Disconnect (OTG only)
+#define USB_IS_CONN 0x00000010 // Session Connect
+#define USB_IS_SOF 0x00000008 // Start of Frame
+#define USB_IS_BABBLE 0x00000004 // Babble Detected
+#define USB_IS_RESET 0x00000004 // RESET Signaling Detected
+#define USB_IS_RESUME 0x00000002 // RESUME Signaling Detected
+#define USB_IS_SUSPEND 0x00000001 // SUSPEND Signaling Detected
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_IE register.
+//
+//*****************************************************************************
+#define USB_IE_VBUSERR 0x00000080 // Enable VBUS Error Interrupt (OTG
+ // only)
+#define USB_IE_SESREQ 0x00000040 // Enable Session Request (OTG
+ // only)
+#define USB_IE_DISCON 0x00000020 // Enable Disconnect Interrupt
+#define USB_IE_CONN 0x00000010 // Enable Connect Interrupt
+#define USB_IE_SOF 0x00000008 // Enable Start-of-Frame Interrupt
+#define USB_IE_BABBLE 0x00000004 // Enable Babble Interrupt
+#define USB_IE_RESET 0x00000004 // Enable RESET Interrupt
+#define USB_IE_RESUME 0x00000002 // Enable RESUME Interrupt
+#define USB_IE_SUSPND 0x00000001 // Enable SUSPEND Interrupt
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FRAME register.
+//
+//*****************************************************************************
+#define USB_FRAME_M 0x000007FF // Frame Number
+#define USB_FRAME_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_EPIDX register.
+//
+//*****************************************************************************
+#define USB_EPIDX_EPIDX_M 0x0000000F // Endpoint Index
+#define USB_EPIDX_EPIDX_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TEST register.
+//
+//*****************************************************************************
+#define USB_TEST_FORCEH 0x00000080 // Force Host Mode
+#define USB_TEST_FIFOACC 0x00000040 // FIFO Access
+#define USB_TEST_FORCEFS 0x00000020 // Force Full-Speed Mode
+#define USB_TEST_FORCEHS 0x00000010 // Force High-Speed Mode
+#define USB_TEST_TESTPKT 0x00000008 // Test Packet Mode Enable
+#define USB_TEST_TESTK 0x00000004 // Test_K Mode Enable
+#define USB_TEST_TESTJ 0x00000002 // Test_J Mode Enable
+#define USB_TEST_TESTSE0NAK 0x00000001 // Test_SE0_NAK Test Mode Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO0 register.
+//
+//*****************************************************************************
+#define USB_FIFO0_EPDATA_M 0xFFFFFFFF // Endpoint Data
+#define USB_FIFO0_EPDATA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO1 register.
+//
+//*****************************************************************************
+#define USB_FIFO1_EPDATA_M 0xFFFFFFFF // Endpoint Data
+#define USB_FIFO1_EPDATA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO2 register.
+//
+//*****************************************************************************
+#define USB_FIFO2_EPDATA_M 0xFFFFFFFF // Endpoint Data
+#define USB_FIFO2_EPDATA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO3 register.
+//
+//*****************************************************************************
+#define USB_FIFO3_EPDATA_M 0xFFFFFFFF // Endpoint Data
+#define USB_FIFO3_EPDATA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO4 register.
+//
+//*****************************************************************************
+#define USB_FIFO4_EPDATA_M 0xFFFFFFFF // Endpoint Data
+#define USB_FIFO4_EPDATA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO5 register.
+//
+//*****************************************************************************
+#define USB_FIFO5_EPDATA_M 0xFFFFFFFF // Endpoint Data
+#define USB_FIFO5_EPDATA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO6 register.
+//
+//*****************************************************************************
+#define USB_FIFO6_EPDATA_M 0xFFFFFFFF // Endpoint Data
+#define USB_FIFO6_EPDATA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO7 register.
+//
+//*****************************************************************************
+#define USB_FIFO7_EPDATA_M 0xFFFFFFFF // Endpoint Data
+#define USB_FIFO7_EPDATA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DEVCTL register.
+//
+//*****************************************************************************
+#define USB_DEVCTL_DEV 0x00000080 // Device Mode (OTG only)
+#define USB_DEVCTL_FSDEV 0x00000040 // Full-Speed Device Detected
+#define USB_DEVCTL_LSDEV 0x00000020 // Low-Speed Device Detected
+#define USB_DEVCTL_VBUS_M 0x00000018 // VBUS Level (OTG only)
+#define USB_DEVCTL_VBUS_NONE 0x00000000 // Below SessionEnd
+#define USB_DEVCTL_VBUS_SEND 0x00000008 // Above SessionEnd, below AValid
+#define USB_DEVCTL_VBUS_AVALID 0x00000010 // Above AValid, below VBUSValid
+#define USB_DEVCTL_VBUS_VALID 0x00000018 // Above VBUSValid
+#define USB_DEVCTL_HOST 0x00000004 // Host Mode
+#define USB_DEVCTL_HOSTREQ 0x00000002 // Host Request (OTG only)
+#define USB_DEVCTL_SESSION 0x00000001 // Session Start/End (OTG only)
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_CCONF register.
+//
+//*****************************************************************************
+#define USB_CCONF_TXEDMA 0x00000002 // TX Early DMA Enable
+#define USB_CCONF_RXEDMA 0x00000001 // TX Early DMA Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFIFOSZ register.
+//
+//*****************************************************************************
+#define USB_TXFIFOSZ_DPB 0x00000010 // Double Packet Buffer Support
+#define USB_TXFIFOSZ_SIZE_M 0x0000000F // Max Packet Size
+#define USB_TXFIFOSZ_SIZE_8 0x00000000 // 8
+#define USB_TXFIFOSZ_SIZE_16 0x00000001 // 16
+#define USB_TXFIFOSZ_SIZE_32 0x00000002 // 32
+#define USB_TXFIFOSZ_SIZE_64 0x00000003 // 64
+#define USB_TXFIFOSZ_SIZE_128 0x00000004 // 128
+#define USB_TXFIFOSZ_SIZE_256 0x00000005 // 256
+#define USB_TXFIFOSZ_SIZE_512 0x00000006 // 512
+#define USB_TXFIFOSZ_SIZE_1024 0x00000007 // 1024
+#define USB_TXFIFOSZ_SIZE_2048 0x00000008 // 2048
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFIFOSZ register.
+//
+//*****************************************************************************
+#define USB_RXFIFOSZ_DPB 0x00000010 // Double Packet Buffer Support
+#define USB_RXFIFOSZ_SIZE_M 0x0000000F // Max Packet Size
+#define USB_RXFIFOSZ_SIZE_8 0x00000000 // 8
+#define USB_RXFIFOSZ_SIZE_16 0x00000001 // 16
+#define USB_RXFIFOSZ_SIZE_32 0x00000002 // 32
+#define USB_RXFIFOSZ_SIZE_64 0x00000003 // 64
+#define USB_RXFIFOSZ_SIZE_128 0x00000004 // 128
+#define USB_RXFIFOSZ_SIZE_256 0x00000005 // 256
+#define USB_RXFIFOSZ_SIZE_512 0x00000006 // 512
+#define USB_RXFIFOSZ_SIZE_1024 0x00000007 // 1024
+#define USB_RXFIFOSZ_SIZE_2048 0x00000008 // 2048
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFIFOADD
+// register.
+//
+//*****************************************************************************
+#define USB_TXFIFOADD_ADDR_M 0x000001FF // Transmit/Receive Start Address
+#define USB_TXFIFOADD_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFIFOADD
+// register.
+//
+//*****************************************************************************
+#define USB_RXFIFOADD_ADDR_M 0x000001FF // Transmit/Receive Start Address
+#define USB_RXFIFOADD_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_ULPIVBUSCTL
+// register.
+//
+//*****************************************************************************
+#define USB_ULPIVBUSCTL_USEEXTVBUSIND \
+ 0x00000002 // Use External VBUS Indicator
+#define USB_ULPIVBUSCTL_USEEXTVBUS \
+ 0x00000001 // Use External VBUS
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_ULPIREGDATA
+// register.
+//
+//*****************************************************************************
+#define USB_ULPIREGDATA_REGDATA_M \
+ 0x000000FF // Register Data
+#define USB_ULPIREGDATA_REGDATA_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_ULPIREGADDR
+// register.
+//
+//*****************************************************************************
+#define USB_ULPIREGADDR_ADDR_M 0x000000FF // Register Address
+#define USB_ULPIREGADDR_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_ULPIREGCTL
+// register.
+//
+//*****************************************************************************
+#define USB_ULPIREGCTL_RDWR 0x00000004 // Read/Write Control
+#define USB_ULPIREGCTL_REGCMPLT 0x00000002 // Register Access Complete
+#define USB_ULPIREGCTL_REGACC 0x00000001 // Initiate Register Access
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_EPINFO register.
+//
+//*****************************************************************************
+#define USB_EPINFO_RXEP_M 0x000000F0 // RX Endpoints
+#define USB_EPINFO_TXEP_M 0x0000000F // TX Endpoints
+#define USB_EPINFO_RXEP_S 4
+#define USB_EPINFO_TXEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RAMINFO register.
+//
+//*****************************************************************************
+#define USB_RAMINFO_DMACHAN_M 0x000000F0 // DMA Channels
+#define USB_RAMINFO_RAMBITS_M 0x0000000F // RAM Address Bus Width
+#define USB_RAMINFO_DMACHAN_S 4
+#define USB_RAMINFO_RAMBITS_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_CONTIM register.
+//
+//*****************************************************************************
+#define USB_CONTIM_WTCON_M 0x000000F0 // Connect Wait
+#define USB_CONTIM_WTID_M 0x0000000F // Wait ID
+#define USB_CONTIM_WTCON_S 4
+#define USB_CONTIM_WTID_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_VPLEN register.
+//
+//*****************************************************************************
+#define USB_VPLEN_VPLEN_M 0x000000FF // VBUS Pulse Length
+#define USB_VPLEN_VPLEN_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_HSEOF register.
+//
+//*****************************************************************************
+#define USB_HSEOF_HSEOFG_M 0x000000FF // HIgh-Speed End-of-Frame Gap
+#define USB_HSEOF_HSEOFG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FSEOF register.
+//
+//*****************************************************************************
+#define USB_FSEOF_FSEOFG_M 0x000000FF // Full-Speed End-of-Frame Gap
+#define USB_FSEOF_FSEOFG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_LSEOF register.
+//
+//*****************************************************************************
+#define USB_LSEOF_LSEOFG_M 0x000000FF // Low-Speed End-of-Frame Gap
+#define USB_LSEOF_LSEOFG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR0
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR0_ADDR_M 0x0000007F // Device Address
+#define USB_TXFUNCADDR0_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR0
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR0_ADDR_M 0x0000007F // Hub Address
+#define USB_TXHUBADDR0_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT0
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT0_PORT_M 0x0000007F // Hub Port
+#define USB_TXHUBPORT0_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR1
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR1_ADDR_M 0x0000007F // Device Address
+#define USB_TXFUNCADDR1_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR1
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR1_ADDR_M 0x0000007F // Hub Address
+#define USB_TXHUBADDR1_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT1
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT1_PORT_M 0x0000007F // Hub Port
+#define USB_TXHUBPORT1_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR1
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR1_ADDR_M 0x0000007F // Device Address
+#define USB_RXFUNCADDR1_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR1
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR1_ADDR_M 0x0000007F // Hub Address
+#define USB_RXHUBADDR1_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT1
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT1_PORT_M 0x0000007F // Hub Port
+#define USB_RXHUBPORT1_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR2
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR2_ADDR_M 0x0000007F // Device Address
+#define USB_TXFUNCADDR2_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR2
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR2_ADDR_M 0x0000007F // Hub Address
+#define USB_TXHUBADDR2_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT2
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT2_PORT_M 0x0000007F // Hub Port
+#define USB_TXHUBPORT2_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR2
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR2_ADDR_M 0x0000007F // Device Address
+#define USB_RXFUNCADDR2_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR2
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR2_ADDR_M 0x0000007F // Hub Address
+#define USB_RXHUBADDR2_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT2
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT2_PORT_M 0x0000007F // Hub Port
+#define USB_RXHUBPORT2_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR3
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR3_ADDR_M 0x0000007F // Device Address
+#define USB_TXFUNCADDR3_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR3
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR3_ADDR_M 0x0000007F // Hub Address
+#define USB_TXHUBADDR3_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT3
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT3_PORT_M 0x0000007F // Hub Port
+#define USB_TXHUBPORT3_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR3
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR3_ADDR_M 0x0000007F // Device Address
+#define USB_RXFUNCADDR3_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR3
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR3_ADDR_M 0x0000007F // Hub Address
+#define USB_RXHUBADDR3_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT3
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT3_PORT_M 0x0000007F // Hub Port
+#define USB_RXHUBPORT3_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR4
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR4_ADDR_M 0x0000007F // Device Address
+#define USB_TXFUNCADDR4_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR4
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR4_ADDR_M 0x0000007F // Hub Address
+#define USB_TXHUBADDR4_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT4
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT4_PORT_M 0x0000007F // Hub Port
+#define USB_TXHUBPORT4_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR4
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR4_ADDR_M 0x0000007F // Device Address
+#define USB_RXFUNCADDR4_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR4
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR4_ADDR_M 0x0000007F // Hub Address
+#define USB_RXHUBADDR4_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT4
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT4_PORT_M 0x0000007F // Hub Port
+#define USB_RXHUBPORT4_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR5
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR5_ADDR_M 0x0000007F // Device Address
+#define USB_TXFUNCADDR5_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR5
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR5_ADDR_M 0x0000007F // Hub Address
+#define USB_TXHUBADDR5_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT5
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT5_PORT_M 0x0000007F // Hub Port
+#define USB_TXHUBPORT5_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR5
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR5_ADDR_M 0x0000007F // Device Address
+#define USB_RXFUNCADDR5_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR5
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR5_ADDR_M 0x0000007F // Hub Address
+#define USB_RXHUBADDR5_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT5
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT5_PORT_M 0x0000007F // Hub Port
+#define USB_RXHUBPORT5_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR6
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR6_ADDR_M 0x0000007F // Device Address
+#define USB_TXFUNCADDR6_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR6
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR6_ADDR_M 0x0000007F // Hub Address
+#define USB_TXHUBADDR6_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT6
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT6_PORT_M 0x0000007F // Hub Port
+#define USB_TXHUBPORT6_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR6
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR6_ADDR_M 0x0000007F // Device Address
+#define USB_RXFUNCADDR6_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR6
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR6_ADDR_M 0x0000007F // Hub Address
+#define USB_RXHUBADDR6_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT6
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT6_PORT_M 0x0000007F // Hub Port
+#define USB_RXHUBPORT6_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR7
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR7_ADDR_M 0x0000007F // Device Address
+#define USB_TXFUNCADDR7_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR7
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR7_ADDR_M 0x0000007F // Hub Address
+#define USB_TXHUBADDR7_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT7
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT7_PORT_M 0x0000007F // Hub Port
+#define USB_TXHUBPORT7_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR7
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR7_ADDR_M 0x0000007F // Device Address
+#define USB_RXFUNCADDR7_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR7
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR7_ADDR_M 0x0000007F // Hub Address
+#define USB_RXHUBADDR7_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT7
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT7_PORT_M 0x0000007F // Hub Port
+#define USB_RXHUBPORT7_PORT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_CSRL0 register.
+//
+//*****************************************************************************
+#define USB_CSRL0_NAKTO 0x00000080 // NAK Timeout
+#define USB_CSRL0_SETENDC 0x00000080 // Setup End Clear
+#define USB_CSRL0_STATUS 0x00000040 // STATUS Packet
+#define USB_CSRL0_RXRDYC 0x00000040 // RXRDY Clear
+#define USB_CSRL0_REQPKT 0x00000020 // Request Packet
+#define USB_CSRL0_STALL 0x00000020 // Send Stall
+#define USB_CSRL0_SETEND 0x00000010 // Setup End
+#define USB_CSRL0_ERROR 0x00000010 // Error
+#define USB_CSRL0_DATAEND 0x00000008 // Data End
+#define USB_CSRL0_SETUP 0x00000008 // Setup Packet
+#define USB_CSRL0_STALLED 0x00000004 // Endpoint Stalled
+#define USB_CSRL0_TXRDY 0x00000002 // Transmit Packet Ready
+#define USB_CSRL0_RXRDY 0x00000001 // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_CSRH0 register.
+//
+//*****************************************************************************
+#define USB_CSRH0_DISPING 0x00000008 // PING Disable
+#define USB_CSRH0_DTWE 0x00000004 // Data Toggle Write Enable
+#define USB_CSRH0_DT 0x00000002 // Data Toggle
+#define USB_CSRH0_FLUSH 0x00000001 // Flush FIFO
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_COUNT0 register.
+//
+//*****************************************************************************
+#define USB_COUNT0_COUNT_M 0x0000007F // FIFO Count
+#define USB_COUNT0_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TYPE0 register.
+//
+//*****************************************************************************
+#define USB_TYPE0_SPEED_M 0x000000C0 // Operating Speed
+#define USB_TYPE0_SPEED_HIGH 0x00000040 // High
+#define USB_TYPE0_SPEED_FULL 0x00000080 // Full
+#define USB_TYPE0_SPEED_LOW 0x000000C0 // Low
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_NAKLMT register.
+//
+//*****************************************************************************
+#define USB_NAKLMT_NAKLMT_M 0x0000001F // EP0 NAK Limit
+#define USB_NAKLMT_NAKLMT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP1 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP1_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_TXMAXP1_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL1 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL1_NAKTO 0x00000080 // NAK Timeout
+#define USB_TXCSRL1_CLRDT 0x00000040 // Clear Data Toggle
+#define USB_TXCSRL1_STALLED 0x00000020 // Endpoint Stalled
+#define USB_TXCSRL1_STALL 0x00000010 // Send STALL
+#define USB_TXCSRL1_SETUP 0x00000010 // Setup Packet
+#define USB_TXCSRL1_FLUSH 0x00000008 // Flush FIFO
+#define USB_TXCSRL1_ERROR 0x00000004 // Error
+#define USB_TXCSRL1_UNDRN 0x00000004 // Underrun
+#define USB_TXCSRL1_FIFONE 0x00000002 // FIFO Not Empty
+#define USB_TXCSRL1_TXRDY 0x00000001 // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH1 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH1_AUTOSET 0x00000080 // Auto Set
+#define USB_TXCSRH1_ISO 0x00000040 // Isochronous Transfers
+#define USB_TXCSRH1_MODE 0x00000020 // Mode
+#define USB_TXCSRH1_DMAEN 0x00000010 // DMA Request Enable
+#define USB_TXCSRH1_FDT 0x00000008 // Force Data Toggle
+#define USB_TXCSRH1_DMAMOD 0x00000004 // DMA Request Mode
+#define USB_TXCSRH1_DTWE 0x00000002 // Data Toggle Write Enable
+#define USB_TXCSRH1_DT 0x00000001 // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP1 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP1_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_RXMAXP1_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL1 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL1_CLRDT 0x00000080 // Clear Data Toggle
+#define USB_RXCSRL1_STALLED 0x00000040 // Endpoint Stalled
+#define USB_RXCSRL1_STALL 0x00000020 // Send STALL
+#define USB_RXCSRL1_REQPKT 0x00000020 // Request Packet
+#define USB_RXCSRL1_FLUSH 0x00000010 // Flush FIFO
+#define USB_RXCSRL1_DATAERR 0x00000008 // Data Error
+#define USB_RXCSRL1_NAKTO 0x00000008 // NAK Timeout
+#define USB_RXCSRL1_OVER 0x00000004 // Overrun
+#define USB_RXCSRL1_ERROR 0x00000004 // Error
+#define USB_RXCSRL1_FULL 0x00000002 // FIFO Full
+#define USB_RXCSRL1_RXRDY 0x00000001 // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH1 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH1_AUTOCL 0x00000080 // Auto Clear
+#define USB_RXCSRH1_AUTORQ 0x00000040 // Auto Request
+#define USB_RXCSRH1_ISO 0x00000040 // Isochronous Transfers
+#define USB_RXCSRH1_DMAEN 0x00000020 // DMA Request Enable
+#define USB_RXCSRH1_DISNYET 0x00000010 // Disable NYET
+#define USB_RXCSRH1_PIDERR 0x00000010 // PID Error
+#define USB_RXCSRH1_DMAMOD 0x00000008 // DMA Request Mode
+#define USB_RXCSRH1_DTWE 0x00000004 // Data Toggle Write Enable
+#define USB_RXCSRH1_DT 0x00000002 // Data Toggle
+#define USB_RXCSRH1_INCOMPRX 0x00000001 // Incomplete RX Transmission
+ // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT1 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT1_COUNT_M 0x00001FFF // Receive Packet Count
+#define USB_RXCOUNT1_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE1 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE1_SPEED_M 0x000000C0 // Operating Speed
+#define USB_TXTYPE1_SPEED_DFLT 0x00000000 // Default
+#define USB_TXTYPE1_SPEED_HIGH 0x00000040 // High
+#define USB_TXTYPE1_SPEED_FULL 0x00000080 // Full
+#define USB_TXTYPE1_SPEED_LOW 0x000000C0 // Low
+#define USB_TXTYPE1_PROTO_M 0x00000030 // Protocol
+#define USB_TXTYPE1_PROTO_CTRL 0x00000000 // Control
+#define USB_TXTYPE1_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_TXTYPE1_PROTO_BULK 0x00000020 // Bulk
+#define USB_TXTYPE1_PROTO_INT 0x00000030 // Interrupt
+#define USB_TXTYPE1_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_TXTYPE1_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL1
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL1_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_TXINTERVAL1_TXPOLL_M \
+ 0x000000FF // TX Polling
+#define USB_TXINTERVAL1_TXPOLL_S \
+ 0
+#define USB_TXINTERVAL1_NAKLMT_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE1 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE1_SPEED_M 0x000000C0 // Operating Speed
+#define USB_RXTYPE1_SPEED_DFLT 0x00000000 // Default
+#define USB_RXTYPE1_SPEED_HIGH 0x00000040 // High
+#define USB_RXTYPE1_SPEED_FULL 0x00000080 // Full
+#define USB_RXTYPE1_SPEED_LOW 0x000000C0 // Low
+#define USB_RXTYPE1_PROTO_M 0x00000030 // Protocol
+#define USB_RXTYPE1_PROTO_CTRL 0x00000000 // Control
+#define USB_RXTYPE1_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_RXTYPE1_PROTO_BULK 0x00000020 // Bulk
+#define USB_RXTYPE1_PROTO_INT 0x00000030 // Interrupt
+#define USB_RXTYPE1_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_RXTYPE1_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL1
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL1_TXPOLL_M \
+ 0x000000FF // RX Polling
+#define USB_RXINTERVAL1_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_RXINTERVAL1_TXPOLL_S \
+ 0
+#define USB_RXINTERVAL1_NAKLMT_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP2 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP2_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_TXMAXP2_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL2 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL2_NAKTO 0x00000080 // NAK Timeout
+#define USB_TXCSRL2_CLRDT 0x00000040 // Clear Data Toggle
+#define USB_TXCSRL2_STALLED 0x00000020 // Endpoint Stalled
+#define USB_TXCSRL2_SETUP 0x00000010 // Setup Packet
+#define USB_TXCSRL2_STALL 0x00000010 // Send STALL
+#define USB_TXCSRL2_FLUSH 0x00000008 // Flush FIFO
+#define USB_TXCSRL2_ERROR 0x00000004 // Error
+#define USB_TXCSRL2_UNDRN 0x00000004 // Underrun
+#define USB_TXCSRL2_FIFONE 0x00000002 // FIFO Not Empty
+#define USB_TXCSRL2_TXRDY 0x00000001 // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH2 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH2_AUTOSET 0x00000080 // Auto Set
+#define USB_TXCSRH2_ISO 0x00000040 // Isochronous Transfers
+#define USB_TXCSRH2_MODE 0x00000020 // Mode
+#define USB_TXCSRH2_DMAEN 0x00000010 // DMA Request Enable
+#define USB_TXCSRH2_FDT 0x00000008 // Force Data Toggle
+#define USB_TXCSRH2_DMAMOD 0x00000004 // DMA Request Mode
+#define USB_TXCSRH2_DTWE 0x00000002 // Data Toggle Write Enable
+#define USB_TXCSRH2_DT 0x00000001 // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP2 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP2_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_RXMAXP2_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL2 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL2_CLRDT 0x00000080 // Clear Data Toggle
+#define USB_RXCSRL2_STALLED 0x00000040 // Endpoint Stalled
+#define USB_RXCSRL2_REQPKT 0x00000020 // Request Packet
+#define USB_RXCSRL2_STALL 0x00000020 // Send STALL
+#define USB_RXCSRL2_FLUSH 0x00000010 // Flush FIFO
+#define USB_RXCSRL2_DATAERR 0x00000008 // Data Error
+#define USB_RXCSRL2_NAKTO 0x00000008 // NAK Timeout
+#define USB_RXCSRL2_ERROR 0x00000004 // Error
+#define USB_RXCSRL2_OVER 0x00000004 // Overrun
+#define USB_RXCSRL2_FULL 0x00000002 // FIFO Full
+#define USB_RXCSRL2_RXRDY 0x00000001 // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH2 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH2_AUTOCL 0x00000080 // Auto Clear
+#define USB_RXCSRH2_AUTORQ 0x00000040 // Auto Request
+#define USB_RXCSRH2_ISO 0x00000040 // Isochronous Transfers
+#define USB_RXCSRH2_DMAEN 0x00000020 // DMA Request Enable
+#define USB_RXCSRH2_DISNYET 0x00000010 // Disable NYET
+#define USB_RXCSRH2_PIDERR 0x00000010 // PID Error
+#define USB_RXCSRH2_DMAMOD 0x00000008 // DMA Request Mode
+#define USB_RXCSRH2_DTWE 0x00000004 // Data Toggle Write Enable
+#define USB_RXCSRH2_DT 0x00000002 // Data Toggle
+#define USB_RXCSRH2_INCOMPRX 0x00000001 // Incomplete RX Transmission
+ // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT2 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT2_COUNT_M 0x00001FFF // Receive Packet Count
+#define USB_RXCOUNT2_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE2 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE2_SPEED_M 0x000000C0 // Operating Speed
+#define USB_TXTYPE2_SPEED_DFLT 0x00000000 // Default
+#define USB_TXTYPE2_SPEED_HIGH 0x00000040 // High
+#define USB_TXTYPE2_SPEED_FULL 0x00000080 // Full
+#define USB_TXTYPE2_SPEED_LOW 0x000000C0 // Low
+#define USB_TXTYPE2_PROTO_M 0x00000030 // Protocol
+#define USB_TXTYPE2_PROTO_CTRL 0x00000000 // Control
+#define USB_TXTYPE2_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_TXTYPE2_PROTO_BULK 0x00000020 // Bulk
+#define USB_TXTYPE2_PROTO_INT 0x00000030 // Interrupt
+#define USB_TXTYPE2_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_TXTYPE2_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL2
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL2_TXPOLL_M \
+ 0x000000FF // TX Polling
+#define USB_TXINTERVAL2_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_TXINTERVAL2_NAKLMT_S \
+ 0
+#define USB_TXINTERVAL2_TXPOLL_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE2 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE2_SPEED_M 0x000000C0 // Operating Speed
+#define USB_RXTYPE2_SPEED_DFLT 0x00000000 // Default
+#define USB_RXTYPE2_SPEED_HIGH 0x00000040 // High
+#define USB_RXTYPE2_SPEED_FULL 0x00000080 // Full
+#define USB_RXTYPE2_SPEED_LOW 0x000000C0 // Low
+#define USB_RXTYPE2_PROTO_M 0x00000030 // Protocol
+#define USB_RXTYPE2_PROTO_CTRL 0x00000000 // Control
+#define USB_RXTYPE2_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_RXTYPE2_PROTO_BULK 0x00000020 // Bulk
+#define USB_RXTYPE2_PROTO_INT 0x00000030 // Interrupt
+#define USB_RXTYPE2_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_RXTYPE2_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL2
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL2_TXPOLL_M \
+ 0x000000FF // RX Polling
+#define USB_RXINTERVAL2_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_RXINTERVAL2_TXPOLL_S \
+ 0
+#define USB_RXINTERVAL2_NAKLMT_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP3 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP3_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_TXMAXP3_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL3 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL3_NAKTO 0x00000080 // NAK Timeout
+#define USB_TXCSRL3_CLRDT 0x00000040 // Clear Data Toggle
+#define USB_TXCSRL3_STALLED 0x00000020 // Endpoint Stalled
+#define USB_TXCSRL3_SETUP 0x00000010 // Setup Packet
+#define USB_TXCSRL3_STALL 0x00000010 // Send STALL
+#define USB_TXCSRL3_FLUSH 0x00000008 // Flush FIFO
+#define USB_TXCSRL3_ERROR 0x00000004 // Error
+#define USB_TXCSRL3_UNDRN 0x00000004 // Underrun
+#define USB_TXCSRL3_FIFONE 0x00000002 // FIFO Not Empty
+#define USB_TXCSRL3_TXRDY 0x00000001 // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH3 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH3_AUTOSET 0x00000080 // Auto Set
+#define USB_TXCSRH3_ISO 0x00000040 // Isochronous Transfers
+#define USB_TXCSRH3_MODE 0x00000020 // Mode
+#define USB_TXCSRH3_DMAEN 0x00000010 // DMA Request Enable
+#define USB_TXCSRH3_FDT 0x00000008 // Force Data Toggle
+#define USB_TXCSRH3_DMAMOD 0x00000004 // DMA Request Mode
+#define USB_TXCSRH3_DTWE 0x00000002 // Data Toggle Write Enable
+#define USB_TXCSRH3_DT 0x00000001 // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP3 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP3_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_RXMAXP3_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL3 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL3_CLRDT 0x00000080 // Clear Data Toggle
+#define USB_RXCSRL3_STALLED 0x00000040 // Endpoint Stalled
+#define USB_RXCSRL3_STALL 0x00000020 // Send STALL
+#define USB_RXCSRL3_REQPKT 0x00000020 // Request Packet
+#define USB_RXCSRL3_FLUSH 0x00000010 // Flush FIFO
+#define USB_RXCSRL3_DATAERR 0x00000008 // Data Error
+#define USB_RXCSRL3_NAKTO 0x00000008 // NAK Timeout
+#define USB_RXCSRL3_ERROR 0x00000004 // Error
+#define USB_RXCSRL3_OVER 0x00000004 // Overrun
+#define USB_RXCSRL3_FULL 0x00000002 // FIFO Full
+#define USB_RXCSRL3_RXRDY 0x00000001 // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH3 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH3_AUTOCL 0x00000080 // Auto Clear
+#define USB_RXCSRH3_AUTORQ 0x00000040 // Auto Request
+#define USB_RXCSRH3_ISO 0x00000040 // Isochronous Transfers
+#define USB_RXCSRH3_DMAEN 0x00000020 // DMA Request Enable
+#define USB_RXCSRH3_DISNYET 0x00000010 // Disable NYET
+#define USB_RXCSRH3_PIDERR 0x00000010 // PID Error
+#define USB_RXCSRH3_DMAMOD 0x00000008 // DMA Request Mode
+#define USB_RXCSRH3_DTWE 0x00000004 // Data Toggle Write Enable
+#define USB_RXCSRH3_DT 0x00000002 // Data Toggle
+#define USB_RXCSRH3_INCOMPRX 0x00000001 // Incomplete RX Transmission
+ // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT3 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT3_COUNT_M 0x00001FFF // Receive Packet Count
+#define USB_RXCOUNT3_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE3 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE3_SPEED_M 0x000000C0 // Operating Speed
+#define USB_TXTYPE3_SPEED_DFLT 0x00000000 // Default
+#define USB_TXTYPE3_SPEED_HIGH 0x00000040 // High
+#define USB_TXTYPE3_SPEED_FULL 0x00000080 // Full
+#define USB_TXTYPE3_SPEED_LOW 0x000000C0 // Low
+#define USB_TXTYPE3_PROTO_M 0x00000030 // Protocol
+#define USB_TXTYPE3_PROTO_CTRL 0x00000000 // Control
+#define USB_TXTYPE3_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_TXTYPE3_PROTO_BULK 0x00000020 // Bulk
+#define USB_TXTYPE3_PROTO_INT 0x00000030 // Interrupt
+#define USB_TXTYPE3_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_TXTYPE3_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL3
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL3_TXPOLL_M \
+ 0x000000FF // TX Polling
+#define USB_TXINTERVAL3_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_TXINTERVAL3_TXPOLL_S \
+ 0
+#define USB_TXINTERVAL3_NAKLMT_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE3 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE3_SPEED_M 0x000000C0 // Operating Speed
+#define USB_RXTYPE3_SPEED_DFLT 0x00000000 // Default
+#define USB_RXTYPE3_SPEED_HIGH 0x00000040 // High
+#define USB_RXTYPE3_SPEED_FULL 0x00000080 // Full
+#define USB_RXTYPE3_SPEED_LOW 0x000000C0 // Low
+#define USB_RXTYPE3_PROTO_M 0x00000030 // Protocol
+#define USB_RXTYPE3_PROTO_CTRL 0x00000000 // Control
+#define USB_RXTYPE3_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_RXTYPE3_PROTO_BULK 0x00000020 // Bulk
+#define USB_RXTYPE3_PROTO_INT 0x00000030 // Interrupt
+#define USB_RXTYPE3_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_RXTYPE3_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL3
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL3_TXPOLL_M \
+ 0x000000FF // RX Polling
+#define USB_RXINTERVAL3_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_RXINTERVAL3_TXPOLL_S \
+ 0
+#define USB_RXINTERVAL3_NAKLMT_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP4 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP4_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_TXMAXP4_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL4 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL4_NAKTO 0x00000080 // NAK Timeout
+#define USB_TXCSRL4_CLRDT 0x00000040 // Clear Data Toggle
+#define USB_TXCSRL4_STALLED 0x00000020 // Endpoint Stalled
+#define USB_TXCSRL4_SETUP 0x00000010 // Setup Packet
+#define USB_TXCSRL4_STALL 0x00000010 // Send STALL
+#define USB_TXCSRL4_FLUSH 0x00000008 // Flush FIFO
+#define USB_TXCSRL4_ERROR 0x00000004 // Error
+#define USB_TXCSRL4_UNDRN 0x00000004 // Underrun
+#define USB_TXCSRL4_FIFONE 0x00000002 // FIFO Not Empty
+#define USB_TXCSRL4_TXRDY 0x00000001 // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH4 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH4_AUTOSET 0x00000080 // Auto Set
+#define USB_TXCSRH4_ISO 0x00000040 // Isochronous Transfers
+#define USB_TXCSRH4_MODE 0x00000020 // Mode
+#define USB_TXCSRH4_DMAEN 0x00000010 // DMA Request Enable
+#define USB_TXCSRH4_FDT 0x00000008 // Force Data Toggle
+#define USB_TXCSRH4_DMAMOD 0x00000004 // DMA Request Mode
+#define USB_TXCSRH4_DTWE 0x00000002 // Data Toggle Write Enable
+#define USB_TXCSRH4_DT 0x00000001 // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP4 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP4_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_RXMAXP4_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL4 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL4_CLRDT 0x00000080 // Clear Data Toggle
+#define USB_RXCSRL4_STALLED 0x00000040 // Endpoint Stalled
+#define USB_RXCSRL4_STALL 0x00000020 // Send STALL
+#define USB_RXCSRL4_REQPKT 0x00000020 // Request Packet
+#define USB_RXCSRL4_FLUSH 0x00000010 // Flush FIFO
+#define USB_RXCSRL4_NAKTO 0x00000008 // NAK Timeout
+#define USB_RXCSRL4_DATAERR 0x00000008 // Data Error
+#define USB_RXCSRL4_OVER 0x00000004 // Overrun
+#define USB_RXCSRL4_ERROR 0x00000004 // Error
+#define USB_RXCSRL4_FULL 0x00000002 // FIFO Full
+#define USB_RXCSRL4_RXRDY 0x00000001 // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH4 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH4_AUTOCL 0x00000080 // Auto Clear
+#define USB_RXCSRH4_AUTORQ 0x00000040 // Auto Request
+#define USB_RXCSRH4_ISO 0x00000040 // Isochronous Transfers
+#define USB_RXCSRH4_DMAEN 0x00000020 // DMA Request Enable
+#define USB_RXCSRH4_DISNYET 0x00000010 // Disable NYET
+#define USB_RXCSRH4_PIDERR 0x00000010 // PID Error
+#define USB_RXCSRH4_DMAMOD 0x00000008 // DMA Request Mode
+#define USB_RXCSRH4_DTWE 0x00000004 // Data Toggle Write Enable
+#define USB_RXCSRH4_DT 0x00000002 // Data Toggle
+#define USB_RXCSRH4_INCOMPRX 0x00000001 // Incomplete RX Transmission
+ // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT4 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT4_COUNT_M 0x00001FFF // Receive Packet Count
+#define USB_RXCOUNT4_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE4 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE4_SPEED_M 0x000000C0 // Operating Speed
+#define USB_TXTYPE4_SPEED_DFLT 0x00000000 // Default
+#define USB_TXTYPE4_SPEED_HIGH 0x00000040 // High
+#define USB_TXTYPE4_SPEED_FULL 0x00000080 // Full
+#define USB_TXTYPE4_SPEED_LOW 0x000000C0 // Low
+#define USB_TXTYPE4_PROTO_M 0x00000030 // Protocol
+#define USB_TXTYPE4_PROTO_CTRL 0x00000000 // Control
+#define USB_TXTYPE4_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_TXTYPE4_PROTO_BULK 0x00000020 // Bulk
+#define USB_TXTYPE4_PROTO_INT 0x00000030 // Interrupt
+#define USB_TXTYPE4_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_TXTYPE4_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL4
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL4_TXPOLL_M \
+ 0x000000FF // TX Polling
+#define USB_TXINTERVAL4_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_TXINTERVAL4_NAKLMT_S \
+ 0
+#define USB_TXINTERVAL4_TXPOLL_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE4 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE4_SPEED_M 0x000000C0 // Operating Speed
+#define USB_RXTYPE4_SPEED_DFLT 0x00000000 // Default
+#define USB_RXTYPE4_SPEED_HIGH 0x00000040 // High
+#define USB_RXTYPE4_SPEED_FULL 0x00000080 // Full
+#define USB_RXTYPE4_SPEED_LOW 0x000000C0 // Low
+#define USB_RXTYPE4_PROTO_M 0x00000030 // Protocol
+#define USB_RXTYPE4_PROTO_CTRL 0x00000000 // Control
+#define USB_RXTYPE4_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_RXTYPE4_PROTO_BULK 0x00000020 // Bulk
+#define USB_RXTYPE4_PROTO_INT 0x00000030 // Interrupt
+#define USB_RXTYPE4_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_RXTYPE4_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL4
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL4_TXPOLL_M \
+ 0x000000FF // RX Polling
+#define USB_RXINTERVAL4_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_RXINTERVAL4_NAKLMT_S \
+ 0
+#define USB_RXINTERVAL4_TXPOLL_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP5 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP5_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_TXMAXP5_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL5 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL5_NAKTO 0x00000080 // NAK Timeout
+#define USB_TXCSRL5_CLRDT 0x00000040 // Clear Data Toggle
+#define USB_TXCSRL5_STALLED 0x00000020 // Endpoint Stalled
+#define USB_TXCSRL5_SETUP 0x00000010 // Setup Packet
+#define USB_TXCSRL5_STALL 0x00000010 // Send STALL
+#define USB_TXCSRL5_FLUSH 0x00000008 // Flush FIFO
+#define USB_TXCSRL5_ERROR 0x00000004 // Error
+#define USB_TXCSRL5_UNDRN 0x00000004 // Underrun
+#define USB_TXCSRL5_FIFONE 0x00000002 // FIFO Not Empty
+#define USB_TXCSRL5_TXRDY 0x00000001 // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH5 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH5_AUTOSET 0x00000080 // Auto Set
+#define USB_TXCSRH5_ISO 0x00000040 // Isochronous Transfers
+#define USB_TXCSRH5_MODE 0x00000020 // Mode
+#define USB_TXCSRH5_DMAEN 0x00000010 // DMA Request Enable
+#define USB_TXCSRH5_FDT 0x00000008 // Force Data Toggle
+#define USB_TXCSRH5_DMAMOD 0x00000004 // DMA Request Mode
+#define USB_TXCSRH5_DTWE 0x00000002 // Data Toggle Write Enable
+#define USB_TXCSRH5_DT 0x00000001 // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP5 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP5_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_RXMAXP5_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL5 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL5_CLRDT 0x00000080 // Clear Data Toggle
+#define USB_RXCSRL5_STALLED 0x00000040 // Endpoint Stalled
+#define USB_RXCSRL5_STALL 0x00000020 // Send STALL
+#define USB_RXCSRL5_REQPKT 0x00000020 // Request Packet
+#define USB_RXCSRL5_FLUSH 0x00000010 // Flush FIFO
+#define USB_RXCSRL5_NAKTO 0x00000008 // NAK Timeout
+#define USB_RXCSRL5_DATAERR 0x00000008 // Data Error
+#define USB_RXCSRL5_ERROR 0x00000004 // Error
+#define USB_RXCSRL5_OVER 0x00000004 // Overrun
+#define USB_RXCSRL5_FULL 0x00000002 // FIFO Full
+#define USB_RXCSRL5_RXRDY 0x00000001 // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH5 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH5_AUTOCL 0x00000080 // Auto Clear
+#define USB_RXCSRH5_AUTORQ 0x00000040 // Auto Request
+#define USB_RXCSRH5_ISO 0x00000040 // Isochronous Transfers
+#define USB_RXCSRH5_DMAEN 0x00000020 // DMA Request Enable
+#define USB_RXCSRH5_DISNYET 0x00000010 // Disable NYET
+#define USB_RXCSRH5_PIDERR 0x00000010 // PID Error
+#define USB_RXCSRH5_DMAMOD 0x00000008 // DMA Request Mode
+#define USB_RXCSRH5_DTWE 0x00000004 // Data Toggle Write Enable
+#define USB_RXCSRH5_DT 0x00000002 // Data Toggle
+#define USB_RXCSRH5_INCOMPRX 0x00000001 // Incomplete RX Transmission
+ // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT5 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT5_COUNT_M 0x00001FFF // Receive Packet Count
+#define USB_RXCOUNT5_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE5 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE5_SPEED_M 0x000000C0 // Operating Speed
+#define USB_TXTYPE5_SPEED_DFLT 0x00000000 // Default
+#define USB_TXTYPE5_SPEED_HIGH 0x00000040 // High
+#define USB_TXTYPE5_SPEED_FULL 0x00000080 // Full
+#define USB_TXTYPE5_SPEED_LOW 0x000000C0 // Low
+#define USB_TXTYPE5_PROTO_M 0x00000030 // Protocol
+#define USB_TXTYPE5_PROTO_CTRL 0x00000000 // Control
+#define USB_TXTYPE5_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_TXTYPE5_PROTO_BULK 0x00000020 // Bulk
+#define USB_TXTYPE5_PROTO_INT 0x00000030 // Interrupt
+#define USB_TXTYPE5_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_TXTYPE5_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL5
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL5_TXPOLL_M \
+ 0x000000FF // TX Polling
+#define USB_TXINTERVAL5_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_TXINTERVAL5_NAKLMT_S \
+ 0
+#define USB_TXINTERVAL5_TXPOLL_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE5 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE5_SPEED_M 0x000000C0 // Operating Speed
+#define USB_RXTYPE5_SPEED_DFLT 0x00000000 // Default
+#define USB_RXTYPE5_SPEED_HIGH 0x00000040 // High
+#define USB_RXTYPE5_SPEED_FULL 0x00000080 // Full
+#define USB_RXTYPE5_SPEED_LOW 0x000000C0 // Low
+#define USB_RXTYPE5_PROTO_M 0x00000030 // Protocol
+#define USB_RXTYPE5_PROTO_CTRL 0x00000000 // Control
+#define USB_RXTYPE5_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_RXTYPE5_PROTO_BULK 0x00000020 // Bulk
+#define USB_RXTYPE5_PROTO_INT 0x00000030 // Interrupt
+#define USB_RXTYPE5_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_RXTYPE5_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL5
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL5_TXPOLL_M \
+ 0x000000FF // RX Polling
+#define USB_RXINTERVAL5_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_RXINTERVAL5_TXPOLL_S \
+ 0
+#define USB_RXINTERVAL5_NAKLMT_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP6 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP6_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_TXMAXP6_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL6 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL6_NAKTO 0x00000080 // NAK Timeout
+#define USB_TXCSRL6_CLRDT 0x00000040 // Clear Data Toggle
+#define USB_TXCSRL6_STALLED 0x00000020 // Endpoint Stalled
+#define USB_TXCSRL6_STALL 0x00000010 // Send STALL
+#define USB_TXCSRL6_SETUP 0x00000010 // Setup Packet
+#define USB_TXCSRL6_FLUSH 0x00000008 // Flush FIFO
+#define USB_TXCSRL6_ERROR 0x00000004 // Error
+#define USB_TXCSRL6_UNDRN 0x00000004 // Underrun
+#define USB_TXCSRL6_FIFONE 0x00000002 // FIFO Not Empty
+#define USB_TXCSRL6_TXRDY 0x00000001 // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH6 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH6_AUTOSET 0x00000080 // Auto Set
+#define USB_TXCSRH6_ISO 0x00000040 // Isochronous Transfers
+#define USB_TXCSRH6_MODE 0x00000020 // Mode
+#define USB_TXCSRH6_DMAEN 0x00000010 // DMA Request Enable
+#define USB_TXCSRH6_FDT 0x00000008 // Force Data Toggle
+#define USB_TXCSRH6_DMAMOD 0x00000004 // DMA Request Mode
+#define USB_TXCSRH6_DTWE 0x00000002 // Data Toggle Write Enable
+#define USB_TXCSRH6_DT 0x00000001 // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP6 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP6_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_RXMAXP6_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL6 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL6_CLRDT 0x00000080 // Clear Data Toggle
+#define USB_RXCSRL6_STALLED 0x00000040 // Endpoint Stalled
+#define USB_RXCSRL6_REQPKT 0x00000020 // Request Packet
+#define USB_RXCSRL6_STALL 0x00000020 // Send STALL
+#define USB_RXCSRL6_FLUSH 0x00000010 // Flush FIFO
+#define USB_RXCSRL6_NAKTO 0x00000008 // NAK Timeout
+#define USB_RXCSRL6_DATAERR 0x00000008 // Data Error
+#define USB_RXCSRL6_ERROR 0x00000004 // Error
+#define USB_RXCSRL6_OVER 0x00000004 // Overrun
+#define USB_RXCSRL6_FULL 0x00000002 // FIFO Full
+#define USB_RXCSRL6_RXRDY 0x00000001 // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH6 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH6_AUTOCL 0x00000080 // Auto Clear
+#define USB_RXCSRH6_AUTORQ 0x00000040 // Auto Request
+#define USB_RXCSRH6_ISO 0x00000040 // Isochronous Transfers
+#define USB_RXCSRH6_DMAEN 0x00000020 // DMA Request Enable
+#define USB_RXCSRH6_DISNYET 0x00000010 // Disable NYET
+#define USB_RXCSRH6_PIDERR 0x00000010 // PID Error
+#define USB_RXCSRH6_DMAMOD 0x00000008 // DMA Request Mode
+#define USB_RXCSRH6_DTWE 0x00000004 // Data Toggle Write Enable
+#define USB_RXCSRH6_DT 0x00000002 // Data Toggle
+#define USB_RXCSRH6_INCOMPRX 0x00000001 // Incomplete RX Transmission
+ // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT6 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT6_COUNT_M 0x00001FFF // Receive Packet Count
+#define USB_RXCOUNT6_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE6 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE6_SPEED_M 0x000000C0 // Operating Speed
+#define USB_TXTYPE6_SPEED_DFLT 0x00000000 // Default
+#define USB_TXTYPE6_SPEED_HIGH 0x00000040 // High
+#define USB_TXTYPE6_SPEED_FULL 0x00000080 // Full
+#define USB_TXTYPE6_SPEED_LOW 0x000000C0 // Low
+#define USB_TXTYPE6_PROTO_M 0x00000030 // Protocol
+#define USB_TXTYPE6_PROTO_CTRL 0x00000000 // Control
+#define USB_TXTYPE6_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_TXTYPE6_PROTO_BULK 0x00000020 // Bulk
+#define USB_TXTYPE6_PROTO_INT 0x00000030 // Interrupt
+#define USB_TXTYPE6_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_TXTYPE6_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL6
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL6_TXPOLL_M \
+ 0x000000FF // TX Polling
+#define USB_TXINTERVAL6_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_TXINTERVAL6_TXPOLL_S \
+ 0
+#define USB_TXINTERVAL6_NAKLMT_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE6 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE6_SPEED_M 0x000000C0 // Operating Speed
+#define USB_RXTYPE6_SPEED_DFLT 0x00000000 // Default
+#define USB_RXTYPE6_SPEED_HIGH 0x00000040 // High
+#define USB_RXTYPE6_SPEED_FULL 0x00000080 // Full
+#define USB_RXTYPE6_SPEED_LOW 0x000000C0 // Low
+#define USB_RXTYPE6_PROTO_M 0x00000030 // Protocol
+#define USB_RXTYPE6_PROTO_CTRL 0x00000000 // Control
+#define USB_RXTYPE6_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_RXTYPE6_PROTO_BULK 0x00000020 // Bulk
+#define USB_RXTYPE6_PROTO_INT 0x00000030 // Interrupt
+#define USB_RXTYPE6_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_RXTYPE6_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL6
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL6_TXPOLL_M \
+ 0x000000FF // RX Polling
+#define USB_RXINTERVAL6_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_RXINTERVAL6_NAKLMT_S \
+ 0
+#define USB_RXINTERVAL6_TXPOLL_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP7 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP7_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_TXMAXP7_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL7 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL7_NAKTO 0x00000080 // NAK Timeout
+#define USB_TXCSRL7_CLRDT 0x00000040 // Clear Data Toggle
+#define USB_TXCSRL7_STALLED 0x00000020 // Endpoint Stalled
+#define USB_TXCSRL7_STALL 0x00000010 // Send STALL
+#define USB_TXCSRL7_SETUP 0x00000010 // Setup Packet
+#define USB_TXCSRL7_FLUSH 0x00000008 // Flush FIFO
+#define USB_TXCSRL7_ERROR 0x00000004 // Error
+#define USB_TXCSRL7_UNDRN 0x00000004 // Underrun
+#define USB_TXCSRL7_FIFONE 0x00000002 // FIFO Not Empty
+#define USB_TXCSRL7_TXRDY 0x00000001 // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH7 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH7_AUTOSET 0x00000080 // Auto Set
+#define USB_TXCSRH7_ISO 0x00000040 // Isochronous Transfers
+#define USB_TXCSRH7_MODE 0x00000020 // Mode
+#define USB_TXCSRH7_DMAEN 0x00000010 // DMA Request Enable
+#define USB_TXCSRH7_FDT 0x00000008 // Force Data Toggle
+#define USB_TXCSRH7_DMAMOD 0x00000004 // DMA Request Mode
+#define USB_TXCSRH7_DTWE 0x00000002 // Data Toggle Write Enable
+#define USB_TXCSRH7_DT 0x00000001 // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP7 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP7_MAXLOAD_M 0x000007FF // Maximum Payload
+#define USB_RXMAXP7_MAXLOAD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL7 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL7_CLRDT 0x00000080 // Clear Data Toggle
+#define USB_RXCSRL7_STALLED 0x00000040 // Endpoint Stalled
+#define USB_RXCSRL7_REQPKT 0x00000020 // Request Packet
+#define USB_RXCSRL7_STALL 0x00000020 // Send STALL
+#define USB_RXCSRL7_FLUSH 0x00000010 // Flush FIFO
+#define USB_RXCSRL7_DATAERR 0x00000008 // Data Error
+#define USB_RXCSRL7_NAKTO 0x00000008 // NAK Timeout
+#define USB_RXCSRL7_ERROR 0x00000004 // Error
+#define USB_RXCSRL7_OVER 0x00000004 // Overrun
+#define USB_RXCSRL7_FULL 0x00000002 // FIFO Full
+#define USB_RXCSRL7_RXRDY 0x00000001 // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH7 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH7_AUTOCL 0x00000080 // Auto Clear
+#define USB_RXCSRH7_ISO 0x00000040 // Isochronous Transfers
+#define USB_RXCSRH7_AUTORQ 0x00000040 // Auto Request
+#define USB_RXCSRH7_DMAEN 0x00000020 // DMA Request Enable
+#define USB_RXCSRH7_PIDERR 0x00000010 // PID Error
+#define USB_RXCSRH7_DISNYET 0x00000010 // Disable NYET
+#define USB_RXCSRH7_DMAMOD 0x00000008 // DMA Request Mode
+#define USB_RXCSRH7_DTWE 0x00000004 // Data Toggle Write Enable
+#define USB_RXCSRH7_DT 0x00000002 // Data Toggle
+#define USB_RXCSRH7_INCOMPRX 0x00000001 // Incomplete RX Transmission
+ // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT7 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT7_COUNT_M 0x00001FFF // Receive Packet Count
+#define USB_RXCOUNT7_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE7 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE7_SPEED_M 0x000000C0 // Operating Speed
+#define USB_TXTYPE7_SPEED_DFLT 0x00000000 // Default
+#define USB_TXTYPE7_SPEED_HIGH 0x00000040 // High
+#define USB_TXTYPE7_SPEED_FULL 0x00000080 // Full
+#define USB_TXTYPE7_SPEED_LOW 0x000000C0 // Low
+#define USB_TXTYPE7_PROTO_M 0x00000030 // Protocol
+#define USB_TXTYPE7_PROTO_CTRL 0x00000000 // Control
+#define USB_TXTYPE7_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_TXTYPE7_PROTO_BULK 0x00000020 // Bulk
+#define USB_TXTYPE7_PROTO_INT 0x00000030 // Interrupt
+#define USB_TXTYPE7_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_TXTYPE7_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL7
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL7_TXPOLL_M \
+ 0x000000FF // TX Polling
+#define USB_TXINTERVAL7_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_TXINTERVAL7_NAKLMT_S \
+ 0
+#define USB_TXINTERVAL7_TXPOLL_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE7 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE7_SPEED_M 0x000000C0 // Operating Speed
+#define USB_RXTYPE7_SPEED_DFLT 0x00000000 // Default
+#define USB_RXTYPE7_SPEED_HIGH 0x00000040 // High
+#define USB_RXTYPE7_SPEED_FULL 0x00000080 // Full
+#define USB_RXTYPE7_SPEED_LOW 0x000000C0 // Low
+#define USB_RXTYPE7_PROTO_M 0x00000030 // Protocol
+#define USB_RXTYPE7_PROTO_CTRL 0x00000000 // Control
+#define USB_RXTYPE7_PROTO_ISOC 0x00000010 // Isochronous
+#define USB_RXTYPE7_PROTO_BULK 0x00000020 // Bulk
+#define USB_RXTYPE7_PROTO_INT 0x00000030 // Interrupt
+#define USB_RXTYPE7_TEP_M 0x0000000F // Target Endpoint Number
+#define USB_RXTYPE7_TEP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL7
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL7_TXPOLL_M \
+ 0x000000FF // RX Polling
+#define USB_RXINTERVAL7_NAKLMT_M \
+ 0x000000FF // NAK Limit
+#define USB_RXINTERVAL7_NAKLMT_S \
+ 0
+#define USB_RXINTERVAL7_TXPOLL_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAINTR register.
+//
+//*****************************************************************************
+#define USB_DMAINTR_CH7 0x00000080 // Channel 7 DMA Interrupt
+#define USB_DMAINTR_CH6 0x00000040 // Channel 6 DMA Interrupt
+#define USB_DMAINTR_CH5 0x00000020 // Channel 5 DMA Interrupt
+#define USB_DMAINTR_CH4 0x00000010 // Channel 4 DMA Interrupt
+#define USB_DMAINTR_CH3 0x00000008 // Channel 3 DMA Interrupt
+#define USB_DMAINTR_CH2 0x00000004 // Channel 2 DMA Interrupt
+#define USB_DMAINTR_CH1 0x00000002 // Channel 1 DMA Interrupt
+#define USB_DMAINTR_CH0 0x00000001 // Channel 0 DMA Interrupt
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL0 register.
+//
+//*****************************************************************************
+#define USB_DMACTL0_BRSTM_M 0x00000600 // Burst Mode
+#define USB_DMACTL0_BRSTM_ANY 0x00000000 // Bursts of unspecified length
+#define USB_DMACTL0_BRSTM_INC4 0x00000200 // INCR4 or unspecified length
+#define USB_DMACTL0_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified
+ // length
+#define USB_DMACTL0_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or
+ // unspecified length
+#define USB_DMACTL0_ERR 0x00000100 // Bus Error Bit
+#define USB_DMACTL0_EP_M 0x000000F0 // Endpoint number
+#define USB_DMACTL0_IE 0x00000008 // DMA Interrupt Enable
+#define USB_DMACTL0_MODE 0x00000004 // DMA Transfer Mode
+#define USB_DMACTL0_DIR 0x00000002 // DMA Direction
+#define USB_DMACTL0_ENABLE 0x00000001 // DMA Transfer Enable
+#define USB_DMACTL0_EP_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR0 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR0_ADDR_M 0xFFFFFFFC // DMA Address
+#define USB_DMAADDR0_ADDR_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT0
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT0_COUNT_M 0xFFFFFFFC // DMA Count
+#define USB_DMACOUNT0_COUNT_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL1 register.
+//
+//*****************************************************************************
+#define USB_DMACTL1_BRSTM_M 0x00000600 // Burst Mode
+#define USB_DMACTL1_BRSTM_ANY 0x00000000 // Bursts of unspecified length
+#define USB_DMACTL1_BRSTM_INC4 0x00000200 // INCR4 or unspecified length
+#define USB_DMACTL1_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified
+ // length
+#define USB_DMACTL1_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or
+ // unspecified length
+#define USB_DMACTL1_ERR 0x00000100 // Bus Error Bit
+#define USB_DMACTL1_EP_M 0x000000F0 // Endpoint number
+#define USB_DMACTL1_IE 0x00000008 // DMA Interrupt Enable
+#define USB_DMACTL1_MODE 0x00000004 // DMA Transfer Mode
+#define USB_DMACTL1_DIR 0x00000002 // DMA Direction
+#define USB_DMACTL1_ENABLE 0x00000001 // DMA Transfer Enable
+#define USB_DMACTL1_EP_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR1 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR1_ADDR_M 0xFFFFFFFC // DMA Address
+#define USB_DMAADDR1_ADDR_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT1
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT1_COUNT_M 0xFFFFFFFC // DMA Count
+#define USB_DMACOUNT1_COUNT_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL2 register.
+//
+//*****************************************************************************
+#define USB_DMACTL2_BRSTM_M 0x00000600 // Burst Mode
+#define USB_DMACTL2_BRSTM_ANY 0x00000000 // Bursts of unspecified length
+#define USB_DMACTL2_BRSTM_INC4 0x00000200 // INCR4 or unspecified length
+#define USB_DMACTL2_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified
+ // length
+#define USB_DMACTL2_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or
+ // unspecified length
+#define USB_DMACTL2_ERR 0x00000100 // Bus Error Bit
+#define USB_DMACTL2_EP_M 0x000000F0 // Endpoint number
+#define USB_DMACTL2_IE 0x00000008 // DMA Interrupt Enable
+#define USB_DMACTL2_MODE 0x00000004 // DMA Transfer Mode
+#define USB_DMACTL2_DIR 0x00000002 // DMA Direction
+#define USB_DMACTL2_ENABLE 0x00000001 // DMA Transfer Enable
+#define USB_DMACTL2_EP_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR2 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR2_ADDR_M 0xFFFFFFFC // DMA Address
+#define USB_DMAADDR2_ADDR_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT2
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT2_COUNT_M 0xFFFFFFFC // DMA Count
+#define USB_DMACOUNT2_COUNT_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL3 register.
+//
+//*****************************************************************************
+#define USB_DMACTL3_BRSTM_M 0x00000600 // Burst Mode
+#define USB_DMACTL3_BRSTM_ANY 0x00000000 // Bursts of unspecified length
+#define USB_DMACTL3_BRSTM_INC4 0x00000200 // INCR4 or unspecified length
+#define USB_DMACTL3_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified
+ // length
+#define USB_DMACTL3_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or
+ // unspecified length
+#define USB_DMACTL3_ERR 0x00000100 // Bus Error Bit
+#define USB_DMACTL3_EP_M 0x000000F0 // Endpoint number
+#define USB_DMACTL3_IE 0x00000008 // DMA Interrupt Enable
+#define USB_DMACTL3_MODE 0x00000004 // DMA Transfer Mode
+#define USB_DMACTL3_DIR 0x00000002 // DMA Direction
+#define USB_DMACTL3_ENABLE 0x00000001 // DMA Transfer Enable
+#define USB_DMACTL3_EP_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR3 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR3_ADDR_M 0xFFFFFFFC // DMA Address
+#define USB_DMAADDR3_ADDR_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT3
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT3_COUNT_M 0xFFFFFFFC // DMA Count
+#define USB_DMACOUNT3_COUNT_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL4 register.
+//
+//*****************************************************************************
+#define USB_DMACTL4_BRSTM_M 0x00000600 // Burst Mode
+#define USB_DMACTL4_BRSTM_ANY 0x00000000 // Bursts of unspecified length
+#define USB_DMACTL4_BRSTM_INC4 0x00000200 // INCR4 or unspecified length
+#define USB_DMACTL4_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified
+ // length
+#define USB_DMACTL4_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or
+ // unspecified length
+#define USB_DMACTL4_ERR 0x00000100 // Bus Error Bit
+#define USB_DMACTL4_EP_M 0x000000F0 // Endpoint number
+#define USB_DMACTL4_IE 0x00000008 // DMA Interrupt Enable
+#define USB_DMACTL4_MODE 0x00000004 // DMA Transfer Mode
+#define USB_DMACTL4_DIR 0x00000002 // DMA Direction
+#define USB_DMACTL4_ENABLE 0x00000001 // DMA Transfer Enable
+#define USB_DMACTL4_EP_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR4 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR4_ADDR_M 0xFFFFFFFC // DMA Address
+#define USB_DMAADDR4_ADDR_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT4
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT4_COUNT_M 0xFFFFFFFC // DMA Count
+#define USB_DMACOUNT4_COUNT_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL5 register.
+//
+//*****************************************************************************
+#define USB_DMACTL5_BRSTM_M 0x00000600 // Burst Mode
+#define USB_DMACTL5_BRSTM_ANY 0x00000000 // Bursts of unspecified length
+#define USB_DMACTL5_BRSTM_INC4 0x00000200 // INCR4 or unspecified length
+#define USB_DMACTL5_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified
+ // length
+#define USB_DMACTL5_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or
+ // unspecified length
+#define USB_DMACTL5_ERR 0x00000100 // Bus Error Bit
+#define USB_DMACTL5_EP_M 0x000000F0 // Endpoint number
+#define USB_DMACTL5_IE 0x00000008 // DMA Interrupt Enable
+#define USB_DMACTL5_MODE 0x00000004 // DMA Transfer Mode
+#define USB_DMACTL5_DIR 0x00000002 // DMA Direction
+#define USB_DMACTL5_ENABLE 0x00000001 // DMA Transfer Enable
+#define USB_DMACTL5_EP_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR5 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR5_ADDR_M 0xFFFFFFFC // DMA Address
+#define USB_DMAADDR5_ADDR_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT5
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT5_COUNT_M 0xFFFFFFFC // DMA Count
+#define USB_DMACOUNT5_COUNT_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL6 register.
+//
+//*****************************************************************************
+#define USB_DMACTL6_BRSTM_M 0x00000600 // Burst Mode
+#define USB_DMACTL6_BRSTM_ANY 0x00000000 // Bursts of unspecified length
+#define USB_DMACTL6_BRSTM_INC4 0x00000200 // INCR4 or unspecified length
+#define USB_DMACTL6_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified
+ // length
+#define USB_DMACTL6_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or
+ // unspecified length
+#define USB_DMACTL6_ERR 0x00000100 // Bus Error Bit
+#define USB_DMACTL6_EP_M 0x000000F0 // Endpoint number
+#define USB_DMACTL6_IE 0x00000008 // DMA Interrupt Enable
+#define USB_DMACTL6_MODE 0x00000004 // DMA Transfer Mode
+#define USB_DMACTL6_DIR 0x00000002 // DMA Direction
+#define USB_DMACTL6_ENABLE 0x00000001 // DMA Transfer Enable
+#define USB_DMACTL6_EP_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR6 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR6_ADDR_M 0xFFFFFFFC // DMA Address
+#define USB_DMAADDR6_ADDR_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT6
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT6_COUNT_M 0xFFFFFFFC // DMA Count
+#define USB_DMACOUNT6_COUNT_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL7 register.
+//
+//*****************************************************************************
+#define USB_DMACTL7_BRSTM_M 0x00000600 // Burst Mode
+#define USB_DMACTL7_BRSTM_ANY 0x00000000 // Bursts of unspecified length
+#define USB_DMACTL7_BRSTM_INC4 0x00000200 // INCR4 or unspecified length
+#define USB_DMACTL7_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified
+ // length
+#define USB_DMACTL7_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or
+ // unspecified length
+#define USB_DMACTL7_ERR 0x00000100 // Bus Error Bit
+#define USB_DMACTL7_EP_M 0x000000F0 // Endpoint number
+#define USB_DMACTL7_IE 0x00000008 // DMA Interrupt Enable
+#define USB_DMACTL7_MODE 0x00000004 // DMA Transfer Mode
+#define USB_DMACTL7_DIR 0x00000002 // DMA Direction
+#define USB_DMACTL7_ENABLE 0x00000001 // DMA Transfer Enable
+#define USB_DMACTL7_EP_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR7 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR7_ADDR_M 0xFFFFFFFC // DMA Address
+#define USB_DMAADDR7_ADDR_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT7
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT7_COUNT_M 0xFFFFFFFC // DMA Count
+#define USB_DMACOUNT7_COUNT_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT1
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT1_M 0x0000FFFF // Block Transfer Packet Count
+#define USB_RQPKTCOUNT1_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT2
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT2_M 0x0000FFFF // Block Transfer Packet Count
+#define USB_RQPKTCOUNT2_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT3
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT3_M 0x0000FFFF // Block Transfer Packet Count
+#define USB_RQPKTCOUNT3_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT4
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT4_COUNT_M 0x0000FFFF // Block Transfer Packet Count
+#define USB_RQPKTCOUNT4_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT5
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT5_COUNT_M 0x0000FFFF // Block Transfer Packet Count
+#define USB_RQPKTCOUNT5_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT6
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT6_COUNT_M 0x0000FFFF // Block Transfer Packet Count
+#define USB_RQPKTCOUNT6_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT7
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT7_COUNT_M 0x0000FFFF // Block Transfer Packet Count
+#define USB_RQPKTCOUNT7_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXDPKTBUFDIS
+// register.
+//
+//*****************************************************************************
+#define USB_RXDPKTBUFDIS_EP7 0x00000080 // EP7 RX Double-Packet Buffer
+ // Disable
+#define USB_RXDPKTBUFDIS_EP6 0x00000040 // EP6 RX Double-Packet Buffer
+ // Disable
+#define USB_RXDPKTBUFDIS_EP5 0x00000020 // EP5 RX Double-Packet Buffer
+ // Disable
+#define USB_RXDPKTBUFDIS_EP4 0x00000010 // EP4 RX Double-Packet Buffer
+ // Disable
+#define USB_RXDPKTBUFDIS_EP3 0x00000008 // EP3 RX Double-Packet Buffer
+ // Disable
+#define USB_RXDPKTBUFDIS_EP2 0x00000004 // EP2 RX Double-Packet Buffer
+ // Disable
+#define USB_RXDPKTBUFDIS_EP1 0x00000002 // EP1 RX Double-Packet Buffer
+ // Disable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXDPKTBUFDIS
+// register.
+//
+//*****************************************************************************
+#define USB_TXDPKTBUFDIS_EP7 0x00000080 // EP7 TX Double-Packet Buffer
+ // Disable
+#define USB_TXDPKTBUFDIS_EP6 0x00000040 // EP6 TX Double-Packet Buffer
+ // Disable
+#define USB_TXDPKTBUFDIS_EP5 0x00000020 // EP5 TX Double-Packet Buffer
+ // Disable
+#define USB_TXDPKTBUFDIS_EP4 0x00000010 // EP4 TX Double-Packet Buffer
+ // Disable
+#define USB_TXDPKTBUFDIS_EP3 0x00000008 // EP3 TX Double-Packet Buffer
+ // Disable
+#define USB_TXDPKTBUFDIS_EP2 0x00000004 // EP2 TX Double-Packet Buffer
+ // Disable
+#define USB_TXDPKTBUFDIS_EP1 0x00000002 // EP1 TX Double-Packet Buffer
+ // Disable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_CTO register.
+//
+//*****************************************************************************
+#define USB_CTO_CCTV_M 0x0000FFFF // Configurable Chirp Timeout Value
+#define USB_CTO_CCTV_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_HHSRTN register.
+//
+//*****************************************************************************
+#define USB_HHSRTN_HHSRTN_M 0x0000FFFF // HIgh Speed to UTM Operating
+ // Delay
+#define USB_HHSRTN_HHSRTN_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_HSBT register.
+//
+//*****************************************************************************
+#define USB_HSBT_HSBT_M 0x0000000F // High Speed Timeout Adder
+#define USB_HSBT_HSBT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_LPMATTR register.
+//
+//*****************************************************************************
+#define USB_LPMATTR_ENDPT_M 0x0000F000 // Endpoint
+#define USB_LPMATTR_RMTWAK 0x00000100 // Remote Wake
+#define USB_LPMATTR_HIRD_M 0x000000F0 // Host Initiated Resume Duration
+#define USB_LPMATTR_LS_M 0x0000000F // Link State
+#define USB_LPMATTR_LS_L1 0x00000001 // Sleep State (L1)
+#define USB_LPMATTR_ENDPT_S 12
+#define USB_LPMATTR_HIRD_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_LPMCNTRL register.
+//
+//*****************************************************************************
+#define USB_LPMCNTRL_NAK 0x00000010 // LPM NAK
+#define USB_LPMCNTRL_EN_M 0x0000000C // LPM Enable
+#define USB_LPMCNTRL_EN_NONE 0x00000000 // LPM and Extended transactions
+ // are not supported. In this case,
+ // the USB does not respond to LPM
+ // transactions and LPM
+ // transactions cause a timeout
+#define USB_LPMCNTRL_EN_EXT 0x00000004 // LPM is not supported but
+ // extended transactions are
+ // supported. In this case, the USB
+ // does respond to an LPM
+ // transaction with a STALL
+#define USB_LPMCNTRL_EN_LPMEXT 0x0000000C // The USB supports LPM extended
+ // transactions. In this case, the
+ // USB responds with a NYET or an
+ // ACK as determined by the value
+ // of TXLPM and other conditions
+#define USB_LPMCNTRL_RES 0x00000002 // LPM Resume
+#define USB_LPMCNTRL_TXLPM 0x00000001 // Transmit LPM Transaction Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_LPMIM register.
+//
+//*****************************************************************************
+#define USB_LPMIM_ERR 0x00000020 // LPM Error Interrupt Mask
+#define USB_LPMIM_RES 0x00000010 // LPM Resume Interrupt Mask
+#define USB_LPMIM_NC 0x00000008 // LPM NC Interrupt Mask
+#define USB_LPMIM_ACK 0x00000004 // LPM ACK Interrupt Mask
+#define USB_LPMIM_NY 0x00000002 // LPM NY Interrupt Mask
+#define USB_LPMIM_STALL 0x00000001 // LPM STALL Interrupt Mask
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_LPMRIS register.
+//
+//*****************************************************************************
+#define USB_LPMRIS_ERR 0x00000020 // LPM Interrupt Status
+#define USB_LPMRIS_RES 0x00000010 // LPM Resume Interrupt Status
+#define USB_LPMRIS_NC 0x00000008 // LPM NC Interrupt Status
+#define USB_LPMRIS_ACK 0x00000004 // LPM ACK Interrupt Status
+#define USB_LPMRIS_NY 0x00000002 // LPM NY Interrupt Status
+#define USB_LPMRIS_LPMST 0x00000001 // LPM STALL Interrupt Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_LPMFADDR register.
+//
+//*****************************************************************************
+#define USB_LPMFADDR_ADDR_M 0x0000007F // LPM Function Address
+#define USB_LPMFADDR_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_EPC register.
+//
+//*****************************************************************************
+#define USB_EPC_PFLTACT_M 0x00000300 // Power Fault Action
+#define USB_EPC_PFLTACT_UNCHG 0x00000000 // Unchanged
+#define USB_EPC_PFLTACT_TRIS 0x00000100 // Tristate
+#define USB_EPC_PFLTACT_LOW 0x00000200 // Low
+#define USB_EPC_PFLTACT_HIGH 0x00000300 // High
+#define USB_EPC_PFLTAEN 0x00000040 // Power Fault Action Enable
+#define USB_EPC_PFLTSEN_HIGH 0x00000020 // Power Fault Sense
+#define USB_EPC_PFLTEN 0x00000010 // Power Fault Input Enable
+#define USB_EPC_EPENDE 0x00000004 // EPEN Drive Enable
+#define USB_EPC_EPEN_M 0x00000003 // External Power Supply Enable
+ // Configuration
+#define USB_EPC_EPEN_LOW 0x00000000 // Power Enable Active Low
+#define USB_EPC_EPEN_HIGH 0x00000001 // Power Enable Active High
+#define USB_EPC_EPEN_VBLOW 0x00000002 // Power Enable High if VBUS Low
+ // (OTG only)
+#define USB_EPC_EPEN_VBHIGH 0x00000003 // Power Enable High if VBUS High
+ // (OTG only)
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_EPCRIS register.
+//
+//*****************************************************************************
+#define USB_EPCRIS_PF 0x00000001 // USB Power Fault Interrupt Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_EPCIM register.
+//
+//*****************************************************************************
+#define USB_EPCIM_PF 0x00000001 // USB Power Fault Interrupt Mask
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_EPCISC register.
+//
+//*****************************************************************************
+#define USB_EPCISC_PF 0x00000001 // USB Power Fault Interrupt Status
+ // and Clear
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DRRIS register.
+//
+//*****************************************************************************
+#define USB_DRRIS_RESUME 0x00000001 // RESUME Interrupt Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DRIM register.
+//
+//*****************************************************************************
+#define USB_DRIM_RESUME 0x00000001 // RESUME Interrupt Mask
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DRISC register.
+//
+//*****************************************************************************
+#define USB_DRISC_RESUME 0x00000001 // RESUME Interrupt Status and
+ // Clear
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_GPCS register.
+//
+//*****************************************************************************
+#define USB_GPCS_DEVMOD_M 0x00000007 // Device Mode
+#define USB_GPCS_DEVMOD_OTG 0x00000000 // Use USB0VBUS and USB0ID pin
+#define USB_GPCS_DEVMOD_HOST 0x00000002 // Force USB0VBUS and USB0ID low
+#define USB_GPCS_DEVMOD_DEV 0x00000003 // Force USB0VBUS and USB0ID high
+#define USB_GPCS_DEVMOD_HOSTVBUS \
+ 0x00000004 // Use USB0VBUS and force USB0ID
+ // low
+#define USB_GPCS_DEVMOD_DEVVBUS 0x00000005 // Use USB0VBUS and force USB0ID
+ // high
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_VDC register.
+//
+//*****************************************************************************
+#define USB_VDC_VBDEN 0x00000001 // VBUS Droop Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_VDCRIS register.
+//
+//*****************************************************************************
+#define USB_VDCRIS_VD 0x00000001 // VBUS Droop Raw Interrupt Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_VDCIM register.
+//
+//*****************************************************************************
+#define USB_VDCIM_VD 0x00000001 // VBUS Droop Interrupt Mask
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_VDCISC register.
+//
+//*****************************************************************************
+#define USB_VDCISC_VD 0x00000001 // VBUS Droop Interrupt Status and
+ // Clear
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_PP register.
+//
+//*****************************************************************************
+#define USB_PP_ECNT_M 0x0000FF00 // Endpoint Count
+#define USB_PP_USB_M 0x000000C0 // USB Capability
+#define USB_PP_USB_DEVICE 0x00000040 // DEVICE
+#define USB_PP_USB_HOSTDEVICE 0x00000080 // HOST
+#define USB_PP_USB_OTG 0x000000C0 // OTG
+#define USB_PP_ULPI 0x00000020 // ULPI Present
+#define USB_PP_PHY 0x00000010 // PHY Present
+#define USB_PP_TYPE_M 0x0000000F // Controller Type
+#define USB_PP_TYPE_0 0x00000000 // The first-generation USB
+ // controller
+#define USB_PP_TYPE_1 0x00000001 // The second-generation USB
+ // controller revision
+#define USB_PP_ECNT_S 8
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_PC register.
+//
+//*****************************************************************************
+#define USB_PC_ULPIEN 0x00010000 // ULPI Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_CC register.
+//
+//*****************************************************************************
+#define USB_CC_CLKEN 0x00000200 // USB Clock Enable
+#define USB_CC_CSD 0x00000100 // Clock Source/Direction
+#define USB_CC_CLKDIV_M 0x0000000F // PLL Clock Divisor
+#define USB_CC_CLKDIV_S 0
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c
new file mode 100644
index 000000000..ccc27c3c9
--- /dev/null
+++ b/src/portable/microchip/pic/dcd_pic.c
@@ -0,0 +1,786 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Koji Kitayama
+ * Copyright (c) 2022 Reimu NotMoe <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && \
+ (CFG_TUSB_MCU == OPT_MCU_PIC32MX || CFG_TUSB_MCU == OPT_MCU_PIC32MM || \
+ CFG_TUSB_MCU == OPT_MCU_PIC32MK || CFG_TUSB_MCU == OPT_MCU_PIC24 || \
+ CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+
+#include <xc.h>
+
+#include "device/dcd.h"
+
+
+#if (CFG_TUSB_MCU == OPT_MCU_PIC32MX || CFG_TUSB_MCU == OPT_MCU_PIC32MM || CFG_TUSB_MCU == OPT_MCU_PIC32MK)
+
+#define TU_PIC_INT_SIZE 4
+
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24 || CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+
+#define TU_PIC_INT_SIZE 2
+
+#else
+
+#error Unsupportd PIC MCU
+
+#endif
+
+
+#if TU_PIC_INT_SIZE == 4
+
+#ifndef KVA_TO_PA
+#define KVA_TO_PA(kva) ((uint32_t)(kva) & 0x1fffffff)
+#endif
+
+#ifndef PA_TO_KVA1
+#define PA_TO_KVA1(pa) ((uint32_t)(pa) | 0xA0000000)
+#endif
+
+#else
+
+#ifndef KVA_TO_PA
+#define KVA_TO_PA(kva) (kva)
+#endif
+
+#ifndef PA_TO_KVA1
+#define PA_TO_KVA1(pa) (pa)
+#endif
+
+#endif
+
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+ TOK_PID_OUT = 0x1u,
+ TOK_PID_IN = 0x9u,
+ TOK_PID_SETUP = 0xDu,
+};
+
+// The BDT is 8 bytes on 32bit PICs and 4 bytes on 8/16bit PICs
+#if TU_PIC_INT_SIZE == 4
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t head;
+ struct {
+ union {
+ struct {
+ uint16_t : 2;
+ uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ uint16_t own : 1;
+ uint16_t : 8;
+ };
+ struct {
+ uint16_t : 2;
+ uint16_t bdt_stall : 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ uint16_t : 10;
+ };
+ };
+ uint16_t bc : 10;
+ uint16_t : 6;
+ };
+ };
+ uint8_t *addr;
+} buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" );
+#else
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint16_t head;
+
+ struct {
+ uint16_t : 10;
+ uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ uint16_t own : 1;
+ };
+ struct {
+ uint16_t : 10;
+ uint16_t bdt_stall : 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ };
+
+ struct {
+ uint16_t bc : 10;
+ uint16_t : 6;
+ };
+ };
+ uint8_t *addr;
+} buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 4, "size is not correct" );
+#endif
+
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t state;
+ struct {
+ uint32_t max_packet_size :11;
+ uint32_t : 5;
+ uint32_t odd : 1;
+ uint32_t :15;
+ };
+ };
+ uint16_t length;
+ uint16_t remaining;
+} endpoint_state_t;
+
+TU_VERIFY_STATIC( sizeof(endpoint_state_t) == 8, "size is not correct" );
+
+typedef struct
+{
+ union {
+ /* [#EP][OUT,IN][EVEN,ODD] */
+ buffer_descriptor_t bdt[16][2][2];
+#if TU_PIC_INT_SIZE == 4
+ uint16_t bda[256];
+#else
+ uint8_t bda[256];
+#endif
+ };
+ TU_ATTR_ALIGNED(4) union {
+ endpoint_state_t endpoint[16][2];
+ endpoint_state_t endpoint_unified[16 * 2];
+ };
+ uint8_t setup_packet[8];
+ uint8_t addr;
+} dcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+// BDT(Buffer Descriptor Table) must be 256-byte aligned
+CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) volatile static dcd_data_t _dcd;
+
+#if TU_PIC_INT_SIZE == 4
+TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
+#else
+TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 256, "size is not correct" );
+#endif
+
+#if TU_PIC_INT_SIZE == 4
+typedef uint32_t ep_reg_t;
+#elif TU_PIC_INT_SIZE == 2
+typedef uint16_t ep_reg_t;
+#endif
+
+static inline volatile void *ep_addr(uint8_t rhport, uint8_t ep_num) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ volatile void *ep_reg_base = rhport ? (&U2EP0) : (&U1EP0);
+#else
+ volatile void *ep_reg_base = &U1EP0;
+#endif
+#if TU_PIC_INT_SIZE == 4
+ const size_t offset = 0x10;
+#else
+ const size_t offset = 0x2;
+#endif
+ return ep_reg_base + offset * ep_num;
+}
+
+static inline ep_reg_t ep_read(uint8_t rhport, uint8_t ep_num) {
+ volatile ep_reg_t *ep = ep_addr(rhport, ep_num);
+ return *ep;
+}
+
+static inline void ep_write(uint8_t rhport, uint8_t ep_num, ep_reg_t val) {
+ volatile ep_reg_t *ep = ep_addr(rhport, ep_num);
+ *ep = val;
+}
+
+static inline void ep_clear(uint8_t rhport, uint8_t ep_num, ep_reg_t val) {
+#if TU_PIC_INT_SIZE == 4
+ volatile ep_reg_t *ep_clr = (ep_addr(rhport, ep_num) + 0x4);
+ *ep_clr = val;
+#else
+ ep_reg_t v = ep_read(rhport, ep_num);
+ v &= ~val;
+ ep_write(rhport, ep_num, v);
+#endif
+}
+
+static inline void ep_set(uint8_t rhport, uint8_t ep_num, ep_reg_t val) {
+#if TU_PIC_INT_SIZE == 4
+ volatile ep_reg_t *ep_s = (ep_addr(rhport, ep_num) + 0x8);
+ *ep_s = val;
+#else
+ ep_reg_t v = ep_read(rhport, ep_num);
+ v |= val;
+ ep_write(rhport, ep_num, v);
+#endif
+}
+
+static inline void intr_enable(uint8_t rhport) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ IEC0SET = _IEC0_USBIE_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ IEC1SET = _IEC1_USBIE_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ if (rhport == 0)
+ IEC1SET = _IEC1_USB1IE_MASK;
+ else
+ IEC7SET = _IEC7_USB2IE_MASK;
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+ IEC5bits.USB1IE = 1;
+#endif
+}
+
+static inline void intr_disable(uint8_t rhport) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ IEC0CLR = _IEC0_USBIE_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ IEC1CLR = _IEC1_USBIE_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ if (rhport == 0)
+ IEC1CLR = _IEC1_USB1IE_MASK;
+ else
+ IEC7CLR = _IEC7_USB2IE_MASK;
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+ IEC5bits.USB1IE = 0;
+#endif
+}
+
+static inline int intr_is_enabled(uint8_t rhport) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ return IEC0bits.USBIE;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ return IEC1bits.USBIE;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ if (rhport == 0)
+ return IEC1bits.USB1IE;
+ else
+ return IEC7bits.USB2IE;
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+ return IEC5bits.USB1IE;
+#endif
+}
+
+static inline void intr_clear(uint8_t rhport) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ IFS0CLR = _IFS0_USBIF_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ IFS1CLR = _IFS1_USBIF_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ if (rhport == 0)
+ IFS1CLR = _IFS1_USB1IF_MASK;
+ else
+ IFS7CLR = _IFS7_USB2IF_MASK;
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+ IFS5bits.USB1IF = 0;
+#endif
+}
+
+static void prepare_next_setup_packet(uint8_t rhport)
+{
+ const unsigned out_odd = _dcd.endpoint[0][0].odd;
+ const unsigned in_odd = _dcd.endpoint[0][1].odd;
+ TU_ASSERT(0 == _dcd.bdt[0][0][out_odd].own, );
+
+ _dcd.bdt[0][0][out_odd].data = 0;
+ _dcd.bdt[0][0][out_odd ^ 1].data = 1;
+ _dcd.bdt[0][1][in_odd].data = 1;
+ _dcd.bdt[0][1][in_odd ^ 1].data = 0;
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT),
+ _dcd.setup_packet, sizeof(_dcd.setup_packet));
+}
+
+static void process_stall(uint8_t rhport)
+{
+ for (int i = 0; i < 16; ++i) {
+ unsigned const endpt = ep_read(rhport, i);
+
+ if (endpt & _U1EP0_EPSTALL_MASK) {
+ // prepare next setup if endpoint0
+ if ( i == 0 ) prepare_next_setup_packet(rhport);
+
+ // clear stall bit
+ ep_clear(rhport, i, _U1EP0_EPSTALL_MASK);
+ }
+ }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+ ep_reg_t s = U1STAT;
+
+ U1IR = _U1IR_TRNIF_MASK;
+
+ uint8_t epnum = (s >> _U1STAT_ENDPT0_POSITION);
+ uint8_t dir = (s & _U1STAT_DIR_MASK) >> _U1STAT_DIR_POSITION;
+ unsigned odd = (s & _U1STAT_PPBI_MASK) ? 1 : 0;
+
+ buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s];
+ endpoint_state_t *ep = &_dcd.endpoint_unified[s >> 3];
+
+ /* fetch pid before discarded by the next steps */
+ const unsigned pid = bd->tok_pid;
+
+ /* reset values for a next transfer */
+ bd->bdt_stall = 0;
+ bd->dts = 1;
+ bd->ninc = 0;
+ bd->keep = 0;
+ /* update the odd variable to prepare for the next transfer */
+ ep->odd = odd ^ 1;
+ if (pid == TOK_PID_SETUP) {
+ dcd_event_setup_received(rhport, (uint8_t *)PA_TO_KVA1(bd->addr), true);
+#if TU_PIC_INT_SIZE == 4
+ U1CONCLR = _U1CON_PKTDIS_TOKBUSY_MASK;
+#else
+ U1CONbits.PKTDIS = 0;
+#endif
+ return;
+ }
+
+ const unsigned bc = bd->bc;
+ const unsigned remaining = ep->remaining - bc;
+ if (remaining && bc == ep->max_packet_size) {
+ /* continue the transferring consecutive data */
+ ep->remaining = remaining;
+ const int next_remaining = remaining - ep->max_packet_size;
+ if (next_remaining > 0) {
+ /* prepare to the after next transfer */
+ bd->addr += ep->max_packet_size * 2;
+ bd->bc = next_remaining > ep->max_packet_size ? ep->max_packet_size: next_remaining;
+ bd->own = 1; /* the own bit must set after addr */
+ }
+ return;
+ }
+ const unsigned length = ep->length;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(epnum, dir),
+ length - remaining, XFER_RESULT_SUCCESS, true);
+ if (0 == epnum && 0 == length) {
+ /* After completion a ZLP of control transfer,
+ * it prepares for the next steup transfer. */
+ if (_dcd.addr) {
+ /* When the transfer was the SetAddress,
+ * the device address should be updated here. */
+ U1ADDR = _dcd.addr;
+ _dcd.addr = 0;
+ }
+ prepare_next_setup_packet(rhport);
+ }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+#if TU_PIC_INT_SIZE == 4
+ U1PWRCCLR = _U1PWRC_USUSPEND_MASK;
+ U1CONSET = _U1CON_PPBRST_MASK;
+#else
+ U1PWRCbits.USUSPND = 0;
+ U1CONbits.PPBRST = 1;
+#endif
+ U1ADDR = 0;
+
+ U1IE = _U1IE_URSTIE_MASK | _U1IE_TRNIE_MASK | _U1IE_IDLEIE_MASK |
+ _U1IE_UERRIE_MASK | _U1IE_STALLIE_MASK;
+
+ U1EP0 = _U1EP0_EPHSHK_MASK | _U1EP0_EPRXEN_MASK | _U1EP0_EPTXEN_MASK;
+
+ for (unsigned i = 1; i < 16; ++i) {
+ ep_write(rhport, i, 0);
+ }
+
+ buffer_descriptor_t *bd = _dcd.bdt[0][0];
+ for (unsigned i = 0; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+ bd->head = 0;
+ }
+ const endpoint_state_t ep0 = {
+ .max_packet_size = CFG_TUD_ENDPOINT0_SIZE,
+ .odd = 0,
+ .length = 0,
+ .remaining = 0,
+ };
+ _dcd.endpoint[0][0] = ep0;
+ _dcd.endpoint[0][1] = ep0;
+ tu_memclr(_dcd.endpoint[1], sizeof(_dcd.endpoint) - sizeof(_dcd.endpoint[0]));
+ _dcd.addr = 0;
+ prepare_next_setup_packet(rhport);
+#if TU_PIC_INT_SIZE == 4
+ U1CONCLR = _U1CON_PPBRST_MASK;
+#else
+ U1CONbits.PPBRST = 0;
+#endif
+ dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+}
+
+static void process_bus_sleep(uint8_t rhport)
+{
+ // Enable resume & disable suspend interrupt
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+}
+
+static void process_bus_resume(uint8_t rhport)
+{
+ // Enable suspend & disable resume interrupt
+#if TU_PIC_INT_SIZE == 4
+ U1PWRCCLR = _U1PWRC_USUSPEND_MASK;
+ U1IECLR = _U1IE_RESUMEIE_MASK;
+ U1IESET = _U1IE_IDLEIE_MASK;
+#else
+ U1PWRCbits.USUSPND = 0;
+ U1IEbits.RESUMEIE = 0;
+ U1IEbits.IDLEIE = 1;
+#endif
+
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+ intr_disable(rhport);
+ intr_clear(rhport);
+
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ TRISBbits.TRISB6 = 1;
+#endif
+
+ tu_memclr(&_dcd, sizeof(_dcd));
+
+#if TU_PIC_INT_SIZE == 4
+ U1PWRCSET = _U1PWRC_USBPWR_MASK;
+#else
+ U1PWRCbits.USBPWR = 1;
+#endif
+
+#if TU_PIC_INT_SIZE == 4
+ uint32_t bdt_phys = KVA_TO_PA((uintptr_t)_dcd.bdt);
+
+ U1BDTP1 = (uint8_t)(bdt_phys >> 8);
+ U1BDTP2 = (uint8_t)(bdt_phys >> 16);
+ U1BDTP3 = (uint8_t)(bdt_phys >> 24);
+#else
+ U1BDTP1 = (uint8_t)((uint16_t)(void *)_dcd.bdt >> 8);
+
+ U1CNFG1bits.PPB = 2;
+#endif
+
+ U1IE = _U1IE_URSTIE_MASK;
+
+ dcd_connect(rhport);
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ intr_enable(rhport);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ intr_disable(rhport);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ _dcd.addr = dev_addr & 0x7F;
+ /* Response with status first before changing device address */
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+#if TU_PIC_INT_SIZE == 4
+ U1CONSET = _U1CON_RESUME_MASK;
+#else
+ U1CONbits.RESUME = 1;
+#endif
+ unsigned cnt = 25000000 / 1000;
+ while (cnt--) asm volatile("nop");
+
+#if TU_PIC_INT_SIZE == 4
+ U1CONCLR = _U1CON_RESUME_MASK;
+#else
+ U1CONbits.RESUME = 0;
+#endif
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ while (!U1CONbits.USBEN) {
+#if TU_PIC_INT_SIZE == 4
+ U1CONSET = _U1CON_USBEN_SOFEN_MASK;
+#else
+ U1CONbits.USBEN = 1;
+#endif
+ }
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ U1CON = 0;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ const unsigned odd = ep->odd;
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+
+ /* No support for control transfer */
+ TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL));
+
+ ep->max_packet_size = tu_edpt_packet_size(ep_desc);
+
+
+ unsigned val = _U1EP0_EPCONDIS_MASK;
+ val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? _U1EP0_EPHSHK_MASK : 0;
+ val |= dir ? _U1EP0_EPTXEN_MASK : _U1EP0_EPRXEN_MASK;
+
+ ep_reg_t tmp = ep_read(rhport, epn);
+ tmp |= val;
+ ep_write(rhport, epn, tmp);
+
+ if (xfer != TUSB_XFER_ISOCHRONOUS) {
+ bd[odd].dts = 1;
+ bd[odd].data = 0;
+ bd[odd ^ 1].dts = 1;
+ bd[odd ^ 1].data = 1;
+ }
+
+ return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ const unsigned ie = intr_is_enabled(rhport);
+ intr_disable(rhport);
+
+ for (unsigned i = 1; i < 16; ++i) {
+ ep_write(rhport, i, 0);
+ }
+
+ if (ie) intr_enable(rhport);
+
+ buffer_descriptor_t *bd = _dcd.bdt[1][0];
+ for (unsigned i = 2; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+ bd->head = 0;
+ }
+ endpoint_state_t *ep = &_dcd.endpoint[1][0];
+ for (unsigned i = 2; i < sizeof(_dcd.endpoint)/sizeof(*ep); ++i, ++ep) {
+ /* Clear except the odd */
+ ep->max_packet_size = 0;
+ ep->length = 0;
+ ep->remaining = 0;
+ }
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+ const unsigned msk = dir ? _U1EP0_EPTXEN_MASK : _U1EP0_EPRXEN_MASK;
+ const unsigned ie = intr_is_enabled(rhport);
+
+ intr_disable(rhport);
+
+ ep_clear(rhport, epn, msk);
+
+ ep->max_packet_size = 0;
+ ep->length = 0;
+ ep->remaining = 0;
+ bd[0].head = 0;
+ bd[1].head = 0;
+
+ if (ie) intr_enable(rhport);
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd];
+ TU_ASSERT(0 == bd->own);
+
+ const unsigned ie = intr_is_enabled(rhport);
+
+ intr_disable(rhport);
+
+ ep->length = total_bytes;
+ ep->remaining = total_bytes;
+
+ const unsigned mps = ep->max_packet_size;
+ if (total_bytes > mps) {
+ buffer_descriptor_t *next = ep->odd ? bd - 1: bd + 1;
+ /* When total_bytes is greater than the max packet size,
+ * it prepares to the next transfer to avoid NAK in advance. */
+ next->bc = total_bytes >= 2 * mps ? mps: total_bytes - mps;
+ next->addr = (uint8_t *)KVA_TO_PA(buffer + mps);
+ next->own = 1;
+ }
+ bd->bc = total_bytes >= mps ? mps: total_bytes;
+ bd->addr = (uint8_t *)KVA_TO_PA(buffer);
+ bd->own = 1; /* This bit must be set last */
+
+ if (ie) intr_enable(rhport);
+
+ return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ const unsigned epn = tu_edpt_number(ep_addr);
+
+ if (0 == epn) {
+ ep_set(rhport, epn, _U1EP0_EPSTALL_MASK);
+ } else {
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned odd = _dcd.endpoint[epn][dir].odd;
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][odd];
+ TU_ASSERT(0 == bd->own,);
+
+ const unsigned ie = intr_is_enabled(rhport);
+
+ intr_disable(rhport);
+
+ bd->bdt_stall = 1;
+ bd->own = 1; /* This bit must be set last */
+
+ if (ie) intr_enable(rhport);
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ TU_VERIFY(epn,);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned odd = _dcd.endpoint[epn][dir].odd;
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+ TU_VERIFY(bd[odd].own,);
+
+ const unsigned ie = intr_is_enabled(rhport);
+
+ intr_disable(rhport);
+
+ bd[odd].own = 0;
+
+ // clear stall
+ bd[odd].bdt_stall = 0;
+
+ // Reset data toggle
+ bd[odd ].data = 0;
+ bd[odd ^ 1].data = 1;
+
+ // We already cleared this in ISR, but just clear it here to be safe
+ const unsigned endpt = ep_read(rhport, epn);
+ if (endpt & _U1EP0_EPSTALL_MASK) {
+ ep_clear(rhport, endpt, _U1EP0_EPSTALL_MASK);
+ }
+
+ if (ie) intr_enable(rhport);
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void dcd_int_handler(uint8_t rhport)
+{
+ uint32_t is = U1IR;
+ uint32_t msk = U1IE;
+
+ U1IR = is & ~msk;
+ is &= msk;
+
+ if (is & _U1IR_UERRIF_MASK) {
+ uint32_t es = U1EIR;
+ U1EIR = es;
+ U1IR = is; /* discard any pending events */
+ }
+
+ if (is & _U1IR_URSTIF_MASK) {
+ U1IR = is; /* discard any pending events */
+ process_bus_reset(rhport);
+ }
+
+ if (is & _U1IR_IDLEIF_MASK) {
+ // Note Host usually has extra delay after bus reset (without SOF), which could falsely
+ // detected as Sleep event. Though usbd has debouncing logic so we are good
+ U1IR = _U1IR_IDLEIF_MASK;
+ process_bus_sleep(rhport);
+ }
+
+ if (is & _U1IR_RESUMEIF_MASK) {
+ U1IR = _U1IR_RESUMEIF_MASK;
+ process_bus_resume(rhport);
+ }
+
+ if (is & _U1IR_SOFIF_MASK) {
+ U1IR = _U1IR_SOFIF_MASK;
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
+
+ if (is & _U1IR_STALLIF_MASK) {
+ U1IR = _U1IR_STALLIF_MASK;
+ process_stall(rhport);
+ }
+
+ if (is & _U1IR_TRNIF_MASK) {
+ process_tokdne(rhport);
+ }
+
+ intr_clear(rhport);
+}
+
+#endif
diff --git a/src/portable/microchip/pic32mz/dcd_pic32mz.c b/src/portable/microchip/pic32mz/dcd_pic32mz.c
new file mode 100644
index 000000000..9ad755670
--- /dev/null
+++ b/src/portable/microchip/pic32mz/dcd_pic32mz.c
@@ -0,0 +1,753 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Jerzy Kasenberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_PIC32MZ
+
+#include <common/tusb_common.h>
+#include <device/dcd.h>
+
+#include <xc.h>
+#include "usbhs_registers.h"
+
+#define USB_REGS ((usbhs_registers_t *) (_USB_BASE_ADDRESS))
+
+// Maximum number of endpoints, could be trimmed down in tusb_config to reduce RAM usage.
+#ifndef EP_MAX
+#define EP_MAX 8
+#endif
+
+
+typedef enum {
+ EP0_STAGE_NONE,
+ EP0_STAGE_SETUP_IN_DATA,
+ EP0_STAGE_SETUP_OUT_NO_DATA,
+ EP0_STAGE_SETUP_OUT_DATA,
+ EP0_STAGE_DATA_IN,
+ EP0_STAGE_DATA_IN_LAST_PACKET_FILLED,
+ EP0_STAGE_DATA_IN_SENT,
+ EP0_STAGE_DATA_OUT,
+ EP0_STAGE_DATA_OUT_COMPLETE,
+ EP0_STAGE_STATUS_IN,
+ EP0_STAGE_ADDRESS_CHANGE,
+} ep0_stage_t;
+
+typedef struct {
+ uint8_t * buffer;
+ // Total length of current transfer
+ uint16_t total_len;
+ // Bytes transferred so far
+ uint16_t transferred;
+ uint16_t max_packet_size;
+ uint16_t fifo_size;
+ // Packet size sent or received so far. It is used to modify transferred field
+ // after ACK is received or when filling ISO endpoint with size larger then
+ // FIFO size.
+ uint16_t last_packet_size;
+ uint8_t ep_addr;
+} xfer_ctl_t;
+
+static struct
+{
+ // Current FIFO RAM address used for FIFO allocation
+ uint16_t fifo_addr_top;
+ // EP0 transfer stage
+ ep0_stage_t ep0_stage;
+ // Device address
+ uint8_t dev_addr;
+ xfer_ctl_t xfer_status[EP_MAX][2];
+} _dcd;
+
+// Two endpoint 0 descriptor definition for unified dcd_edpt_open()
+static tusb_desc_endpoint_t const ep0OUT_desc =
+{
+ .bLength = sizeof(tusb_desc_endpoint_t),
+ .bDescriptorType = TUSB_DESC_ENDPOINT,
+
+ .bEndpointAddress = 0x00,
+ .bmAttributes = { .xfer = TUSB_XFER_CONTROL },
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
+ .bInterval = 0
+};
+
+static tusb_desc_endpoint_t const ep0IN_desc =
+{
+ .bLength = sizeof(tusb_desc_endpoint_t),
+ .bDescriptorType = TUSB_DESC_ENDPOINT,
+
+ .bEndpointAddress = 0x80,
+ .bmAttributes = { .xfer = TUSB_XFER_CONTROL },
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
+ .bInterval = 0
+};
+
+#define XFER_CTL_BASE(_ep, _dir) &_dcd.xfer_status[_ep][_dir]
+
+static void ep0_set_stage(ep0_stage_t stage)
+{
+ _dcd.ep0_stage = stage;
+}
+
+static ep0_stage_t ep0_get_stage(void)
+{
+ return _dcd.ep0_stage;
+}
+
+/*------------------------------------------------------------------*/
+/* Controller API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+ // Disable endpoint interrupts for now
+ USB_REGS->INTRRXEbits.w = 0;
+ USB_REGS->INTRTXEbits.w = 0;
+ // Enable Reset/Suspend/Resume interrupts only
+ USB_REGS->INTRUSBEbits.w = 7;
+
+ dcd_connect(rhport);
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ (void) rhport;
+
+ USBCRCONbits.USBIE = 1;
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ (void) rhport;
+
+ USBCRCONbits.USBIE = 0;
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ (void) rhport;
+
+ ep0_set_stage(EP0_STAGE_ADDRESS_CHANGE);
+ // Store address it will be used later after status stage is done
+ _dcd.dev_addr = dev_addr;
+ // Confirm packet now, address will be set when status stage is detected
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.w = (USBHS_EP0_DEVICE_SERVICED_RXPKTRDY | USBHS_EP0_DEVICE_DATAEND);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void) rhport;
+
+ USB_REGS->POWERbits.RESUME = 1;
+#if CFG_TUSB_OS != OPT_OS_NONE
+ osal_task_delay(10);
+#else
+ // TODO: Wait in non blocking mode
+ unsigned cnt = 2000;
+ while (cnt--) __asm__("nop");
+#endif
+ USB_REGS->POWERbits.RESUME = 0;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ (void) rhport;
+
+ USB_REGS->POWERbits.HSEN = TUD_OPT_HIGH_SPEED ? 1 : 0;
+ USB_REGS->POWERbits.SOFTCONN = 1;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ (void) rhport;
+
+ USB_REGS->POWERbits.SOFTCONN = 1;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
+{
+ return (_CP0_GET_STATUS() & (_CP0_STATUS_EXL_MASK | _CP0_STATUS_IPL_MASK)) != 0;
+}
+
+static void epn_rx_configure(uint8_t endpoint, uint16_t endpointSize,
+ uint16_t fifoAddress, uint8_t fifoSize,
+ uint32_t transferType)
+{
+ uint8_t old_index = USB_REGS->INDEXbits.ENDPOINT;
+
+ // Select endpoint register set (same register address is used for all endpoints.
+ USB_REGS->INDEXbits.ENDPOINT = endpoint;
+
+ // Configure the Endpoint size
+ USB_REGS->INDEXED_EPCSR.RXMAXPbits.RXMAXP = endpointSize;
+
+ // Set up the fifo address.
+ USB_REGS->RXFIFOADDbits.RXFIFOAD = fifoAddress;
+
+ // Resets the endpoint data toggle to 0
+ USB_REGS->INDEXED_EPCSR.RXCSRL_DEVICEbits.CLRDT = 1;
+
+ // Set up the FIFO size
+ USB_REGS->RXFIFOSZbits.RXFIFOSZ = fifoSize;
+
+ USB_REGS->INDEXED_EPCSR.RXCSRH_DEVICEbits.ISO = transferType == 1 ? 1 : 0;
+ // Disable NYET Handshakes for interrupt endpoints
+ USB_REGS->INDEXED_EPCSR.RXCSRH_DEVICEbits.DISNYET = transferType == 3 ? 1 : 0;
+
+ // Restore the index register.
+ USB_REGS->INDEXbits.ENDPOINT = old_index;
+
+ // Enable the endpoint interrupt.
+ USB_REGS->INTRRXEbits.w |= (1 << endpoint);
+}
+
+static void epn_tx_configure(uint8_t endpoint, uint16_t endpointSize,
+ uint16_t fifoAddress, uint8_t fifoSize,
+ uint32_t transferType)
+{
+ uint8_t old_index = USB_REGS->INDEXbits.ENDPOINT;
+
+ // Select endpoint register set (same register address is used for all endpoints.
+ USB_REGS->INDEXbits.ENDPOINT = endpoint;
+
+ // Configure the Endpoint size
+ USB_REGS->INDEXED_EPCSR.TXMAXPbits.TXMAXP = endpointSize;
+
+ // Set up the fifo address
+ USB_REGS->TXFIFOADDbits.TXFIFOAD = fifoAddress;
+
+ // Resets the endpoint data toggle to 0
+ USB_REGS->INDEXED_EPCSR.TXCSRL_DEVICEbits.CLRDT = 1;
+
+ // Set up the FIFO size
+ USB_REGS->TXFIFOSZbits.TXFIFOSZ = fifoSize;
+
+ USB_REGS->INDEXED_EPCSR.TXCSRH_DEVICEbits.ISO = 1 == transferType ? 1 : 0;
+
+ // Restore the index register
+ USB_REGS->INDEXbits.ENDPOINT = old_index;
+
+ // Enable the interrupt
+ USB_REGS->INTRTXEbits.w |= (1 << endpoint);
+}
+
+static void tx_fifo_write(uint8_t endpoint, uint8_t const * buffer, size_t count)
+{
+ size_t i;
+ volatile uint8_t * fifo_reg;
+
+ fifo_reg = (volatile uint8_t *) (&USB_REGS->FIFO[endpoint]);
+
+ for (i = 0; i < count; i++)
+ {
+ *fifo_reg = buffer[i];
+ }
+}
+
+static int rx_fifo_read(uint8_t epnum, uint8_t * buffer)
+{
+ uint32_t i;
+ uint32_t count;
+ volatile uint8_t * fifo_reg;
+
+ fifo_reg = (volatile uint8_t *) (&USB_REGS->FIFO[epnum]);
+
+ count = USB_REGS->EPCSR[epnum].RXCOUNTbits.RXCNT;
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = fifo_reg[i & 3];
+ }
+
+ return count;
+}
+
+static void xfer_complete(xfer_ctl_t * xfer, uint8_t result, bool in_isr)
+{
+ dcd_event_xfer_complete(0, xfer->ep_addr, xfer->transferred, result, in_isr);
+}
+
+static void ep0_fill_tx(xfer_ctl_t * xfer_in)
+{
+ uint16_t left = xfer_in->total_len - xfer_in->transferred;
+
+ if (left)
+ {
+ xfer_in->last_packet_size = tu_min16(xfer_in->max_packet_size, left);
+ tx_fifo_write(0, xfer_in->buffer + xfer_in->transferred, xfer_in->last_packet_size);
+ xfer_in->transferred += xfer_in->last_packet_size;
+ left = xfer_in->total_len - xfer_in->transferred;
+ }
+
+ if (xfer_in->last_packet_size < xfer_in->max_packet_size || left == 0)
+ {
+ switch (ep0_get_stage())
+ {
+ case EP0_STAGE_SETUP_IN_DATA:
+ case EP0_STAGE_DATA_IN:
+ case EP0_STAGE_DATA_IN_SENT:
+ ep0_set_stage(EP0_STAGE_DATA_IN_LAST_PACKET_FILLED);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.TXPKTRDY = 1;
+ break;
+ case EP0_STAGE_SETUP_OUT_NO_DATA:
+ ep0_set_stage(EP0_STAGE_STATUS_IN);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.w = (USBHS_EP0_DEVICE_SERVICED_RXPKTRDY | USBHS_EP0_DEVICE_DATAEND);
+ break;
+ case EP0_STAGE_DATA_OUT_COMPLETE:
+ ep0_set_stage(EP0_STAGE_STATUS_IN);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.w = (USBHS_EP0_DEVICE_SERVICED_RXPKTRDY | USBHS_EP0_DEVICE_DATAEND);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (ep0_get_stage())
+ {
+ case EP0_STAGE_SETUP_IN_DATA:
+ ep0_set_stage(EP0_STAGE_DATA_IN);
+ // fall through
+ case EP0_STAGE_DATA_IN:
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.TXPKTRDY = 1;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void epn_fill_tx(xfer_ctl_t * xfer_in, uint8_t epnum)
+{
+ uint16_t left = xfer_in->total_len - xfer_in->transferred;
+ if (left)
+ {
+ xfer_in->last_packet_size = tu_min16(xfer_in->max_packet_size, left);
+ tx_fifo_write(epnum, xfer_in->buffer + xfer_in->transferred, xfer_in->last_packet_size);
+ }
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.TXPKTRDY = 1;
+}
+
+static bool ep0_xfer(xfer_ctl_t * xfer, int dir)
+{
+ if (dir == TUSB_DIR_OUT)
+ {
+ if (xfer->total_len)
+ {
+ switch (_dcd.ep0_stage)
+ {
+ case EP0_STAGE_DATA_OUT_COMPLETE:
+ case EP0_STAGE_SETUP_OUT_DATA:
+ ep0_set_stage(EP0_STAGE_DATA_OUT);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVCRPR = 1;
+ break;
+ default:
+ TU_ASSERT(0);
+ }
+ }
+ else
+ {
+ switch (_dcd.ep0_stage)
+ {
+ case EP0_STAGE_DATA_IN_SENT:
+ ep0_set_stage(EP0_STAGE_NONE);
+ // fall through
+ case EP0_STAGE_NONE:
+ xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else // IN
+ {
+ ep0_fill_tx(xfer);
+ }
+
+ return true;
+}
+
+/*------------------------------------------------------------------*/
+/* DCD Endpoint port
+ *------------------------------------------------------------------*/
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
+{
+ (void) rhport;
+ uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
+ uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+
+ TU_ASSERT(epnum < EP_MAX);
+
+ xfer->max_packet_size = tu_edpt_packet_size(desc_edpt);
+ xfer->fifo_size = xfer->max_packet_size;
+ xfer->ep_addr = desc_edpt->bEndpointAddress;
+
+ if (epnum != 0)
+ {
+ if (dir == TUSB_DIR_OUT)
+ {
+ epn_rx_configure(epnum, xfer->max_packet_size, _dcd.fifo_addr_top, __builtin_ctz(xfer->fifo_size) - 3, desc_edpt->bmAttributes.xfer);
+ _dcd.fifo_addr_top += (xfer->fifo_size + 7) >> 3;
+ }
+ else
+ {
+ epn_tx_configure(epnum, xfer->max_packet_size, _dcd.fifo_addr_top, __builtin_ctz(xfer->fifo_size) - 3, desc_edpt->bmAttributes.xfer);
+ _dcd.fifo_addr_top += (xfer->fifo_size + 7) >> 3;
+ }
+ }
+ return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+
+ // Reserve EP0 FIFO address
+ _dcd.fifo_addr_top = 64 >> 3;
+ for (int i = 1; i < EP_MAX; ++i)
+ {
+ tu_memclr(&_dcd.xfer_status[i], sizeof(_dcd.xfer_status[i]));
+ }
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ (void) ep_addr;
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+ (void) rhport;
+
+ xfer->buffer = buffer;
+ xfer->total_len = total_bytes;
+ xfer->last_packet_size = 0;
+ xfer->transferred = 0;
+
+ if (epnum == 0)
+ {
+ return ep0_xfer(xfer, dir);
+ }
+ if (dir == TUSB_DIR_OUT)
+ {
+ USB_REGS->INTRRXEbits.w |= (1u << epnum);
+ }
+ else // IN
+ {
+ epn_fill_tx(xfer, epnum);
+ }
+
+ return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ (void) rhport;
+
+ if (epnum == 0)
+ {
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SENDSTALL = 1;
+ }
+ else
+ {
+ if (dir == TUSB_DIR_OUT)
+ {
+ USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.SENDSTALL = 1;
+ }
+ else
+ {
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.SENDSTALL = 1;
+ }
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ (void) rhport;
+
+ if (epnum == 0)
+ {
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SENDSTALL = 0;
+ }
+ else
+ {
+ if (dir == TUSB_DIR_OUT)
+ {
+ USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.w &= ~(USBHS_EP_DEVICE_RX_SENT_STALL | USBHS_EP_DEVICE_RX_SEND_STALL);
+ USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.CLRDT = 1;
+ }
+ else
+ {
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.w &= ~(USBHS_EP_DEVICE_TX_SENT_STALL | USBHS_EP_DEVICE_TX_SEND_STALL);
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.CLRDT = 1;
+ }
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* Interrupt Handler
+ *------------------------------------------------------------------*/
+
+static void ep0_handle_rx(void)
+{
+ int transferred;
+ xfer_ctl_t * xfer = XFER_CTL_BASE(0, TUSB_DIR_OUT);
+
+ TU_ASSERT(xfer->buffer,);
+
+ transferred = rx_fifo_read(0, xfer->buffer + xfer->transferred);
+ xfer->transferred += transferred;
+ TU_ASSERT(xfer->transferred <= xfer->total_len,);
+ if (transferred < xfer->max_packet_size || xfer->transferred == xfer->total_len)
+ {
+ ep0_set_stage(EP0_STAGE_DATA_OUT_COMPLETE);
+ xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
+ }
+ else
+ {
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVCRPR = 1;
+ }
+}
+
+static void epn_handle_rx_int(uint8_t epnum)
+{
+ uint8_t ep_status;
+ int transferred;
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
+
+ ep_status = USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.w;
+ if (ep_status & USBHS_EP_DEVICE_RX_SENT_STALL)
+ {
+ USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.w &= ~USBHS_EP_DEVICE_RX_SENT_STALL;
+ }
+
+ if (ep_status & USBHS_EP0_HOST_RXPKTRDY)
+ {
+ TU_ASSERT(xfer->buffer != NULL,);
+
+ transferred = rx_fifo_read(epnum, xfer->buffer + xfer->transferred);
+ USB_REGS->EPCSR[epnum].RXCSRL_HOSTbits.RXPKTRDY = 0;
+ xfer->transferred += transferred;
+ TU_ASSERT(xfer->transferred <= xfer->total_len,);
+ if (transferred < xfer->max_packet_size || xfer->transferred == xfer->total_len)
+ {
+ USB_REGS->INTRRXEbits.w &= ~(1u << epnum);
+ xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
+ }
+ }
+}
+
+static void epn_handle_tx_int(uint8_t epnum)
+{
+ uint8_t ep_status = USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.w;
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
+
+ if (ep_status & USBHS_EP_DEVICE_TX_SENT_STALL)
+ {
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.w &= ~USBHS_EP_DEVICE_TX_SENT_STALL;
+ }
+ else
+ {
+ xfer->transferred += xfer->last_packet_size;
+ TU_ASSERT(xfer->transferred <= xfer->total_len,);
+ if (xfer->last_packet_size < xfer->max_packet_size || xfer->transferred == xfer->total_len)
+ {
+ xfer->last_packet_size = 0;
+ xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
+ }
+ else
+ {
+ epn_fill_tx(xfer, epnum);
+ }
+ }
+}
+
+static void ep0_handle_int(void)
+{
+ __USBHS_CSR0L_DEVICE_t ep0_status;
+ union {
+ tusb_control_request_t request;
+ uint32_t setup_buffer[2];
+ } setup_packet;
+ xfer_ctl_t * xfer_in = XFER_CTL_BASE(0, TUSB_DIR_IN);
+ uint8_t old_index = USB_REGS->INDEXbits.ENDPOINT;
+
+ // Select EP0 registers
+ USB_REGS->INDEXbits.ENDPOINT = 0;
+
+ ep0_status = USB_REGS->EPCSR[0].CSR0L_DEVICEbits;
+
+ if (ep0_status.SENTSTALL)
+ {
+ // Stall was sent. Reset the endpoint 0 state.
+ // Clear the sent stall bit.
+ ep0_set_stage(EP0_STAGE_NONE);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SENTSTALL = 0;
+ }
+
+ if (ep0_status.SETUPEND)
+ {
+ // This means the current control transfer end prematurely. We don't
+ // need to end any transfers. The device layer will manage the
+ // premature transfer end. We clear the SetupEnd bit and reset the
+ // driver control transfer state machine to waiting for next setup
+ // packet from host.
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVSSETEND = 1;
+ ep0_set_stage(EP0_STAGE_NONE);
+ }
+
+ if (ep0_status.RXPKTRDY)
+ {
+ switch (ep0_get_stage())
+ {
+ default:
+ // Data arrived at unexpected state, this must be setup stage packet after all.
+ // Fall through
+ case EP0_STAGE_NONE:
+ // This means we were expecting a SETUP packet and we got one.
+ setup_packet.setup_buffer[0] = USB_REGS->FIFO[0];
+ setup_packet.setup_buffer[1] = USB_REGS->FIFO[0];
+ if (setup_packet.request.bmRequestType_bit.direction == TUSB_DIR_OUT)
+ {
+ // SVCRPR is not set yet, it will be set later when out xfer is started
+ // Till then NAKs will hold incommint data
+ ep0_set_stage(setup_packet.request.wLength == 0 ? EP0_STAGE_SETUP_OUT_NO_DATA : EP0_STAGE_SETUP_OUT_DATA);
+ }
+ else
+ {
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVCRPR = 1;
+ ep0_set_stage(EP0_STAGE_SETUP_IN_DATA);
+ }
+ dcd_event_setup_received(0, &setup_packet.request.bmRequestType, true);
+ break;
+ case EP0_STAGE_DATA_OUT:
+ ep0_handle_rx();
+ break;
+ }
+ }
+ else
+ {
+ switch (ep0_get_stage())
+ {
+ case EP0_STAGE_STATUS_IN:
+ // Status was just sent, this concludes request, notify client
+ ep0_set_stage(EP0_STAGE_NONE);
+ xfer_complete(xfer_in, XFER_RESULT_SUCCESS, true);
+ break;
+ case EP0_STAGE_DATA_IN:
+ // Packet sent, fill more data
+ ep0_fill_tx(xfer_in);
+ break;
+ case EP0_STAGE_DATA_IN_LAST_PACKET_FILLED:
+ ep0_set_stage(EP0_STAGE_DATA_IN_SENT);
+ xfer_complete(xfer_in, XFER_RESULT_SUCCESS, true);
+ break;
+ case EP0_STAGE_ADDRESS_CHANGE:
+ // Status stage after set address request finished, address can be changed
+ USB_REGS->FADDRbits.FUNC = _dcd.dev_addr;
+ ep0_set_stage(EP0_STAGE_NONE);
+ break;
+ default:
+ break;
+ }
+ }
+ // Restore register index
+ USB_REGS->INDEXbits.ENDPOINT = old_index;
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+ int i;
+ uint8_t mask;
+ __USBCSR2bits_t csr2_bits;
+ uint16_t rxints = USB_REGS->INTRRX & USB_REGS->INTRRXEbits.w;
+ uint16_t txints = USB_REGS->INTRTX;
+ csr2_bits = USBCSR2bits;
+ (void) rhport;
+
+ IFS4CLR = _IFS4_USBIF_MASK;
+
+ if (csr2_bits.SOFIF && csr2_bits.SOFIE)
+ {
+ dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+ }
+ if (csr2_bits.RESETIF)
+ {
+ dcd_edpt_open(0, &ep0OUT_desc);
+ dcd_edpt_open(0, &ep0IN_desc);
+ dcd_event_bus_reset(0, USB_REGS->POWERbits.HSMODE ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL, true);
+ }
+ if (csr2_bits.SUSPIF)
+ {
+ dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+ }
+ if (csr2_bits.RESUMEIF)
+ {
+ dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+ }
+ // INTRTX has bit for EP0
+ if (txints & 1)
+ {
+ txints ^= 1;
+ ep0_handle_int();
+ }
+ for (mask = 0x02, i = 1; rxints != 0 && mask != 0; mask <<= 1, ++i)
+ {
+ if (rxints & mask)
+ {
+ rxints ^= mask;
+ epn_handle_rx_int(i);
+ }
+ }
+ for (mask = 0x02, i = 1; txints != 0 && mask != 0; mask <<= 1, ++i)
+ {
+ if (txints & mask)
+ {
+ txints ^= mask;
+ epn_handle_tx_int(i);
+ }
+ }
+}
+
+#endif
diff --git a/src/portable/microchip/pic32mz/usbhs_registers.h b/src/portable/microchip/pic32mz/usbhs_registers.h
new file mode 100644
index 000000000..03fe78bbd
--- /dev/null
+++ b/src/portable/microchip/pic32mz/usbhs_registers.h
@@ -0,0 +1,931 @@
+/*******************************************************************************
+* Copyright (C) 2019 Microchip Technology Inc. and its subsidiaries.
+*
+* Subject to your compliance with these terms, you may use Microchip software
+* and any derivatives exclusively with Microchip products. It is your
+* responsibility to comply with third party license terms applicable to your
+* use of third party software (including open source software) that may
+* accompany Microchip software.
+*
+* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
+* EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
+* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
+* PARTICULAR PURPOSE.
+*
+* IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
+* INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
+* WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
+* BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
+* FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
+* ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+*******************************************************************************/
+/*******************************************************************************
+ USBHS Peripheral Library Register Definitions
+
+ File Name:
+ usbhs_registers.h
+
+ Summary:
+ USBHS PLIB Register Definitions
+
+ Description:
+ This file contains the constants and definitions which are required by the
+ the USBHS library.
+*******************************************************************************/
+
+#ifndef __USBHS_REGISTERS_H__
+#define __USBHS_REGISTERS_H__
+
+#include <p32xxxx.h>
+#include <stdint.h>
+
+/*****************************************
+ * Module Register Offsets.
+ *****************************************/
+
+#define USBHS_REG_FADDR 0x000
+#define USBHS_REG_POWER 0x001
+#define USBHS_REG_INTRTX 0x002
+#define USBHS_REG_INTRRX 0x004
+#define USBHS_REG_INTRTXE 0x006
+#define USBHS_REG_INTRRXE 0x008
+#define USBHS_REG_INTRUSB 0x00A
+#define USBHS_REG_INTRUSBE 0x00B
+#define USBHS_REG_FRAME 0x00C
+#define USBHS_REG_INDEX 0x00E
+#define USBHS_REG_TESTMODE 0x00F
+
+/*******************************************************
+ * Endpoint Control Status Registers (CSR). These values
+ * should be added to either the 0x10 to access the
+ * register through Indexed CSR. To access the actual
+ * CSR, see ahead in this header file.
+ ******************************************************/
+
+#define USBHS_REG_EP_TXMAXP 0x000
+#define USBHS_REG_EP_CSR0L 0x002
+#define USBHS_REG_EP_CSR0H 0x003
+#define USBHS_REG_EP_TXCSRL 0x002
+#define USBHS_REG_EP_TXCSRH 0x003
+#define USBHS_REG_EP_RXMAXP 0x004
+#define USBHS_REG_EP_RXCSRL 0x006
+#define USBHS_REG_EP_RXCSRH 0x007
+#define USBHS_REG_EP_COUNT0 0x008
+#define USBHS_REG_EP_RXCOUNT 0x008
+#define USBHS_REG_EP_TYPE0 0x01A
+#define USBHS_REG_EP_TXTYPE 0x01A
+#define USBHS_REG_EP_NAKLIMIT0 0x01B
+#define USBHS_REG_EP_TXINTERVAL 0x01B
+#define USBHS_REG_EP_RXTYPE 0x01C
+#define USBHS_REG_EP_RXINTERVAL 0x01D
+#define USBHS_REG_EP_CONFIGDATA 0x01F
+#define USBHS_REG_EP_FIFOSIZE 0x01F
+
+#define USBHS_HOST_EP0_SETUPKT_SET 0x8
+#define USBHS_HOST_EP0_TXPKTRDY_SET 0x2
+#define USBHS_SOFT_RST_NRST_SET 0x1
+#define USBHS_SOFT_RST_NRSTX_SET 0x2
+#define USBHS_EP0_DEVICE_SERVICED_RXPKTRDY 0x40
+#define USBHS_EP0_DEVICE_DATAEND 0x08
+#define USBHS_EP0_DEVICE_TXPKTRDY 0x02
+#define USBHS_EP0_HOST_STATUS_STAGE_START 0x40
+#define USBHS_EP0_HOST_REQPKT 0x20
+#define USBHS_EP0_HOST_TXPKTRDY 0x02
+#define USBHS_EP0_HOST_RXPKTRDY 0x01
+#define USBHS_EP_DEVICE_TX_SENT_STALL 0x20
+#define USBHS_EP_DEVICE_TX_SEND_STALL 0x10
+#define USBHS_EP_DEVICE_RX_SENT_STALL 0x40
+#define USBHS_EP_DEVICE_RX_SEND_STALL 0x20
+
+/* FADDR - Device Function Address */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned FUNC:7;
+ unsigned :1;
+ };
+
+ uint8_t w;
+
+} __USBHS_FADDR_t;
+
+/* POWER - Control Resume and Suspend signalling */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned SUSPEN:1;
+ unsigned SUSPMODE:1;
+ unsigned RESUME:1;
+ unsigned RESET:1;
+ unsigned HSMODE:1;
+ unsigned HSEN:1;
+ unsigned SOFTCONN:1;
+ unsigned ISOUPD:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_POWER_t;
+
+/* INTRTXE - Transmit endpoint interrupt enable */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned EP0IE:1;
+ unsigned EP1TXIE:1;
+ unsigned EP2TXIE:1;
+ unsigned EP3TXIE:1;
+ unsigned EP4TXIE:1;
+ unsigned EP5TXIE:1;
+ unsigned EP6TXIE:1;
+ unsigned EP7TXIE:1;
+ unsigned :8;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_INTRTXE_t;
+
+/* INTRRXE - Receive endpoint interrupt enable */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned :1;
+ unsigned EP1RXIE:1;
+ unsigned EP2RXIE:1;
+ unsigned EP3RXIE:1;
+ unsigned EP4RXIE:1;
+ unsigned EP5RXIE:1;
+ unsigned EP6RXIE:1;
+ unsigned EP7RXIE:1;
+ unsigned :8;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_INTRRXE_t;
+
+/* INTRUSBE - General USB Interrupt enable */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned SUSPIE:1;
+ unsigned RESUMEIE:1;
+ unsigned RESETIE:1;
+ unsigned SOFIE:1;
+ unsigned CONNIE:1;
+ unsigned DISCONIE:1;
+ unsigned SESSRQIE:1;
+ unsigned VBUSERRIE:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_INTRUSBE_t;
+
+/* FRAME - Frame number */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RFRMNUM:11;
+ unsigned :5;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_FRAME_t;
+
+/* INDEX - Endpoint index */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned ENDPOINT:4;
+ unsigned :4;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_INDEX_t;
+
+/* TESTMODE - Test mode register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned NAK:1;
+ unsigned TESTJ:1;
+ unsigned TESTK:1;
+ unsigned PACKET:1;
+ unsigned FORCEHS:1;
+ unsigned FORCEFS:1;
+ unsigned FIFOACC:1;
+ unsigned FORCEHST:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TESTMODE_t;
+
+/* COUNT0 - Indicates the amount of data received in endpoint 0 */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXCNT:7;
+ unsigned :1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_COUNT0_t;
+
+/* TYPE0 - Operating speed of target device */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned :6;
+ unsigned SPEED:2;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TYPE0_t;
+
+/* DEVCTL - Module control register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned SESSION:1;
+ unsigned HOSTREQ:1;
+ unsigned HOSTMODE:1;
+ unsigned VBUS:2;
+ unsigned LSDEV:1;
+ unsigned FSDEV:1;
+ unsigned BDEV:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_DEVCTL_t;
+
+/* CSR0L Device - Endpoint Device Mode Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXPKTRDY:1;
+ unsigned TXPKTRDY:1;
+ unsigned SENTSTALL:1;
+ unsigned DATAEND:1;
+ unsigned SETUPEND:1;
+ unsigned SENDSTALL:1;
+ unsigned SVCRPR:1;
+ unsigned SVSSETEND:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_CSR0L_DEVICE_t;
+
+/* CSR0L Host - Endpoint Host Mode Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXPKTRDY:1;
+ unsigned TXPKTRDY:1;
+ unsigned RXSTALL:1;
+ unsigned SETUPPKT:1;
+ unsigned ERROR:1;
+ unsigned REQPKT:1;
+ unsigned STATPKT:1;
+ unsigned NAKTMOUT:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_CSR0L_HOST_t;
+
+/* TXCSRL Device - Endpoint Transmit Control Status Register Low */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXPKTRDY:1;
+ unsigned FIFOONE:1;
+ unsigned UNDERRUN:1;
+ unsigned FLUSH:1;
+ unsigned SENDSTALL:1;
+ unsigned SENTSTALL:1;
+ unsigned CLRDT:1;
+ unsigned INCOMPTX:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXCSRL_DEVICE_t;
+
+/* TXCSRL Host - Endpoint Transmit Control Status Register Low */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXPKTRDY:1;
+ unsigned FIFONE:1;
+ unsigned ERROR:1;
+ unsigned FLUSH:1;
+ unsigned SETUPPKT:1;
+ unsigned RXSTALL:1;
+ unsigned CLRDT:1;
+ unsigned INCOMPTX:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXCSRL_HOST_t;
+
+/* TXCSRH Device - Endpoint Transmit Control Status Register High */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned :2;
+ unsigned DMAREQMD:1;
+ unsigned FRCDATTG:1;
+ unsigned DMAREQENL:1;
+ unsigned MODE:1;
+ unsigned ISO:1;
+ unsigned AUTOSET:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXCSRH_DEVICE_t;
+
+/* TXCSRH Host - Endpoint Transmit Control Status Register High */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned DATATGGL:1;
+ unsigned DTWREN:1;
+ unsigned DMAREQMD:1;
+ unsigned FRCDATTG:1;
+ unsigned DMAREQEN:1;
+ unsigned MODE:1;
+ unsigned :1;
+ unsigned AUOTSET:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXCSRH_HOST_t;
+
+/* CSR0H Device - Endpoint 0 Control Status Register High */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned FLSHFIFO:1;
+ unsigned :7;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_CSR0H_DEVICE_t;
+
+/* CSR0H Host - Endpoint 0 Control Status Register High */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned FLSHFIFO:1;
+ unsigned DATATGGL:1;
+ unsigned DTWREN:1;
+ unsigned DISPING:1;
+ unsigned :4;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_CSR0H_HOST_t;
+
+/* RXMAXP - Receive Endpoint Max packet size. */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXMAXP:11;
+ unsigned MULT:5;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_RXMAXP_t;
+
+/* RXCSRL Device - Receive endpoint Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXPKTRDY:1;
+ unsigned FIFOFULL:1;
+ unsigned OVERRUN:1;
+ unsigned DATAERR:1;
+ unsigned FLUSH:1;
+ unsigned SENDSTALL:1;
+ unsigned SENTSTALL:1;
+ unsigned CLRDT:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXCSRL_DEVICE_t;
+
+/* RXCSRL Host - Receive endpoint Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXPKTRDY:1;
+ unsigned FIFOFULL:1;
+ unsigned ERROR:1;
+ unsigned DERRNAKT:1;
+ unsigned FLUSH:1;
+ unsigned REQPKT:1;
+ unsigned RXSTALL:1;
+ unsigned CLRDT:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXCSRL_HOST_t;
+
+/* RXCSRH Device - Receive endpoint Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned INCOMPRX:1;
+ unsigned :2;
+ unsigned DMAREQMODE:1;
+ unsigned DISNYET:1;
+ unsigned DMAREQEN:1;
+ unsigned ISO:1;
+ unsigned AUTOCLR:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXCSRH_DEVICE_t;
+
+/* RXCSRH Host - Receive endpoint Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned INCOMPRX:1;
+ unsigned DATATGGL:1;
+ unsigned DATATWEN:1;
+ unsigned DMAREQMD:1;
+ unsigned PIDERR:1;
+ unsigned DMAREQEN:1;
+ unsigned AUTORQ:1;
+ unsigned AUOTCLR:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXCSRH_HOST_t;
+
+/* RXCOUNT - Amount of data pending in RX FIFO */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXCNT:14;
+ unsigned :2;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_RXCOUNT_t;
+
+/* TXTYPE - Specifies the target transmit endpoint */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TEP:4;
+ unsigned PROTOCOL:2;
+ unsigned SPEED:2;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXTYPE_t;
+
+/* RXTYPE - Specifies the target receive endpoint */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TEP:4;
+ unsigned PROTOCOL:2;
+ unsigned SPEED:2;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXTYPE_t;
+
+/* TXINTERVAL - Defines the polling interval */
+typedef struct
+{
+ uint8_t TXINTERV;
+
+} __USBHS_TXINTERVAL_t;
+
+/* RXINTERVAL - Defines the polling interval */
+typedef struct
+{
+ uint8_t RXINTERV;
+
+} __USBHS_RXINTERVAL_t;
+
+/* TXMAXP - Maximum amount of data that can be transferred through a TX endpoint
+ * */
+
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXMAXP:11;
+ unsigned MULT:5;
+ };
+ uint16_t w;
+
+} __USBHS_TXMAXP_t;
+
+/* TXFIFOSZ - Size of the transmit endpoint FIFO */
+typedef struct __attribute__((packed))
+{
+ unsigned TXFIFOSZ:4;
+ unsigned TXDPB:1;
+ unsigned :3;
+
+} __USBHS_TXFIFOSZ_t;
+
+/* RXFIFOSZ - Size of the receive endpoint FIFO */
+typedef struct __attribute__((packed))
+{
+ unsigned RXFIFOSZ:4;
+ unsigned RXDPB:1;
+ unsigned :3;
+
+} __USBHS_RXFIFOSZ_t;
+
+/* TXFIFOADD - Start address of the transmit endpoint FIFO */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXFIFOAD:13;
+ unsigned :3;
+ };
+ uint16_t w;
+
+} __USBHS_TXFIFOADD_t;
+
+/* RXFIFOADD - Start address of the receive endpoint FIFO */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXFIFOAD:13;
+ unsigned :3;
+ };
+ uint16_t w;
+
+} __USBHS_RXFIFOADD_t;
+
+/* SOFTRST - Asserts NRSTO and NRSTOX */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned NRST:1;
+ unsigned NRSTX:1;
+ unsigned :6;
+ };
+ uint8_t w;
+
+} __USBHS_SOFTRST_t;
+
+/* TXFUNCADDR - Target address of transmit endpoint */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXFADDR:7;
+ unsigned :1;
+ };
+ uint8_t w;
+
+} __USBHS_TXFUNCADDR_t;
+
+/* RXFUNCADDR - Target address of receive endpoint */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXFADDR:7;
+ unsigned :1;
+ };
+ uint8_t w;
+
+} __USBHS_RXFUNCADDR_t;
+
+/* TXHUBADDR - Address of the hub to which the target transmit device endpoint
+ * is connected */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXHUBADDR:7;
+ unsigned MULTTRAN:1;
+ };
+ uint8_t w;
+
+} __USBHS_TXHUBADDR_t;
+
+/* RXHUBADDR - Address of the hub to which the target receive device endpoint is
+ * connected */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXHUBADDR:7;
+ unsigned MULTTRAN:1;
+ };
+ uint8_t w;
+
+} __USBHS_RXHUBADDR_t;
+
+/* TXHUBPORT - Address of the hub to which the target transmit device endpoint
+ * is connected. */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXHUBPRT:7;
+ unsigned :1;
+ };
+
+ uint8_t w;
+
+} __USBHS_TXHUBPORT_t;
+
+/* RXHUBPORT - Address of the hub to which the target receive device endpoint
+ * is connected. */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXHUBPRT:7;
+ unsigned :1;
+ };
+
+ uint8_t w;
+
+} __USBHS_RXHUBPORT_t;
+
+/* DMACONTROL - Configures a DMA channel */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned DMAEN:1;
+ unsigned DMADIR:1;
+ unsigned DMAMODE:1;
+ unsigned DMAIE:1;
+ unsigned DMAEP:4;
+ unsigned DMAERR:1;
+ unsigned DMABRSTM:2;
+ unsigned:21;
+ };
+
+ uint32_t w;
+
+} __USBHS_DMACNTL_t;
+
+/* Endpoint Control and Status Register Set */
+typedef struct __attribute__((packed))
+{
+ volatile __USBHS_TXMAXP_t TXMAXPbits;
+ union
+ {
+ struct
+ {
+ union
+ {
+ volatile __USBHS_CSR0L_DEVICE_t CSR0L_DEVICEbits;
+ volatile __USBHS_CSR0L_HOST_t CSR0L_HOSTbits;
+ };
+ union
+ {
+ volatile __USBHS_CSR0H_DEVICE_t CSR0H_DEVICEbits;
+ volatile __USBHS_CSR0H_HOST_t CSR0H_HOSTbits;
+ };
+ };
+
+ struct
+ {
+ union
+ {
+ volatile __USBHS_TXCSRL_DEVICE_t TXCSRL_DEVICEbits;
+ volatile __USBHS_TXCSRL_HOST_t TXCSRL_HOSTbits;
+ };
+
+ union
+ {
+ volatile __USBHS_TXCSRH_DEVICE_t TXCSRH_DEVICEbits;
+ volatile __USBHS_TXCSRH_HOST_t TXCSRH_HOSTbits;
+ };
+ };
+ };
+
+ volatile __USBHS_RXMAXP_t RXMAXPbits;
+
+ union
+ {
+ volatile __USBHS_RXCSRL_DEVICE_t RXCSRL_DEVICEbits;
+ volatile __USBHS_RXCSRL_HOST_t RXCSRL_HOSTbits;
+ };
+
+ union
+ {
+ volatile __USBHS_RXCSRH_DEVICE_t RXCSRH_DEVICEbits;
+ volatile __USBHS_RXCSRH_HOST_t RXCSRH_HOSTbits;
+ };
+
+ union
+ {
+ volatile __USBHS_COUNT0_t COUNT0bits;
+ volatile __USBHS_RXCOUNT_t RXCOUNTbits;
+ };
+
+ union
+ {
+ volatile __USBHS_TYPE0_t TYPE0bits;
+ volatile __USBHS_TXTYPE_t TXTYPEbits;
+ };
+
+ union
+ {
+ volatile uint8_t NAKLIMIT0;
+ volatile __USBHS_TXINTERVAL_t TXINTERVALbits;
+ };
+
+ volatile __USBHS_RXTYPE_t RXTYPEbits;
+ volatile __USBHS_RXINTERVAL_t RXINTERVALbits;
+ unsigned :8;
+ union
+ {
+ volatile uint8_t CONFIGDATA;
+ volatile uint8_t FIFOSIZE;
+ };
+
+} __USBHS_EPCSR_t;
+
+/* Set of registers that configure the multi-point option */
+typedef struct __attribute__((packed))
+{
+ volatile __USBHS_TXFUNCADDR_t TXFUNCADDRbits;
+ unsigned :8;
+ volatile __USBHS_TXHUBADDR_t TXHUBADDRbits;
+ volatile __USBHS_TXHUBPORT_t TXHUBPORTbits;
+ volatile __USBHS_RXFUNCADDR_t RXFUNCADDRbits;
+ unsigned :8;
+ volatile __USBHS_RXHUBADDR_t RXHUBADDRbits;
+ volatile __USBHS_RXHUBPORT_t RXHUBPORTbits;
+
+} __USBHS_TARGET_ADDR_t;
+
+/* Set of registers that configure the DMA channel */
+typedef struct __attribute__((packed))
+{
+ volatile __USBHS_DMACNTL_t DMACNTLbits;
+ volatile uint32_t DMAADDR;
+ volatile uint32_t DMACOUNT;
+ volatile uint32_t pad;
+} __USBHS_DMA_CHANNEL_t;
+
+/* USBHS module register set */
+typedef struct __attribute__((aligned(4),packed))
+{
+ volatile __USBHS_FADDR_t FADDRbits;
+ volatile __USBHS_POWER_t POWERbits;
+ volatile uint16_t INTRTX;
+ volatile uint16_t INTRRX;
+ volatile __USBHS_INTRTXE_t INTRTXEbits;
+ volatile __USBHS_INTRRXE_t INTRRXEbits;
+ volatile uint8_t INTRUSB;
+ volatile __USBHS_INTRUSBE_t INTRUSBEbits;
+ volatile __USBHS_FRAME_t FRAMEbits;
+ volatile __USBHS_INDEX_t INDEXbits;
+ volatile __USBHS_TESTMODE_t TESTMODEbits;
+ volatile __USBHS_EPCSR_t INDEXED_EPCSR;
+ volatile uint32_t FIFO[16];
+ volatile __USBHS_DEVCTL_t DEVCTLbits;
+ volatile uint8_t MISC;
+ volatile __USBHS_TXFIFOSZ_t TXFIFOSZbits;
+ volatile __USBHS_RXFIFOSZ_t RXFIFOSZbits;
+
+ volatile __USBHS_TXFIFOADD_t TXFIFOADDbits;
+ volatile __USBHS_RXFIFOADD_t RXFIFOADDbits;
+
+ volatile uint32_t VCONTROL;
+ volatile uint16_t HWVERS;
+ volatile uint8_t padding1[10];
+ volatile uint8_t EPINFO;
+ volatile uint8_t RAMINFO;
+ volatile uint8_t LINKINFO;
+ volatile uint8_t VPLEN;
+ volatile uint8_t HS_EOF1;
+ volatile uint8_t FS_EOF1;
+ volatile uint8_t LS_EOF1;
+
+ volatile __USBHS_SOFTRST_t SOFTRSTbits;
+
+ volatile __USBHS_TARGET_ADDR_t TADDR[16];
+ volatile __USBHS_EPCSR_t EPCSR[16];
+ volatile uint32_t DMA_INTR;
+ volatile __USBHS_DMA_CHANNEL_t DMA_CHANNEL[8];
+ volatile uint32_t RQPKTXOUNT[16];
+
+} usbhs_registers_t;
+
+#endif
diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c
index 13e56453d..976d3dfd0 100644
--- a/src/portable/microchip/samd/dcd_samd.c
+++ b/src/portable/microchip/samd/dcd_samd.c
@@ -26,10 +26,10 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && \
+#if CFG_TUD_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \
CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAME5X || \
- CFG_TUSB_MCU == OPT_MCU_SAML22)
+ CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21)
#include "sam.h"
#include "device/dcd.h"
@@ -125,7 +125,7 @@ void dcd_int_disable(uint8_t rhport)
}
#elif CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \
- CFG_TUSB_MCU == OPT_MCU_SAML22
+ CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21
void dcd_int_enable(uint8_t rhport)
{
@@ -180,6 +180,14 @@ void dcd_connect(uint8_t rhport)
USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
@@ -214,14 +222,14 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
UsbDeviceDescBank* bank = &sram_registers[epnum][dir];
uint32_t size_value = 0;
while (size_value < 7) {
- if (1 << (size_value + 3) == desc_edpt->wMaxPacketSize.size) {
+ if (1 << (size_value + 3) >= tu_edpt_packet_size(desc_edpt)) {
break;
}
size_value++;
}
// unsupported endpoint size
- if ( size_value == 7 && desc_edpt->wMaxPacketSize.size != 1023 ) return false;
+ if ( size_value == 7 && tu_edpt_packet_size(desc_edpt) > 1023 ) return false;
bank->PCKSIZE.bit.SIZE = size_value;
@@ -230,16 +238,31 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
if ( dir == TUSB_DIR_OUT )
{
ep->EPCFG.bit.EPTYPE0 = desc_edpt->bmAttributes.xfer + 1;
+ ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0 | USB_DEVICE_EPSTATUSCLR_DTGLOUT; // clear stall & dtoggle
ep->EPINTENSET.bit.TRCPT0 = true;
}else
{
ep->EPCFG.bit.EPTYPE1 = desc_edpt->bmAttributes.xfer + 1;
+ ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1 | USB_DEVICE_EPSTATUSCLR_DTGLIN; // clear stall & dtoggle
ep->EPINTENSET.bit.TRCPT1 = true;
}
return true;
}
+void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
+ (void) ep_addr;
+
+ // TODO: implement if necessary?
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
(void) rhport;
@@ -263,14 +286,14 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
{
bank->PCKSIZE.bit.MULTI_PACKET_SIZE = total_bytes;
bank->PCKSIZE.bit.BYTE_COUNT = 0;
- ep->EPSTATUSCLR.reg |= USB_DEVICE_EPSTATUSCLR_BK0RDY;
- ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL0;
+ ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY;
+ ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRFAIL0;
} else
{
bank->PCKSIZE.bit.MULTI_PACKET_SIZE = 0;
bank->PCKSIZE.bit.BYTE_COUNT = total_bytes;
- ep->EPSTATUSSET.reg |= USB_DEVICE_EPSTATUSSET_BK1RDY;
- ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL1;
+ ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK1RDY;
+ ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRFAIL1;
}
return true;
diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c
index d50621ce4..e3fa51e31 100644
--- a/src/portable/microchip/samg/dcd_samg.c
+++ b/src/portable/microchip/samg/dcd_samg.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2018, hathach (tinyusb.org)
@@ -210,6 +210,14 @@ void dcd_disconnect(uint8_t rhport)
UDP->UDP_TXVC = UDP_TXVC_TXVDIS_Msk;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -258,7 +266,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
// Must not already enabled
TU_ASSERT((UDP->UDP_CSR[epnum] & UDP_CSR_EPEDS_Msk) == 0);
- xfer_epsize_set(&_dcd_xfer[epnum], ep_desc->wMaxPacketSize.size);
+ xfer_epsize_set(&_dcd_xfer[epnum], tu_edpt_packet_size(ep_desc));
// Configure type and enable EP
csr_write(epnum, UDP_CSR_EPEDS_Msk | UDP_CSR_EPTYPE(ep_desc->bmAttributes.xfer + 4*dir));
@@ -269,6 +277,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
diff --git a/src/portable/microchip/samx7x/common_usb_regs.h b/src/portable/microchip/samx7x/common_usb_regs.h
new file mode 100644
index 000000000..db4a81e0e
--- /dev/null
+++ b/src/portable/microchip/samx7x/common_usb_regs.h
@@ -0,0 +1,2108 @@
+ /*
+* The MIT License (MIT)
+*
+* Copyright (c) 2019 Microchip Technology Inc.
+* Copyright (c) 2018, hathach (tinyusb.org)
+* Copyright (c) 2021, HiFiPhile
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*
+* This file is part of the TinyUSB stack.
+*/
+
+#ifndef _COMMON_USB_REGS_H_
+#define _COMMON_USB_REGS_H_
+
+#if CFG_TUSB_MCU == OPT_MCU_SAMX7X
+
+/* -------- DEVDMANXTDSC : (USBHS Offset: 0x00) (R/W 32) Device DMA Channel Next Descriptor Address Register -------- */
+
+#define DEVDMANXTDSC_OFFSET (0x00) /**< (DEVDMANXTDSC) Device DMA Channel Next Descriptor Address Register Offset */
+
+#define DEVDMANXTDSC_NXT_DSC_ADD_Pos 0 /**< (DEVDMANXTDSC) Next Descriptor Address Position */
+#define DEVDMANXTDSC_NXT_DSC_ADD (_U_(0xFFFFFFFF) << DEVDMANXTDSC_NXT_DSC_ADD_Pos) /**< (DEVDMANXTDSC) Next Descriptor Address Mask */
+#define DEVDMANXTDSC_Msk _U_(0xFFFFFFFF) /**< (DEVDMANXTDSC) Register Mask */
+
+
+/* -------- DEVDMAADDRESS : (USBHS Offset: 0x04) (R/W 32) Device DMA Channel Address Register -------- */
+
+#define DEVDMAADDRESS_OFFSET (0x04) /**< (DEVDMAADDRESS) Device DMA Channel Address Register Offset */
+
+#define DEVDMAADDRESS_BUFF_ADD_Pos 0 /**< (DEVDMAADDRESS) Buffer Address Position */
+#define DEVDMAADDRESS_BUFF_ADD (_U_(0xFFFFFFFF) << DEVDMAADDRESS_BUFF_ADD_Pos) /**< (DEVDMAADDRESS) Buffer Address Mask */
+#define DEVDMAADDRESS_Msk _U_(0xFFFFFFFF) /**< (DEVDMAADDRESS) Register Mask */
+
+
+/* -------- DEVDMACONTROL : (USBHS Offset: 0x08) (R/W 32) Device DMA Channel Control Register -------- */
+
+#define DEVDMACONTROL_OFFSET (0x08) /**< (DEVDMACONTROL) Device DMA Channel Control Register Offset */
+
+#define DEVDMACONTROL_CHANN_ENB_Pos 0 /**< (DEVDMACONTROL) Channel Enable Command Position */
+#define DEVDMACONTROL_CHANN_ENB (_U_(0x1) << DEVDMACONTROL_CHANN_ENB_Pos) /**< (DEVDMACONTROL) Channel Enable Command Mask */
+#define DEVDMACONTROL_LDNXT_DSC_Pos 1 /**< (DEVDMACONTROL) Load Next Channel Transfer Descriptor Enable Command Position */
+#define DEVDMACONTROL_LDNXT_DSC (_U_(0x1) << DEVDMACONTROL_LDNXT_DSC_Pos) /**< (DEVDMACONTROL) Load Next Channel Transfer Descriptor Enable Command Mask */
+#define DEVDMACONTROL_END_TR_EN_Pos 2 /**< (DEVDMACONTROL) End of Transfer Enable Control (OUT transfers only) Position */
+#define DEVDMACONTROL_END_TR_EN (_U_(0x1) << DEVDMACONTROL_END_TR_EN_Pos) /**< (DEVDMACONTROL) End of Transfer Enable Control (OUT transfers only) Mask */
+#define DEVDMACONTROL_END_B_EN_Pos 3 /**< (DEVDMACONTROL) End of Buffer Enable Control Position */
+#define DEVDMACONTROL_END_B_EN (_U_(0x1) << DEVDMACONTROL_END_B_EN_Pos) /**< (DEVDMACONTROL) End of Buffer Enable Control Mask */
+#define DEVDMACONTROL_END_TR_IT_Pos 4 /**< (DEVDMACONTROL) End of Transfer Interrupt Enable Position */
+#define DEVDMACONTROL_END_TR_IT (_U_(0x1) << DEVDMACONTROL_END_TR_IT_Pos) /**< (DEVDMACONTROL) End of Transfer Interrupt Enable Mask */
+#define DEVDMACONTROL_END_BUFFIT_Pos 5 /**< (DEVDMACONTROL) End of Buffer Interrupt Enable Position */
+#define DEVDMACONTROL_END_BUFFIT (_U_(0x1) << DEVDMACONTROL_END_BUFFIT_Pos) /**< (DEVDMACONTROL) End of Buffer Interrupt Enable Mask */
+#define DEVDMACONTROL_DESC_LD_IT_Pos 6 /**< (DEVDMACONTROL) Descriptor Loaded Interrupt Enable Position */
+#define DEVDMACONTROL_DESC_LD_IT (_U_(0x1) << DEVDMACONTROL_DESC_LD_IT_Pos) /**< (DEVDMACONTROL) Descriptor Loaded Interrupt Enable Mask */
+#define DEVDMACONTROL_BURST_LCK_Pos 7 /**< (DEVDMACONTROL) Burst Lock Enable Position */
+#define DEVDMACONTROL_BURST_LCK (_U_(0x1) << DEVDMACONTROL_BURST_LCK_Pos) /**< (DEVDMACONTROL) Burst Lock Enable Mask */
+#define DEVDMACONTROL_BUFF_LENGTH_Pos 16 /**< (DEVDMACONTROL) Buffer Byte Length (Write-only) Position */
+#define DEVDMACONTROL_BUFF_LENGTH (_U_(0xFFFF) << DEVDMACONTROL_BUFF_LENGTH_Pos) /**< (DEVDMACONTROL) Buffer Byte Length (Write-only) Mask */
+#define DEVDMACONTROL_Msk _U_(0xFFFF00FF) /**< (DEVDMACONTROL) Register Mask */
+
+
+/* -------- DEVDMASTATUS : (USBHS Offset: 0x0c) (R/W 32) Device DMA Channel Status Register -------- */
+
+#define DEVDMASTATUS_OFFSET (0x0C) /**< (DEVDMASTATUS) Device DMA Channel Status Register Offset */
+
+#define DEVDMASTATUS_CHANN_ENB_Pos 0 /**< (DEVDMASTATUS) Channel Enable Status Position */
+#define DEVDMASTATUS_CHANN_ENB (_U_(0x1) << DEVDMASTATUS_CHANN_ENB_Pos) /**< (DEVDMASTATUS) Channel Enable Status Mask */
+#define DEVDMASTATUS_CHANN_ACT_Pos 1 /**< (DEVDMASTATUS) Channel Active Status Position */
+#define DEVDMASTATUS_CHANN_ACT (_U_(0x1) << DEVDMASTATUS_CHANN_ACT_Pos) /**< (DEVDMASTATUS) Channel Active Status Mask */
+#define DEVDMASTATUS_END_TR_ST_Pos 4 /**< (DEVDMASTATUS) End of Channel Transfer Status Position */
+#define DEVDMASTATUS_END_TR_ST (_U_(0x1) << DEVDMASTATUS_END_TR_ST_Pos) /**< (DEVDMASTATUS) End of Channel Transfer Status Mask */
+#define DEVDMASTATUS_END_BF_ST_Pos 5 /**< (DEVDMASTATUS) End of Channel Buffer Status Position */
+#define DEVDMASTATUS_END_BF_ST (_U_(0x1) << DEVDMASTATUS_END_BF_ST_Pos) /**< (DEVDMASTATUS) End of Channel Buffer Status Mask */
+#define DEVDMASTATUS_DESC_LDST_Pos 6 /**< (DEVDMASTATUS) Descriptor Loaded Status Position */
+#define DEVDMASTATUS_DESC_LDST (_U_(0x1) << DEVDMASTATUS_DESC_LDST_Pos) /**< (DEVDMASTATUS) Descriptor Loaded Status Mask */
+#define DEVDMASTATUS_BUFF_COUNT_Pos 16 /**< (DEVDMASTATUS) Buffer Byte Count Position */
+#define DEVDMASTATUS_BUFF_COUNT (_U_(0xFFFF) << DEVDMASTATUS_BUFF_COUNT_Pos) /**< (DEVDMASTATUS) Buffer Byte Count Mask */
+#define DEVDMASTATUS_Msk _U_(0xFFFF0073) /**< (DEVDMASTATUS) Register Mask */
+
+
+/* -------- HSTDMANXTDSC : (USBHS Offset: 0x00) (R/W 32) Host DMA Channel Next Descriptor Address Register -------- */
+
+#define HSTDMANXTDSC_OFFSET (0x00) /**< (HSTDMANXTDSC) Host DMA Channel Next Descriptor Address Register Offset */
+
+#define HSTDMANXTDSC_NXT_DSC_ADD_Pos 0 /**< (HSTDMANXTDSC) Next Descriptor Address Position */
+#define HSTDMANXTDSC_NXT_DSC_ADD (_U_(0xFFFFFFFF) << HSTDMANXTDSC_NXT_DSC_ADD_Pos) /**< (HSTDMANXTDSC) Next Descriptor Address Mask */
+#define HSTDMANXTDSC_Msk _U_(0xFFFFFFFF) /**< (HSTDMANXTDSC) Register Mask */
+
+
+/* -------- HSTDMAADDRESS : (USBHS Offset: 0x04) (R/W 32) Host DMA Channel Address Register -------- */
+
+#define HSTDMAADDRESS_OFFSET (0x04) /**< (HSTDMAADDRESS) Host DMA Channel Address Register Offset */
+
+#define HSTDMAADDRESS_BUFF_ADD_Pos 0 /**< (HSTDMAADDRESS) Buffer Address Position */
+#define HSTDMAADDRESS_BUFF_ADD (_U_(0xFFFFFFFF) << HSTDMAADDRESS_BUFF_ADD_Pos) /**< (HSTDMAADDRESS) Buffer Address Mask */
+#define HSTDMAADDRESS_Msk _U_(0xFFFFFFFF) /**< (HSTDMAADDRESS) Register Mask */
+
+
+/* -------- HSTDMACONTROL : (USBHS Offset: 0x08) (R/W 32) Host DMA Channel Control Register -------- */
+
+#define HSTDMACONTROL_OFFSET (0x08) /**< (HSTDMACONTROL) Host DMA Channel Control Register Offset */
+
+#define HSTDMACONTROL_CHANN_ENB_Pos 0 /**< (HSTDMACONTROL) Channel Enable Command Position */
+#define HSTDMACONTROL_CHANN_ENB (_U_(0x1) << HSTDMACONTROL_CHANN_ENB_Pos) /**< (HSTDMACONTROL) Channel Enable Command Mask */
+#define HSTDMACONTROL_LDNXT_DSC_Pos 1 /**< (HSTDMACONTROL) Load Next Channel Transfer Descriptor Enable Command Position */
+#define HSTDMACONTROL_LDNXT_DSC (_U_(0x1) << HSTDMACONTROL_LDNXT_DSC_Pos) /**< (HSTDMACONTROL) Load Next Channel Transfer Descriptor Enable Command Mask */
+#define HSTDMACONTROL_END_TR_EN_Pos 2 /**< (HSTDMACONTROL) End of Transfer Enable Control (OUT transfers only) Position */
+#define HSTDMACONTROL_END_TR_EN (_U_(0x1) << HSTDMACONTROL_END_TR_EN_Pos) /**< (HSTDMACONTROL) End of Transfer Enable Control (OUT transfers only) Mask */
+#define HSTDMACONTROL_END_B_EN_Pos 3 /**< (HSTDMACONTROL) End of Buffer Enable Control Position */
+#define HSTDMACONTROL_END_B_EN (_U_(0x1) << HSTDMACONTROL_END_B_EN_Pos) /**< (HSTDMACONTROL) End of Buffer Enable Control Mask */
+#define HSTDMACONTROL_END_TR_IT_Pos 4 /**< (HSTDMACONTROL) End of Transfer Interrupt Enable Position */
+#define HSTDMACONTROL_END_TR_IT (_U_(0x1) << HSTDMACONTROL_END_TR_IT_Pos) /**< (HSTDMACONTROL) End of Transfer Interrupt Enable Mask */
+#define HSTDMACONTROL_END_BUFFIT_Pos 5 /**< (HSTDMACONTROL) End of Buffer Interrupt Enable Position */
+#define HSTDMACONTROL_END_BUFFIT (_U_(0x1) << HSTDMACONTROL_END_BUFFIT_Pos) /**< (HSTDMACONTROL) End of Buffer Interrupt Enable Mask */
+#define HSTDMACONTROL_DESC_LD_IT_Pos 6 /**< (HSTDMACONTROL) Descriptor Loaded Interrupt Enable Position */
+#define HSTDMACONTROL_DESC_LD_IT (_U_(0x1) << HSTDMACONTROL_DESC_LD_IT_Pos) /**< (HSTDMACONTROL) Descriptor Loaded Interrupt Enable Mask */
+#define HSTDMACONTROL_BURST_LCK_Pos 7 /**< (HSTDMACONTROL) Burst Lock Enable Position */
+#define HSTDMACONTROL_BURST_LCK (_U_(0x1) << HSTDMACONTROL_BURST_LCK_Pos) /**< (HSTDMACONTROL) Burst Lock Enable Mask */
+#define HSTDMACONTROL_BUFF_LENGTH_Pos 16 /**< (HSTDMACONTROL) Buffer Byte Length (Write-only) Position */
+#define HSTDMACONTROL_BUFF_LENGTH (_U_(0xFFFF) << HSTDMACONTROL_BUFF_LENGTH_Pos) /**< (HSTDMACONTROL) Buffer Byte Length (Write-only) Mask */
+#define HSTDMACONTROL_Msk _U_(0xFFFF00FF) /**< (HSTDMACONTROL) Register Mask */
+
+
+/* -------- HSTDMASTATUS : (USBHS Offset: 0x0c) (R/W 32) Host DMA Channel Status Register -------- */
+
+#define HSTDMASTATUS_OFFSET (0x0C) /**< (HSTDMASTATUS) Host DMA Channel Status Register Offset */
+
+#define HSTDMASTATUS_CHANN_ENB_Pos 0 /**< (HSTDMASTATUS) Channel Enable Status Position */
+#define HSTDMASTATUS_CHANN_ENB (_U_(0x1) << HSTDMASTATUS_CHANN_ENB_Pos) /**< (HSTDMASTATUS) Channel Enable Status Mask */
+#define HSTDMASTATUS_CHANN_ACT_Pos 1 /**< (HSTDMASTATUS) Channel Active Status Position */
+#define HSTDMASTATUS_CHANN_ACT (_U_(0x1) << HSTDMASTATUS_CHANN_ACT_Pos) /**< (HSTDMASTATUS) Channel Active Status Mask */
+#define HSTDMASTATUS_END_TR_ST_Pos 4 /**< (HSTDMASTATUS) End of Channel Transfer Status Position */
+#define HSTDMASTATUS_END_TR_ST (_U_(0x1) << HSTDMASTATUS_END_TR_ST_Pos) /**< (HSTDMASTATUS) End of Channel Transfer Status Mask */
+#define HSTDMASTATUS_END_BF_ST_Pos 5 /**< (HSTDMASTATUS) End of Channel Buffer Status Position */
+#define HSTDMASTATUS_END_BF_ST (_U_(0x1) << HSTDMASTATUS_END_BF_ST_Pos) /**< (HSTDMASTATUS) End of Channel Buffer Status Mask */
+#define HSTDMASTATUS_DESC_LDST_Pos 6 /**< (HSTDMASTATUS) Descriptor Loaded Status Position */
+#define HSTDMASTATUS_DESC_LDST (_U_(0x1) << HSTDMASTATUS_DESC_LDST_Pos) /**< (HSTDMASTATUS) Descriptor Loaded Status Mask */
+#define HSTDMASTATUS_BUFF_COUNT_Pos 16 /**< (HSTDMASTATUS) Buffer Byte Count Position */
+#define HSTDMASTATUS_BUFF_COUNT (_U_(0xFFFF) << HSTDMASTATUS_BUFF_COUNT_Pos) /**< (HSTDMASTATUS) Buffer Byte Count Mask */
+#define HSTDMASTATUS_Msk _U_(0xFFFF0073) /**< (HSTDMASTATUS) Register Mask */
+
+
+/* -------- DEVCTRL : (USBHS Offset: 0x00) (R/W 32) Device General Control Register -------- */
+
+#define DEVCTRL_OFFSET (0x00) /**< (DEVCTRL) Device General Control Register Offset */
+
+#define DEVCTRL_UADD_Pos 0 /**< (DEVCTRL) USB Address Position */
+#define DEVCTRL_UADD (_U_(0x7F) << DEVCTRL_UADD_Pos) /**< (DEVCTRL) USB Address Mask */
+#define DEVCTRL_ADDEN_Pos 7 /**< (DEVCTRL) Address Enable Position */
+#define DEVCTRL_ADDEN (_U_(0x1) << DEVCTRL_ADDEN_Pos) /**< (DEVCTRL) Address Enable Mask */
+#define DEVCTRL_DETACH_Pos 8 /**< (DEVCTRL) Detach Position */
+#define DEVCTRL_DETACH (_U_(0x1) << DEVCTRL_DETACH_Pos) /**< (DEVCTRL) Detach Mask */
+#define DEVCTRL_RMWKUP_Pos 9 /**< (DEVCTRL) Remote Wake-Up Position */
+#define DEVCTRL_RMWKUP (_U_(0x1) << DEVCTRL_RMWKUP_Pos) /**< (DEVCTRL) Remote Wake-Up Mask */
+#define DEVCTRL_SPDCONF_Pos 10 /**< (DEVCTRL) Mode Configuration Position */
+#define DEVCTRL_SPDCONF (_U_(0x3) << DEVCTRL_SPDCONF_Pos) /**< (DEVCTRL) Mode Configuration Mask */
+#define DEVCTRL_SPDCONF_NORMAL_Val _U_(0x0) /**< (DEVCTRL) The peripheral starts in Full-speed mode and performs a high-speed reset to switch to High-speed mode if the host is high-speed-capable. */
+#define DEVCTRL_SPDCONF_LOW_POWER_Val _U_(0x1) /**< (DEVCTRL) For a better consumption, if high speed is not needed. */
+#define DEVCTRL_SPDCONF_HIGH_SPEED_Val _U_(0x2) /**< (DEVCTRL) Forced high speed. */
+#define DEVCTRL_SPDCONF_FORCED_FS_Val _U_(0x3) /**< (DEVCTRL) The peripheral remains in Full-speed mode whatever the host speed capability. */
+#define DEVCTRL_SPDCONF_NORMAL (DEVCTRL_SPDCONF_NORMAL_Val << DEVCTRL_SPDCONF_Pos) /**< (DEVCTRL) The peripheral starts in Full-speed mode and performs a high-speed reset to switch to High-speed mode if the host is high-speed-capable. Position */
+#define DEVCTRL_SPDCONF_LOW_POWER (DEVCTRL_SPDCONF_LOW_POWER_Val << DEVCTRL_SPDCONF_Pos) /**< (DEVCTRL) For a better consumption, if high speed is not needed. Position */
+#define DEVCTRL_SPDCONF_HIGH_SPEED (DEVCTRL_SPDCONF_HIGH_SPEED_Val << DEVCTRL_SPDCONF_Pos) /**< (DEVCTRL) Forced high speed. Position */
+#define DEVCTRL_SPDCONF_FORCED_FS (DEVCTRL_SPDCONF_FORCED_FS_Val << DEVCTRL_SPDCONF_Pos) /**< (DEVCTRL) The peripheral remains in Full-speed mode whatever the host speed capability. Position */
+#define DEVCTRL_LS_Pos 12 /**< (DEVCTRL) Low-Speed Mode Force Position */
+#define DEVCTRL_LS (_U_(0x1) << DEVCTRL_LS_Pos) /**< (DEVCTRL) Low-Speed Mode Force Mask */
+#define DEVCTRL_TSTJ_Pos 13 /**< (DEVCTRL) Test mode J Position */
+#define DEVCTRL_TSTJ (_U_(0x1) << DEVCTRL_TSTJ_Pos) /**< (DEVCTRL) Test mode J Mask */
+#define DEVCTRL_TSTK_Pos 14 /**< (DEVCTRL) Test mode K Position */
+#define DEVCTRL_TSTK (_U_(0x1) << DEVCTRL_TSTK_Pos) /**< (DEVCTRL) Test mode K Mask */
+#define DEVCTRL_TSTPCKT_Pos 15 /**< (DEVCTRL) Test packet mode Position */
+#define DEVCTRL_TSTPCKT (_U_(0x1) << DEVCTRL_TSTPCKT_Pos) /**< (DEVCTRL) Test packet mode Mask */
+#define DEVCTRL_OPMODE2_Pos 16 /**< (DEVCTRL) Specific Operational mode Position */
+#define DEVCTRL_OPMODE2 (_U_(0x1) << DEVCTRL_OPMODE2_Pos) /**< (DEVCTRL) Specific Operational mode Mask */
+#define DEVCTRL_Msk _U_(0x1FFFF) /**< (DEVCTRL) Register Mask */
+
+#define DEVCTRL_OPMODE_Pos 16 /**< (DEVCTRL Position) Specific Operational mode */
+#define DEVCTRL_OPMODE (_U_(0x1) << DEVCTRL_OPMODE_Pos) /**< (DEVCTRL Mask) OPMODE */
+
+/* -------- DEVISR : (USBHS Offset: 0x04) (R/ 32) Device Global Interrupt Status Register -------- */
+
+#define DEVISR_OFFSET (0x04) /**< (DEVISR) Device Global Interrupt Status Register Offset */
+
+#define DEVISR_SUSP_Pos 0 /**< (DEVISR) Suspend Interrupt Position */
+#define DEVISR_SUSP (_U_(0x1) << DEVISR_SUSP_Pos) /**< (DEVISR) Suspend Interrupt Mask */
+#define DEVISR_MSOF_Pos 1 /**< (DEVISR) Micro Start of Frame Interrupt Position */
+#define DEVISR_MSOF (_U_(0x1) << DEVISR_MSOF_Pos) /**< (DEVISR) Micro Start of Frame Interrupt Mask */
+#define DEVISR_SOF_Pos 2 /**< (DEVISR) Start of Frame Interrupt Position */
+#define DEVISR_SOF (_U_(0x1) << DEVISR_SOF_Pos) /**< (DEVISR) Start of Frame Interrupt Mask */
+#define DEVISR_EORST_Pos 3 /**< (DEVISR) End of Reset Interrupt Position */
+#define DEVISR_EORST (_U_(0x1) << DEVISR_EORST_Pos) /**< (DEVISR) End of Reset Interrupt Mask */
+#define DEVISR_WAKEUP_Pos 4 /**< (DEVISR) Wake-Up Interrupt Position */
+#define DEVISR_WAKEUP (_U_(0x1) << DEVISR_WAKEUP_Pos) /**< (DEVISR) Wake-Up Interrupt Mask */
+#define DEVISR_EORSM_Pos 5 /**< (DEVISR) End of Resume Interrupt Position */
+#define DEVISR_EORSM (_U_(0x1) << DEVISR_EORSM_Pos) /**< (DEVISR) End of Resume Interrupt Mask */
+#define DEVISR_UPRSM_Pos 6 /**< (DEVISR) Upstream Resume Interrupt Position */
+#define DEVISR_UPRSM (_U_(0x1) << DEVISR_UPRSM_Pos) /**< (DEVISR) Upstream Resume Interrupt Mask */
+#define DEVISR_PEP_0_Pos 12 /**< (DEVISR) Endpoint 0 Interrupt Position */
+#define DEVISR_PEP_0 (_U_(0x1) << DEVISR_PEP_0_Pos) /**< (DEVISR) Endpoint 0 Interrupt Mask */
+#define DEVISR_PEP_1_Pos 13 /**< (DEVISR) Endpoint 1 Interrupt Position */
+#define DEVISR_PEP_1 (_U_(0x1) << DEVISR_PEP_1_Pos) /**< (DEVISR) Endpoint 1 Interrupt Mask */
+#define DEVISR_PEP_2_Pos 14 /**< (DEVISR) Endpoint 2 Interrupt Position */
+#define DEVISR_PEP_2 (_U_(0x1) << DEVISR_PEP_2_Pos) /**< (DEVISR) Endpoint 2 Interrupt Mask */
+#define DEVISR_PEP_3_Pos 15 /**< (DEVISR) Endpoint 3 Interrupt Position */
+#define DEVISR_PEP_3 (_U_(0x1) << DEVISR_PEP_3_Pos) /**< (DEVISR) Endpoint 3 Interrupt Mask */
+#define DEVISR_PEP_4_Pos 16 /**< (DEVISR) Endpoint 4 Interrupt Position */
+#define DEVISR_PEP_4 (_U_(0x1) << DEVISR_PEP_4_Pos) /**< (DEVISR) Endpoint 4 Interrupt Mask */
+#define DEVISR_PEP_5_Pos 17 /**< (DEVISR) Endpoint 5 Interrupt Position */
+#define DEVISR_PEP_5 (_U_(0x1) << DEVISR_PEP_5_Pos) /**< (DEVISR) Endpoint 5 Interrupt Mask */
+#define DEVISR_PEP_6_Pos 18 /**< (DEVISR) Endpoint 6 Interrupt Position */
+#define DEVISR_PEP_6 (_U_(0x1) << DEVISR_PEP_6_Pos) /**< (DEVISR) Endpoint 6 Interrupt Mask */
+#define DEVISR_PEP_7_Pos 19 /**< (DEVISR) Endpoint 7 Interrupt Position */
+#define DEVISR_PEP_7 (_U_(0x1) << DEVISR_PEP_7_Pos) /**< (DEVISR) Endpoint 7 Interrupt Mask */
+#define DEVISR_PEP_8_Pos 20 /**< (DEVISR) Endpoint 8 Interrupt Position */
+#define DEVISR_PEP_8 (_U_(0x1) << DEVISR_PEP_8_Pos) /**< (DEVISR) Endpoint 8 Interrupt Mask */
+#define DEVISR_PEP_9_Pos 21 /**< (DEVISR) Endpoint 9 Interrupt Position */
+#define DEVISR_PEP_9 (_U_(0x1) << DEVISR_PEP_9_Pos) /**< (DEVISR) Endpoint 9 Interrupt Mask */
+#define DEVISR_DMA_1_Pos 25 /**< (DEVISR) DMA Channel 1 Interrupt Position */
+#define DEVISR_DMA_1 (_U_(0x1) << DEVISR_DMA_1_Pos) /**< (DEVISR) DMA Channel 1 Interrupt Mask */
+#define DEVISR_DMA_2_Pos 26 /**< (DEVISR) DMA Channel 2 Interrupt Position */
+#define DEVISR_DMA_2 (_U_(0x1) << DEVISR_DMA_2_Pos) /**< (DEVISR) DMA Channel 2 Interrupt Mask */
+#define DEVISR_DMA_3_Pos 27 /**< (DEVISR) DMA Channel 3 Interrupt Position */
+#define DEVISR_DMA_3 (_U_(0x1) << DEVISR_DMA_3_Pos) /**< (DEVISR) DMA Channel 3 Interrupt Mask */
+#define DEVISR_DMA_4_Pos 28 /**< (DEVISR) DMA Channel 4 Interrupt Position */
+#define DEVISR_DMA_4 (_U_(0x1) << DEVISR_DMA_4_Pos) /**< (DEVISR) DMA Channel 4 Interrupt Mask */
+#define DEVISR_DMA_5_Pos 29 /**< (DEVISR) DMA Channel 5 Interrupt Position */
+#define DEVISR_DMA_5 (_U_(0x1) << DEVISR_DMA_5_Pos) /**< (DEVISR) DMA Channel 5 Interrupt Mask */
+#define DEVISR_DMA_6_Pos 30 /**< (DEVISR) DMA Channel 6 Interrupt Position */
+#define DEVISR_DMA_6 (_U_(0x1) << DEVISR_DMA_6_Pos) /**< (DEVISR) DMA Channel 6 Interrupt Mask */
+#define DEVISR_DMA_7_Pos 31 /**< (DEVISR) DMA Channel 7 Interrupt Position */
+#define DEVISR_DMA_7 (_U_(0x1) << DEVISR_DMA_7_Pos) /**< (DEVISR) DMA Channel 7 Interrupt Mask */
+#define DEVISR_Msk _U_(0xFE3FF07F) /**< (DEVISR) Register Mask */
+
+#define DEVISR_PEP__Pos 12 /**< (DEVISR Position) Endpoint x Interrupt */
+#define DEVISR_PEP_ (_U_(0x3FF) << DEVISR_PEP__Pos) /**< (DEVISR Mask) PEP_ */
+#define DEVISR_DMA__Pos 25 /**< (DEVISR Position) DMA Channel 7 Interrupt */
+#define DEVISR_DMA_ (_U_(0x7F) << DEVISR_DMA__Pos) /**< (DEVISR Mask) DMA_ */
+
+/* -------- DEVICR : (USBHS Offset: 0x08) (/W 32) Device Global Interrupt Clear Register -------- */
+
+#define DEVICR_OFFSET (0x08) /**< (DEVICR) Device Global Interrupt Clear Register Offset */
+
+#define DEVICR_SUSPC_Pos 0 /**< (DEVICR) Suspend Interrupt Clear Position */
+#define DEVICR_SUSPC (_U_(0x1) << DEVICR_SUSPC_Pos) /**< (DEVICR) Suspend Interrupt Clear Mask */
+#define DEVICR_MSOFC_Pos 1 /**< (DEVICR) Micro Start of Frame Interrupt Clear Position */
+#define DEVICR_MSOFC (_U_(0x1) << DEVICR_MSOFC_Pos) /**< (DEVICR) Micro Start of Frame Interrupt Clear Mask */
+#define DEVICR_SOFC_Pos 2 /**< (DEVICR) Start of Frame Interrupt Clear Position */
+#define DEVICR_SOFC (_U_(0x1) << DEVICR_SOFC_Pos) /**< (DEVICR) Start of Frame Interrupt Clear Mask */
+#define DEVICR_EORSTC_Pos 3 /**< (DEVICR) End of Reset Interrupt Clear Position */
+#define DEVICR_EORSTC (_U_(0x1) << DEVICR_EORSTC_Pos) /**< (DEVICR) End of Reset Interrupt Clear Mask */
+#define DEVICR_WAKEUPC_Pos 4 /**< (DEVICR) Wake-Up Interrupt Clear Position */
+#define DEVICR_WAKEUPC (_U_(0x1) << DEVICR_WAKEUPC_Pos) /**< (DEVICR) Wake-Up Interrupt Clear Mask */
+#define DEVICR_EORSMC_Pos 5 /**< (DEVICR) End of Resume Interrupt Clear Position */
+#define DEVICR_EORSMC (_U_(0x1) << DEVICR_EORSMC_Pos) /**< (DEVICR) End of Resume Interrupt Clear Mask */
+#define DEVICR_UPRSMC_Pos 6 /**< (DEVICR) Upstream Resume Interrupt Clear Position */
+#define DEVICR_UPRSMC (_U_(0x1) << DEVICR_UPRSMC_Pos) /**< (DEVICR) Upstream Resume Interrupt Clear Mask */
+#define DEVICR_Msk _U_(0x7F) /**< (DEVICR) Register Mask */
+
+
+/* -------- DEVIFR : (USBHS Offset: 0x0c) (/W 32) Device Global Interrupt Set Register -------- */
+
+#define DEVIFR_OFFSET (0x0C) /**< (DEVIFR) Device Global Interrupt Set Register Offset */
+
+#define DEVIFR_SUSPS_Pos 0 /**< (DEVIFR) Suspend Interrupt Set Position */
+#define DEVIFR_SUSPS (_U_(0x1) << DEVIFR_SUSPS_Pos) /**< (DEVIFR) Suspend Interrupt Set Mask */
+#define DEVIFR_MSOFS_Pos 1 /**< (DEVIFR) Micro Start of Frame Interrupt Set Position */
+#define DEVIFR_MSOFS (_U_(0x1) << DEVIFR_MSOFS_Pos) /**< (DEVIFR) Micro Start of Frame Interrupt Set Mask */
+#define DEVIFR_SOFS_Pos 2 /**< (DEVIFR) Start of Frame Interrupt Set Position */
+#define DEVIFR_SOFS (_U_(0x1) << DEVIFR_SOFS_Pos) /**< (DEVIFR) Start of Frame Interrupt Set Mask */
+#define DEVIFR_EORSTS_Pos 3 /**< (DEVIFR) End of Reset Interrupt Set Position */
+#define DEVIFR_EORSTS (_U_(0x1) << DEVIFR_EORSTS_Pos) /**< (DEVIFR) End of Reset Interrupt Set Mask */
+#define DEVIFR_WAKEUPS_Pos 4 /**< (DEVIFR) Wake-Up Interrupt Set Position */
+#define DEVIFR_WAKEUPS (_U_(0x1) << DEVIFR_WAKEUPS_Pos) /**< (DEVIFR) Wake-Up Interrupt Set Mask */
+#define DEVIFR_EORSMS_Pos 5 /**< (DEVIFR) End of Resume Interrupt Set Position */
+#define DEVIFR_EORSMS (_U_(0x1) << DEVIFR_EORSMS_Pos) /**< (DEVIFR) End of Resume Interrupt Set Mask */
+#define DEVIFR_UPRSMS_Pos 6 /**< (DEVIFR) Upstream Resume Interrupt Set Position */
+#define DEVIFR_UPRSMS (_U_(0x1) << DEVIFR_UPRSMS_Pos) /**< (DEVIFR) Upstream Resume Interrupt Set Mask */
+#define DEVIFR_DMA_1_Pos 25 /**< (DEVIFR) DMA Channel 1 Interrupt Set Position */
+#define DEVIFR_DMA_1 (_U_(0x1) << DEVIFR_DMA_1_Pos) /**< (DEVIFR) DMA Channel 1 Interrupt Set Mask */
+#define DEVIFR_DMA_2_Pos 26 /**< (DEVIFR) DMA Channel 2 Interrupt Set Position */
+#define DEVIFR_DMA_2 (_U_(0x1) << DEVIFR_DMA_2_Pos) /**< (DEVIFR) DMA Channel 2 Interrupt Set Mask */
+#define DEVIFR_DMA_3_Pos 27 /**< (DEVIFR) DMA Channel 3 Interrupt Set Position */
+#define DEVIFR_DMA_3 (_U_(0x1) << DEVIFR_DMA_3_Pos) /**< (DEVIFR) DMA Channel 3 Interrupt Set Mask */
+#define DEVIFR_DMA_4_Pos 28 /**< (DEVIFR) DMA Channel 4 Interrupt Set Position */
+#define DEVIFR_DMA_4 (_U_(0x1) << DEVIFR_DMA_4_Pos) /**< (DEVIFR) DMA Channel 4 Interrupt Set Mask */
+#define DEVIFR_DMA_5_Pos 29 /**< (DEVIFR) DMA Channel 5 Interrupt Set Position */
+#define DEVIFR_DMA_5 (_U_(0x1) << DEVIFR_DMA_5_Pos) /**< (DEVIFR) DMA Channel 5 Interrupt Set Mask */
+#define DEVIFR_DMA_6_Pos 30 /**< (DEVIFR) DMA Channel 6 Interrupt Set Position */
+#define DEVIFR_DMA_6 (_U_(0x1) << DEVIFR_DMA_6_Pos) /**< (DEVIFR) DMA Channel 6 Interrupt Set Mask */
+#define DEVIFR_DMA_7_Pos 31 /**< (DEVIFR) DMA Channel 7 Interrupt Set Position */
+#define DEVIFR_DMA_7 (_U_(0x1) << DEVIFR_DMA_7_Pos) /**< (DEVIFR) DMA Channel 7 Interrupt Set Mask */
+#define DEVIFR_Msk _U_(0xFE00007F) /**< (DEVIFR) Register Mask */
+
+#define DEVIFR_DMA__Pos 25 /**< (DEVIFR Position) DMA Channel 7 Interrupt Set */
+#define DEVIFR_DMA_ (_U_(0x7F) << DEVIFR_DMA__Pos) /**< (DEVIFR Mask) DMA_ */
+
+/* -------- DEVIMR : (USBHS Offset: 0x10) (R/ 32) Device Global Interrupt Mask Register -------- */
+
+#define DEVIMR_OFFSET (0x10) /**< (DEVIMR) Device Global Interrupt Mask Register Offset */
+
+#define DEVIMR_SUSPE_Pos 0 /**< (DEVIMR) Suspend Interrupt Mask Position */
+#define DEVIMR_SUSPE (_U_(0x1) << DEVIMR_SUSPE_Pos) /**< (DEVIMR) Suspend Interrupt Mask Mask */
+#define DEVIMR_MSOFE_Pos 1 /**< (DEVIMR) Micro Start of Frame Interrupt Mask Position */
+#define DEVIMR_MSOFE (_U_(0x1) << DEVIMR_MSOFE_Pos) /**< (DEVIMR) Micro Start of Frame Interrupt Mask Mask */
+#define DEVIMR_SOFE_Pos 2 /**< (DEVIMR) Start of Frame Interrupt Mask Position */
+#define DEVIMR_SOFE (_U_(0x1) << DEVIMR_SOFE_Pos) /**< (DEVIMR) Start of Frame Interrupt Mask Mask */
+#define DEVIMR_EORSTE_Pos 3 /**< (DEVIMR) End of Reset Interrupt Mask Position */
+#define DEVIMR_EORSTE (_U_(0x1) << DEVIMR_EORSTE_Pos) /**< (DEVIMR) End of Reset Interrupt Mask Mask */
+#define DEVIMR_WAKEUPE_Pos 4 /**< (DEVIMR) Wake-Up Interrupt Mask Position */
+#define DEVIMR_WAKEUPE (_U_(0x1) << DEVIMR_WAKEUPE_Pos) /**< (DEVIMR) Wake-Up Interrupt Mask Mask */
+#define DEVIMR_EORSME_Pos 5 /**< (DEVIMR) End of Resume Interrupt Mask Position */
+#define DEVIMR_EORSME (_U_(0x1) << DEVIMR_EORSME_Pos) /**< (DEVIMR) End of Resume Interrupt Mask Mask */
+#define DEVIMR_UPRSME_Pos 6 /**< (DEVIMR) Upstream Resume Interrupt Mask Position */
+#define DEVIMR_UPRSME (_U_(0x1) << DEVIMR_UPRSME_Pos) /**< (DEVIMR) Upstream Resume Interrupt Mask Mask */
+#define DEVIMR_PEP_0_Pos 12 /**< (DEVIMR) Endpoint 0 Interrupt Mask Position */
+#define DEVIMR_PEP_0 (_U_(0x1) << DEVIMR_PEP_0_Pos) /**< (DEVIMR) Endpoint 0 Interrupt Mask Mask */
+#define DEVIMR_PEP_1_Pos 13 /**< (DEVIMR) Endpoint 1 Interrupt Mask Position */
+#define DEVIMR_PEP_1 (_U_(0x1) << DEVIMR_PEP_1_Pos) /**< (DEVIMR) Endpoint 1 Interrupt Mask Mask */
+#define DEVIMR_PEP_2_Pos 14 /**< (DEVIMR) Endpoint 2 Interrupt Mask Position */
+#define DEVIMR_PEP_2 (_U_(0x1) << DEVIMR_PEP_2_Pos) /**< (DEVIMR) Endpoint 2 Interrupt Mask Mask */
+#define DEVIMR_PEP_3_Pos 15 /**< (DEVIMR) Endpoint 3 Interrupt Mask Position */
+#define DEVIMR_PEP_3 (_U_(0x1) << DEVIMR_PEP_3_Pos) /**< (DEVIMR) Endpoint 3 Interrupt Mask Mask */
+#define DEVIMR_PEP_4_Pos 16 /**< (DEVIMR) Endpoint 4 Interrupt Mask Position */
+#define DEVIMR_PEP_4 (_U_(0x1) << DEVIMR_PEP_4_Pos) /**< (DEVIMR) Endpoint 4 Interrupt Mask Mask */
+#define DEVIMR_PEP_5_Pos 17 /**< (DEVIMR) Endpoint 5 Interrupt Mask Position */
+#define DEVIMR_PEP_5 (_U_(0x1) << DEVIMR_PEP_5_Pos) /**< (DEVIMR) Endpoint 5 Interrupt Mask Mask */
+#define DEVIMR_PEP_6_Pos 18 /**< (DEVIMR) Endpoint 6 Interrupt Mask Position */
+#define DEVIMR_PEP_6 (_U_(0x1) << DEVIMR_PEP_6_Pos) /**< (DEVIMR) Endpoint 6 Interrupt Mask Mask */
+#define DEVIMR_PEP_7_Pos 19 /**< (DEVIMR) Endpoint 7 Interrupt Mask Position */
+#define DEVIMR_PEP_7 (_U_(0x1) << DEVIMR_PEP_7_Pos) /**< (DEVIMR) Endpoint 7 Interrupt Mask Mask */
+#define DEVIMR_PEP_8_Pos 20 /**< (DEVIMR) Endpoint 8 Interrupt Mask Position */
+#define DEVIMR_PEP_8 (_U_(0x1) << DEVIMR_PEP_8_Pos) /**< (DEVIMR) Endpoint 8 Interrupt Mask Mask */
+#define DEVIMR_PEP_9_Pos 21 /**< (DEVIMR) Endpoint 9 Interrupt Mask Position */
+#define DEVIMR_PEP_9 (_U_(0x1) << DEVIMR_PEP_9_Pos) /**< (DEVIMR) Endpoint 9 Interrupt Mask Mask */
+#define DEVIMR_DMA_1_Pos 25 /**< (DEVIMR) DMA Channel 1 Interrupt Mask Position */
+#define DEVIMR_DMA_1 (_U_(0x1) << DEVIMR_DMA_1_Pos) /**< (DEVIMR) DMA Channel 1 Interrupt Mask Mask */
+#define DEVIMR_DMA_2_Pos 26 /**< (DEVIMR) DMA Channel 2 Interrupt Mask Position */
+#define DEVIMR_DMA_2 (_U_(0x1) << DEVIMR_DMA_2_Pos) /**< (DEVIMR) DMA Channel 2 Interrupt Mask Mask */
+#define DEVIMR_DMA_3_Pos 27 /**< (DEVIMR) DMA Channel 3 Interrupt Mask Position */
+#define DEVIMR_DMA_3 (_U_(0x1) << DEVIMR_DMA_3_Pos) /**< (DEVIMR) DMA Channel 3 Interrupt Mask Mask */
+#define DEVIMR_DMA_4_Pos 28 /**< (DEVIMR) DMA Channel 4 Interrupt Mask Position */
+#define DEVIMR_DMA_4 (_U_(0x1) << DEVIMR_DMA_4_Pos) /**< (DEVIMR) DMA Channel 4 Interrupt Mask Mask */
+#define DEVIMR_DMA_5_Pos 29 /**< (DEVIMR) DMA Channel 5 Interrupt Mask Position */
+#define DEVIMR_DMA_5 (_U_(0x1) << DEVIMR_DMA_5_Pos) /**< (DEVIMR) DMA Channel 5 Interrupt Mask Mask */
+#define DEVIMR_DMA_6_Pos 30 /**< (DEVIMR) DMA Channel 6 Interrupt Mask Position */
+#define DEVIMR_DMA_6 (_U_(0x1) << DEVIMR_DMA_6_Pos) /**< (DEVIMR) DMA Channel 6 Interrupt Mask Mask */
+#define DEVIMR_DMA_7_Pos 31 /**< (DEVIMR) DMA Channel 7 Interrupt Mask Position */
+#define DEVIMR_DMA_7 (_U_(0x1) << DEVIMR_DMA_7_Pos) /**< (DEVIMR) DMA Channel 7 Interrupt Mask Mask */
+#define DEVIMR_Msk _U_(0xFE3FF07F) /**< (DEVIMR) Register Mask */
+
+#define DEVIMR_PEP__Pos 12 /**< (DEVIMR Position) Endpoint x Interrupt Mask */
+#define DEVIMR_PEP_ (_U_(0x3FF) << DEVIMR_PEP__Pos) /**< (DEVIMR Mask) PEP_ */
+#define DEVIMR_DMA__Pos 25 /**< (DEVIMR Position) DMA Channel 7 Interrupt Mask */
+#define DEVIMR_DMA_ (_U_(0x7F) << DEVIMR_DMA__Pos) /**< (DEVIMR Mask) DMA_ */
+
+/* -------- DEVIDR : (USBHS Offset: 0x14) (/W 32) Device Global Interrupt Disable Register -------- */
+
+#define DEVIDR_OFFSET (0x14) /**< (DEVIDR) Device Global Interrupt Disable Register Offset */
+
+#define DEVIDR_SUSPEC_Pos 0 /**< (DEVIDR) Suspend Interrupt Disable Position */
+#define DEVIDR_SUSPEC (_U_(0x1) << DEVIDR_SUSPEC_Pos) /**< (DEVIDR) Suspend Interrupt Disable Mask */
+#define DEVIDR_MSOFEC_Pos 1 /**< (DEVIDR) Micro Start of Frame Interrupt Disable Position */
+#define DEVIDR_MSOFEC (_U_(0x1) << DEVIDR_MSOFEC_Pos) /**< (DEVIDR) Micro Start of Frame Interrupt Disable Mask */
+#define DEVIDR_SOFEC_Pos 2 /**< (DEVIDR) Start of Frame Interrupt Disable Position */
+#define DEVIDR_SOFEC (_U_(0x1) << DEVIDR_SOFEC_Pos) /**< (DEVIDR) Start of Frame Interrupt Disable Mask */
+#define DEVIDR_EORSTEC_Pos 3 /**< (DEVIDR) End of Reset Interrupt Disable Position */
+#define DEVIDR_EORSTEC (_U_(0x1) << DEVIDR_EORSTEC_Pos) /**< (DEVIDR) End of Reset Interrupt Disable Mask */
+#define DEVIDR_WAKEUPEC_Pos 4 /**< (DEVIDR) Wake-Up Interrupt Disable Position */
+#define DEVIDR_WAKEUPEC (_U_(0x1) << DEVIDR_WAKEUPEC_Pos) /**< (DEVIDR) Wake-Up Interrupt Disable Mask */
+#define DEVIDR_EORSMEC_Pos 5 /**< (DEVIDR) End of Resume Interrupt Disable Position */
+#define DEVIDR_EORSMEC (_U_(0x1) << DEVIDR_EORSMEC_Pos) /**< (DEVIDR) End of Resume Interrupt Disable Mask */
+#define DEVIDR_UPRSMEC_Pos 6 /**< (DEVIDR) Upstream Resume Interrupt Disable Position */
+#define DEVIDR_UPRSMEC (_U_(0x1) << DEVIDR_UPRSMEC_Pos) /**< (DEVIDR) Upstream Resume Interrupt Disable Mask */
+#define DEVIDR_PEP_0_Pos 12 /**< (DEVIDR) Endpoint 0 Interrupt Disable Position */
+#define DEVIDR_PEP_0 (_U_(0x1) << DEVIDR_PEP_0_Pos) /**< (DEVIDR) Endpoint 0 Interrupt Disable Mask */
+#define DEVIDR_PEP_1_Pos 13 /**< (DEVIDR) Endpoint 1 Interrupt Disable Position */
+#define DEVIDR_PEP_1 (_U_(0x1) << DEVIDR_PEP_1_Pos) /**< (DEVIDR) Endpoint 1 Interrupt Disable Mask */
+#define DEVIDR_PEP_2_Pos 14 /**< (DEVIDR) Endpoint 2 Interrupt Disable Position */
+#define DEVIDR_PEP_2 (_U_(0x1) << DEVIDR_PEP_2_Pos) /**< (DEVIDR) Endpoint 2 Interrupt Disable Mask */
+#define DEVIDR_PEP_3_Pos 15 /**< (DEVIDR) Endpoint 3 Interrupt Disable Position */
+#define DEVIDR_PEP_3 (_U_(0x1) << DEVIDR_PEP_3_Pos) /**< (DEVIDR) Endpoint 3 Interrupt Disable Mask */
+#define DEVIDR_PEP_4_Pos 16 /**< (DEVIDR) Endpoint 4 Interrupt Disable Position */
+#define DEVIDR_PEP_4 (_U_(0x1) << DEVIDR_PEP_4_Pos) /**< (DEVIDR) Endpoint 4 Interrupt Disable Mask */
+#define DEVIDR_PEP_5_Pos 17 /**< (DEVIDR) Endpoint 5 Interrupt Disable Position */
+#define DEVIDR_PEP_5 (_U_(0x1) << DEVIDR_PEP_5_Pos) /**< (DEVIDR) Endpoint 5 Interrupt Disable Mask */
+#define DEVIDR_PEP_6_Pos 18 /**< (DEVIDR) Endpoint 6 Interrupt Disable Position */
+#define DEVIDR_PEP_6 (_U_(0x1) << DEVIDR_PEP_6_Pos) /**< (DEVIDR) Endpoint 6 Interrupt Disable Mask */
+#define DEVIDR_PEP_7_Pos 19 /**< (DEVIDR) Endpoint 7 Interrupt Disable Position */
+#define DEVIDR_PEP_7 (_U_(0x1) << DEVIDR_PEP_7_Pos) /**< (DEVIDR) Endpoint 7 Interrupt Disable Mask */
+#define DEVIDR_PEP_8_Pos 20 /**< (DEVIDR) Endpoint 8 Interrupt Disable Position */
+#define DEVIDR_PEP_8 (_U_(0x1) << DEVIDR_PEP_8_Pos) /**< (DEVIDR) Endpoint 8 Interrupt Disable Mask */
+#define DEVIDR_PEP_9_Pos 21 /**< (DEVIDR) Endpoint 9 Interrupt Disable Position */
+#define DEVIDR_PEP_9 (_U_(0x1) << DEVIDR_PEP_9_Pos) /**< (DEVIDR) Endpoint 9 Interrupt Disable Mask */
+#define DEVIDR_DMA_1_Pos 25 /**< (DEVIDR) DMA Channel 1 Interrupt Disable Position */
+#define DEVIDR_DMA_1 (_U_(0x1) << DEVIDR_DMA_1_Pos) /**< (DEVIDR) DMA Channel 1 Interrupt Disable Mask */
+#define DEVIDR_DMA_2_Pos 26 /**< (DEVIDR) DMA Channel 2 Interrupt Disable Position */
+#define DEVIDR_DMA_2 (_U_(0x1) << DEVIDR_DMA_2_Pos) /**< (DEVIDR) DMA Channel 2 Interrupt Disable Mask */
+#define DEVIDR_DMA_3_Pos 27 /**< (DEVIDR) DMA Channel 3 Interrupt Disable Position */
+#define DEVIDR_DMA_3 (_U_(0x1) << DEVIDR_DMA_3_Pos) /**< (DEVIDR) DMA Channel 3 Interrupt Disable Mask */
+#define DEVIDR_DMA_4_Pos 28 /**< (DEVIDR) DMA Channel 4 Interrupt Disable Position */
+#define DEVIDR_DMA_4 (_U_(0x1) << DEVIDR_DMA_4_Pos) /**< (DEVIDR) DMA Channel 4 Interrupt Disable Mask */
+#define DEVIDR_DMA_5_Pos 29 /**< (DEVIDR) DMA Channel 5 Interrupt Disable Position */
+#define DEVIDR_DMA_5 (_U_(0x1) << DEVIDR_DMA_5_Pos) /**< (DEVIDR) DMA Channel 5 Interrupt Disable Mask */
+#define DEVIDR_DMA_6_Pos 30 /**< (DEVIDR) DMA Channel 6 Interrupt Disable Position */
+#define DEVIDR_DMA_6 (_U_(0x1) << DEVIDR_DMA_6_Pos) /**< (DEVIDR) DMA Channel 6 Interrupt Disable Mask */
+#define DEVIDR_DMA_7_Pos 31 /**< (DEVIDR) DMA Channel 7 Interrupt Disable Position */
+#define DEVIDR_DMA_7 (_U_(0x1) << DEVIDR_DMA_7_Pos) /**< (DEVIDR) DMA Channel 7 Interrupt Disable Mask */
+#define DEVIDR_Msk _U_(0xFE3FF07F) /**< (DEVIDR) Register Mask */
+
+#define DEVIDR_PEP__Pos 12 /**< (DEVIDR Position) Endpoint x Interrupt Disable */
+#define DEVIDR_PEP_ (_U_(0x3FF) << DEVIDR_PEP__Pos) /**< (DEVIDR Mask) PEP_ */
+#define DEVIDR_DMA__Pos 25 /**< (DEVIDR Position) DMA Channel 7 Interrupt Disable */
+#define DEVIDR_DMA_ (_U_(0x7F) << DEVIDR_DMA__Pos) /**< (DEVIDR Mask) DMA_ */
+
+/* -------- DEVIER : (USBHS Offset: 0x18) (/W 32) Device Global Interrupt Enable Register -------- */
+
+#define DEVIER_OFFSET (0x18) /**< (DEVIER) Device Global Interrupt Enable Register Offset */
+
+#define DEVIER_SUSPES_Pos 0 /**< (DEVIER) Suspend Interrupt Enable Position */
+#define DEVIER_SUSPES (_U_(0x1) << DEVIER_SUSPES_Pos) /**< (DEVIER) Suspend Interrupt Enable Mask */
+#define DEVIER_MSOFES_Pos 1 /**< (DEVIER) Micro Start of Frame Interrupt Enable Position */
+#define DEVIER_MSOFES (_U_(0x1) << DEVIER_MSOFES_Pos) /**< (DEVIER) Micro Start of Frame Interrupt Enable Mask */
+#define DEVIER_SOFES_Pos 2 /**< (DEVIER) Start of Frame Interrupt Enable Position */
+#define DEVIER_SOFES (_U_(0x1) << DEVIER_SOFES_Pos) /**< (DEVIER) Start of Frame Interrupt Enable Mask */
+#define DEVIER_EORSTES_Pos 3 /**< (DEVIER) End of Reset Interrupt Enable Position */
+#define DEVIER_EORSTES (_U_(0x1) << DEVIER_EORSTES_Pos) /**< (DEVIER) End of Reset Interrupt Enable Mask */
+#define DEVIER_WAKEUPES_Pos 4 /**< (DEVIER) Wake-Up Interrupt Enable Position */
+#define DEVIER_WAKEUPES (_U_(0x1) << DEVIER_WAKEUPES_Pos) /**< (DEVIER) Wake-Up Interrupt Enable Mask */
+#define DEVIER_EORSMES_Pos 5 /**< (DEVIER) End of Resume Interrupt Enable Position */
+#define DEVIER_EORSMES (_U_(0x1) << DEVIER_EORSMES_Pos) /**< (DEVIER) End of Resume Interrupt Enable Mask */
+#define DEVIER_UPRSMES_Pos 6 /**< (DEVIER) Upstream Resume Interrupt Enable Position */
+#define DEVIER_UPRSMES (_U_(0x1) << DEVIER_UPRSMES_Pos) /**< (DEVIER) Upstream Resume Interrupt Enable Mask */
+#define DEVIER_PEP_0_Pos 12 /**< (DEVIER) Endpoint 0 Interrupt Enable Position */
+#define DEVIER_PEP_0 (_U_(0x1) << DEVIER_PEP_0_Pos) /**< (DEVIER) Endpoint 0 Interrupt Enable Mask */
+#define DEVIER_PEP_1_Pos 13 /**< (DEVIER) Endpoint 1 Interrupt Enable Position */
+#define DEVIER_PEP_1 (_U_(0x1) << DEVIER_PEP_1_Pos) /**< (DEVIER) Endpoint 1 Interrupt Enable Mask */
+#define DEVIER_PEP_2_Pos 14 /**< (DEVIER) Endpoint 2 Interrupt Enable Position */
+#define DEVIER_PEP_2 (_U_(0x1) << DEVIER_PEP_2_Pos) /**< (DEVIER) Endpoint 2 Interrupt Enable Mask */
+#define DEVIER_PEP_3_Pos 15 /**< (DEVIER) Endpoint 3 Interrupt Enable Position */
+#define DEVIER_PEP_3 (_U_(0x1) << DEVIER_PEP_3_Pos) /**< (DEVIER) Endpoint 3 Interrupt Enable Mask */
+#define DEVIER_PEP_4_Pos 16 /**< (DEVIER) Endpoint 4 Interrupt Enable Position */
+#define DEVIER_PEP_4 (_U_(0x1) << DEVIER_PEP_4_Pos) /**< (DEVIER) Endpoint 4 Interrupt Enable Mask */
+#define DEVIER_PEP_5_Pos 17 /**< (DEVIER) Endpoint 5 Interrupt Enable Position */
+#define DEVIER_PEP_5 (_U_(0x1) << DEVIER_PEP_5_Pos) /**< (DEVIER) Endpoint 5 Interrupt Enable Mask */
+#define DEVIER_PEP_6_Pos 18 /**< (DEVIER) Endpoint 6 Interrupt Enable Position */
+#define DEVIER_PEP_6 (_U_(0x1) << DEVIER_PEP_6_Pos) /**< (DEVIER) Endpoint 6 Interrupt Enable Mask */
+#define DEVIER_PEP_7_Pos 19 /**< (DEVIER) Endpoint 7 Interrupt Enable Position */
+#define DEVIER_PEP_7 (_U_(0x1) << DEVIER_PEP_7_Pos) /**< (DEVIER) Endpoint 7 Interrupt Enable Mask */
+#define DEVIER_PEP_8_Pos 20 /**< (DEVIER) Endpoint 8 Interrupt Enable Position */
+#define DEVIER_PEP_8 (_U_(0x1) << DEVIER_PEP_8_Pos) /**< (DEVIER) Endpoint 8 Interrupt Enable Mask */
+#define DEVIER_PEP_9_Pos 21 /**< (DEVIER) Endpoint 9 Interrupt Enable Position */
+#define DEVIER_PEP_9 (_U_(0x1) << DEVIER_PEP_9_Pos) /**< (DEVIER) Endpoint 9 Interrupt Enable Mask */
+#define DEVIER_DMA_1_Pos 25 /**< (DEVIER) DMA Channel 1 Interrupt Enable Position */
+#define DEVIER_DMA_1 (_U_(0x1) << DEVIER_DMA_1_Pos) /**< (DEVIER) DMA Channel 1 Interrupt Enable Mask */
+#define DEVIER_DMA_2_Pos 26 /**< (DEVIER) DMA Channel 2 Interrupt Enable Position */
+#define DEVIER_DMA_2 (_U_(0x1) << DEVIER_DMA_2_Pos) /**< (DEVIER) DMA Channel 2 Interrupt Enable Mask */
+#define DEVIER_DMA_3_Pos 27 /**< (DEVIER) DMA Channel 3 Interrupt Enable Position */
+#define DEVIER_DMA_3 (_U_(0x1) << DEVIER_DMA_3_Pos) /**< (DEVIER) DMA Channel 3 Interrupt Enable Mask */
+#define DEVIER_DMA_4_Pos 28 /**< (DEVIER) DMA Channel 4 Interrupt Enable Position */
+#define DEVIER_DMA_4 (_U_(0x1) << DEVIER_DMA_4_Pos) /**< (DEVIER) DMA Channel 4 Interrupt Enable Mask */
+#define DEVIER_DMA_5_Pos 29 /**< (DEVIER) DMA Channel 5 Interrupt Enable Position */
+#define DEVIER_DMA_5 (_U_(0x1) << DEVIER_DMA_5_Pos) /**< (DEVIER) DMA Channel 5 Interrupt Enable Mask */
+#define DEVIER_DMA_6_Pos 30 /**< (DEVIER) DMA Channel 6 Interrupt Enable Position */
+#define DEVIER_DMA_6 (_U_(0x1) << DEVIER_DMA_6_Pos) /**< (DEVIER) DMA Channel 6 Interrupt Enable Mask */
+#define DEVIER_DMA_7_Pos 31 /**< (DEVIER) DMA Channel 7 Interrupt Enable Position */
+#define DEVIER_DMA_7 (_U_(0x1) << DEVIER_DMA_7_Pos) /**< (DEVIER) DMA Channel 7 Interrupt Enable Mask */
+#define DEVIER_Msk _U_(0xFE3FF07F) /**< (DEVIER) Register Mask */
+
+#define DEVIER_PEP__Pos 12 /**< (DEVIER Position) Endpoint x Interrupt Enable */
+#define DEVIER_PEP_ (_U_(0x3FF) << DEVIER_PEP__Pos) /**< (DEVIER Mask) PEP_ */
+#define DEVIER_DMA__Pos 25 /**< (DEVIER Position) DMA Channel 7 Interrupt Enable */
+#define DEVIER_DMA_ (_U_(0x7F) << DEVIER_DMA__Pos) /**< (DEVIER Mask) DMA_ */
+
+/* -------- DEVEPT : (USBHS Offset: 0x1c) (R/W 32) Device Endpoint Register -------- */
+
+#define DEVEPT_OFFSET (0x1C) /**< (DEVEPT) Device Endpoint Register Offset */
+
+#define DEVEPT_EPEN0_Pos 0 /**< (DEVEPT) Endpoint 0 Enable Position */
+#define DEVEPT_EPEN0 (_U_(0x1) << DEVEPT_EPEN0_Pos) /**< (DEVEPT) Endpoint 0 Enable Mask */
+#define DEVEPT_EPEN1_Pos 1 /**< (DEVEPT) Endpoint 1 Enable Position */
+#define DEVEPT_EPEN1 (_U_(0x1) << DEVEPT_EPEN1_Pos) /**< (DEVEPT) Endpoint 1 Enable Mask */
+#define DEVEPT_EPEN2_Pos 2 /**< (DEVEPT) Endpoint 2 Enable Position */
+#define DEVEPT_EPEN2 (_U_(0x1) << DEVEPT_EPEN2_Pos) /**< (DEVEPT) Endpoint 2 Enable Mask */
+#define DEVEPT_EPEN3_Pos 3 /**< (DEVEPT) Endpoint 3 Enable Position */
+#define DEVEPT_EPEN3 (_U_(0x1) << DEVEPT_EPEN3_Pos) /**< (DEVEPT) Endpoint 3 Enable Mask */
+#define DEVEPT_EPEN4_Pos 4 /**< (DEVEPT) Endpoint 4 Enable Position */
+#define DEVEPT_EPEN4 (_U_(0x1) << DEVEPT_EPEN4_Pos) /**< (DEVEPT) Endpoint 4 Enable Mask */
+#define DEVEPT_EPEN5_Pos 5 /**< (DEVEPT) Endpoint 5 Enable Position */
+#define DEVEPT_EPEN5 (_U_(0x1) << DEVEPT_EPEN5_Pos) /**< (DEVEPT) Endpoint 5 Enable Mask */
+#define DEVEPT_EPEN6_Pos 6 /**< (DEVEPT) Endpoint 6 Enable Position */
+#define DEVEPT_EPEN6 (_U_(0x1) << DEVEPT_EPEN6_Pos) /**< (DEVEPT) Endpoint 6 Enable Mask */
+#define DEVEPT_EPEN7_Pos 7 /**< (DEVEPT) Endpoint 7 Enable Position */
+#define DEVEPT_EPEN7 (_U_(0x1) << DEVEPT_EPEN7_Pos) /**< (DEVEPT) Endpoint 7 Enable Mask */
+#define DEVEPT_EPEN8_Pos 8 /**< (DEVEPT) Endpoint 8 Enable Position */
+#define DEVEPT_EPEN8 (_U_(0x1) << DEVEPT_EPEN8_Pos) /**< (DEVEPT) Endpoint 8 Enable Mask */
+#define DEVEPT_EPEN9_Pos 9 /**< (DEVEPT) Endpoint 9 Enable Position */
+#define DEVEPT_EPEN9 (_U_(0x1) << DEVEPT_EPEN9_Pos) /**< (DEVEPT) Endpoint 9 Enable Mask */
+#define DEVEPT_EPRST0_Pos 16 /**< (DEVEPT) Endpoint 0 Reset Position */
+#define DEVEPT_EPRST0 (_U_(0x1) << DEVEPT_EPRST0_Pos) /**< (DEVEPT) Endpoint 0 Reset Mask */
+#define DEVEPT_EPRST1_Pos 17 /**< (DEVEPT) Endpoint 1 Reset Position */
+#define DEVEPT_EPRST1 (_U_(0x1) << DEVEPT_EPRST1_Pos) /**< (DEVEPT) Endpoint 1 Reset Mask */
+#define DEVEPT_EPRST2_Pos 18 /**< (DEVEPT) Endpoint 2 Reset Position */
+#define DEVEPT_EPRST2 (_U_(0x1) << DEVEPT_EPRST2_Pos) /**< (DEVEPT) Endpoint 2 Reset Mask */
+#define DEVEPT_EPRST3_Pos 19 /**< (DEVEPT) Endpoint 3 Reset Position */
+#define DEVEPT_EPRST3 (_U_(0x1) << DEVEPT_EPRST3_Pos) /**< (DEVEPT) Endpoint 3 Reset Mask */
+#define DEVEPT_EPRST4_Pos 20 /**< (DEVEPT) Endpoint 4 Reset Position */
+#define DEVEPT_EPRST4 (_U_(0x1) << DEVEPT_EPRST4_Pos) /**< (DEVEPT) Endpoint 4 Reset Mask */
+#define DEVEPT_EPRST5_Pos 21 /**< (DEVEPT) Endpoint 5 Reset Position */
+#define DEVEPT_EPRST5 (_U_(0x1) << DEVEPT_EPRST5_Pos) /**< (DEVEPT) Endpoint 5 Reset Mask */
+#define DEVEPT_EPRST6_Pos 22 /**< (DEVEPT) Endpoint 6 Reset Position */
+#define DEVEPT_EPRST6 (_U_(0x1) << DEVEPT_EPRST6_Pos) /**< (DEVEPT) Endpoint 6 Reset Mask */
+#define DEVEPT_EPRST7_Pos 23 /**< (DEVEPT) Endpoint 7 Reset Position */
+#define DEVEPT_EPRST7 (_U_(0x1) << DEVEPT_EPRST7_Pos) /**< (DEVEPT) Endpoint 7 Reset Mask */
+#define DEVEPT_EPRST8_Pos 24 /**< (DEVEPT) Endpoint 8 Reset Position */
+#define DEVEPT_EPRST8 (_U_(0x1) << DEVEPT_EPRST8_Pos) /**< (DEVEPT) Endpoint 8 Reset Mask */
+#define DEVEPT_EPRST9_Pos 25 /**< (DEVEPT) Endpoint 9 Reset Position */
+#define DEVEPT_EPRST9 (_U_(0x1) << DEVEPT_EPRST9_Pos) /**< (DEVEPT) Endpoint 9 Reset Mask */
+#define DEVEPT_Msk _U_(0x3FF03FF) /**< (DEVEPT) Register Mask */
+
+#define DEVEPT_EPEN_Pos 0 /**< (DEVEPT Position) Endpoint x Enable */
+#define DEVEPT_EPEN (_U_(0x3FF) << DEVEPT_EPEN_Pos) /**< (DEVEPT Mask) EPEN */
+#define DEVEPT_EPRST_Pos 16 /**< (DEVEPT Position) Endpoint 9 Reset */
+#define DEVEPT_EPRST (_U_(0x3FF) << DEVEPT_EPRST_Pos) /**< (DEVEPT Mask) EPRST */
+
+/* -------- DEVFNUM : (USBHS Offset: 0x20) (R/ 32) Device Frame Number Register -------- */
+
+#define DEVFNUM_OFFSET (0x20) /**< (DEVFNUM) Device Frame Number Register Offset */
+
+#define DEVFNUM_MFNUM_Pos 0 /**< (DEVFNUM) Micro Frame Number Position */
+#define DEVFNUM_MFNUM (_U_(0x7) << DEVFNUM_MFNUM_Pos) /**< (DEVFNUM) Micro Frame Number Mask */
+#define DEVFNUM_FNUM_Pos 3 /**< (DEVFNUM) Frame Number Position */
+#define DEVFNUM_FNUM (_U_(0x7FF) << DEVFNUM_FNUM_Pos) /**< (DEVFNUM) Frame Number Mask */
+#define DEVFNUM_FNCERR_Pos 15 /**< (DEVFNUM) Frame Number CRC Error Position */
+#define DEVFNUM_FNCERR (_U_(0x1) << DEVFNUM_FNCERR_Pos) /**< (DEVFNUM) Frame Number CRC Error Mask */
+#define DEVFNUM_Msk _U_(0xBFFF) /**< (DEVFNUM) Register Mask */
+
+
+/* -------- DEVEPTCFG : (USBHS Offset: 0x100) (R/W 32) Device Endpoint Configuration Register -------- */
+
+#define DEVEPTCFG_OFFSET (0x100) /**< (DEVEPTCFG) Device Endpoint Configuration Register Offset */
+
+#define DEVEPTCFG_ALLOC_Pos 1 /**< (DEVEPTCFG) Endpoint Memory Allocate Position */
+#define DEVEPTCFG_ALLOC (_U_(0x1) << DEVEPTCFG_ALLOC_Pos) /**< (DEVEPTCFG) Endpoint Memory Allocate Mask */
+#define DEVEPTCFG_EPBK_Pos 2 /**< (DEVEPTCFG) Endpoint Banks Position */
+#define DEVEPTCFG_EPBK (_U_(0x3) << DEVEPTCFG_EPBK_Pos) /**< (DEVEPTCFG) Endpoint Banks Mask */
+#define DEVEPTCFG_EPBK_1_BANK_Val _U_(0x0) /**< (DEVEPTCFG) Single-bank endpoint */
+#define DEVEPTCFG_EPBK_2_BANK_Val _U_(0x1) /**< (DEVEPTCFG) Double-bank endpoint */
+#define DEVEPTCFG_EPBK_3_BANK_Val _U_(0x2) /**< (DEVEPTCFG) Triple-bank endpoint */
+#define DEVEPTCFG_EPBK_1_BANK (DEVEPTCFG_EPBK_1_BANK_Val << DEVEPTCFG_EPBK_Pos) /**< (DEVEPTCFG) Single-bank endpoint Position */
+#define DEVEPTCFG_EPBK_2_BANK (DEVEPTCFG_EPBK_2_BANK_Val << DEVEPTCFG_EPBK_Pos) /**< (DEVEPTCFG) Double-bank endpoint Position */
+#define DEVEPTCFG_EPBK_3_BANK (DEVEPTCFG_EPBK_3_BANK_Val << DEVEPTCFG_EPBK_Pos) /**< (DEVEPTCFG) Triple-bank endpoint Position */
+#define DEVEPTCFG_EPSIZE_Pos 4 /**< (DEVEPTCFG) Endpoint Size Position */
+#define DEVEPTCFG_EPSIZE (_U_(0x7) << DEVEPTCFG_EPSIZE_Pos) /**< (DEVEPTCFG) Endpoint Size Mask */
+#define DEVEPTCFG_EPSIZE_8_BYTE_Val _U_(0x0) /**< (DEVEPTCFG) 8 bytes */
+#define DEVEPTCFG_EPSIZE_16_BYTE_Val _U_(0x1) /**< (DEVEPTCFG) 16 bytes */
+#define DEVEPTCFG_EPSIZE_32_BYTE_Val _U_(0x2) /**< (DEVEPTCFG) 32 bytes */
+#define DEVEPTCFG_EPSIZE_64_BYTE_Val _U_(0x3) /**< (DEVEPTCFG) 64 bytes */
+#define DEVEPTCFG_EPSIZE_128_BYTE_Val _U_(0x4) /**< (DEVEPTCFG) 128 bytes */
+#define DEVEPTCFG_EPSIZE_256_BYTE_Val _U_(0x5) /**< (DEVEPTCFG) 256 bytes */
+#define DEVEPTCFG_EPSIZE_512_BYTE_Val _U_(0x6) /**< (DEVEPTCFG) 512 bytes */
+#define DEVEPTCFG_EPSIZE_1024_BYTE_Val _U_(0x7) /**< (DEVEPTCFG) 1024 bytes */
+#define DEVEPTCFG_EPSIZE_8_BYTE (DEVEPTCFG_EPSIZE_8_BYTE_Val << DEVEPTCFG_EPSIZE_Pos) /**< (DEVEPTCFG) 8 bytes Position */
+#define DEVEPTCFG_EPSIZE_16_BYTE (DEVEPTCFG_EPSIZE_16_BYTE_Val << DEVEPTCFG_EPSIZE_Pos) /**< (DEVEPTCFG) 16 bytes Position */
+#define DEVEPTCFG_EPSIZE_32_BYTE (DEVEPTCFG_EPSIZE_32_BYTE_Val << DEVEPTCFG_EPSIZE_Pos) /**< (DEVEPTCFG) 32 bytes Position */
+#define DEVEPTCFG_EPSIZE_64_BYTE (DEVEPTCFG_EPSIZE_64_BYTE_Val << DEVEPTCFG_EPSIZE_Pos) /**< (DEVEPTCFG) 64 bytes Position */
+#define DEVEPTCFG_EPSIZE_128_BYTE (DEVEPTCFG_EPSIZE_128_BYTE_Val << DEVEPTCFG_EPSIZE_Pos) /**< (DEVEPTCFG) 128 bytes Position */
+#define DEVEPTCFG_EPSIZE_256_BYTE (DEVEPTCFG_EPSIZE_256_BYTE_Val << DEVEPTCFG_EPSIZE_Pos) /**< (DEVEPTCFG) 256 bytes Position */
+#define DEVEPTCFG_EPSIZE_512_BYTE (DEVEPTCFG_EPSIZE_512_BYTE_Val << DEVEPTCFG_EPSIZE_Pos) /**< (DEVEPTCFG) 512 bytes Position */
+#define DEVEPTCFG_EPSIZE_1024_BYTE (DEVEPTCFG_EPSIZE_1024_BYTE_Val << DEVEPTCFG_EPSIZE_Pos) /**< (DEVEPTCFG) 1024 bytes Position */
+#define DEVEPTCFG_EPDIR_Pos 8 /**< (DEVEPTCFG) Endpoint Direction Position */
+#define DEVEPTCFG_EPDIR (_U_(0x1) << DEVEPTCFG_EPDIR_Pos) /**< (DEVEPTCFG) Endpoint Direction Mask */
+#define DEVEPTCFG_EPDIR_OUT_Val _U_(0x0) /**< (DEVEPTCFG) The endpoint direction is OUT. */
+#define DEVEPTCFG_EPDIR_IN_Val _U_(0x1) /**< (DEVEPTCFG) The endpoint direction is IN (nor for control endpoints). */
+#define DEVEPTCFG_EPDIR_OUT (DEVEPTCFG_EPDIR_OUT_Val << DEVEPTCFG_EPDIR_Pos) /**< (DEVEPTCFG) The endpoint direction is OUT. Position */
+#define DEVEPTCFG_EPDIR_IN (DEVEPTCFG_EPDIR_IN_Val << DEVEPTCFG_EPDIR_Pos) /**< (DEVEPTCFG) The endpoint direction is IN (nor for control endpoints). Position */
+#define DEVEPTCFG_AUTOSW_Pos 9 /**< (DEVEPTCFG) Automatic Switch Position */
+#define DEVEPTCFG_AUTOSW (_U_(0x1) << DEVEPTCFG_AUTOSW_Pos) /**< (DEVEPTCFG) Automatic Switch Mask */
+#define DEVEPTCFG_EPTYPE_Pos 11 /**< (DEVEPTCFG) Endpoint Type Position */
+#define DEVEPTCFG_EPTYPE (_U_(0x3) << DEVEPTCFG_EPTYPE_Pos) /**< (DEVEPTCFG) Endpoint Type Mask */
+#define DEVEPTCFG_EPTYPE_CTRL_Val _U_(0x0) /**< (DEVEPTCFG) Control */
+#define DEVEPTCFG_EPTYPE_ISO_Val _U_(0x1) /**< (DEVEPTCFG) Isochronous */
+#define DEVEPTCFG_EPTYPE_BLK_Val _U_(0x2) /**< (DEVEPTCFG) Bulk */
+#define DEVEPTCFG_EPTYPE_INTRPT_Val _U_(0x3) /**< (DEVEPTCFG) Interrupt */
+#define DEVEPTCFG_EPTYPE_CTRL (DEVEPTCFG_EPTYPE_CTRL_Val << DEVEPTCFG_EPTYPE_Pos) /**< (DEVEPTCFG) Control Position */
+#define DEVEPTCFG_EPTYPE_ISO (DEVEPTCFG_EPTYPE_ISO_Val << DEVEPTCFG_EPTYPE_Pos) /**< (DEVEPTCFG) Isochronous Position */
+#define DEVEPTCFG_EPTYPE_BLK (DEVEPTCFG_EPTYPE_BLK_Val << DEVEPTCFG_EPTYPE_Pos) /**< (DEVEPTCFG) Bulk Position */
+#define DEVEPTCFG_EPTYPE_INTRPT (DEVEPTCFG_EPTYPE_INTRPT_Val << DEVEPTCFG_EPTYPE_Pos) /**< (DEVEPTCFG) Interrupt Position */
+#define DEVEPTCFG_NBTRANS_Pos 13 /**< (DEVEPTCFG) Number of transactions per microframe for isochronous endpoint Position */
+#define DEVEPTCFG_NBTRANS (_U_(0x3) << DEVEPTCFG_NBTRANS_Pos) /**< (DEVEPTCFG) Number of transactions per microframe for isochronous endpoint Mask */
+#define DEVEPTCFG_NBTRANS_0_TRANS_Val _U_(0x0) /**< (DEVEPTCFG) Reserved to endpoint that does not have the high-bandwidth isochronous capability. */
+#define DEVEPTCFG_NBTRANS_1_TRANS_Val _U_(0x1) /**< (DEVEPTCFG) Default value: one transaction per microframe. */
+#define DEVEPTCFG_NBTRANS_2_TRANS_Val _U_(0x2) /**< (DEVEPTCFG) Two transactions per microframe. This endpoint should be configured as double-bank. */
+#define DEVEPTCFG_NBTRANS_3_TRANS_Val _U_(0x3) /**< (DEVEPTCFG) Three transactions per microframe. This endpoint should be configured as triple-bank. */
+#define DEVEPTCFG_NBTRANS_0_TRANS (DEVEPTCFG_NBTRANS_0_TRANS_Val << DEVEPTCFG_NBTRANS_Pos) /**< (DEVEPTCFG) Reserved to endpoint that does not have the high-bandwidth isochronous capability. Position */
+#define DEVEPTCFG_NBTRANS_1_TRANS (DEVEPTCFG_NBTRANS_1_TRANS_Val << DEVEPTCFG_NBTRANS_Pos) /**< (DEVEPTCFG) Default value: one transaction per microframe. Position */
+#define DEVEPTCFG_NBTRANS_2_TRANS (DEVEPTCFG_NBTRANS_2_TRANS_Val << DEVEPTCFG_NBTRANS_Pos) /**< (DEVEPTCFG) Two transactions per microframe. This endpoint should be configured as double-bank. Position */
+#define DEVEPTCFG_NBTRANS_3_TRANS (DEVEPTCFG_NBTRANS_3_TRANS_Val << DEVEPTCFG_NBTRANS_Pos) /**< (DEVEPTCFG) Three transactions per microframe. This endpoint should be configured as triple-bank. Position */
+#define DEVEPTCFG_Msk _U_(0x7B7E) /**< (DEVEPTCFG) Register Mask */
+
+
+/* -------- DEVEPTISR : (USBHS Offset: 0x130) (R/ 32) Device Endpoint Interrupt Status Register -------- */
+
+#define DEVEPTISR_OFFSET (0x130) /**< (DEVEPTISR) Device Endpoint Interrupt Status Register Offset */
+
+#define DEVEPTISR_TXINI_Pos 0 /**< (DEVEPTISR) Transmitted IN Data Interrupt Position */
+#define DEVEPTISR_TXINI (_U_(0x1) << DEVEPTISR_TXINI_Pos) /**< (DEVEPTISR) Transmitted IN Data Interrupt Mask */
+#define DEVEPTISR_RXOUTI_Pos 1 /**< (DEVEPTISR) Received OUT Data Interrupt Position */
+#define DEVEPTISR_RXOUTI (_U_(0x1) << DEVEPTISR_RXOUTI_Pos) /**< (DEVEPTISR) Received OUT Data Interrupt Mask */
+#define DEVEPTISR_OVERFI_Pos 5 /**< (DEVEPTISR) Overflow Interrupt Position */
+#define DEVEPTISR_OVERFI (_U_(0x1) << DEVEPTISR_OVERFI_Pos) /**< (DEVEPTISR) Overflow Interrupt Mask */
+#define DEVEPTISR_SHORTPACKET_Pos 7 /**< (DEVEPTISR) Short Packet Interrupt Position */
+#define DEVEPTISR_SHORTPACKET (_U_(0x1) << DEVEPTISR_SHORTPACKET_Pos) /**< (DEVEPTISR) Short Packet Interrupt Mask */
+#define DEVEPTISR_DTSEQ_Pos 8 /**< (DEVEPTISR) Data Toggle Sequence Position */
+#define DEVEPTISR_DTSEQ (_U_(0x3) << DEVEPTISR_DTSEQ_Pos) /**< (DEVEPTISR) Data Toggle Sequence Mask */
+#define DEVEPTISR_DTSEQ_DATA0_Val _U_(0x0) /**< (DEVEPTISR) Data0 toggle sequence */
+#define DEVEPTISR_DTSEQ_DATA1_Val _U_(0x1) /**< (DEVEPTISR) Data1 toggle sequence */
+#define DEVEPTISR_DTSEQ_DATA2_Val _U_(0x2) /**< (DEVEPTISR) Reserved for high-bandwidth isochronous endpoint */
+#define DEVEPTISR_DTSEQ_MDATA_Val _U_(0x3) /**< (DEVEPTISR) Reserved for high-bandwidth isochronous endpoint */
+#define DEVEPTISR_DTSEQ_DATA0 (DEVEPTISR_DTSEQ_DATA0_Val << DEVEPTISR_DTSEQ_Pos) /**< (DEVEPTISR) Data0 toggle sequence Position */
+#define DEVEPTISR_DTSEQ_DATA1 (DEVEPTISR_DTSEQ_DATA1_Val << DEVEPTISR_DTSEQ_Pos) /**< (DEVEPTISR) Data1 toggle sequence Position */
+#define DEVEPTISR_DTSEQ_DATA2 (DEVEPTISR_DTSEQ_DATA2_Val << DEVEPTISR_DTSEQ_Pos) /**< (DEVEPTISR) Reserved for high-bandwidth isochronous endpoint Position */
+#define DEVEPTISR_DTSEQ_MDATA (DEVEPTISR_DTSEQ_MDATA_Val << DEVEPTISR_DTSEQ_Pos) /**< (DEVEPTISR) Reserved for high-bandwidth isochronous endpoint Position */
+#define DEVEPTISR_NBUSYBK_Pos 12 /**< (DEVEPTISR) Number of Busy Banks Position */
+#define DEVEPTISR_NBUSYBK (_U_(0x3) << DEVEPTISR_NBUSYBK_Pos) /**< (DEVEPTISR) Number of Busy Banks Mask */
+#define DEVEPTISR_NBUSYBK_0_BUSY_Val _U_(0x0) /**< (DEVEPTISR) 0 busy bank (all banks free) */
+#define DEVEPTISR_NBUSYBK_1_BUSY_Val _U_(0x1) /**< (DEVEPTISR) 1 busy bank */
+#define DEVEPTISR_NBUSYBK_2_BUSY_Val _U_(0x2) /**< (DEVEPTISR) 2 busy banks */
+#define DEVEPTISR_NBUSYBK_3_BUSY_Val _U_(0x3) /**< (DEVEPTISR) 3 busy banks */
+#define DEVEPTISR_NBUSYBK_0_BUSY (DEVEPTISR_NBUSYBK_0_BUSY_Val << DEVEPTISR_NBUSYBK_Pos) /**< (DEVEPTISR) 0 busy bank (all banks free) Position */
+#define DEVEPTISR_NBUSYBK_1_BUSY (DEVEPTISR_NBUSYBK_1_BUSY_Val << DEVEPTISR_NBUSYBK_Pos) /**< (DEVEPTISR) 1 busy bank Position */
+#define DEVEPTISR_NBUSYBK_2_BUSY (DEVEPTISR_NBUSYBK_2_BUSY_Val << DEVEPTISR_NBUSYBK_Pos) /**< (DEVEPTISR) 2 busy banks Position */
+#define DEVEPTISR_NBUSYBK_3_BUSY (DEVEPTISR_NBUSYBK_3_BUSY_Val << DEVEPTISR_NBUSYBK_Pos) /**< (DEVEPTISR) 3 busy banks Position */
+#define DEVEPTISR_CURRBK_Pos 14 /**< (DEVEPTISR) Current Bank Position */
+#define DEVEPTISR_CURRBK (_U_(0x3) << DEVEPTISR_CURRBK_Pos) /**< (DEVEPTISR) Current Bank Mask */
+#define DEVEPTISR_CURRBK_BANK0_Val _U_(0x0) /**< (DEVEPTISR) Current bank is bank0 */
+#define DEVEPTISR_CURRBK_BANK1_Val _U_(0x1) /**< (DEVEPTISR) Current bank is bank1 */
+#define DEVEPTISR_CURRBK_BANK2_Val _U_(0x2) /**< (DEVEPTISR) Current bank is bank2 */
+#define DEVEPTISR_CURRBK_BANK0 (DEVEPTISR_CURRBK_BANK0_Val << DEVEPTISR_CURRBK_Pos) /**< (DEVEPTISR) Current bank is bank0 Position */
+#define DEVEPTISR_CURRBK_BANK1 (DEVEPTISR_CURRBK_BANK1_Val << DEVEPTISR_CURRBK_Pos) /**< (DEVEPTISR) Current bank is bank1 Position */
+#define DEVEPTISR_CURRBK_BANK2 (DEVEPTISR_CURRBK_BANK2_Val << DEVEPTISR_CURRBK_Pos) /**< (DEVEPTISR) Current bank is bank2 Position */
+#define DEVEPTISR_RWALL_Pos 16 /**< (DEVEPTISR) Read/Write Allowed Position */
+#define DEVEPTISR_RWALL (_U_(0x1) << DEVEPTISR_RWALL_Pos) /**< (DEVEPTISR) Read/Write Allowed Mask */
+#define DEVEPTISR_CFGOK_Pos 18 /**< (DEVEPTISR) Configuration OK Status Position */
+#define DEVEPTISR_CFGOK (_U_(0x1) << DEVEPTISR_CFGOK_Pos) /**< (DEVEPTISR) Configuration OK Status Mask */
+#define DEVEPTISR_BYCT_Pos 20 /**< (DEVEPTISR) Byte Count Position */
+#define DEVEPTISR_BYCT (_U_(0x7FF) << DEVEPTISR_BYCT_Pos) /**< (DEVEPTISR) Byte Count Mask */
+#define DEVEPTISR_Msk _U_(0x7FF5F3A3) /**< (DEVEPTISR) Register Mask */
+
+/* CTRL mode */
+#define DEVEPTISR_CTRL_RXSTPI_Pos 2 /**< (DEVEPTISR) Received SETUP Interrupt Position */
+#define DEVEPTISR_CTRL_RXSTPI (_U_(0x1) << DEVEPTISR_CTRL_RXSTPI_Pos) /**< (DEVEPTISR) Received SETUP Interrupt Mask */
+#define DEVEPTISR_CTRL_NAKOUTI_Pos 3 /**< (DEVEPTISR) NAKed OUT Interrupt Position */
+#define DEVEPTISR_CTRL_NAKOUTI (_U_(0x1) << DEVEPTISR_CTRL_NAKOUTI_Pos) /**< (DEVEPTISR) NAKed OUT Interrupt Mask */
+#define DEVEPTISR_CTRL_NAKINI_Pos 4 /**< (DEVEPTISR) NAKed IN Interrupt Position */
+#define DEVEPTISR_CTRL_NAKINI (_U_(0x1) << DEVEPTISR_CTRL_NAKINI_Pos) /**< (DEVEPTISR) NAKed IN Interrupt Mask */
+#define DEVEPTISR_CTRL_STALLEDI_Pos 6 /**< (DEVEPTISR) STALLed Interrupt Position */
+#define DEVEPTISR_CTRL_STALLEDI (_U_(0x1) << DEVEPTISR_CTRL_STALLEDI_Pos) /**< (DEVEPTISR) STALLed Interrupt Mask */
+#define DEVEPTISR_CTRL_CTRLDIR_Pos 17 /**< (DEVEPTISR) Control Direction Position */
+#define DEVEPTISR_CTRL_CTRLDIR (_U_(0x1) << DEVEPTISR_CTRL_CTRLDIR_Pos) /**< (DEVEPTISR) Control Direction Mask */
+#define DEVEPTISR_CTRL_Msk _U_(0x2005C) /**< (DEVEPTISR_CTRL) Register Mask */
+
+/* ISO mode */
+#define DEVEPTISR_ISO_UNDERFI_Pos 2 /**< (DEVEPTISR) Underflow Interrupt Position */
+#define DEVEPTISR_ISO_UNDERFI (_U_(0x1) << DEVEPTISR_ISO_UNDERFI_Pos) /**< (DEVEPTISR) Underflow Interrupt Mask */
+#define DEVEPTISR_ISO_HBISOINERRI_Pos 3 /**< (DEVEPTISR) High Bandwidth Isochronous IN Underflow Error Interrupt Position */
+#define DEVEPTISR_ISO_HBISOINERRI (_U_(0x1) << DEVEPTISR_ISO_HBISOINERRI_Pos) /**< (DEVEPTISR) High Bandwidth Isochronous IN Underflow Error Interrupt Mask */
+#define DEVEPTISR_ISO_HBISOFLUSHI_Pos 4 /**< (DEVEPTISR) High Bandwidth Isochronous IN Flush Interrupt Position */
+#define DEVEPTISR_ISO_HBISOFLUSHI (_U_(0x1) << DEVEPTISR_ISO_HBISOFLUSHI_Pos) /**< (DEVEPTISR) High Bandwidth Isochronous IN Flush Interrupt Mask */
+#define DEVEPTISR_ISO_CRCERRI_Pos 6 /**< (DEVEPTISR) CRC Error Interrupt Position */
+#define DEVEPTISR_ISO_CRCERRI (_U_(0x1) << DEVEPTISR_ISO_CRCERRI_Pos) /**< (DEVEPTISR) CRC Error Interrupt Mask */
+#define DEVEPTISR_ISO_ERRORTRANS_Pos 10 /**< (DEVEPTISR) High-bandwidth Isochronous OUT Endpoint Transaction Error Interrupt Position */
+#define DEVEPTISR_ISO_ERRORTRANS (_U_(0x1) << DEVEPTISR_ISO_ERRORTRANS_Pos) /**< (DEVEPTISR) High-bandwidth Isochronous OUT Endpoint Transaction Error Interrupt Mask */
+#define DEVEPTISR_ISO_Msk _U_(0x45C) /**< (DEVEPTISR_ISO) Register Mask */
+
+/* BLK mode */
+#define DEVEPTISR_BLK_RXSTPI_Pos 2 /**< (DEVEPTISR) Received SETUP Interrupt Position */
+#define DEVEPTISR_BLK_RXSTPI (_U_(0x1) << DEVEPTISR_BLK_RXSTPI_Pos) /**< (DEVEPTISR) Received SETUP Interrupt Mask */
+#define DEVEPTISR_BLK_NAKOUTI_Pos 3 /**< (DEVEPTISR) NAKed OUT Interrupt Position */
+#define DEVEPTISR_BLK_NAKOUTI (_U_(0x1) << DEVEPTISR_BLK_NAKOUTI_Pos) /**< (DEVEPTISR) NAKed OUT Interrupt Mask */
+#define DEVEPTISR_BLK_NAKINI_Pos 4 /**< (DEVEPTISR) NAKed IN Interrupt Position */
+#define DEVEPTISR_BLK_NAKINI (_U_(0x1) << DEVEPTISR_BLK_NAKINI_Pos) /**< (DEVEPTISR) NAKed IN Interrupt Mask */
+#define DEVEPTISR_BLK_STALLEDI_Pos 6 /**< (DEVEPTISR) STALLed Interrupt Position */
+#define DEVEPTISR_BLK_STALLEDI (_U_(0x1) << DEVEPTISR_BLK_STALLEDI_Pos) /**< (DEVEPTISR) STALLed Interrupt Mask */
+#define DEVEPTISR_BLK_CTRLDIR_Pos 17 /**< (DEVEPTISR) Control Direction Position */
+#define DEVEPTISR_BLK_CTRLDIR (_U_(0x1) << DEVEPTISR_BLK_CTRLDIR_Pos) /**< (DEVEPTISR) Control Direction Mask */
+#define DEVEPTISR_BLK_Msk _U_(0x2005C) /**< (DEVEPTISR_BLK) Register Mask */
+
+/* INTRPT mode */
+#define DEVEPTISR_INTRPT_RXSTPI_Pos 2 /**< (DEVEPTISR) Received SETUP Interrupt Position */
+#define DEVEPTISR_INTRPT_RXSTPI (_U_(0x1) << DEVEPTISR_INTRPT_RXSTPI_Pos) /**< (DEVEPTISR) Received SETUP Interrupt Mask */
+#define DEVEPTISR_INTRPT_NAKOUTI_Pos 3 /**< (DEVEPTISR) NAKed OUT Interrupt Position */
+#define DEVEPTISR_INTRPT_NAKOUTI (_U_(0x1) << DEVEPTISR_INTRPT_NAKOUTI_Pos) /**< (DEVEPTISR) NAKed OUT Interrupt Mask */
+#define DEVEPTISR_INTRPT_NAKINI_Pos 4 /**< (DEVEPTISR) NAKed IN Interrupt Position */
+#define DEVEPTISR_INTRPT_NAKINI (_U_(0x1) << DEVEPTISR_INTRPT_NAKINI_Pos) /**< (DEVEPTISR) NAKed IN Interrupt Mask */
+#define DEVEPTISR_INTRPT_STALLEDI_Pos 6 /**< (DEVEPTISR) STALLed Interrupt Position */
+#define DEVEPTISR_INTRPT_STALLEDI (_U_(0x1) << DEVEPTISR_INTRPT_STALLEDI_Pos) /**< (DEVEPTISR) STALLed Interrupt Mask */
+#define DEVEPTISR_INTRPT_CTRLDIR_Pos 17 /**< (DEVEPTISR) Control Direction Position */
+#define DEVEPTISR_INTRPT_CTRLDIR (_U_(0x1) << DEVEPTISR_INTRPT_CTRLDIR_Pos) /**< (DEVEPTISR) Control Direction Mask */
+#define DEVEPTISR_INTRPT_Msk _U_(0x2005C) /**< (DEVEPTISR_INTRPT) Register Mask */
+
+
+/* -------- DEVEPTICR : (USBHS Offset: 0x160) (/W 32) Device Endpoint Interrupt Clear Register -------- */
+
+#define DEVEPTICR_OFFSET (0x160) /**< (DEVEPTICR) Device Endpoint Interrupt Clear Register Offset */
+
+#define DEVEPTICR_TXINIC_Pos 0 /**< (DEVEPTICR) Transmitted IN Data Interrupt Clear Position */
+#define DEVEPTICR_TXINIC (_U_(0x1) << DEVEPTICR_TXINIC_Pos) /**< (DEVEPTICR) Transmitted IN Data Interrupt Clear Mask */
+#define DEVEPTICR_RXOUTIC_Pos 1 /**< (DEVEPTICR) Received OUT Data Interrupt Clear Position */
+#define DEVEPTICR_RXOUTIC (_U_(0x1) << DEVEPTICR_RXOUTIC_Pos) /**< (DEVEPTICR) Received OUT Data Interrupt Clear Mask */
+#define DEVEPTICR_OVERFIC_Pos 5 /**< (DEVEPTICR) Overflow Interrupt Clear Position */
+#define DEVEPTICR_OVERFIC (_U_(0x1) << DEVEPTICR_OVERFIC_Pos) /**< (DEVEPTICR) Overflow Interrupt Clear Mask */
+#define DEVEPTICR_SHORTPACKETC_Pos 7 /**< (DEVEPTICR) Short Packet Interrupt Clear Position */
+#define DEVEPTICR_SHORTPACKETC (_U_(0x1) << DEVEPTICR_SHORTPACKETC_Pos) /**< (DEVEPTICR) Short Packet Interrupt Clear Mask */
+#define DEVEPTICR_Msk _U_(0xA3) /**< (DEVEPTICR) Register Mask */
+
+/* CTRL mode */
+#define DEVEPTICR_CTRL_RXSTPIC_Pos 2 /**< (DEVEPTICR) Received SETUP Interrupt Clear Position */
+#define DEVEPTICR_CTRL_RXSTPIC (_U_(0x1) << DEVEPTICR_CTRL_RXSTPIC_Pos) /**< (DEVEPTICR) Received SETUP Interrupt Clear Mask */
+#define DEVEPTICR_CTRL_NAKOUTIC_Pos 3 /**< (DEVEPTICR) NAKed OUT Interrupt Clear Position */
+#define DEVEPTICR_CTRL_NAKOUTIC (_U_(0x1) << DEVEPTICR_CTRL_NAKOUTIC_Pos) /**< (DEVEPTICR) NAKed OUT Interrupt Clear Mask */
+#define DEVEPTICR_CTRL_NAKINIC_Pos 4 /**< (DEVEPTICR) NAKed IN Interrupt Clear Position */
+#define DEVEPTICR_CTRL_NAKINIC (_U_(0x1) << DEVEPTICR_CTRL_NAKINIC_Pos) /**< (DEVEPTICR) NAKed IN Interrupt Clear Mask */
+#define DEVEPTICR_CTRL_STALLEDIC_Pos 6 /**< (DEVEPTICR) STALLed Interrupt Clear Position */
+#define DEVEPTICR_CTRL_STALLEDIC (_U_(0x1) << DEVEPTICR_CTRL_STALLEDIC_Pos) /**< (DEVEPTICR) STALLed Interrupt Clear Mask */
+#define DEVEPTICR_CTRL_Msk _U_(0x5C) /**< (DEVEPTICR_CTRL) Register Mask */
+
+/* ISO mode */
+#define DEVEPTICR_ISO_UNDERFIC_Pos 2 /**< (DEVEPTICR) Underflow Interrupt Clear Position */
+#define DEVEPTICR_ISO_UNDERFIC (_U_(0x1) << DEVEPTICR_ISO_UNDERFIC_Pos) /**< (DEVEPTICR) Underflow Interrupt Clear Mask */
+#define DEVEPTICR_ISO_HBISOINERRIC_Pos 3 /**< (DEVEPTICR) High Bandwidth Isochronous IN Underflow Error Interrupt Clear Position */
+#define DEVEPTICR_ISO_HBISOINERRIC (_U_(0x1) << DEVEPTICR_ISO_HBISOINERRIC_Pos) /**< (DEVEPTICR) High Bandwidth Isochronous IN Underflow Error Interrupt Clear Mask */
+#define DEVEPTICR_ISO_HBISOFLUSHIC_Pos 4 /**< (DEVEPTICR) High Bandwidth Isochronous IN Flush Interrupt Clear Position */
+#define DEVEPTICR_ISO_HBISOFLUSHIC (_U_(0x1) << DEVEPTICR_ISO_HBISOFLUSHIC_Pos) /**< (DEVEPTICR) High Bandwidth Isochronous IN Flush Interrupt Clear Mask */
+#define DEVEPTICR_ISO_CRCERRIC_Pos 6 /**< (DEVEPTICR) CRC Error Interrupt Clear Position */
+#define DEVEPTICR_ISO_CRCERRIC (_U_(0x1) << DEVEPTICR_ISO_CRCERRIC_Pos) /**< (DEVEPTICR) CRC Error Interrupt Clear Mask */
+#define DEVEPTICR_ISO_Msk _U_(0x5C) /**< (DEVEPTICR_ISO) Register Mask */
+
+/* BLK mode */
+#define DEVEPTICR_BLK_RXSTPIC_Pos 2 /**< (DEVEPTICR) Received SETUP Interrupt Clear Position */
+#define DEVEPTICR_BLK_RXSTPIC (_U_(0x1) << DEVEPTICR_BLK_RXSTPIC_Pos) /**< (DEVEPTICR) Received SETUP Interrupt Clear Mask */
+#define DEVEPTICR_BLK_NAKOUTIC_Pos 3 /**< (DEVEPTICR) NAKed OUT Interrupt Clear Position */
+#define DEVEPTICR_BLK_NAKOUTIC (_U_(0x1) << DEVEPTICR_BLK_NAKOUTIC_Pos) /**< (DEVEPTICR) NAKed OUT Interrupt Clear Mask */
+#define DEVEPTICR_BLK_NAKINIC_Pos 4 /**< (DEVEPTICR) NAKed IN Interrupt Clear Position */
+#define DEVEPTICR_BLK_NAKINIC (_U_(0x1) << DEVEPTICR_BLK_NAKINIC_Pos) /**< (DEVEPTICR) NAKed IN Interrupt Clear Mask */
+#define DEVEPTICR_BLK_STALLEDIC_Pos 6 /**< (DEVEPTICR) STALLed Interrupt Clear Position */
+#define DEVEPTICR_BLK_STALLEDIC (_U_(0x1) << DEVEPTICR_BLK_STALLEDIC_Pos) /**< (DEVEPTICR) STALLed Interrupt Clear Mask */
+#define DEVEPTICR_BLK_Msk _U_(0x5C) /**< (DEVEPTICR_BLK) Register Mask */
+
+/* INTRPT mode */
+#define DEVEPTICR_INTRPT_RXSTPIC_Pos 2 /**< (DEVEPTICR) Received SETUP Interrupt Clear Position */
+#define DEVEPTICR_INTRPT_RXSTPIC (_U_(0x1) << DEVEPTICR_INTRPT_RXSTPIC_Pos) /**< (DEVEPTICR) Received SETUP Interrupt Clear Mask */
+#define DEVEPTICR_INTRPT_NAKOUTIC_Pos 3 /**< (DEVEPTICR) NAKed OUT Interrupt Clear Position */
+#define DEVEPTICR_INTRPT_NAKOUTIC (_U_(0x1) << DEVEPTICR_INTRPT_NAKOUTIC_Pos) /**< (DEVEPTICR) NAKed OUT Interrupt Clear Mask */
+#define DEVEPTICR_INTRPT_NAKINIC_Pos 4 /**< (DEVEPTICR) NAKed IN Interrupt Clear Position */
+#define DEVEPTICR_INTRPT_NAKINIC (_U_(0x1) << DEVEPTICR_INTRPT_NAKINIC_Pos) /**< (DEVEPTICR) NAKed IN Interrupt Clear Mask */
+#define DEVEPTICR_INTRPT_STALLEDIC_Pos 6 /**< (DEVEPTICR) STALLed Interrupt Clear Position */
+#define DEVEPTICR_INTRPT_STALLEDIC (_U_(0x1) << DEVEPTICR_INTRPT_STALLEDIC_Pos) /**< (DEVEPTICR) STALLed Interrupt Clear Mask */
+#define DEVEPTICR_INTRPT_Msk _U_(0x5C) /**< (DEVEPTICR_INTRPT) Register Mask */
+
+
+/* -------- DEVEPTIFR : (USBHS Offset: 0x190) (/W 32) Device Endpoint Interrupt Set Register -------- */
+
+#define DEVEPTIFR_OFFSET (0x190) /**< (DEVEPTIFR) Device Endpoint Interrupt Set Register Offset */
+
+#define DEVEPTIFR_TXINIS_Pos 0 /**< (DEVEPTIFR) Transmitted IN Data Interrupt Set Position */
+#define DEVEPTIFR_TXINIS (_U_(0x1) << DEVEPTIFR_TXINIS_Pos) /**< (DEVEPTIFR) Transmitted IN Data Interrupt Set Mask */
+#define DEVEPTIFR_RXOUTIS_Pos 1 /**< (DEVEPTIFR) Received OUT Data Interrupt Set Position */
+#define DEVEPTIFR_RXOUTIS (_U_(0x1) << DEVEPTIFR_RXOUTIS_Pos) /**< (DEVEPTIFR) Received OUT Data Interrupt Set Mask */
+#define DEVEPTIFR_OVERFIS_Pos 5 /**< (DEVEPTIFR) Overflow Interrupt Set Position */
+#define DEVEPTIFR_OVERFIS (_U_(0x1) << DEVEPTIFR_OVERFIS_Pos) /**< (DEVEPTIFR) Overflow Interrupt Set Mask */
+#define DEVEPTIFR_SHORTPACKETS_Pos 7 /**< (DEVEPTIFR) Short Packet Interrupt Set Position */
+#define DEVEPTIFR_SHORTPACKETS (_U_(0x1) << DEVEPTIFR_SHORTPACKETS_Pos) /**< (DEVEPTIFR) Short Packet Interrupt Set Mask */
+#define DEVEPTIFR_NBUSYBKS_Pos 12 /**< (DEVEPTIFR) Number of Busy Banks Interrupt Set Position */
+#define DEVEPTIFR_NBUSYBKS (_U_(0x1) << DEVEPTIFR_NBUSYBKS_Pos) /**< (DEVEPTIFR) Number of Busy Banks Interrupt Set Mask */
+#define DEVEPTIFR_Msk _U_(0x10A3) /**< (DEVEPTIFR) Register Mask */
+
+/* CTRL mode */
+#define DEVEPTIFR_CTRL_RXSTPIS_Pos 2 /**< (DEVEPTIFR) Received SETUP Interrupt Set Position */
+#define DEVEPTIFR_CTRL_RXSTPIS (_U_(0x1) << DEVEPTIFR_CTRL_RXSTPIS_Pos) /**< (DEVEPTIFR) Received SETUP Interrupt Set Mask */
+#define DEVEPTIFR_CTRL_NAKOUTIS_Pos 3 /**< (DEVEPTIFR) NAKed OUT Interrupt Set Position */
+#define DEVEPTIFR_CTRL_NAKOUTIS (_U_(0x1) << DEVEPTIFR_CTRL_NAKOUTIS_Pos) /**< (DEVEPTIFR) NAKed OUT Interrupt Set Mask */
+#define DEVEPTIFR_CTRL_NAKINIS_Pos 4 /**< (DEVEPTIFR) NAKed IN Interrupt Set Position */
+#define DEVEPTIFR_CTRL_NAKINIS (_U_(0x1) << DEVEPTIFR_CTRL_NAKINIS_Pos) /**< (DEVEPTIFR) NAKed IN Interrupt Set Mask */
+#define DEVEPTIFR_CTRL_STALLEDIS_Pos 6 /**< (DEVEPTIFR) STALLed Interrupt Set Position */
+#define DEVEPTIFR_CTRL_STALLEDIS (_U_(0x1) << DEVEPTIFR_CTRL_STALLEDIS_Pos) /**< (DEVEPTIFR) STALLed Interrupt Set Mask */
+#define DEVEPTIFR_CTRL_Msk _U_(0x5C) /**< (DEVEPTIFR_CTRL) Register Mask */
+
+/* ISO mode */
+#define DEVEPTIFR_ISO_UNDERFIS_Pos 2 /**< (DEVEPTIFR) Underflow Interrupt Set Position */
+#define DEVEPTIFR_ISO_UNDERFIS (_U_(0x1) << DEVEPTIFR_ISO_UNDERFIS_Pos) /**< (DEVEPTIFR) Underflow Interrupt Set Mask */
+#define DEVEPTIFR_ISO_HBISOINERRIS_Pos 3 /**< (DEVEPTIFR) High Bandwidth Isochronous IN Underflow Error Interrupt Set Position */
+#define DEVEPTIFR_ISO_HBISOINERRIS (_U_(0x1) << DEVEPTIFR_ISO_HBISOINERRIS_Pos) /**< (DEVEPTIFR) High Bandwidth Isochronous IN Underflow Error Interrupt Set Mask */
+#define DEVEPTIFR_ISO_HBISOFLUSHIS_Pos 4 /**< (DEVEPTIFR) High Bandwidth Isochronous IN Flush Interrupt Set Position */
+#define DEVEPTIFR_ISO_HBISOFLUSHIS (_U_(0x1) << DEVEPTIFR_ISO_HBISOFLUSHIS_Pos) /**< (DEVEPTIFR) High Bandwidth Isochronous IN Flush Interrupt Set Mask */
+#define DEVEPTIFR_ISO_CRCERRIS_Pos 6 /**< (DEVEPTIFR) CRC Error Interrupt Set Position */
+#define DEVEPTIFR_ISO_CRCERRIS (_U_(0x1) << DEVEPTIFR_ISO_CRCERRIS_Pos) /**< (DEVEPTIFR) CRC Error Interrupt Set Mask */
+#define DEVEPTIFR_ISO_Msk _U_(0x5C) /**< (DEVEPTIFR_ISO) Register Mask */
+
+/* BLK mode */
+#define DEVEPTIFR_BLK_RXSTPIS_Pos 2 /**< (DEVEPTIFR) Received SETUP Interrupt Set Position */
+#define DEVEPTIFR_BLK_RXSTPIS (_U_(0x1) << DEVEPTIFR_BLK_RXSTPIS_Pos) /**< (DEVEPTIFR) Received SETUP Interrupt Set Mask */
+#define DEVEPTIFR_BLK_NAKOUTIS_Pos 3 /**< (DEVEPTIFR) NAKed OUT Interrupt Set Position */
+#define DEVEPTIFR_BLK_NAKOUTIS (_U_(0x1) << DEVEPTIFR_BLK_NAKOUTIS_Pos) /**< (DEVEPTIFR) NAKed OUT Interrupt Set Mask */
+#define DEVEPTIFR_BLK_NAKINIS_Pos 4 /**< (DEVEPTIFR) NAKed IN Interrupt Set Position */
+#define DEVEPTIFR_BLK_NAKINIS (_U_(0x1) << DEVEPTIFR_BLK_NAKINIS_Pos) /**< (DEVEPTIFR) NAKed IN Interrupt Set Mask */
+#define DEVEPTIFR_BLK_STALLEDIS_Pos 6 /**< (DEVEPTIFR) STALLed Interrupt Set Position */
+#define DEVEPTIFR_BLK_STALLEDIS (_U_(0x1) << DEVEPTIFR_BLK_STALLEDIS_Pos) /**< (DEVEPTIFR) STALLed Interrupt Set Mask */
+#define DEVEPTIFR_BLK_Msk _U_(0x5C) /**< (DEVEPTIFR_BLK) Register Mask */
+
+/* INTRPT mode */
+#define DEVEPTIFR_INTRPT_RXSTPIS_Pos 2 /**< (DEVEPTIFR) Received SETUP Interrupt Set Position */
+#define DEVEPTIFR_INTRPT_RXSTPIS (_U_(0x1) << DEVEPTIFR_INTRPT_RXSTPIS_Pos) /**< (DEVEPTIFR) Received SETUP Interrupt Set Mask */
+#define DEVEPTIFR_INTRPT_NAKOUTIS_Pos 3 /**< (DEVEPTIFR) NAKed OUT Interrupt Set Position */
+#define DEVEPTIFR_INTRPT_NAKOUTIS (_U_(0x1) << DEVEPTIFR_INTRPT_NAKOUTIS_Pos) /**< (DEVEPTIFR) NAKed OUT Interrupt Set Mask */
+#define DEVEPTIFR_INTRPT_NAKINIS_Pos 4 /**< (DEVEPTIFR) NAKed IN Interrupt Set Position */
+#define DEVEPTIFR_INTRPT_NAKINIS (_U_(0x1) << DEVEPTIFR_INTRPT_NAKINIS_Pos) /**< (DEVEPTIFR) NAKed IN Interrupt Set Mask */
+#define DEVEPTIFR_INTRPT_STALLEDIS_Pos 6 /**< (DEVEPTIFR) STALLed Interrupt Set Position */
+#define DEVEPTIFR_INTRPT_STALLEDIS (_U_(0x1) << DEVEPTIFR_INTRPT_STALLEDIS_Pos) /**< (DEVEPTIFR) STALLed Interrupt Set Mask */
+#define DEVEPTIFR_INTRPT_Msk _U_(0x5C) /**< (DEVEPTIFR_INTRPT) Register Mask */
+
+
+/* -------- DEVEPTIMR : (USBHS Offset: 0x1c0) (R/ 32) Device Endpoint Interrupt Mask Register -------- */
+
+#define DEVEPTIMR_OFFSET (0x1C0) /**< (DEVEPTIMR) Device Endpoint Interrupt Mask Register Offset */
+
+#define DEVEPTIMR_TXINE_Pos 0 /**< (DEVEPTIMR) Transmitted IN Data Interrupt Position */
+#define DEVEPTIMR_TXINE (_U_(0x1) << DEVEPTIMR_TXINE_Pos) /**< (DEVEPTIMR) Transmitted IN Data Interrupt Mask */
+#define DEVEPTIMR_RXOUTE_Pos 1 /**< (DEVEPTIMR) Received OUT Data Interrupt Position */
+#define DEVEPTIMR_RXOUTE (_U_(0x1) << DEVEPTIMR_RXOUTE_Pos) /**< (DEVEPTIMR) Received OUT Data Interrupt Mask */
+#define DEVEPTIMR_OVERFE_Pos 5 /**< (DEVEPTIMR) Overflow Interrupt Position */
+#define DEVEPTIMR_OVERFE (_U_(0x1) << DEVEPTIMR_OVERFE_Pos) /**< (DEVEPTIMR) Overflow Interrupt Mask */
+#define DEVEPTIMR_SHORTPACKETE_Pos 7 /**< (DEVEPTIMR) Short Packet Interrupt Position */
+#define DEVEPTIMR_SHORTPACKETE (_U_(0x1) << DEVEPTIMR_SHORTPACKETE_Pos) /**< (DEVEPTIMR) Short Packet Interrupt Mask */
+#define DEVEPTIMR_NBUSYBKE_Pos 12 /**< (DEVEPTIMR) Number of Busy Banks Interrupt Position */
+#define DEVEPTIMR_NBUSYBKE (_U_(0x1) << DEVEPTIMR_NBUSYBKE_Pos) /**< (DEVEPTIMR) Number of Busy Banks Interrupt Mask */
+#define DEVEPTIMR_KILLBK_Pos 13 /**< (DEVEPTIMR) Kill IN Bank Position */
+#define DEVEPTIMR_KILLBK (_U_(0x1) << DEVEPTIMR_KILLBK_Pos) /**< (DEVEPTIMR) Kill IN Bank Mask */
+#define DEVEPTIMR_FIFOCON_Pos 14 /**< (DEVEPTIMR) FIFO Control Position */
+#define DEVEPTIMR_FIFOCON (_U_(0x1) << DEVEPTIMR_FIFOCON_Pos) /**< (DEVEPTIMR) FIFO Control Mask */
+#define DEVEPTIMR_EPDISHDMA_Pos 16 /**< (DEVEPTIMR) Endpoint Interrupts Disable HDMA Request Position */
+#define DEVEPTIMR_EPDISHDMA (_U_(0x1) << DEVEPTIMR_EPDISHDMA_Pos) /**< (DEVEPTIMR) Endpoint Interrupts Disable HDMA Request Mask */
+#define DEVEPTIMR_RSTDT_Pos 18 /**< (DEVEPTIMR) Reset Data Toggle Position */
+#define DEVEPTIMR_RSTDT (_U_(0x1) << DEVEPTIMR_RSTDT_Pos) /**< (DEVEPTIMR) Reset Data Toggle Mask */
+#define DEVEPTIMR_Msk _U_(0x570A3) /**< (DEVEPTIMR) Register Mask */
+
+/* CTRL mode */
+#define DEVEPTIMR_CTRL_RXSTPE_Pos 2 /**< (DEVEPTIMR) Received SETUP Interrupt Position */
+#define DEVEPTIMR_CTRL_RXSTPE (_U_(0x1) << DEVEPTIMR_CTRL_RXSTPE_Pos) /**< (DEVEPTIMR) Received SETUP Interrupt Mask */
+#define DEVEPTIMR_CTRL_NAKOUTE_Pos 3 /**< (DEVEPTIMR) NAKed OUT Interrupt Position */
+#define DEVEPTIMR_CTRL_NAKOUTE (_U_(0x1) << DEVEPTIMR_CTRL_NAKOUTE_Pos) /**< (DEVEPTIMR) NAKed OUT Interrupt Mask */
+#define DEVEPTIMR_CTRL_NAKINE_Pos 4 /**< (DEVEPTIMR) NAKed IN Interrupt Position */
+#define DEVEPTIMR_CTRL_NAKINE (_U_(0x1) << DEVEPTIMR_CTRL_NAKINE_Pos) /**< (DEVEPTIMR) NAKed IN Interrupt Mask */
+#define DEVEPTIMR_CTRL_STALLEDE_Pos 6 /**< (DEVEPTIMR) STALLed Interrupt Position */
+#define DEVEPTIMR_CTRL_STALLEDE (_U_(0x1) << DEVEPTIMR_CTRL_STALLEDE_Pos) /**< (DEVEPTIMR) STALLed Interrupt Mask */
+#define DEVEPTIMR_CTRL_NYETDIS_Pos 17 /**< (DEVEPTIMR) NYET Token Disable Position */
+#define DEVEPTIMR_CTRL_NYETDIS (_U_(0x1) << DEVEPTIMR_CTRL_NYETDIS_Pos) /**< (DEVEPTIMR) NYET Token Disable Mask */
+#define DEVEPTIMR_CTRL_STALLRQ_Pos 19 /**< (DEVEPTIMR) STALL Request Position */
+#define DEVEPTIMR_CTRL_STALLRQ (_U_(0x1) << DEVEPTIMR_CTRL_STALLRQ_Pos) /**< (DEVEPTIMR) STALL Request Mask */
+#define DEVEPTIMR_CTRL_Msk _U_(0xA005C) /**< (DEVEPTIMR_CTRL) Register Mask */
+
+/* ISO mode */
+#define DEVEPTIMR_ISO_UNDERFE_Pos 2 /**< (DEVEPTIMR) Underflow Interrupt Position */
+#define DEVEPTIMR_ISO_UNDERFE (_U_(0x1) << DEVEPTIMR_ISO_UNDERFE_Pos) /**< (DEVEPTIMR) Underflow Interrupt Mask */
+#define DEVEPTIMR_ISO_HBISOINERRE_Pos 3 /**< (DEVEPTIMR) High Bandwidth Isochronous IN Underflow Error Interrupt Position */
+#define DEVEPTIMR_ISO_HBISOINERRE (_U_(0x1) << DEVEPTIMR_ISO_HBISOINERRE_Pos) /**< (DEVEPTIMR) High Bandwidth Isochronous IN Underflow Error Interrupt Mask */
+#define DEVEPTIMR_ISO_HBISOFLUSHE_Pos 4 /**< (DEVEPTIMR) High Bandwidth Isochronous IN Flush Interrupt Position */
+#define DEVEPTIMR_ISO_HBISOFLUSHE (_U_(0x1) << DEVEPTIMR_ISO_HBISOFLUSHE_Pos) /**< (DEVEPTIMR) High Bandwidth Isochronous IN Flush Interrupt Mask */
+#define DEVEPTIMR_ISO_CRCERRE_Pos 6 /**< (DEVEPTIMR) CRC Error Interrupt Position */
+#define DEVEPTIMR_ISO_CRCERRE (_U_(0x1) << DEVEPTIMR_ISO_CRCERRE_Pos) /**< (DEVEPTIMR) CRC Error Interrupt Mask */
+#define DEVEPTIMR_ISO_MDATAE_Pos 8 /**< (DEVEPTIMR) MData Interrupt Position */
+#define DEVEPTIMR_ISO_MDATAE (_U_(0x1) << DEVEPTIMR_ISO_MDATAE_Pos) /**< (DEVEPTIMR) MData Interrupt Mask */
+#define DEVEPTIMR_ISO_DATAXE_Pos 9 /**< (DEVEPTIMR) DataX Interrupt Position */
+#define DEVEPTIMR_ISO_DATAXE (_U_(0x1) << DEVEPTIMR_ISO_DATAXE_Pos) /**< (DEVEPTIMR) DataX Interrupt Mask */
+#define DEVEPTIMR_ISO_ERRORTRANSE_Pos 10 /**< (DEVEPTIMR) Transaction Error Interrupt Position */
+#define DEVEPTIMR_ISO_ERRORTRANSE (_U_(0x1) << DEVEPTIMR_ISO_ERRORTRANSE_Pos) /**< (DEVEPTIMR) Transaction Error Interrupt Mask */
+#define DEVEPTIMR_ISO_Msk _U_(0x75C) /**< (DEVEPTIMR_ISO) Register Mask */
+
+/* BLK mode */
+#define DEVEPTIMR_BLK_RXSTPE_Pos 2 /**< (DEVEPTIMR) Received SETUP Interrupt Position */
+#define DEVEPTIMR_BLK_RXSTPE (_U_(0x1) << DEVEPTIMR_BLK_RXSTPE_Pos) /**< (DEVEPTIMR) Received SETUP Interrupt Mask */
+#define DEVEPTIMR_BLK_NAKOUTE_Pos 3 /**< (DEVEPTIMR) NAKed OUT Interrupt Position */
+#define DEVEPTIMR_BLK_NAKOUTE (_U_(0x1) << DEVEPTIMR_BLK_NAKOUTE_Pos) /**< (DEVEPTIMR) NAKed OUT Interrupt Mask */
+#define DEVEPTIMR_BLK_NAKINE_Pos 4 /**< (DEVEPTIMR) NAKed IN Interrupt Position */
+#define DEVEPTIMR_BLK_NAKINE (_U_(0x1) << DEVEPTIMR_BLK_NAKINE_Pos) /**< (DEVEPTIMR) NAKed IN Interrupt Mask */
+#define DEVEPTIMR_BLK_STALLEDE_Pos 6 /**< (DEVEPTIMR) STALLed Interrupt Position */
+#define DEVEPTIMR_BLK_STALLEDE (_U_(0x1) << DEVEPTIMR_BLK_STALLEDE_Pos) /**< (DEVEPTIMR) STALLed Interrupt Mask */
+#define DEVEPTIMR_BLK_NYETDIS_Pos 17 /**< (DEVEPTIMR) NYET Token Disable Position */
+#define DEVEPTIMR_BLK_NYETDIS (_U_(0x1) << DEVEPTIMR_BLK_NYETDIS_Pos) /**< (DEVEPTIMR) NYET Token Disable Mask */
+#define DEVEPTIMR_BLK_STALLRQ_Pos 19 /**< (DEVEPTIMR) STALL Request Position */
+#define DEVEPTIMR_BLK_STALLRQ (_U_(0x1) << DEVEPTIMR_BLK_STALLRQ_Pos) /**< (DEVEPTIMR) STALL Request Mask */
+#define DEVEPTIMR_BLK_Msk _U_(0xA005C) /**< (DEVEPTIMR_BLK) Register Mask */
+
+/* INTRPT mode */
+#define DEVEPTIMR_INTRPT_RXSTPE_Pos 2 /**< (DEVEPTIMR) Received SETUP Interrupt Position */
+#define DEVEPTIMR_INTRPT_RXSTPE (_U_(0x1) << DEVEPTIMR_INTRPT_RXSTPE_Pos) /**< (DEVEPTIMR) Received SETUP Interrupt Mask */
+#define DEVEPTIMR_INTRPT_NAKOUTE_Pos 3 /**< (DEVEPTIMR) NAKed OUT Interrupt Position */
+#define DEVEPTIMR_INTRPT_NAKOUTE (_U_(0x1) << DEVEPTIMR_INTRPT_NAKOUTE_Pos) /**< (DEVEPTIMR) NAKed OUT Interrupt Mask */
+#define DEVEPTIMR_INTRPT_NAKINE_Pos 4 /**< (DEVEPTIMR) NAKed IN Interrupt Position */
+#define DEVEPTIMR_INTRPT_NAKINE (_U_(0x1) << DEVEPTIMR_INTRPT_NAKINE_Pos) /**< (DEVEPTIMR) NAKed IN Interrupt Mask */
+#define DEVEPTIMR_INTRPT_STALLEDE_Pos 6 /**< (DEVEPTIMR) STALLed Interrupt Position */
+#define DEVEPTIMR_INTRPT_STALLEDE (_U_(0x1) << DEVEPTIMR_INTRPT_STALLEDE_Pos) /**< (DEVEPTIMR) STALLed Interrupt Mask */
+#define DEVEPTIMR_INTRPT_NYETDIS_Pos 17 /**< (DEVEPTIMR) NYET Token Disable Position */
+#define DEVEPTIMR_INTRPT_NYETDIS (_U_(0x1) << DEVEPTIMR_INTRPT_NYETDIS_Pos) /**< (DEVEPTIMR) NYET Token Disable Mask */
+#define DEVEPTIMR_INTRPT_STALLRQ_Pos 19 /**< (DEVEPTIMR) STALL Request Position */
+#define DEVEPTIMR_INTRPT_STALLRQ (_U_(0x1) << DEVEPTIMR_INTRPT_STALLRQ_Pos) /**< (DEVEPTIMR) STALL Request Mask */
+#define DEVEPTIMR_INTRPT_Msk _U_(0xA005C) /**< (DEVEPTIMR_INTRPT) Register Mask */
+
+
+/* -------- DEVEPTIER : (USBHS Offset: 0x1f0) (/W 32) Device Endpoint Interrupt Enable Register -------- */
+
+#define DEVEPTIER_OFFSET (0x1F0) /**< (DEVEPTIER) Device Endpoint Interrupt Enable Register Offset */
+
+#define DEVEPTIER_TXINES_Pos 0 /**< (DEVEPTIER) Transmitted IN Data Interrupt Enable Position */
+#define DEVEPTIER_TXINES (_U_(0x1) << DEVEPTIER_TXINES_Pos) /**< (DEVEPTIER) Transmitted IN Data Interrupt Enable Mask */
+#define DEVEPTIER_RXOUTES_Pos 1 /**< (DEVEPTIER) Received OUT Data Interrupt Enable Position */
+#define DEVEPTIER_RXOUTES (_U_(0x1) << DEVEPTIER_RXOUTES_Pos) /**< (DEVEPTIER) Received OUT Data Interrupt Enable Mask */
+#define DEVEPTIER_OVERFES_Pos 5 /**< (DEVEPTIER) Overflow Interrupt Enable Position */
+#define DEVEPTIER_OVERFES (_U_(0x1) << DEVEPTIER_OVERFES_Pos) /**< (DEVEPTIER) Overflow Interrupt Enable Mask */
+#define DEVEPTIER_SHORTPACKETES_Pos 7 /**< (DEVEPTIER) Short Packet Interrupt Enable Position */
+#define DEVEPTIER_SHORTPACKETES (_U_(0x1) << DEVEPTIER_SHORTPACKETES_Pos) /**< (DEVEPTIER) Short Packet Interrupt Enable Mask */
+#define DEVEPTIER_NBUSYBKES_Pos 12 /**< (DEVEPTIER) Number of Busy Banks Interrupt Enable Position */
+#define DEVEPTIER_NBUSYBKES (_U_(0x1) << DEVEPTIER_NBUSYBKES_Pos) /**< (DEVEPTIER) Number of Busy Banks Interrupt Enable Mask */
+#define DEVEPTIER_KILLBKS_Pos 13 /**< (DEVEPTIER) Kill IN Bank Position */
+#define DEVEPTIER_KILLBKS (_U_(0x1) << DEVEPTIER_KILLBKS_Pos) /**< (DEVEPTIER) Kill IN Bank Mask */
+#define DEVEPTIER_FIFOCONS_Pos 14 /**< (DEVEPTIER) FIFO Control Position */
+#define DEVEPTIER_FIFOCONS (_U_(0x1) << DEVEPTIER_FIFOCONS_Pos) /**< (DEVEPTIER) FIFO Control Mask */
+#define DEVEPTIER_EPDISHDMAS_Pos 16 /**< (DEVEPTIER) Endpoint Interrupts Disable HDMA Request Enable Position */
+#define DEVEPTIER_EPDISHDMAS (_U_(0x1) << DEVEPTIER_EPDISHDMAS_Pos) /**< (DEVEPTIER) Endpoint Interrupts Disable HDMA Request Enable Mask */
+#define DEVEPTIER_RSTDTS_Pos 18 /**< (DEVEPTIER) Reset Data Toggle Enable Position */
+#define DEVEPTIER_RSTDTS (_U_(0x1) << DEVEPTIER_RSTDTS_Pos) /**< (DEVEPTIER) Reset Data Toggle Enable Mask */
+#define DEVEPTIER_Msk _U_(0x570A3) /**< (DEVEPTIER) Register Mask */
+
+/* CTRL mode */
+#define DEVEPTIER_CTRL_RXSTPES_Pos 2 /**< (DEVEPTIER) Received SETUP Interrupt Enable Position */
+#define DEVEPTIER_CTRL_RXSTPES (_U_(0x1) << DEVEPTIER_CTRL_RXSTPES_Pos) /**< (DEVEPTIER) Received SETUP Interrupt Enable Mask */
+#define DEVEPTIER_CTRL_NAKOUTES_Pos 3 /**< (DEVEPTIER) NAKed OUT Interrupt Enable Position */
+#define DEVEPTIER_CTRL_NAKOUTES (_U_(0x1) << DEVEPTIER_CTRL_NAKOUTES_Pos) /**< (DEVEPTIER) NAKed OUT Interrupt Enable Mask */
+#define DEVEPTIER_CTRL_NAKINES_Pos 4 /**< (DEVEPTIER) NAKed IN Interrupt Enable Position */
+#define DEVEPTIER_CTRL_NAKINES (_U_(0x1) << DEVEPTIER_CTRL_NAKINES_Pos) /**< (DEVEPTIER) NAKed IN Interrupt Enable Mask */
+#define DEVEPTIER_CTRL_STALLEDES_Pos 6 /**< (DEVEPTIER) STALLed Interrupt Enable Position */
+#define DEVEPTIER_CTRL_STALLEDES (_U_(0x1) << DEVEPTIER_CTRL_STALLEDES_Pos) /**< (DEVEPTIER) STALLed Interrupt Enable Mask */
+#define DEVEPTIER_CTRL_NYETDISS_Pos 17 /**< (DEVEPTIER) NYET Token Disable Enable Position */
+#define DEVEPTIER_CTRL_NYETDISS (_U_(0x1) << DEVEPTIER_CTRL_NYETDISS_Pos) /**< (DEVEPTIER) NYET Token Disable Enable Mask */
+#define DEVEPTIER_CTRL_STALLRQS_Pos 19 /**< (DEVEPTIER) STALL Request Enable Position */
+#define DEVEPTIER_CTRL_STALLRQS (_U_(0x1) << DEVEPTIER_CTRL_STALLRQS_Pos) /**< (DEVEPTIER) STALL Request Enable Mask */
+#define DEVEPTIER_CTRL_Msk _U_(0xA005C) /**< (DEVEPTIER_CTRL) Register Mask */
+
+/* ISO mode */
+#define DEVEPTIER_ISO_UNDERFES_Pos 2 /**< (DEVEPTIER) Underflow Interrupt Enable Position */
+#define DEVEPTIER_ISO_UNDERFES (_U_(0x1) << DEVEPTIER_ISO_UNDERFES_Pos) /**< (DEVEPTIER) Underflow Interrupt Enable Mask */
+#define DEVEPTIER_ISO_HBISOINERRES_Pos 3 /**< (DEVEPTIER) High Bandwidth Isochronous IN Underflow Error Interrupt Enable Position */
+#define DEVEPTIER_ISO_HBISOINERRES (_U_(0x1) << DEVEPTIER_ISO_HBISOINERRES_Pos) /**< (DEVEPTIER) High Bandwidth Isochronous IN Underflow Error Interrupt Enable Mask */
+#define DEVEPTIER_ISO_HBISOFLUSHES_Pos 4 /**< (DEVEPTIER) High Bandwidth Isochronous IN Flush Interrupt Enable Position */
+#define DEVEPTIER_ISO_HBISOFLUSHES (_U_(0x1) << DEVEPTIER_ISO_HBISOFLUSHES_Pos) /**< (DEVEPTIER) High Bandwidth Isochronous IN Flush Interrupt Enable Mask */
+#define DEVEPTIER_ISO_CRCERRES_Pos 6 /**< (DEVEPTIER) CRC Error Interrupt Enable Position */
+#define DEVEPTIER_ISO_CRCERRES (_U_(0x1) << DEVEPTIER_ISO_CRCERRES_Pos) /**< (DEVEPTIER) CRC Error Interrupt Enable Mask */
+#define DEVEPTIER_ISO_MDATAES_Pos 8 /**< (DEVEPTIER) MData Interrupt Enable Position */
+#define DEVEPTIER_ISO_MDATAES (_U_(0x1) << DEVEPTIER_ISO_MDATAES_Pos) /**< (DEVEPTIER) MData Interrupt Enable Mask */
+#define DEVEPTIER_ISO_DATAXES_Pos 9 /**< (DEVEPTIER) DataX Interrupt Enable Position */
+#define DEVEPTIER_ISO_DATAXES (_U_(0x1) << DEVEPTIER_ISO_DATAXES_Pos) /**< (DEVEPTIER) DataX Interrupt Enable Mask */
+#define DEVEPTIER_ISO_ERRORTRANSES_Pos 10 /**< (DEVEPTIER) Transaction Error Interrupt Enable Position */
+#define DEVEPTIER_ISO_ERRORTRANSES (_U_(0x1) << DEVEPTIER_ISO_ERRORTRANSES_Pos) /**< (DEVEPTIER) Transaction Error Interrupt Enable Mask */
+#define DEVEPTIER_ISO_Msk _U_(0x75C) /**< (DEVEPTIER_ISO) Register Mask */
+
+/* BLK mode */
+#define DEVEPTIER_BLK_RXSTPES_Pos 2 /**< (DEVEPTIER) Received SETUP Interrupt Enable Position */
+#define DEVEPTIER_BLK_RXSTPES (_U_(0x1) << DEVEPTIER_BLK_RXSTPES_Pos) /**< (DEVEPTIER) Received SETUP Interrupt Enable Mask */
+#define DEVEPTIER_BLK_NAKOUTES_Pos 3 /**< (DEVEPTIER) NAKed OUT Interrupt Enable Position */
+#define DEVEPTIER_BLK_NAKOUTES (_U_(0x1) << DEVEPTIER_BLK_NAKOUTES_Pos) /**< (DEVEPTIER) NAKed OUT Interrupt Enable Mask */
+#define DEVEPTIER_BLK_NAKINES_Pos 4 /**< (DEVEPTIER) NAKed IN Interrupt Enable Position */
+#define DEVEPTIER_BLK_NAKINES (_U_(0x1) << DEVEPTIER_BLK_NAKINES_Pos) /**< (DEVEPTIER) NAKed IN Interrupt Enable Mask */
+#define DEVEPTIER_BLK_STALLEDES_Pos 6 /**< (DEVEPTIER) STALLed Interrupt Enable Position */
+#define DEVEPTIER_BLK_STALLEDES (_U_(0x1) << DEVEPTIER_BLK_STALLEDES_Pos) /**< (DEVEPTIER) STALLed Interrupt Enable Mask */
+#define DEVEPTIER_BLK_NYETDISS_Pos 17 /**< (DEVEPTIER) NYET Token Disable Enable Position */
+#define DEVEPTIER_BLK_NYETDISS (_U_(0x1) << DEVEPTIER_BLK_NYETDISS_Pos) /**< (DEVEPTIER) NYET Token Disable Enable Mask */
+#define DEVEPTIER_BLK_STALLRQS_Pos 19 /**< (DEVEPTIER) STALL Request Enable Position */
+#define DEVEPTIER_BLK_STALLRQS (_U_(0x1) << DEVEPTIER_BLK_STALLRQS_Pos) /**< (DEVEPTIER) STALL Request Enable Mask */
+#define DEVEPTIER_BLK_Msk _U_(0xA005C) /**< (DEVEPTIER_BLK) Register Mask */
+
+/* INTRPT mode */
+#define DEVEPTIER_INTRPT_RXSTPES_Pos 2 /**< (DEVEPTIER) Received SETUP Interrupt Enable Position */
+#define DEVEPTIER_INTRPT_RXSTPES (_U_(0x1) << DEVEPTIER_INTRPT_RXSTPES_Pos) /**< (DEVEPTIER) Received SETUP Interrupt Enable Mask */
+#define DEVEPTIER_INTRPT_NAKOUTES_Pos 3 /**< (DEVEPTIER) NAKed OUT Interrupt Enable Position */
+#define DEVEPTIER_INTRPT_NAKOUTES (_U_(0x1) << DEVEPTIER_INTRPT_NAKOUTES_Pos) /**< (DEVEPTIER) NAKed OUT Interrupt Enable Mask */
+#define DEVEPTIER_INTRPT_NAKINES_Pos 4 /**< (DEVEPTIER) NAKed IN Interrupt Enable Position */
+#define DEVEPTIER_INTRPT_NAKINES (_U_(0x1) << DEVEPTIER_INTRPT_NAKINES_Pos) /**< (DEVEPTIER) NAKed IN Interrupt Enable Mask */
+#define DEVEPTIER_INTRPT_STALLEDES_Pos 6 /**< (DEVEPTIER) STALLed Interrupt Enable Position */
+#define DEVEPTIER_INTRPT_STALLEDES (_U_(0x1) << DEVEPTIER_INTRPT_STALLEDES_Pos) /**< (DEVEPTIER) STALLed Interrupt Enable Mask */
+#define DEVEPTIER_INTRPT_NYETDISS_Pos 17 /**< (DEVEPTIER) NYET Token Disable Enable Position */
+#define DEVEPTIER_INTRPT_NYETDISS (_U_(0x1) << DEVEPTIER_INTRPT_NYETDISS_Pos) /**< (DEVEPTIER) NYET Token Disable Enable Mask */
+#define DEVEPTIER_INTRPT_STALLRQS_Pos 19 /**< (DEVEPTIER) STALL Request Enable Position */
+#define DEVEPTIER_INTRPT_STALLRQS (_U_(0x1) << DEVEPTIER_INTRPT_STALLRQS_Pos) /**< (DEVEPTIER) STALL Request Enable Mask */
+#define DEVEPTIER_INTRPT_Msk _U_(0xA005C) /**< (DEVEPTIER_INTRPT) Register Mask */
+
+
+/* -------- DEVEPTIDR : (USBHS Offset: 0x220) (/W 32) Device Endpoint Interrupt Disable Register -------- */
+
+#define DEVEPTIDR_OFFSET (0x220) /**< (DEVEPTIDR) Device Endpoint Interrupt Disable Register Offset */
+
+#define DEVEPTIDR_TXINEC_Pos 0 /**< (DEVEPTIDR) Transmitted IN Interrupt Clear Position */
+#define DEVEPTIDR_TXINEC (_U_(0x1) << DEVEPTIDR_TXINEC_Pos) /**< (DEVEPTIDR) Transmitted IN Interrupt Clear Mask */
+#define DEVEPTIDR_RXOUTEC_Pos 1 /**< (DEVEPTIDR) Received OUT Data Interrupt Clear Position */
+#define DEVEPTIDR_RXOUTEC (_U_(0x1) << DEVEPTIDR_RXOUTEC_Pos) /**< (DEVEPTIDR) Received OUT Data Interrupt Clear Mask */
+#define DEVEPTIDR_OVERFEC_Pos 5 /**< (DEVEPTIDR) Overflow Interrupt Clear Position */
+#define DEVEPTIDR_OVERFEC (_U_(0x1) << DEVEPTIDR_OVERFEC_Pos) /**< (DEVEPTIDR) Overflow Interrupt Clear Mask */
+#define DEVEPTIDR_SHORTPACKETEC_Pos 7 /**< (DEVEPTIDR) Shortpacket Interrupt Clear Position */
+#define DEVEPTIDR_SHORTPACKETEC (_U_(0x1) << DEVEPTIDR_SHORTPACKETEC_Pos) /**< (DEVEPTIDR) Shortpacket Interrupt Clear Mask */
+#define DEVEPTIDR_NBUSYBKEC_Pos 12 /**< (DEVEPTIDR) Number of Busy Banks Interrupt Clear Position */
+#define DEVEPTIDR_NBUSYBKEC (_U_(0x1) << DEVEPTIDR_NBUSYBKEC_Pos) /**< (DEVEPTIDR) Number of Busy Banks Interrupt Clear Mask */
+#define DEVEPTIDR_FIFOCONC_Pos 14 /**< (DEVEPTIDR) FIFO Control Clear Position */
+#define DEVEPTIDR_FIFOCONC (_U_(0x1) << DEVEPTIDR_FIFOCONC_Pos) /**< (DEVEPTIDR) FIFO Control Clear Mask */
+#define DEVEPTIDR_EPDISHDMAC_Pos 16 /**< (DEVEPTIDR) Endpoint Interrupts Disable HDMA Request Clear Position */
+#define DEVEPTIDR_EPDISHDMAC (_U_(0x1) << DEVEPTIDR_EPDISHDMAC_Pos) /**< (DEVEPTIDR) Endpoint Interrupts Disable HDMA Request Clear Mask */
+#define DEVEPTIDR_Msk _U_(0x150A3) /**< (DEVEPTIDR) Register Mask */
+
+/* CTRL mode */
+#define DEVEPTIDR_CTRL_RXSTPEC_Pos 2 /**< (DEVEPTIDR) Received SETUP Interrupt Clear Position */
+#define DEVEPTIDR_CTRL_RXSTPEC (_U_(0x1) << DEVEPTIDR_CTRL_RXSTPEC_Pos) /**< (DEVEPTIDR) Received SETUP Interrupt Clear Mask */
+#define DEVEPTIDR_CTRL_NAKOUTEC_Pos 3 /**< (DEVEPTIDR) NAKed OUT Interrupt Clear Position */
+#define DEVEPTIDR_CTRL_NAKOUTEC (_U_(0x1) << DEVEPTIDR_CTRL_NAKOUTEC_Pos) /**< (DEVEPTIDR) NAKed OUT Interrupt Clear Mask */
+#define DEVEPTIDR_CTRL_NAKINEC_Pos 4 /**< (DEVEPTIDR) NAKed IN Interrupt Clear Position */
+#define DEVEPTIDR_CTRL_NAKINEC (_U_(0x1) << DEVEPTIDR_CTRL_NAKINEC_Pos) /**< (DEVEPTIDR) NAKed IN Interrupt Clear Mask */
+#define DEVEPTIDR_CTRL_STALLEDEC_Pos 6 /**< (DEVEPTIDR) STALLed Interrupt Clear Position */
+#define DEVEPTIDR_CTRL_STALLEDEC (_U_(0x1) << DEVEPTIDR_CTRL_STALLEDEC_Pos) /**< (DEVEPTIDR) STALLed Interrupt Clear Mask */
+#define DEVEPTIDR_CTRL_NYETDISC_Pos 17 /**< (DEVEPTIDR) NYET Token Disable Clear Position */
+#define DEVEPTIDR_CTRL_NYETDISC (_U_(0x1) << DEVEPTIDR_CTRL_NYETDISC_Pos) /**< (DEVEPTIDR) NYET Token Disable Clear Mask */
+#define DEVEPTIDR_CTRL_STALLRQC_Pos 19 /**< (DEVEPTIDR) STALL Request Clear Position */
+#define DEVEPTIDR_CTRL_STALLRQC (_U_(0x1) << DEVEPTIDR_CTRL_STALLRQC_Pos) /**< (DEVEPTIDR) STALL Request Clear Mask */
+#define DEVEPTIDR_CTRL_Msk _U_(0xA005C) /**< (DEVEPTIDR_CTRL) Register Mask */
+
+/* ISO mode */
+#define DEVEPTIDR_ISO_UNDERFEC_Pos 2 /**< (DEVEPTIDR) Underflow Interrupt Clear Position */
+#define DEVEPTIDR_ISO_UNDERFEC (_U_(0x1) << DEVEPTIDR_ISO_UNDERFEC_Pos) /**< (DEVEPTIDR) Underflow Interrupt Clear Mask */
+#define DEVEPTIDR_ISO_HBISOINERREC_Pos 3 /**< (DEVEPTIDR) High Bandwidth Isochronous IN Underflow Error Interrupt Clear Position */
+#define DEVEPTIDR_ISO_HBISOINERREC (_U_(0x1) << DEVEPTIDR_ISO_HBISOINERREC_Pos) /**< (DEVEPTIDR) High Bandwidth Isochronous IN Underflow Error Interrupt Clear Mask */
+#define DEVEPTIDR_ISO_HBISOFLUSHEC_Pos 4 /**< (DEVEPTIDR) High Bandwidth Isochronous IN Flush Interrupt Clear Position */
+#define DEVEPTIDR_ISO_HBISOFLUSHEC (_U_(0x1) << DEVEPTIDR_ISO_HBISOFLUSHEC_Pos) /**< (DEVEPTIDR) High Bandwidth Isochronous IN Flush Interrupt Clear Mask */
+#define DEVEPTIDR_ISO_MDATAEC_Pos 8 /**< (DEVEPTIDR) MData Interrupt Clear Position */
+#define DEVEPTIDR_ISO_MDATAEC (_U_(0x1) << DEVEPTIDR_ISO_MDATAEC_Pos) /**< (DEVEPTIDR) MData Interrupt Clear Mask */
+#define DEVEPTIDR_ISO_DATAXEC_Pos 9 /**< (DEVEPTIDR) DataX Interrupt Clear Position */
+#define DEVEPTIDR_ISO_DATAXEC (_U_(0x1) << DEVEPTIDR_ISO_DATAXEC_Pos) /**< (DEVEPTIDR) DataX Interrupt Clear Mask */
+#define DEVEPTIDR_ISO_ERRORTRANSEC_Pos 10 /**< (DEVEPTIDR) Transaction Error Interrupt Clear Position */
+#define DEVEPTIDR_ISO_ERRORTRANSEC (_U_(0x1) << DEVEPTIDR_ISO_ERRORTRANSEC_Pos) /**< (DEVEPTIDR) Transaction Error Interrupt Clear Mask */
+#define DEVEPTIDR_ISO_Msk _U_(0x71C) /**< (DEVEPTIDR_ISO) Register Mask */
+
+/* BLK mode */
+#define DEVEPTIDR_BLK_RXSTPEC_Pos 2 /**< (DEVEPTIDR) Received SETUP Interrupt Clear Position */
+#define DEVEPTIDR_BLK_RXSTPEC (_U_(0x1) << DEVEPTIDR_BLK_RXSTPEC_Pos) /**< (DEVEPTIDR) Received SETUP Interrupt Clear Mask */
+#define DEVEPTIDR_BLK_NAKOUTEC_Pos 3 /**< (DEVEPTIDR) NAKed OUT Interrupt Clear Position */
+#define DEVEPTIDR_BLK_NAKOUTEC (_U_(0x1) << DEVEPTIDR_BLK_NAKOUTEC_Pos) /**< (DEVEPTIDR) NAKed OUT Interrupt Clear Mask */
+#define DEVEPTIDR_BLK_NAKINEC_Pos 4 /**< (DEVEPTIDR) NAKed IN Interrupt Clear Position */
+#define DEVEPTIDR_BLK_NAKINEC (_U_(0x1) << DEVEPTIDR_BLK_NAKINEC_Pos) /**< (DEVEPTIDR) NAKed IN Interrupt Clear Mask */
+#define DEVEPTIDR_BLK_STALLEDEC_Pos 6 /**< (DEVEPTIDR) STALLed Interrupt Clear Position */
+#define DEVEPTIDR_BLK_STALLEDEC (_U_(0x1) << DEVEPTIDR_BLK_STALLEDEC_Pos) /**< (DEVEPTIDR) STALLed Interrupt Clear Mask */
+#define DEVEPTIDR_BLK_NYETDISC_Pos 17 /**< (DEVEPTIDR) NYET Token Disable Clear Position */
+#define DEVEPTIDR_BLK_NYETDISC (_U_(0x1) << DEVEPTIDR_BLK_NYETDISC_Pos) /**< (DEVEPTIDR) NYET Token Disable Clear Mask */
+#define DEVEPTIDR_BLK_STALLRQC_Pos 19 /**< (DEVEPTIDR) STALL Request Clear Position */
+#define DEVEPTIDR_BLK_STALLRQC (_U_(0x1) << DEVEPTIDR_BLK_STALLRQC_Pos) /**< (DEVEPTIDR) STALL Request Clear Mask */
+#define DEVEPTIDR_BLK_Msk _U_(0xA005C) /**< (DEVEPTIDR_BLK) Register Mask */
+
+/* INTRPT mode */
+#define DEVEPTIDR_INTRPT_RXSTPEC_Pos 2 /**< (DEVEPTIDR) Received SETUP Interrupt Clear Position */
+#define DEVEPTIDR_INTRPT_RXSTPEC (_U_(0x1) << DEVEPTIDR_INTRPT_RXSTPEC_Pos) /**< (DEVEPTIDR) Received SETUP Interrupt Clear Mask */
+#define DEVEPTIDR_INTRPT_NAKOUTEC_Pos 3 /**< (DEVEPTIDR) NAKed OUT Interrupt Clear Position */
+#define DEVEPTIDR_INTRPT_NAKOUTEC (_U_(0x1) << DEVEPTIDR_INTRPT_NAKOUTEC_Pos) /**< (DEVEPTIDR) NAKed OUT Interrupt Clear Mask */
+#define DEVEPTIDR_INTRPT_NAKINEC_Pos 4 /**< (DEVEPTIDR) NAKed IN Interrupt Clear Position */
+#define DEVEPTIDR_INTRPT_NAKINEC (_U_(0x1) << DEVEPTIDR_INTRPT_NAKINEC_Pos) /**< (DEVEPTIDR) NAKed IN Interrupt Clear Mask */
+#define DEVEPTIDR_INTRPT_STALLEDEC_Pos 6 /**< (DEVEPTIDR) STALLed Interrupt Clear Position */
+#define DEVEPTIDR_INTRPT_STALLEDEC (_U_(0x1) << DEVEPTIDR_INTRPT_STALLEDEC_Pos) /**< (DEVEPTIDR) STALLed Interrupt Clear Mask */
+#define DEVEPTIDR_INTRPT_NYETDISC_Pos 17 /**< (DEVEPTIDR) NYET Token Disable Clear Position */
+#define DEVEPTIDR_INTRPT_NYETDISC (_U_(0x1) << DEVEPTIDR_INTRPT_NYETDISC_Pos) /**< (DEVEPTIDR) NYET Token Disable Clear Mask */
+#define DEVEPTIDR_INTRPT_STALLRQC_Pos 19 /**< (DEVEPTIDR) STALL Request Clear Position */
+#define DEVEPTIDR_INTRPT_STALLRQC (_U_(0x1) << DEVEPTIDR_INTRPT_STALLRQC_Pos) /**< (DEVEPTIDR) STALL Request Clear Mask */
+#define DEVEPTIDR_INTRPT_Msk _U_(0xA005C) /**< (DEVEPTIDR_INTRPT) Register Mask */
+
+
+/* -------- HSTCTRL : (USBHS Offset: 0x400) (R/W 32) Host General Control Register -------- */
+
+#define HSTCTRL_OFFSET (0x400) /**< (HSTCTRL) Host General Control Register Offset */
+
+#define HSTCTRL_SOFE_Pos 8 /**< (HSTCTRL) Start of Frame Generation Enable Position */
+#define HSTCTRL_SOFE (_U_(0x1) << HSTCTRL_SOFE_Pos) /**< (HSTCTRL) Start of Frame Generation Enable Mask */
+#define HSTCTRL_RESET_Pos 9 /**< (HSTCTRL) Send USB Reset Position */
+#define HSTCTRL_RESET (_U_(0x1) << HSTCTRL_RESET_Pos) /**< (HSTCTRL) Send USB Reset Mask */
+#define HSTCTRL_RESUME_Pos 10 /**< (HSTCTRL) Send USB Resume Position */
+#define HSTCTRL_RESUME (_U_(0x1) << HSTCTRL_RESUME_Pos) /**< (HSTCTRL) Send USB Resume Mask */
+#define HSTCTRL_SPDCONF_Pos 12 /**< (HSTCTRL) Mode Configuration Position */
+#define HSTCTRL_SPDCONF (_U_(0x3) << HSTCTRL_SPDCONF_Pos) /**< (HSTCTRL) Mode Configuration Mask */
+#define HSTCTRL_SPDCONF_NORMAL_Val _U_(0x0) /**< (HSTCTRL) The host starts in Full-speed mode and performs a high-speed reset to switch to High-speed mode if the downstream peripheral is high-speed capable. */
+#define HSTCTRL_SPDCONF_LOW_POWER_Val _U_(0x1) /**< (HSTCTRL) For a better consumption, if high speed is not needed. */
+#define HSTCTRL_SPDCONF_HIGH_SPEED_Val _U_(0x2) /**< (HSTCTRL) Forced high speed. */
+#define HSTCTRL_SPDCONF_FORCED_FS_Val _U_(0x3) /**< (HSTCTRL) The host remains in Full-speed mode whatever the peripheral speed capability. */
+#define HSTCTRL_SPDCONF_NORMAL (HSTCTRL_SPDCONF_NORMAL_Val << HSTCTRL_SPDCONF_Pos) /**< (HSTCTRL) The host starts in Full-speed mode and performs a high-speed reset to switch to High-speed mode if the downstream peripheral is high-speed capable. Position */
+#define HSTCTRL_SPDCONF_LOW_POWER (HSTCTRL_SPDCONF_LOW_POWER_Val << HSTCTRL_SPDCONF_Pos) /**< (HSTCTRL) For a better consumption, if high speed is not needed. Position */
+#define HSTCTRL_SPDCONF_HIGH_SPEED (HSTCTRL_SPDCONF_HIGH_SPEED_Val << HSTCTRL_SPDCONF_Pos) /**< (HSTCTRL) Forced high speed. Position */
+#define HSTCTRL_SPDCONF_FORCED_FS (HSTCTRL_SPDCONF_FORCED_FS_Val << HSTCTRL_SPDCONF_Pos) /**< (HSTCTRL) The host remains in Full-speed mode whatever the peripheral speed capability. Position */
+#define HSTCTRL_Msk _U_(0x3700) /**< (HSTCTRL) Register Mask */
+
+
+/* -------- HSTISR : (USBHS Offset: 0x404) (R/ 32) Host Global Interrupt Status Register -------- */
+
+#define HSTISR_OFFSET (0x404) /**< (HSTISR) Host Global Interrupt Status Register Offset */
+
+#define HSTISR_DCONNI_Pos 0 /**< (HSTISR) Device Connection Interrupt Position */
+#define HSTISR_DCONNI (_U_(0x1) << HSTISR_DCONNI_Pos) /**< (HSTISR) Device Connection Interrupt Mask */
+#define HSTISR_DDISCI_Pos 1 /**< (HSTISR) Device Disconnection Interrupt Position */
+#define HSTISR_DDISCI (_U_(0x1) << HSTISR_DDISCI_Pos) /**< (HSTISR) Device Disconnection Interrupt Mask */
+#define HSTISR_RSTI_Pos 2 /**< (HSTISR) USB Reset Sent Interrupt Position */
+#define HSTISR_RSTI (_U_(0x1) << HSTISR_RSTI_Pos) /**< (HSTISR) USB Reset Sent Interrupt Mask */
+#define HSTISR_RSMEDI_Pos 3 /**< (HSTISR) Downstream Resume Sent Interrupt Position */
+#define HSTISR_RSMEDI (_U_(0x1) << HSTISR_RSMEDI_Pos) /**< (HSTISR) Downstream Resume Sent Interrupt Mask */
+#define HSTISR_RXRSMI_Pos 4 /**< (HSTISR) Upstream Resume Received Interrupt Position */
+#define HSTISR_RXRSMI (_U_(0x1) << HSTISR_RXRSMI_Pos) /**< (HSTISR) Upstream Resume Received Interrupt Mask */
+#define HSTISR_HSOFI_Pos 5 /**< (HSTISR) Host Start of Frame Interrupt Position */
+#define HSTISR_HSOFI (_U_(0x1) << HSTISR_HSOFI_Pos) /**< (HSTISR) Host Start of Frame Interrupt Mask */
+#define HSTISR_HWUPI_Pos 6 /**< (HSTISR) Host Wake-Up Interrupt Position */
+#define HSTISR_HWUPI (_U_(0x1) << HSTISR_HWUPI_Pos) /**< (HSTISR) Host Wake-Up Interrupt Mask */
+#define HSTISR_PEP_0_Pos 8 /**< (HSTISR) Pipe 0 Interrupt Position */
+#define HSTISR_PEP_0 (_U_(0x1) << HSTISR_PEP_0_Pos) /**< (HSTISR) Pipe 0 Interrupt Mask */
+#define HSTISR_PEP_1_Pos 9 /**< (HSTISR) Pipe 1 Interrupt Position */
+#define HSTISR_PEP_1 (_U_(0x1) << HSTISR_PEP_1_Pos) /**< (HSTISR) Pipe 1 Interrupt Mask */
+#define HSTISR_PEP_2_Pos 10 /**< (HSTISR) Pipe 2 Interrupt Position */
+#define HSTISR_PEP_2 (_U_(0x1) << HSTISR_PEP_2_Pos) /**< (HSTISR) Pipe 2 Interrupt Mask */
+#define HSTISR_PEP_3_Pos 11 /**< (HSTISR) Pipe 3 Interrupt Position */
+#define HSTISR_PEP_3 (_U_(0x1) << HSTISR_PEP_3_Pos) /**< (HSTISR) Pipe 3 Interrupt Mask */
+#define HSTISR_PEP_4_Pos 12 /**< (HSTISR) Pipe 4 Interrupt Position */
+#define HSTISR_PEP_4 (_U_(0x1) << HSTISR_PEP_4_Pos) /**< (HSTISR) Pipe 4 Interrupt Mask */
+#define HSTISR_PEP_5_Pos 13 /**< (HSTISR) Pipe 5 Interrupt Position */
+#define HSTISR_PEP_5 (_U_(0x1) << HSTISR_PEP_5_Pos) /**< (HSTISR) Pipe 5 Interrupt Mask */
+#define HSTISR_PEP_6_Pos 14 /**< (HSTISR) Pipe 6 Interrupt Position */
+#define HSTISR_PEP_6 (_U_(0x1) << HSTISR_PEP_6_Pos) /**< (HSTISR) Pipe 6 Interrupt Mask */
+#define HSTISR_PEP_7_Pos 15 /**< (HSTISR) Pipe 7 Interrupt Position */
+#define HSTISR_PEP_7 (_U_(0x1) << HSTISR_PEP_7_Pos) /**< (HSTISR) Pipe 7 Interrupt Mask */
+#define HSTISR_PEP_8_Pos 16 /**< (HSTISR) Pipe 8 Interrupt Position */
+#define HSTISR_PEP_8 (_U_(0x1) << HSTISR_PEP_8_Pos) /**< (HSTISR) Pipe 8 Interrupt Mask */
+#define HSTISR_PEP_9_Pos 17 /**< (HSTISR) Pipe 9 Interrupt Position */
+#define HSTISR_PEP_9 (_U_(0x1) << HSTISR_PEP_9_Pos) /**< (HSTISR) Pipe 9 Interrupt Mask */
+#define HSTISR_DMA_0_Pos 25 /**< (HSTISR) DMA Channel 0 Interrupt Position */
+#define HSTISR_DMA_0 (_U_(0x1) << HSTISR_DMA_0_Pos) /**< (HSTISR) DMA Channel 0 Interrupt Mask */
+#define HSTISR_DMA_1_Pos 26 /**< (HSTISR) DMA Channel 1 Interrupt Position */
+#define HSTISR_DMA_1 (_U_(0x1) << HSTISR_DMA_1_Pos) /**< (HSTISR) DMA Channel 1 Interrupt Mask */
+#define HSTISR_DMA_2_Pos 27 /**< (HSTISR) DMA Channel 2 Interrupt Position */
+#define HSTISR_DMA_2 (_U_(0x1) << HSTISR_DMA_2_Pos) /**< (HSTISR) DMA Channel 2 Interrupt Mask */
+#define HSTISR_DMA_3_Pos 28 /**< (HSTISR) DMA Channel 3 Interrupt Position */
+#define HSTISR_DMA_3 (_U_(0x1) << HSTISR_DMA_3_Pos) /**< (HSTISR) DMA Channel 3 Interrupt Mask */
+#define HSTISR_DMA_4_Pos 29 /**< (HSTISR) DMA Channel 4 Interrupt Position */
+#define HSTISR_DMA_4 (_U_(0x1) << HSTISR_DMA_4_Pos) /**< (HSTISR) DMA Channel 4 Interrupt Mask */
+#define HSTISR_DMA_5_Pos 30 /**< (HSTISR) DMA Channel 5 Interrupt Position */
+#define HSTISR_DMA_5 (_U_(0x1) << HSTISR_DMA_5_Pos) /**< (HSTISR) DMA Channel 5 Interrupt Mask */
+#define HSTISR_DMA_6_Pos 31 /**< (HSTISR) DMA Channel 6 Interrupt Position */
+#define HSTISR_DMA_6 (_U_(0x1) << HSTISR_DMA_6_Pos) /**< (HSTISR) DMA Channel 6 Interrupt Mask */
+#define HSTISR_Msk _U_(0xFE03FF7F) /**< (HSTISR) Register Mask */
+
+#define HSTISR_PEP__Pos 8 /**< (HSTISR Position) Pipe x Interrupt */
+#define HSTISR_PEP_ (_U_(0x3FF) << HSTISR_PEP__Pos) /**< (HSTISR Mask) PEP_ */
+#define HSTISR_DMA__Pos 25 /**< (HSTISR Position) DMA Channel 6 Interrupt */
+#define HSTISR_DMA_ (_U_(0x7F) << HSTISR_DMA__Pos) /**< (HSTISR Mask) DMA_ */
+
+/* -------- HSTICR : (USBHS Offset: 0x408) (/W 32) Host Global Interrupt Clear Register -------- */
+
+#define HSTICR_OFFSET (0x408) /**< (HSTICR) Host Global Interrupt Clear Register Offset */
+
+#define HSTICR_DCONNIC_Pos 0 /**< (HSTICR) Device Connection Interrupt Clear Position */
+#define HSTICR_DCONNIC (_U_(0x1) << HSTICR_DCONNIC_Pos) /**< (HSTICR) Device Connection Interrupt Clear Mask */
+#define HSTICR_DDISCIC_Pos 1 /**< (HSTICR) Device Disconnection Interrupt Clear Position */
+#define HSTICR_DDISCIC (_U_(0x1) << HSTICR_DDISCIC_Pos) /**< (HSTICR) Device Disconnection Interrupt Clear Mask */
+#define HSTICR_RSTIC_Pos 2 /**< (HSTICR) USB Reset Sent Interrupt Clear Position */
+#define HSTICR_RSTIC (_U_(0x1) << HSTICR_RSTIC_Pos) /**< (HSTICR) USB Reset Sent Interrupt Clear Mask */
+#define HSTICR_RSMEDIC_Pos 3 /**< (HSTICR) Downstream Resume Sent Interrupt Clear Position */
+#define HSTICR_RSMEDIC (_U_(0x1) << HSTICR_RSMEDIC_Pos) /**< (HSTICR) Downstream Resume Sent Interrupt Clear Mask */
+#define HSTICR_RXRSMIC_Pos 4 /**< (HSTICR) Upstream Resume Received Interrupt Clear Position */
+#define HSTICR_RXRSMIC (_U_(0x1) << HSTICR_RXRSMIC_Pos) /**< (HSTICR) Upstream Resume Received Interrupt Clear Mask */
+#define HSTICR_HSOFIC_Pos 5 /**< (HSTICR) Host Start of Frame Interrupt Clear Position */
+#define HSTICR_HSOFIC (_U_(0x1) << HSTICR_HSOFIC_Pos) /**< (HSTICR) Host Start of Frame Interrupt Clear Mask */
+#define HSTICR_HWUPIC_Pos 6 /**< (HSTICR) Host Wake-Up Interrupt Clear Position */
+#define HSTICR_HWUPIC (_U_(0x1) << HSTICR_HWUPIC_Pos) /**< (HSTICR) Host Wake-Up Interrupt Clear Mask */
+#define HSTICR_Msk _U_(0x7F) /**< (HSTICR) Register Mask */
+
+
+/* -------- HSTIFR : (USBHS Offset: 0x40c) (/W 32) Host Global Interrupt Set Register -------- */
+
+#define HSTIFR_OFFSET (0x40C) /**< (HSTIFR) Host Global Interrupt Set Register Offset */
+
+#define HSTIFR_DCONNIS_Pos 0 /**< (HSTIFR) Device Connection Interrupt Set Position */
+#define HSTIFR_DCONNIS (_U_(0x1) << HSTIFR_DCONNIS_Pos) /**< (HSTIFR) Device Connection Interrupt Set Mask */
+#define HSTIFR_DDISCIS_Pos 1 /**< (HSTIFR) Device Disconnection Interrupt Set Position */
+#define HSTIFR_DDISCIS (_U_(0x1) << HSTIFR_DDISCIS_Pos) /**< (HSTIFR) Device Disconnection Interrupt Set Mask */
+#define HSTIFR_RSTIS_Pos 2 /**< (HSTIFR) USB Reset Sent Interrupt Set Position */
+#define HSTIFR_RSTIS (_U_(0x1) << HSTIFR_RSTIS_Pos) /**< (HSTIFR) USB Reset Sent Interrupt Set Mask */
+#define HSTIFR_RSMEDIS_Pos 3 /**< (HSTIFR) Downstream Resume Sent Interrupt Set Position */
+#define HSTIFR_RSMEDIS (_U_(0x1) << HSTIFR_RSMEDIS_Pos) /**< (HSTIFR) Downstream Resume Sent Interrupt Set Mask */
+#define HSTIFR_RXRSMIS_Pos 4 /**< (HSTIFR) Upstream Resume Received Interrupt Set Position */
+#define HSTIFR_RXRSMIS (_U_(0x1) << HSTIFR_RXRSMIS_Pos) /**< (HSTIFR) Upstream Resume Received Interrupt Set Mask */
+#define HSTIFR_HSOFIS_Pos 5 /**< (HSTIFR) Host Start of Frame Interrupt Set Position */
+#define HSTIFR_HSOFIS (_U_(0x1) << HSTIFR_HSOFIS_Pos) /**< (HSTIFR) Host Start of Frame Interrupt Set Mask */
+#define HSTIFR_HWUPIS_Pos 6 /**< (HSTIFR) Host Wake-Up Interrupt Set Position */
+#define HSTIFR_HWUPIS (_U_(0x1) << HSTIFR_HWUPIS_Pos) /**< (HSTIFR) Host Wake-Up Interrupt Set Mask */
+#define HSTIFR_DMA_0_Pos 25 /**< (HSTIFR) DMA Channel 0 Interrupt Set Position */
+#define HSTIFR_DMA_0 (_U_(0x1) << HSTIFR_DMA_0_Pos) /**< (HSTIFR) DMA Channel 0 Interrupt Set Mask */
+#define HSTIFR_DMA_1_Pos 26 /**< (HSTIFR) DMA Channel 1 Interrupt Set Position */
+#define HSTIFR_DMA_1 (_U_(0x1) << HSTIFR_DMA_1_Pos) /**< (HSTIFR) DMA Channel 1 Interrupt Set Mask */
+#define HSTIFR_DMA_2_Pos 27 /**< (HSTIFR) DMA Channel 2 Interrupt Set Position */
+#define HSTIFR_DMA_2 (_U_(0x1) << HSTIFR_DMA_2_Pos) /**< (HSTIFR) DMA Channel 2 Interrupt Set Mask */
+#define HSTIFR_DMA_3_Pos 28 /**< (HSTIFR) DMA Channel 3 Interrupt Set Position */
+#define HSTIFR_DMA_3 (_U_(0x1) << HSTIFR_DMA_3_Pos) /**< (HSTIFR) DMA Channel 3 Interrupt Set Mask */
+#define HSTIFR_DMA_4_Pos 29 /**< (HSTIFR) DMA Channel 4 Interrupt Set Position */
+#define HSTIFR_DMA_4 (_U_(0x1) << HSTIFR_DMA_4_Pos) /**< (HSTIFR) DMA Channel 4 Interrupt Set Mask */
+#define HSTIFR_DMA_5_Pos 30 /**< (HSTIFR) DMA Channel 5 Interrupt Set Position */
+#define HSTIFR_DMA_5 (_U_(0x1) << HSTIFR_DMA_5_Pos) /**< (HSTIFR) DMA Channel 5 Interrupt Set Mask */
+#define HSTIFR_DMA_6_Pos 31 /**< (HSTIFR) DMA Channel 6 Interrupt Set Position */
+#define HSTIFR_DMA_6 (_U_(0x1) << HSTIFR_DMA_6_Pos) /**< (HSTIFR) DMA Channel 6 Interrupt Set Mask */
+#define HSTIFR_Msk _U_(0xFE00007F) /**< (HSTIFR) Register Mask */
+
+#define HSTIFR_DMA__Pos 25 /**< (HSTIFR Position) DMA Channel 6 Interrupt Set */
+#define HSTIFR_DMA_ (_U_(0x7F) << HSTIFR_DMA__Pos) /**< (HSTIFR Mask) DMA_ */
+
+/* -------- HSTIMR : (USBHS Offset: 0x410) (R/ 32) Host Global Interrupt Mask Register -------- */
+
+#define HSTIMR_OFFSET (0x410) /**< (HSTIMR) Host Global Interrupt Mask Register Offset */
+
+#define HSTIMR_DCONNIE_Pos 0 /**< (HSTIMR) Device Connection Interrupt Enable Position */
+#define HSTIMR_DCONNIE (_U_(0x1) << HSTIMR_DCONNIE_Pos) /**< (HSTIMR) Device Connection Interrupt Enable Mask */
+#define HSTIMR_DDISCIE_Pos 1 /**< (HSTIMR) Device Disconnection Interrupt Enable Position */
+#define HSTIMR_DDISCIE (_U_(0x1) << HSTIMR_DDISCIE_Pos) /**< (HSTIMR) Device Disconnection Interrupt Enable Mask */
+#define HSTIMR_RSTIE_Pos 2 /**< (HSTIMR) USB Reset Sent Interrupt Enable Position */
+#define HSTIMR_RSTIE (_U_(0x1) << HSTIMR_RSTIE_Pos) /**< (HSTIMR) USB Reset Sent Interrupt Enable Mask */
+#define HSTIMR_RSMEDIE_Pos 3 /**< (HSTIMR) Downstream Resume Sent Interrupt Enable Position */
+#define HSTIMR_RSMEDIE (_U_(0x1) << HSTIMR_RSMEDIE_Pos) /**< (HSTIMR) Downstream Resume Sent Interrupt Enable Mask */
+#define HSTIMR_RXRSMIE_Pos 4 /**< (HSTIMR) Upstream Resume Received Interrupt Enable Position */
+#define HSTIMR_RXRSMIE (_U_(0x1) << HSTIMR_RXRSMIE_Pos) /**< (HSTIMR) Upstream Resume Received Interrupt Enable Mask */
+#define HSTIMR_HSOFIE_Pos 5 /**< (HSTIMR) Host Start of Frame Interrupt Enable Position */
+#define HSTIMR_HSOFIE (_U_(0x1) << HSTIMR_HSOFIE_Pos) /**< (HSTIMR) Host Start of Frame Interrupt Enable Mask */
+#define HSTIMR_HWUPIE_Pos 6 /**< (HSTIMR) Host Wake-Up Interrupt Enable Position */
+#define HSTIMR_HWUPIE (_U_(0x1) << HSTIMR_HWUPIE_Pos) /**< (HSTIMR) Host Wake-Up Interrupt Enable Mask */
+#define HSTIMR_PEP_0_Pos 8 /**< (HSTIMR) Pipe 0 Interrupt Enable Position */
+#define HSTIMR_PEP_0 (_U_(0x1) << HSTIMR_PEP_0_Pos) /**< (HSTIMR) Pipe 0 Interrupt Enable Mask */
+#define HSTIMR_PEP_1_Pos 9 /**< (HSTIMR) Pipe 1 Interrupt Enable Position */
+#define HSTIMR_PEP_1 (_U_(0x1) << HSTIMR_PEP_1_Pos) /**< (HSTIMR) Pipe 1 Interrupt Enable Mask */
+#define HSTIMR_PEP_2_Pos 10 /**< (HSTIMR) Pipe 2 Interrupt Enable Position */
+#define HSTIMR_PEP_2 (_U_(0x1) << HSTIMR_PEP_2_Pos) /**< (HSTIMR) Pipe 2 Interrupt Enable Mask */
+#define HSTIMR_PEP_3_Pos 11 /**< (HSTIMR) Pipe 3 Interrupt Enable Position */
+#define HSTIMR_PEP_3 (_U_(0x1) << HSTIMR_PEP_3_Pos) /**< (HSTIMR) Pipe 3 Interrupt Enable Mask */
+#define HSTIMR_PEP_4_Pos 12 /**< (HSTIMR) Pipe 4 Interrupt Enable Position */
+#define HSTIMR_PEP_4 (_U_(0x1) << HSTIMR_PEP_4_Pos) /**< (HSTIMR) Pipe 4 Interrupt Enable Mask */
+#define HSTIMR_PEP_5_Pos 13 /**< (HSTIMR) Pipe 5 Interrupt Enable Position */
+#define HSTIMR_PEP_5 (_U_(0x1) << HSTIMR_PEP_5_Pos) /**< (HSTIMR) Pipe 5 Interrupt Enable Mask */
+#define HSTIMR_PEP_6_Pos 14 /**< (HSTIMR) Pipe 6 Interrupt Enable Position */
+#define HSTIMR_PEP_6 (_U_(0x1) << HSTIMR_PEP_6_Pos) /**< (HSTIMR) Pipe 6 Interrupt Enable Mask */
+#define HSTIMR_PEP_7_Pos 15 /**< (HSTIMR) Pipe 7 Interrupt Enable Position */
+#define HSTIMR_PEP_7 (_U_(0x1) << HSTIMR_PEP_7_Pos) /**< (HSTIMR) Pipe 7 Interrupt Enable Mask */
+#define HSTIMR_PEP_8_Pos 16 /**< (HSTIMR) Pipe 8 Interrupt Enable Position */
+#define HSTIMR_PEP_8 (_U_(0x1) << HSTIMR_PEP_8_Pos) /**< (HSTIMR) Pipe 8 Interrupt Enable Mask */
+#define HSTIMR_PEP_9_Pos 17 /**< (HSTIMR) Pipe 9 Interrupt Enable Position */
+#define HSTIMR_PEP_9 (_U_(0x1) << HSTIMR_PEP_9_Pos) /**< (HSTIMR) Pipe 9 Interrupt Enable Mask */
+#define HSTIMR_DMA_0_Pos 25 /**< (HSTIMR) DMA Channel 0 Interrupt Enable Position */
+#define HSTIMR_DMA_0 (_U_(0x1) << HSTIMR_DMA_0_Pos) /**< (HSTIMR) DMA Channel 0 Interrupt Enable Mask */
+#define HSTIMR_DMA_1_Pos 26 /**< (HSTIMR) DMA Channel 1 Interrupt Enable Position */
+#define HSTIMR_DMA_1 (_U_(0x1) << HSTIMR_DMA_1_Pos) /**< (HSTIMR) DMA Channel 1 Interrupt Enable Mask */
+#define HSTIMR_DMA_2_Pos 27 /**< (HSTIMR) DMA Channel 2 Interrupt Enable Position */
+#define HSTIMR_DMA_2 (_U_(0x1) << HSTIMR_DMA_2_Pos) /**< (HSTIMR) DMA Channel 2 Interrupt Enable Mask */
+#define HSTIMR_DMA_3_Pos 28 /**< (HSTIMR) DMA Channel 3 Interrupt Enable Position */
+#define HSTIMR_DMA_3 (_U_(0x1) << HSTIMR_DMA_3_Pos) /**< (HSTIMR) DMA Channel 3 Interrupt Enable Mask */
+#define HSTIMR_DMA_4_Pos 29 /**< (HSTIMR) DMA Channel 4 Interrupt Enable Position */
+#define HSTIMR_DMA_4 (_U_(0x1) << HSTIMR_DMA_4_Pos) /**< (HSTIMR) DMA Channel 4 Interrupt Enable Mask */
+#define HSTIMR_DMA_5_Pos 30 /**< (HSTIMR) DMA Channel 5 Interrupt Enable Position */
+#define HSTIMR_DMA_5 (_U_(0x1) << HSTIMR_DMA_5_Pos) /**< (HSTIMR) DMA Channel 5 Interrupt Enable Mask */
+#define HSTIMR_DMA_6_Pos 31 /**< (HSTIMR) DMA Channel 6 Interrupt Enable Position */
+#define HSTIMR_DMA_6 (_U_(0x1) << HSTIMR_DMA_6_Pos) /**< (HSTIMR) DMA Channel 6 Interrupt Enable Mask */
+#define HSTIMR_Msk _U_(0xFE03FF7F) /**< (HSTIMR) Register Mask */
+
+#define HSTIMR_PEP__Pos 8 /**< (HSTIMR Position) Pipe x Interrupt Enable */
+#define HSTIMR_PEP_ (_U_(0x3FF) << HSTIMR_PEP__Pos) /**< (HSTIMR Mask) PEP_ */
+#define HSTIMR_DMA__Pos 25 /**< (HSTIMR Position) DMA Channel 6 Interrupt Enable */
+#define HSTIMR_DMA_ (_U_(0x7F) << HSTIMR_DMA__Pos) /**< (HSTIMR Mask) DMA_ */
+
+/* -------- HSTIDR : (USBHS Offset: 0x414) (/W 32) Host Global Interrupt Disable Register -------- */
+
+#define HSTIDR_OFFSET (0x414) /**< (HSTIDR) Host Global Interrupt Disable Register Offset */
+
+#define HSTIDR_DCONNIEC_Pos 0 /**< (HSTIDR) Device Connection Interrupt Disable Position */
+#define HSTIDR_DCONNIEC (_U_(0x1) << HSTIDR_DCONNIEC_Pos) /**< (HSTIDR) Device Connection Interrupt Disable Mask */
+#define HSTIDR_DDISCIEC_Pos 1 /**< (HSTIDR) Device Disconnection Interrupt Disable Position */
+#define HSTIDR_DDISCIEC (_U_(0x1) << HSTIDR_DDISCIEC_Pos) /**< (HSTIDR) Device Disconnection Interrupt Disable Mask */
+#define HSTIDR_RSTIEC_Pos 2 /**< (HSTIDR) USB Reset Sent Interrupt Disable Position */
+#define HSTIDR_RSTIEC (_U_(0x1) << HSTIDR_RSTIEC_Pos) /**< (HSTIDR) USB Reset Sent Interrupt Disable Mask */
+#define HSTIDR_RSMEDIEC_Pos 3 /**< (HSTIDR) Downstream Resume Sent Interrupt Disable Position */
+#define HSTIDR_RSMEDIEC (_U_(0x1) << HSTIDR_RSMEDIEC_Pos) /**< (HSTIDR) Downstream Resume Sent Interrupt Disable Mask */
+#define HSTIDR_RXRSMIEC_Pos 4 /**< (HSTIDR) Upstream Resume Received Interrupt Disable Position */
+#define HSTIDR_RXRSMIEC (_U_(0x1) << HSTIDR_RXRSMIEC_Pos) /**< (HSTIDR) Upstream Resume Received Interrupt Disable Mask */
+#define HSTIDR_HSOFIEC_Pos 5 /**< (HSTIDR) Host Start of Frame Interrupt Disable Position */
+#define HSTIDR_HSOFIEC (_U_(0x1) << HSTIDR_HSOFIEC_Pos) /**< (HSTIDR) Host Start of Frame Interrupt Disable Mask */
+#define HSTIDR_HWUPIEC_Pos 6 /**< (HSTIDR) Host Wake-Up Interrupt Disable Position */
+#define HSTIDR_HWUPIEC (_U_(0x1) << HSTIDR_HWUPIEC_Pos) /**< (HSTIDR) Host Wake-Up Interrupt Disable Mask */
+#define HSTIDR_PEP_0_Pos 8 /**< (HSTIDR) Pipe 0 Interrupt Disable Position */
+#define HSTIDR_PEP_0 (_U_(0x1) << HSTIDR_PEP_0_Pos) /**< (HSTIDR) Pipe 0 Interrupt Disable Mask */
+#define HSTIDR_PEP_1_Pos 9 /**< (HSTIDR) Pipe 1 Interrupt Disable Position */
+#define HSTIDR_PEP_1 (_U_(0x1) << HSTIDR_PEP_1_Pos) /**< (HSTIDR) Pipe 1 Interrupt Disable Mask */
+#define HSTIDR_PEP_2_Pos 10 /**< (HSTIDR) Pipe 2 Interrupt Disable Position */
+#define HSTIDR_PEP_2 (_U_(0x1) << HSTIDR_PEP_2_Pos) /**< (HSTIDR) Pipe 2 Interrupt Disable Mask */
+#define HSTIDR_PEP_3_Pos 11 /**< (HSTIDR) Pipe 3 Interrupt Disable Position */
+#define HSTIDR_PEP_3 (_U_(0x1) << HSTIDR_PEP_3_Pos) /**< (HSTIDR) Pipe 3 Interrupt Disable Mask */
+#define HSTIDR_PEP_4_Pos 12 /**< (HSTIDR) Pipe 4 Interrupt Disable Position */
+#define HSTIDR_PEP_4 (_U_(0x1) << HSTIDR_PEP_4_Pos) /**< (HSTIDR) Pipe 4 Interrupt Disable Mask */
+#define HSTIDR_PEP_5_Pos 13 /**< (HSTIDR) Pipe 5 Interrupt Disable Position */
+#define HSTIDR_PEP_5 (_U_(0x1) << HSTIDR_PEP_5_Pos) /**< (HSTIDR) Pipe 5 Interrupt Disable Mask */
+#define HSTIDR_PEP_6_Pos 14 /**< (HSTIDR) Pipe 6 Interrupt Disable Position */
+#define HSTIDR_PEP_6 (_U_(0x1) << HSTIDR_PEP_6_Pos) /**< (HSTIDR) Pipe 6 Interrupt Disable Mask */
+#define HSTIDR_PEP_7_Pos 15 /**< (HSTIDR) Pipe 7 Interrupt Disable Position */
+#define HSTIDR_PEP_7 (_U_(0x1) << HSTIDR_PEP_7_Pos) /**< (HSTIDR) Pipe 7 Interrupt Disable Mask */
+#define HSTIDR_PEP_8_Pos 16 /**< (HSTIDR) Pipe 8 Interrupt Disable Position */
+#define HSTIDR_PEP_8 (_U_(0x1) << HSTIDR_PEP_8_Pos) /**< (HSTIDR) Pipe 8 Interrupt Disable Mask */
+#define HSTIDR_PEP_9_Pos 17 /**< (HSTIDR) Pipe 9 Interrupt Disable Position */
+#define HSTIDR_PEP_9 (_U_(0x1) << HSTIDR_PEP_9_Pos) /**< (HSTIDR) Pipe 9 Interrupt Disable Mask */
+#define HSTIDR_DMA_0_Pos 25 /**< (HSTIDR) DMA Channel 0 Interrupt Disable Position */
+#define HSTIDR_DMA_0 (_U_(0x1) << HSTIDR_DMA_0_Pos) /**< (HSTIDR) DMA Channel 0 Interrupt Disable Mask */
+#define HSTIDR_DMA_1_Pos 26 /**< (HSTIDR) DMA Channel 1 Interrupt Disable Position */
+#define HSTIDR_DMA_1 (_U_(0x1) << HSTIDR_DMA_1_Pos) /**< (HSTIDR) DMA Channel 1 Interrupt Disable Mask */
+#define HSTIDR_DMA_2_Pos 27 /**< (HSTIDR) DMA Channel 2 Interrupt Disable Position */
+#define HSTIDR_DMA_2 (_U_(0x1) << HSTIDR_DMA_2_Pos) /**< (HSTIDR) DMA Channel 2 Interrupt Disable Mask */
+#define HSTIDR_DMA_3_Pos 28 /**< (HSTIDR) DMA Channel 3 Interrupt Disable Position */
+#define HSTIDR_DMA_3 (_U_(0x1) << HSTIDR_DMA_3_Pos) /**< (HSTIDR) DMA Channel 3 Interrupt Disable Mask */
+#define HSTIDR_DMA_4_Pos 29 /**< (HSTIDR) DMA Channel 4 Interrupt Disable Position */
+#define HSTIDR_DMA_4 (_U_(0x1) << HSTIDR_DMA_4_Pos) /**< (HSTIDR) DMA Channel 4 Interrupt Disable Mask */
+#define HSTIDR_DMA_5_Pos 30 /**< (HSTIDR) DMA Channel 5 Interrupt Disable Position */
+#define HSTIDR_DMA_5 (_U_(0x1) << HSTIDR_DMA_5_Pos) /**< (HSTIDR) DMA Channel 5 Interrupt Disable Mask */
+#define HSTIDR_DMA_6_Pos 31 /**< (HSTIDR) DMA Channel 6 Interrupt Disable Position */
+#define HSTIDR_DMA_6 (_U_(0x1) << HSTIDR_DMA_6_Pos) /**< (HSTIDR) DMA Channel 6 Interrupt Disable Mask */
+#define HSTIDR_Msk _U_(0xFE03FF7F) /**< (HSTIDR) Register Mask */
+
+#define HSTIDR_PEP__Pos 8 /**< (HSTIDR Position) Pipe x Interrupt Disable */
+#define HSTIDR_PEP_ (_U_(0x3FF) << HSTIDR_PEP__Pos) /**< (HSTIDR Mask) PEP_ */
+#define HSTIDR_DMA__Pos 25 /**< (HSTIDR Position) DMA Channel 6 Interrupt Disable */
+#define HSTIDR_DMA_ (_U_(0x7F) << HSTIDR_DMA__Pos) /**< (HSTIDR Mask) DMA_ */
+
+/* -------- HSTIER : (USBHS Offset: 0x418) (/W 32) Host Global Interrupt Enable Register -------- */
+
+#define HSTIER_OFFSET (0x418) /**< (HSTIER) Host Global Interrupt Enable Register Offset */
+
+#define HSTIER_DCONNIES_Pos 0 /**< (HSTIER) Device Connection Interrupt Enable Position */
+#define HSTIER_DCONNIES (_U_(0x1) << HSTIER_DCONNIES_Pos) /**< (HSTIER) Device Connection Interrupt Enable Mask */
+#define HSTIER_DDISCIES_Pos 1 /**< (HSTIER) Device Disconnection Interrupt Enable Position */
+#define HSTIER_DDISCIES (_U_(0x1) << HSTIER_DDISCIES_Pos) /**< (HSTIER) Device Disconnection Interrupt Enable Mask */
+#define HSTIER_RSTIES_Pos 2 /**< (HSTIER) USB Reset Sent Interrupt Enable Position */
+#define HSTIER_RSTIES (_U_(0x1) << HSTIER_RSTIES_Pos) /**< (HSTIER) USB Reset Sent Interrupt Enable Mask */
+#define HSTIER_RSMEDIES_Pos 3 /**< (HSTIER) Downstream Resume Sent Interrupt Enable Position */
+#define HSTIER_RSMEDIES (_U_(0x1) << HSTIER_RSMEDIES_Pos) /**< (HSTIER) Downstream Resume Sent Interrupt Enable Mask */
+#define HSTIER_RXRSMIES_Pos 4 /**< (HSTIER) Upstream Resume Received Interrupt Enable Position */
+#define HSTIER_RXRSMIES (_U_(0x1) << HSTIER_RXRSMIES_Pos) /**< (HSTIER) Upstream Resume Received Interrupt Enable Mask */
+#define HSTIER_HSOFIES_Pos 5 /**< (HSTIER) Host Start of Frame Interrupt Enable Position */
+#define HSTIER_HSOFIES (_U_(0x1) << HSTIER_HSOFIES_Pos) /**< (HSTIER) Host Start of Frame Interrupt Enable Mask */
+#define HSTIER_HWUPIES_Pos 6 /**< (HSTIER) Host Wake-Up Interrupt Enable Position */
+#define HSTIER_HWUPIES (_U_(0x1) << HSTIER_HWUPIES_Pos) /**< (HSTIER) Host Wake-Up Interrupt Enable Mask */
+#define HSTIER_PEP_0_Pos 8 /**< (HSTIER) Pipe 0 Interrupt Enable Position */
+#define HSTIER_PEP_0 (_U_(0x1) << HSTIER_PEP_0_Pos) /**< (HSTIER) Pipe 0 Interrupt Enable Mask */
+#define HSTIER_PEP_1_Pos 9 /**< (HSTIER) Pipe 1 Interrupt Enable Position */
+#define HSTIER_PEP_1 (_U_(0x1) << HSTIER_PEP_1_Pos) /**< (HSTIER) Pipe 1 Interrupt Enable Mask */
+#define HSTIER_PEP_2_Pos 10 /**< (HSTIER) Pipe 2 Interrupt Enable Position */
+#define HSTIER_PEP_2 (_U_(0x1) << HSTIER_PEP_2_Pos) /**< (HSTIER) Pipe 2 Interrupt Enable Mask */
+#define HSTIER_PEP_3_Pos 11 /**< (HSTIER) Pipe 3 Interrupt Enable Position */
+#define HSTIER_PEP_3 (_U_(0x1) << HSTIER_PEP_3_Pos) /**< (HSTIER) Pipe 3 Interrupt Enable Mask */
+#define HSTIER_PEP_4_Pos 12 /**< (HSTIER) Pipe 4 Interrupt Enable Position */
+#define HSTIER_PEP_4 (_U_(0x1) << HSTIER_PEP_4_Pos) /**< (HSTIER) Pipe 4 Interrupt Enable Mask */
+#define HSTIER_PEP_5_Pos 13 /**< (HSTIER) Pipe 5 Interrupt Enable Position */
+#define HSTIER_PEP_5 (_U_(0x1) << HSTIER_PEP_5_Pos) /**< (HSTIER) Pipe 5 Interrupt Enable Mask */
+#define HSTIER_PEP_6_Pos 14 /**< (HSTIER) Pipe 6 Interrupt Enable Position */
+#define HSTIER_PEP_6 (_U_(0x1) << HSTIER_PEP_6_Pos) /**< (HSTIER) Pipe 6 Interrupt Enable Mask */
+#define HSTIER_PEP_7_Pos 15 /**< (HSTIER) Pipe 7 Interrupt Enable Position */
+#define HSTIER_PEP_7 (_U_(0x1) << HSTIER_PEP_7_Pos) /**< (HSTIER) Pipe 7 Interrupt Enable Mask */
+#define HSTIER_PEP_8_Pos 16 /**< (HSTIER) Pipe 8 Interrupt Enable Position */
+#define HSTIER_PEP_8 (_U_(0x1) << HSTIER_PEP_8_Pos) /**< (HSTIER) Pipe 8 Interrupt Enable Mask */
+#define HSTIER_PEP_9_Pos 17 /**< (HSTIER) Pipe 9 Interrupt Enable Position */
+#define HSTIER_PEP_9 (_U_(0x1) << HSTIER_PEP_9_Pos) /**< (HSTIER) Pipe 9 Interrupt Enable Mask */
+#define HSTIER_DMA_0_Pos 25 /**< (HSTIER) DMA Channel 0 Interrupt Enable Position */
+#define HSTIER_DMA_0 (_U_(0x1) << HSTIER_DMA_0_Pos) /**< (HSTIER) DMA Channel 0 Interrupt Enable Mask */
+#define HSTIER_DMA_1_Pos 26 /**< (HSTIER) DMA Channel 1 Interrupt Enable Position */
+#define HSTIER_DMA_1 (_U_(0x1) << HSTIER_DMA_1_Pos) /**< (HSTIER) DMA Channel 1 Interrupt Enable Mask */
+#define HSTIER_DMA_2_Pos 27 /**< (HSTIER) DMA Channel 2 Interrupt Enable Position */
+#define HSTIER_DMA_2 (_U_(0x1) << HSTIER_DMA_2_Pos) /**< (HSTIER) DMA Channel 2 Interrupt Enable Mask */
+#define HSTIER_DMA_3_Pos 28 /**< (HSTIER) DMA Channel 3 Interrupt Enable Position */
+#define HSTIER_DMA_3 (_U_(0x1) << HSTIER_DMA_3_Pos) /**< (HSTIER) DMA Channel 3 Interrupt Enable Mask */
+#define HSTIER_DMA_4_Pos 29 /**< (HSTIER) DMA Channel 4 Interrupt Enable Position */
+#define HSTIER_DMA_4 (_U_(0x1) << HSTIER_DMA_4_Pos) /**< (HSTIER) DMA Channel 4 Interrupt Enable Mask */
+#define HSTIER_DMA_5_Pos 30 /**< (HSTIER) DMA Channel 5 Interrupt Enable Position */
+#define HSTIER_DMA_5 (_U_(0x1) << HSTIER_DMA_5_Pos) /**< (HSTIER) DMA Channel 5 Interrupt Enable Mask */
+#define HSTIER_DMA_6_Pos 31 /**< (HSTIER) DMA Channel 6 Interrupt Enable Position */
+#define HSTIER_DMA_6 (_U_(0x1) << HSTIER_DMA_6_Pos) /**< (HSTIER) DMA Channel 6 Interrupt Enable Mask */
+#define HSTIER_Msk _U_(0xFE03FF7F) /**< (HSTIER) Register Mask */
+
+#define HSTIER_PEP__Pos 8 /**< (HSTIER Position) Pipe x Interrupt Enable */
+#define HSTIER_PEP_ (_U_(0x3FF) << HSTIER_PEP__Pos) /**< (HSTIER Mask) PEP_ */
+#define HSTIER_DMA__Pos 25 /**< (HSTIER Position) DMA Channel 6 Interrupt Enable */
+#define HSTIER_DMA_ (_U_(0x7F) << HSTIER_DMA__Pos) /**< (HSTIER Mask) DMA_ */
+
+/* -------- HSTPIP : (USBHS Offset: 0x41c) (R/W 32) Host Pipe Register -------- */
+
+#define HSTPIP_OFFSET (0x41C) /**< (HSTPIP) Host Pipe Register Offset */
+
+#define HSTPIP_PEN0_Pos 0 /**< (HSTPIP) Pipe 0 Enable Position */
+#define HSTPIP_PEN0 (_U_(0x1) << HSTPIP_PEN0_Pos) /**< (HSTPIP) Pipe 0 Enable Mask */
+#define HSTPIP_PEN1_Pos 1 /**< (HSTPIP) Pipe 1 Enable Position */
+#define HSTPIP_PEN1 (_U_(0x1) << HSTPIP_PEN1_Pos) /**< (HSTPIP) Pipe 1 Enable Mask */
+#define HSTPIP_PEN2_Pos 2 /**< (HSTPIP) Pipe 2 Enable Position */
+#define HSTPIP_PEN2 (_U_(0x1) << HSTPIP_PEN2_Pos) /**< (HSTPIP) Pipe 2 Enable Mask */
+#define HSTPIP_PEN3_Pos 3 /**< (HSTPIP) Pipe 3 Enable Position */
+#define HSTPIP_PEN3 (_U_(0x1) << HSTPIP_PEN3_Pos) /**< (HSTPIP) Pipe 3 Enable Mask */
+#define HSTPIP_PEN4_Pos 4 /**< (HSTPIP) Pipe 4 Enable Position */
+#define HSTPIP_PEN4 (_U_(0x1) << HSTPIP_PEN4_Pos) /**< (HSTPIP) Pipe 4 Enable Mask */
+#define HSTPIP_PEN5_Pos 5 /**< (HSTPIP) Pipe 5 Enable Position */
+#define HSTPIP_PEN5 (_U_(0x1) << HSTPIP_PEN5_Pos) /**< (HSTPIP) Pipe 5 Enable Mask */
+#define HSTPIP_PEN6_Pos 6 /**< (HSTPIP) Pipe 6 Enable Position */
+#define HSTPIP_PEN6 (_U_(0x1) << HSTPIP_PEN6_Pos) /**< (HSTPIP) Pipe 6 Enable Mask */
+#define HSTPIP_PEN7_Pos 7 /**< (HSTPIP) Pipe 7 Enable Position */
+#define HSTPIP_PEN7 (_U_(0x1) << HSTPIP_PEN7_Pos) /**< (HSTPIP) Pipe 7 Enable Mask */
+#define HSTPIP_PEN8_Pos 8 /**< (HSTPIP) Pipe 8 Enable Position */
+#define HSTPIP_PEN8 (_U_(0x1) << HSTPIP_PEN8_Pos) /**< (HSTPIP) Pipe 8 Enable Mask */
+#define HSTPIP_PRST0_Pos 16 /**< (HSTPIP) Pipe 0 Reset Position */
+#define HSTPIP_PRST0 (_U_(0x1) << HSTPIP_PRST0_Pos) /**< (HSTPIP) Pipe 0 Reset Mask */
+#define HSTPIP_PRST1_Pos 17 /**< (HSTPIP) Pipe 1 Reset Position */
+#define HSTPIP_PRST1 (_U_(0x1) << HSTPIP_PRST1_Pos) /**< (HSTPIP) Pipe 1 Reset Mask */
+#define HSTPIP_PRST2_Pos 18 /**< (HSTPIP) Pipe 2 Reset Position */
+#define HSTPIP_PRST2 (_U_(0x1) << HSTPIP_PRST2_Pos) /**< (HSTPIP) Pipe 2 Reset Mask */
+#define HSTPIP_PRST3_Pos 19 /**< (HSTPIP) Pipe 3 Reset Position */
+#define HSTPIP_PRST3 (_U_(0x1) << HSTPIP_PRST3_Pos) /**< (HSTPIP) Pipe 3 Reset Mask */
+#define HSTPIP_PRST4_Pos 20 /**< (HSTPIP) Pipe 4 Reset Position */
+#define HSTPIP_PRST4 (_U_(0x1) << HSTPIP_PRST4_Pos) /**< (HSTPIP) Pipe 4 Reset Mask */
+#define HSTPIP_PRST5_Pos 21 /**< (HSTPIP) Pipe 5 Reset Position */
+#define HSTPIP_PRST5 (_U_(0x1) << HSTPIP_PRST5_Pos) /**< (HSTPIP) Pipe 5 Reset Mask */
+#define HSTPIP_PRST6_Pos 22 /**< (HSTPIP) Pipe 6 Reset Position */
+#define HSTPIP_PRST6 (_U_(0x1) << HSTPIP_PRST6_Pos) /**< (HSTPIP) Pipe 6 Reset Mask */
+#define HSTPIP_PRST7_Pos 23 /**< (HSTPIP) Pipe 7 Reset Position */
+#define HSTPIP_PRST7 (_U_(0x1) << HSTPIP_PRST7_Pos) /**< (HSTPIP) Pipe 7 Reset Mask */
+#define HSTPIP_PRST8_Pos 24 /**< (HSTPIP) Pipe 8 Reset Position */
+#define HSTPIP_PRST8 (_U_(0x1) << HSTPIP_PRST8_Pos) /**< (HSTPIP) Pipe 8 Reset Mask */
+#define HSTPIP_Msk _U_(0x1FF01FF) /**< (HSTPIP) Register Mask */
+
+#define HSTPIP_PEN_Pos 0 /**< (HSTPIP Position) Pipe x Enable */
+#define HSTPIP_PEN (_U_(0x1FF) << HSTPIP_PEN_Pos) /**< (HSTPIP Mask) PEN */
+#define HSTPIP_PRST_Pos 16 /**< (HSTPIP Position) Pipe 8 Reset */
+#define HSTPIP_PRST (_U_(0x1FF) << HSTPIP_PRST_Pos) /**< (HSTPIP Mask) PRST */
+
+/* -------- HSTFNUM : (USBHS Offset: 0x420) (R/W 32) Host Frame Number Register -------- */
+
+#define HSTFNUM_OFFSET (0x420) /**< (HSTFNUM) Host Frame Number Register Offset */
+
+#define HSTFNUM_MFNUM_Pos 0 /**< (HSTFNUM) Micro Frame Number Position */
+#define HSTFNUM_MFNUM (_U_(0x7) << HSTFNUM_MFNUM_Pos) /**< (HSTFNUM) Micro Frame Number Mask */
+#define HSTFNUM_FNUM_Pos 3 /**< (HSTFNUM) Frame Number Position */
+#define HSTFNUM_FNUM (_U_(0x7FF) << HSTFNUM_FNUM_Pos) /**< (HSTFNUM) Frame Number Mask */
+#define HSTFNUM_FLENHIGH_Pos 16 /**< (HSTFNUM) Frame Length Position */
+#define HSTFNUM_FLENHIGH (_U_(0xFF) << HSTFNUM_FLENHIGH_Pos) /**< (HSTFNUM) Frame Length Mask */
+#define HSTFNUM_Msk _U_(0xFF3FFF) /**< (HSTFNUM) Register Mask */
+
+
+/* -------- HSTADDR1 : (USBHS Offset: 0x424) (R/W 32) Host Address 1 Register -------- */
+
+#define HSTADDR1_OFFSET (0x424) /**< (HSTADDR1) Host Address 1 Register Offset */
+
+#define HSTADDR1_HSTADDRP0_Pos 0 /**< (HSTADDR1) USB Host Address Position */
+#define HSTADDR1_HSTADDRP0 (_U_(0x7F) << HSTADDR1_HSTADDRP0_Pos) /**< (HSTADDR1) USB Host Address Mask */
+#define HSTADDR1_HSTADDRP1_Pos 8 /**< (HSTADDR1) USB Host Address Position */
+#define HSTADDR1_HSTADDRP1 (_U_(0x7F) << HSTADDR1_HSTADDRP1_Pos) /**< (HSTADDR1) USB Host Address Mask */
+#define HSTADDR1_HSTADDRP2_Pos 16 /**< (HSTADDR1) USB Host Address Position */
+#define HSTADDR1_HSTADDRP2 (_U_(0x7F) << HSTADDR1_HSTADDRP2_Pos) /**< (HSTADDR1) USB Host Address Mask */
+#define HSTADDR1_HSTADDRP3_Pos 24 /**< (HSTADDR1) USB Host Address Position */
+#define HSTADDR1_HSTADDRP3 (_U_(0x7F) << HSTADDR1_HSTADDRP3_Pos) /**< (HSTADDR1) USB Host Address Mask */
+#define HSTADDR1_Msk _U_(0x7F7F7F7F) /**< (HSTADDR1) Register Mask */
+
+
+/* -------- HSTADDR2 : (USBHS Offset: 0x428) (R/W 32) Host Address 2 Register -------- */
+
+#define HSTADDR2_OFFSET (0x428) /**< (HSTADDR2) Host Address 2 Register Offset */
+
+#define HSTADDR2_HSTADDRP4_Pos 0 /**< (HSTADDR2) USB Host Address Position */
+#define HSTADDR2_HSTADDRP4 (_U_(0x7F) << HSTADDR2_HSTADDRP4_Pos) /**< (HSTADDR2) USB Host Address Mask */
+#define HSTADDR2_HSTADDRP5_Pos 8 /**< (HSTADDR2) USB Host Address Position */
+#define HSTADDR2_HSTADDRP5 (_U_(0x7F) << HSTADDR2_HSTADDRP5_Pos) /**< (HSTADDR2) USB Host Address Mask */
+#define HSTADDR2_HSTADDRP6_Pos 16 /**< (HSTADDR2) USB Host Address Position */
+#define HSTADDR2_HSTADDRP6 (_U_(0x7F) << HSTADDR2_HSTADDRP6_Pos) /**< (HSTADDR2) USB Host Address Mask */
+#define HSTADDR2_HSTADDRP7_Pos 24 /**< (HSTADDR2) USB Host Address Position */
+#define HSTADDR2_HSTADDRP7 (_U_(0x7F) << HSTADDR2_HSTADDRP7_Pos) /**< (HSTADDR2) USB Host Address Mask */
+#define HSTADDR2_Msk _U_(0x7F7F7F7F) /**< (HSTADDR2) Register Mask */
+
+
+/* -------- HSTADDR3 : (USBHS Offset: 0x42c) (R/W 32) Host Address 3 Register -------- */
+
+#define HSTADDR3_OFFSET (0x42C) /**< (HSTADDR3) Host Address 3 Register Offset */
+
+#define HSTADDR3_HSTADDRP8_Pos 0 /**< (HSTADDR3) USB Host Address Position */
+#define HSTADDR3_HSTADDRP8 (_U_(0x7F) << HSTADDR3_HSTADDRP8_Pos) /**< (HSTADDR3) USB Host Address Mask */
+#define HSTADDR3_HSTADDRP9_Pos 8 /**< (HSTADDR3) USB Host Address Position */
+#define HSTADDR3_HSTADDRP9 (_U_(0x7F) << HSTADDR3_HSTADDRP9_Pos) /**< (HSTADDR3) USB Host Address Mask */
+#define HSTADDR3_Msk _U_(0x7F7F) /**< (HSTADDR3) Register Mask */
+
+
+/* -------- HSTPIPCFG : (USBHS Offset: 0x500) (R/W 32) Host Pipe Configuration Register -------- */
+
+#define HSTPIPCFG_OFFSET (0x500) /**< (HSTPIPCFG) Host Pipe Configuration Register Offset */
+
+#define HSTPIPCFG_ALLOC_Pos 1 /**< (HSTPIPCFG) Pipe Memory Allocate Position */
+#define HSTPIPCFG_ALLOC (_U_(0x1) << HSTPIPCFG_ALLOC_Pos) /**< (HSTPIPCFG) Pipe Memory Allocate Mask */
+#define HSTPIPCFG_PBK_Pos 2 /**< (HSTPIPCFG) Pipe Banks Position */
+#define HSTPIPCFG_PBK (_U_(0x3) << HSTPIPCFG_PBK_Pos) /**< (HSTPIPCFG) Pipe Banks Mask */
+#define HSTPIPCFG_PBK_1_BANK_Val _U_(0x0) /**< (HSTPIPCFG) Single-bank pipe */
+#define HSTPIPCFG_PBK_2_BANK_Val _U_(0x1) /**< (HSTPIPCFG) Double-bank pipe */
+#define HSTPIPCFG_PBK_3_BANK_Val _U_(0x2) /**< (HSTPIPCFG) Triple-bank pipe */
+#define HSTPIPCFG_PBK_1_BANK (HSTPIPCFG_PBK_1_BANK_Val << HSTPIPCFG_PBK_Pos) /**< (HSTPIPCFG) Single-bank pipe Position */
+#define HSTPIPCFG_PBK_2_BANK (HSTPIPCFG_PBK_2_BANK_Val << HSTPIPCFG_PBK_Pos) /**< (HSTPIPCFG) Double-bank pipe Position */
+#define HSTPIPCFG_PBK_3_BANK (HSTPIPCFG_PBK_3_BANK_Val << HSTPIPCFG_PBK_Pos) /**< (HSTPIPCFG) Triple-bank pipe Position */
+#define HSTPIPCFG_PSIZE_Pos 4 /**< (HSTPIPCFG) Pipe Size Position */
+#define HSTPIPCFG_PSIZE (_U_(0x7) << HSTPIPCFG_PSIZE_Pos) /**< (HSTPIPCFG) Pipe Size Mask */
+#define HSTPIPCFG_PSIZE_8_BYTE_Val _U_(0x0) /**< (HSTPIPCFG) 8 bytes */
+#define HSTPIPCFG_PSIZE_16_BYTE_Val _U_(0x1) /**< (HSTPIPCFG) 16 bytes */
+#define HSTPIPCFG_PSIZE_32_BYTE_Val _U_(0x2) /**< (HSTPIPCFG) 32 bytes */
+#define HSTPIPCFG_PSIZE_64_BYTE_Val _U_(0x3) /**< (HSTPIPCFG) 64 bytes */
+#define HSTPIPCFG_PSIZE_128_BYTE_Val _U_(0x4) /**< (HSTPIPCFG) 128 bytes */
+#define HSTPIPCFG_PSIZE_256_BYTE_Val _U_(0x5) /**< (HSTPIPCFG) 256 bytes */
+#define HSTPIPCFG_PSIZE_512_BYTE_Val _U_(0x6) /**< (HSTPIPCFG) 512 bytes */
+#define HSTPIPCFG_PSIZE_1024_BYTE_Val _U_(0x7) /**< (HSTPIPCFG) 1024 bytes */
+#define HSTPIPCFG_PSIZE_8_BYTE (HSTPIPCFG_PSIZE_8_BYTE_Val << HSTPIPCFG_PSIZE_Pos) /**< (HSTPIPCFG) 8 bytes Position */
+#define HSTPIPCFG_PSIZE_16_BYTE (HSTPIPCFG_PSIZE_16_BYTE_Val << HSTPIPCFG_PSIZE_Pos) /**< (HSTPIPCFG) 16 bytes Position */
+#define HSTPIPCFG_PSIZE_32_BYTE (HSTPIPCFG_PSIZE_32_BYTE_Val << HSTPIPCFG_PSIZE_Pos) /**< (HSTPIPCFG) 32 bytes Position */
+#define HSTPIPCFG_PSIZE_64_BYTE (HSTPIPCFG_PSIZE_64_BYTE_Val << HSTPIPCFG_PSIZE_Pos) /**< (HSTPIPCFG) 64 bytes Position */
+#define HSTPIPCFG_PSIZE_128_BYTE (HSTPIPCFG_PSIZE_128_BYTE_Val << HSTPIPCFG_PSIZE_Pos) /**< (HSTPIPCFG) 128 bytes Position */
+#define HSTPIPCFG_PSIZE_256_BYTE (HSTPIPCFG_PSIZE_256_BYTE_Val << HSTPIPCFG_PSIZE_Pos) /**< (HSTPIPCFG) 256 bytes Position */
+#define HSTPIPCFG_PSIZE_512_BYTE (HSTPIPCFG_PSIZE_512_BYTE_Val << HSTPIPCFG_PSIZE_Pos) /**< (HSTPIPCFG) 512 bytes Position */
+#define HSTPIPCFG_PSIZE_1024_BYTE (HSTPIPCFG_PSIZE_1024_BYTE_Val << HSTPIPCFG_PSIZE_Pos) /**< (HSTPIPCFG) 1024 bytes Position */
+#define HSTPIPCFG_PTOKEN_Pos 8 /**< (HSTPIPCFG) Pipe Token Position */
+#define HSTPIPCFG_PTOKEN (_U_(0x3) << HSTPIPCFG_PTOKEN_Pos) /**< (HSTPIPCFG) Pipe Token Mask */
+#define HSTPIPCFG_PTOKEN_SETUP_Val _U_(0x0) /**< (HSTPIPCFG) SETUP */
+#define HSTPIPCFG_PTOKEN_IN_Val _U_(0x1) /**< (HSTPIPCFG) IN */
+#define HSTPIPCFG_PTOKEN_OUT_Val _U_(0x2) /**< (HSTPIPCFG) OUT */
+#define HSTPIPCFG_PTOKEN_SETUP (HSTPIPCFG_PTOKEN_SETUP_Val << HSTPIPCFG_PTOKEN_Pos) /**< (HSTPIPCFG) SETUP Position */
+#define HSTPIPCFG_PTOKEN_IN (HSTPIPCFG_PTOKEN_IN_Val << HSTPIPCFG_PTOKEN_Pos) /**< (HSTPIPCFG) IN Position */
+#define HSTPIPCFG_PTOKEN_OUT (HSTPIPCFG_PTOKEN_OUT_Val << HSTPIPCFG_PTOKEN_Pos) /**< (HSTPIPCFG) OUT Position */
+#define HSTPIPCFG_AUTOSW_Pos 10 /**< (HSTPIPCFG) Automatic Switch Position */
+#define HSTPIPCFG_AUTOSW (_U_(0x1) << HSTPIPCFG_AUTOSW_Pos) /**< (HSTPIPCFG) Automatic Switch Mask */
+#define HSTPIPCFG_PTYPE_Pos 12 /**< (HSTPIPCFG) Pipe Type Position */
+#define HSTPIPCFG_PTYPE (_U_(0x3) << HSTPIPCFG_PTYPE_Pos) /**< (HSTPIPCFG) Pipe Type Mask */
+#define HSTPIPCFG_PTYPE_CTRL_Val _U_(0x0) /**< (HSTPIPCFG) Control */
+#define HSTPIPCFG_PTYPE_ISO_Val _U_(0x1) /**< (HSTPIPCFG) Isochronous */
+#define HSTPIPCFG_PTYPE_BLK_Val _U_(0x2) /**< (HSTPIPCFG) Bulk */
+#define HSTPIPCFG_PTYPE_INTRPT_Val _U_(0x3) /**< (HSTPIPCFG) Interrupt */
+#define HSTPIPCFG_PTYPE_CTRL (HSTPIPCFG_PTYPE_CTRL_Val << HSTPIPCFG_PTYPE_Pos) /**< (HSTPIPCFG) Control Position */
+#define HSTPIPCFG_PTYPE_ISO (HSTPIPCFG_PTYPE_ISO_Val << HSTPIPCFG_PTYPE_Pos) /**< (HSTPIPCFG) Isochronous Position */
+#define HSTPIPCFG_PTYPE_BLK (HSTPIPCFG_PTYPE_BLK_Val << HSTPIPCFG_PTYPE_Pos) /**< (HSTPIPCFG) Bulk Position */
+#define HSTPIPCFG_PTYPE_INTRPT (HSTPIPCFG_PTYPE_INTRPT_Val << HSTPIPCFG_PTYPE_Pos) /**< (HSTPIPCFG) Interrupt Position */
+#define HSTPIPCFG_PEPNUM_Pos 16 /**< (HSTPIPCFG) Pipe Endpoint Number Position */
+#define HSTPIPCFG_PEPNUM (_U_(0xF) << HSTPIPCFG_PEPNUM_Pos) /**< (HSTPIPCFG) Pipe Endpoint Number Mask */
+#define HSTPIPCFG_INTFRQ_Pos 24 /**< (HSTPIPCFG) Pipe Interrupt Request Frequency Position */
+#define HSTPIPCFG_INTFRQ (_U_(0xFF) << HSTPIPCFG_INTFRQ_Pos) /**< (HSTPIPCFG) Pipe Interrupt Request Frequency Mask */
+#define HSTPIPCFG_Msk _U_(0xFF0F377E) /**< (HSTPIPCFG) Register Mask */
+
+/* CTRL_BULK mode */
+#define HSTPIPCFG_CTRL_BULK_PINGEN_Pos 20 /**< (HSTPIPCFG) Ping Enable Position */
+#define HSTPIPCFG_CTRL_BULK_PINGEN (_U_(0x1) << HSTPIPCFG_CTRL_BULK_PINGEN_Pos) /**< (HSTPIPCFG) Ping Enable Mask */
+#define HSTPIPCFG_CTRL_BULK_BINTERVAL_Pos 24 /**< (HSTPIPCFG) bInterval Parameter for the Bulk-Out/Ping Transaction Position */
+#define HSTPIPCFG_CTRL_BULK_BINTERVAL (_U_(0xFF) << HSTPIPCFG_CTRL_BULK_BINTERVAL_Pos) /**< (HSTPIPCFG) bInterval Parameter for the Bulk-Out/Ping Transaction Mask */
+#define HSTPIPCFG_CTRL_BULK_Msk _U_(0xFF100000) /**< (HSTPIPCFG_CTRL_BULK) Register Mask */
+
+
+/* -------- HSTPIPISR : (USBHS Offset: 0x530) (R/ 32) Host Pipe Status Register -------- */
+
+#define HSTPIPISR_OFFSET (0x530) /**< (HSTPIPISR) Host Pipe Status Register Offset */
+
+#define HSTPIPISR_RXINI_Pos 0 /**< (HSTPIPISR) Received IN Data Interrupt Position */
+#define HSTPIPISR_RXINI (_U_(0x1) << HSTPIPISR_RXINI_Pos) /**< (HSTPIPISR) Received IN Data Interrupt Mask */
+#define HSTPIPISR_TXOUTI_Pos 1 /**< (HSTPIPISR) Transmitted OUT Data Interrupt Position */
+#define HSTPIPISR_TXOUTI (_U_(0x1) << HSTPIPISR_TXOUTI_Pos) /**< (HSTPIPISR) Transmitted OUT Data Interrupt Mask */
+#define HSTPIPISR_PERRI_Pos 3 /**< (HSTPIPISR) Pipe Error Interrupt Position */
+#define HSTPIPISR_PERRI (_U_(0x1) << HSTPIPISR_PERRI_Pos) /**< (HSTPIPISR) Pipe Error Interrupt Mask */
+#define HSTPIPISR_NAKEDI_Pos 4 /**< (HSTPIPISR) NAKed Interrupt Position */
+#define HSTPIPISR_NAKEDI (_U_(0x1) << HSTPIPISR_NAKEDI_Pos) /**< (HSTPIPISR) NAKed Interrupt Mask */
+#define HSTPIPISR_OVERFI_Pos 5 /**< (HSTPIPISR) Overflow Interrupt Position */
+#define HSTPIPISR_OVERFI (_U_(0x1) << HSTPIPISR_OVERFI_Pos) /**< (HSTPIPISR) Overflow Interrupt Mask */
+#define HSTPIPISR_SHORTPACKETI_Pos 7 /**< (HSTPIPISR) Short Packet Interrupt Position */
+#define HSTPIPISR_SHORTPACKETI (_U_(0x1) << HSTPIPISR_SHORTPACKETI_Pos) /**< (HSTPIPISR) Short Packet Interrupt Mask */
+#define HSTPIPISR_DTSEQ_Pos 8 /**< (HSTPIPISR) Data Toggle Sequence Position */
+#define HSTPIPISR_DTSEQ (_U_(0x3) << HSTPIPISR_DTSEQ_Pos) /**< (HSTPIPISR) Data Toggle Sequence Mask */
+#define HSTPIPISR_DTSEQ_DATA0_Val _U_(0x0) /**< (HSTPIPISR) Data0 toggle sequence */
+#define HSTPIPISR_DTSEQ_DATA1_Val _U_(0x1) /**< (HSTPIPISR) Data1 toggle sequence */
+#define HSTPIPISR_DTSEQ_DATA0 (HSTPIPISR_DTSEQ_DATA0_Val << HSTPIPISR_DTSEQ_Pos) /**< (HSTPIPISR) Data0 toggle sequence Position */
+#define HSTPIPISR_DTSEQ_DATA1 (HSTPIPISR_DTSEQ_DATA1_Val << HSTPIPISR_DTSEQ_Pos) /**< (HSTPIPISR) Data1 toggle sequence Position */
+#define HSTPIPISR_NBUSYBK_Pos 12 /**< (HSTPIPISR) Number of Busy Banks Position */
+#define HSTPIPISR_NBUSYBK (_U_(0x3) << HSTPIPISR_NBUSYBK_Pos) /**< (HSTPIPISR) Number of Busy Banks Mask */
+#define HSTPIPISR_NBUSYBK_0_BUSY_Val _U_(0x0) /**< (HSTPIPISR) 0 busy bank (all banks free) */
+#define HSTPIPISR_NBUSYBK_1_BUSY_Val _U_(0x1) /**< (HSTPIPISR) 1 busy bank */
+#define HSTPIPISR_NBUSYBK_2_BUSY_Val _U_(0x2) /**< (HSTPIPISR) 2 busy banks */
+#define HSTPIPISR_NBUSYBK_3_BUSY_Val _U_(0x3) /**< (HSTPIPISR) 3 busy banks */
+#define HSTPIPISR_NBUSYBK_0_BUSY (HSTPIPISR_NBUSYBK_0_BUSY_Val << HSTPIPISR_NBUSYBK_Pos) /**< (HSTPIPISR) 0 busy bank (all banks free) Position */
+#define HSTPIPISR_NBUSYBK_1_BUSY (HSTPIPISR_NBUSYBK_1_BUSY_Val << HSTPIPISR_NBUSYBK_Pos) /**< (HSTPIPISR) 1 busy bank Position */
+#define HSTPIPISR_NBUSYBK_2_BUSY (HSTPIPISR_NBUSYBK_2_BUSY_Val << HSTPIPISR_NBUSYBK_Pos) /**< (HSTPIPISR) 2 busy banks Position */
+#define HSTPIPISR_NBUSYBK_3_BUSY (HSTPIPISR_NBUSYBK_3_BUSY_Val << HSTPIPISR_NBUSYBK_Pos) /**< (HSTPIPISR) 3 busy banks Position */
+#define HSTPIPISR_CURRBK_Pos 14 /**< (HSTPIPISR) Current Bank Position */
+#define HSTPIPISR_CURRBK (_U_(0x3) << HSTPIPISR_CURRBK_Pos) /**< (HSTPIPISR) Current Bank Mask */
+#define HSTPIPISR_CURRBK_BANK0_Val _U_(0x0) /**< (HSTPIPISR) Current bank is bank0 */
+#define HSTPIPISR_CURRBK_BANK1_Val _U_(0x1) /**< (HSTPIPISR) Current bank is bank1 */
+#define HSTPIPISR_CURRBK_BANK2_Val _U_(0x2) /**< (HSTPIPISR) Current bank is bank2 */
+#define HSTPIPISR_CURRBK_BANK0 (HSTPIPISR_CURRBK_BANK0_Val << HSTPIPISR_CURRBK_Pos) /**< (HSTPIPISR) Current bank is bank0 Position */
+#define HSTPIPISR_CURRBK_BANK1 (HSTPIPISR_CURRBK_BANK1_Val << HSTPIPISR_CURRBK_Pos) /**< (HSTPIPISR) Current bank is bank1 Position */
+#define HSTPIPISR_CURRBK_BANK2 (HSTPIPISR_CURRBK_BANK2_Val << HSTPIPISR_CURRBK_Pos) /**< (HSTPIPISR) Current bank is bank2 Position */
+#define HSTPIPISR_RWALL_Pos 16 /**< (HSTPIPISR) Read/Write Allowed Position */
+#define HSTPIPISR_RWALL (_U_(0x1) << HSTPIPISR_RWALL_Pos) /**< (HSTPIPISR) Read/Write Allowed Mask */
+#define HSTPIPISR_CFGOK_Pos 18 /**< (HSTPIPISR) Configuration OK Status Position */
+#define HSTPIPISR_CFGOK (_U_(0x1) << HSTPIPISR_CFGOK_Pos) /**< (HSTPIPISR) Configuration OK Status Mask */
+#define HSTPIPISR_PBYCT_Pos 20 /**< (HSTPIPISR) Pipe Byte Count Position */
+#define HSTPIPISR_PBYCT (_U_(0x7FF) << HSTPIPISR_PBYCT_Pos) /**< (HSTPIPISR) Pipe Byte Count Mask */
+#define HSTPIPISR_Msk _U_(0x7FF5F3BB) /**< (HSTPIPISR) Register Mask */
+
+/* CTRL mode */
+#define HSTPIPISR_CTRL_TXSTPI_Pos 2 /**< (HSTPIPISR) Transmitted SETUP Interrupt Position */
+#define HSTPIPISR_CTRL_TXSTPI (_U_(0x1) << HSTPIPISR_CTRL_TXSTPI_Pos) /**< (HSTPIPISR) Transmitted SETUP Interrupt Mask */
+#define HSTPIPISR_CTRL_RXSTALLDI_Pos 6 /**< (HSTPIPISR) Received STALLed Interrupt Position */
+#define HSTPIPISR_CTRL_RXSTALLDI (_U_(0x1) << HSTPIPISR_CTRL_RXSTALLDI_Pos) /**< (HSTPIPISR) Received STALLed Interrupt Mask */
+#define HSTPIPISR_CTRL_Msk _U_(0x44) /**< (HSTPIPISR_CTRL) Register Mask */
+
+/* ISO mode */
+#define HSTPIPISR_ISO_UNDERFI_Pos 2 /**< (HSTPIPISR) Underflow Interrupt Position */
+#define HSTPIPISR_ISO_UNDERFI (_U_(0x1) << HSTPIPISR_ISO_UNDERFI_Pos) /**< (HSTPIPISR) Underflow Interrupt Mask */
+#define HSTPIPISR_ISO_CRCERRI_Pos 6 /**< (HSTPIPISR) CRC Error Interrupt Position */
+#define HSTPIPISR_ISO_CRCERRI (_U_(0x1) << HSTPIPISR_ISO_CRCERRI_Pos) /**< (HSTPIPISR) CRC Error Interrupt Mask */
+#define HSTPIPISR_ISO_Msk _U_(0x44) /**< (HSTPIPISR_ISO) Register Mask */
+
+/* BLK mode */
+#define HSTPIPISR_BLK_TXSTPI_Pos 2 /**< (HSTPIPISR) Transmitted SETUP Interrupt Position */
+#define HSTPIPISR_BLK_TXSTPI (_U_(0x1) << HSTPIPISR_BLK_TXSTPI_Pos) /**< (HSTPIPISR) Transmitted SETUP Interrupt Mask */
+#define HSTPIPISR_BLK_RXSTALLDI_Pos 6 /**< (HSTPIPISR) Received STALLed Interrupt Position */
+#define HSTPIPISR_BLK_RXSTALLDI (_U_(0x1) << HSTPIPISR_BLK_RXSTALLDI_Pos) /**< (HSTPIPISR) Received STALLed Interrupt Mask */
+#define HSTPIPISR_BLK_Msk _U_(0x44) /**< (HSTPIPISR_BLK) Register Mask */
+
+/* INTRPT mode */
+#define HSTPIPISR_INTRPT_UNDERFI_Pos 2 /**< (HSTPIPISR) Underflow Interrupt Position */
+#define HSTPIPISR_INTRPT_UNDERFI (_U_(0x1) << HSTPIPISR_INTRPT_UNDERFI_Pos) /**< (HSTPIPISR) Underflow Interrupt Mask */
+#define HSTPIPISR_INTRPT_RXSTALLDI_Pos 6 /**< (HSTPIPISR) Received STALLed Interrupt Position */
+#define HSTPIPISR_INTRPT_RXSTALLDI (_U_(0x1) << HSTPIPISR_INTRPT_RXSTALLDI_Pos) /**< (HSTPIPISR) Received STALLed Interrupt Mask */
+#define HSTPIPISR_INTRPT_Msk _U_(0x44) /**< (HSTPIPISR_INTRPT) Register Mask */
+
+
+/* -------- HSTPIPICR : (USBHS Offset: 0x560) (/W 32) Host Pipe Clear Register -------- */
+
+#define HSTPIPICR_OFFSET (0x560) /**< (HSTPIPICR) Host Pipe Clear Register Offset */
+
+#define HSTPIPICR_RXINIC_Pos 0 /**< (HSTPIPICR) Received IN Data Interrupt Clear Position */
+#define HSTPIPICR_RXINIC (_U_(0x1) << HSTPIPICR_RXINIC_Pos) /**< (HSTPIPICR) Received IN Data Interrupt Clear Mask */
+#define HSTPIPICR_TXOUTIC_Pos 1 /**< (HSTPIPICR) Transmitted OUT Data Interrupt Clear Position */
+#define HSTPIPICR_TXOUTIC (_U_(0x1) << HSTPIPICR_TXOUTIC_Pos) /**< (HSTPIPICR) Transmitted OUT Data Interrupt Clear Mask */
+#define HSTPIPICR_NAKEDIC_Pos 4 /**< (HSTPIPICR) NAKed Interrupt Clear Position */
+#define HSTPIPICR_NAKEDIC (_U_(0x1) << HSTPIPICR_NAKEDIC_Pos) /**< (HSTPIPICR) NAKed Interrupt Clear Mask */
+#define HSTPIPICR_OVERFIC_Pos 5 /**< (HSTPIPICR) Overflow Interrupt Clear Position */
+#define HSTPIPICR_OVERFIC (_U_(0x1) << HSTPIPICR_OVERFIC_Pos) /**< (HSTPIPICR) Overflow Interrupt Clear Mask */
+#define HSTPIPICR_SHORTPACKETIC_Pos 7 /**< (HSTPIPICR) Short Packet Interrupt Clear Position */
+#define HSTPIPICR_SHORTPACKETIC (_U_(0x1) << HSTPIPICR_SHORTPACKETIC_Pos) /**< (HSTPIPICR) Short Packet Interrupt Clear Mask */
+#define HSTPIPICR_Msk _U_(0xB3) /**< (HSTPIPICR) Register Mask */
+
+/* CTRL mode */
+#define HSTPIPICR_CTRL_TXSTPIC_Pos 2 /**< (HSTPIPICR) Transmitted SETUP Interrupt Clear Position */
+#define HSTPIPICR_CTRL_TXSTPIC (_U_(0x1) << HSTPIPICR_CTRL_TXSTPIC_Pos) /**< (HSTPIPICR) Transmitted SETUP Interrupt Clear Mask */
+#define HSTPIPICR_CTRL_RXSTALLDIC_Pos 6 /**< (HSTPIPICR) Received STALLed Interrupt Clear Position */
+#define HSTPIPICR_CTRL_RXSTALLDIC (_U_(0x1) << HSTPIPICR_CTRL_RXSTALLDIC_Pos) /**< (HSTPIPICR) Received STALLed Interrupt Clear Mask */
+#define HSTPIPICR_CTRL_Msk _U_(0x44) /**< (HSTPIPICR_CTRL) Register Mask */
+
+/* ISO mode */
+#define HSTPIPICR_ISO_UNDERFIC_Pos 2 /**< (HSTPIPICR) Underflow Interrupt Clear Position */
+#define HSTPIPICR_ISO_UNDERFIC (_U_(0x1) << HSTPIPICR_ISO_UNDERFIC_Pos) /**< (HSTPIPICR) Underflow Interrupt Clear Mask */
+#define HSTPIPICR_ISO_CRCERRIC_Pos 6 /**< (HSTPIPICR) CRC Error Interrupt Clear Position */
+#define HSTPIPICR_ISO_CRCERRIC (_U_(0x1) << HSTPIPICR_ISO_CRCERRIC_Pos) /**< (HSTPIPICR) CRC Error Interrupt Clear Mask */
+#define HSTPIPICR_ISO_Msk _U_(0x44) /**< (HSTPIPICR_ISO) Register Mask */
+
+/* BLK mode */
+#define HSTPIPICR_BLK_TXSTPIC_Pos 2 /**< (HSTPIPICR) Transmitted SETUP Interrupt Clear Position */
+#define HSTPIPICR_BLK_TXSTPIC (_U_(0x1) << HSTPIPICR_BLK_TXSTPIC_Pos) /**< (HSTPIPICR) Transmitted SETUP Interrupt Clear Mask */
+#define HSTPIPICR_BLK_RXSTALLDIC_Pos 6 /**< (HSTPIPICR) Received STALLed Interrupt Clear Position */
+#define HSTPIPICR_BLK_RXSTALLDIC (_U_(0x1) << HSTPIPICR_BLK_RXSTALLDIC_Pos) /**< (HSTPIPICR) Received STALLed Interrupt Clear Mask */
+#define HSTPIPICR_BLK_Msk _U_(0x44) /**< (HSTPIPICR_BLK) Register Mask */
+
+/* INTRPT mode */
+#define HSTPIPICR_INTRPT_UNDERFIC_Pos 2 /**< (HSTPIPICR) Underflow Interrupt Clear Position */
+#define HSTPIPICR_INTRPT_UNDERFIC (_U_(0x1) << HSTPIPICR_INTRPT_UNDERFIC_Pos) /**< (HSTPIPICR) Underflow Interrupt Clear Mask */
+#define HSTPIPICR_INTRPT_RXSTALLDIC_Pos 6 /**< (HSTPIPICR) Received STALLed Interrupt Clear Position */
+#define HSTPIPICR_INTRPT_RXSTALLDIC (_U_(0x1) << HSTPIPICR_INTRPT_RXSTALLDIC_Pos) /**< (HSTPIPICR) Received STALLed Interrupt Clear Mask */
+#define HSTPIPICR_INTRPT_Msk _U_(0x44) /**< (HSTPIPICR_INTRPT) Register Mask */
+
+
+/* -------- HSTPIPIFR : (USBHS Offset: 0x590) (/W 32) Host Pipe Set Register -------- */
+
+#define HSTPIPIFR_OFFSET (0x590) /**< (HSTPIPIFR) Host Pipe Set Register Offset */
+
+#define HSTPIPIFR_RXINIS_Pos 0 /**< (HSTPIPIFR) Received IN Data Interrupt Set Position */
+#define HSTPIPIFR_RXINIS (_U_(0x1) << HSTPIPIFR_RXINIS_Pos) /**< (HSTPIPIFR) Received IN Data Interrupt Set Mask */
+#define HSTPIPIFR_TXOUTIS_Pos 1 /**< (HSTPIPIFR) Transmitted OUT Data Interrupt Set Position */
+#define HSTPIPIFR_TXOUTIS (_U_(0x1) << HSTPIPIFR_TXOUTIS_Pos) /**< (HSTPIPIFR) Transmitted OUT Data Interrupt Set Mask */
+#define HSTPIPIFR_PERRIS_Pos 3 /**< (HSTPIPIFR) Pipe Error Interrupt Set Position */
+#define HSTPIPIFR_PERRIS (_U_(0x1) << HSTPIPIFR_PERRIS_Pos) /**< (HSTPIPIFR) Pipe Error Interrupt Set Mask */
+#define HSTPIPIFR_NAKEDIS_Pos 4 /**< (HSTPIPIFR) NAKed Interrupt Set Position */
+#define HSTPIPIFR_NAKEDIS (_U_(0x1) << HSTPIPIFR_NAKEDIS_Pos) /**< (HSTPIPIFR) NAKed Interrupt Set Mask */
+#define HSTPIPIFR_OVERFIS_Pos 5 /**< (HSTPIPIFR) Overflow Interrupt Set Position */
+#define HSTPIPIFR_OVERFIS (_U_(0x1) << HSTPIPIFR_OVERFIS_Pos) /**< (HSTPIPIFR) Overflow Interrupt Set Mask */
+#define HSTPIPIFR_SHORTPACKETIS_Pos 7 /**< (HSTPIPIFR) Short Packet Interrupt Set Position */
+#define HSTPIPIFR_SHORTPACKETIS (_U_(0x1) << HSTPIPIFR_SHORTPACKETIS_Pos) /**< (HSTPIPIFR) Short Packet Interrupt Set Mask */
+#define HSTPIPIFR_NBUSYBKS_Pos 12 /**< (HSTPIPIFR) Number of Busy Banks Set Position */
+#define HSTPIPIFR_NBUSYBKS (_U_(0x1) << HSTPIPIFR_NBUSYBKS_Pos) /**< (HSTPIPIFR) Number of Busy Banks Set Mask */
+#define HSTPIPIFR_Msk _U_(0x10BB) /**< (HSTPIPIFR) Register Mask */
+
+/* CTRL mode */
+#define HSTPIPIFR_CTRL_TXSTPIS_Pos 2 /**< (HSTPIPIFR) Transmitted SETUP Interrupt Set Position */
+#define HSTPIPIFR_CTRL_TXSTPIS (_U_(0x1) << HSTPIPIFR_CTRL_TXSTPIS_Pos) /**< (HSTPIPIFR) Transmitted SETUP Interrupt Set Mask */
+#define HSTPIPIFR_CTRL_RXSTALLDIS_Pos 6 /**< (HSTPIPIFR) Received STALLed Interrupt Set Position */
+#define HSTPIPIFR_CTRL_RXSTALLDIS (_U_(0x1) << HSTPIPIFR_CTRL_RXSTALLDIS_Pos) /**< (HSTPIPIFR) Received STALLed Interrupt Set Mask */
+#define HSTPIPIFR_CTRL_Msk _U_(0x44) /**< (HSTPIPIFR_CTRL) Register Mask */
+
+/* ISO mode */
+#define HSTPIPIFR_ISO_UNDERFIS_Pos 2 /**< (HSTPIPIFR) Underflow Interrupt Set Position */
+#define HSTPIPIFR_ISO_UNDERFIS (_U_(0x1) << HSTPIPIFR_ISO_UNDERFIS_Pos) /**< (HSTPIPIFR) Underflow Interrupt Set Mask */
+#define HSTPIPIFR_ISO_CRCERRIS_Pos 6 /**< (HSTPIPIFR) CRC Error Interrupt Set Position */
+#define HSTPIPIFR_ISO_CRCERRIS (_U_(0x1) << HSTPIPIFR_ISO_CRCERRIS_Pos) /**< (HSTPIPIFR) CRC Error Interrupt Set Mask */
+#define HSTPIPIFR_ISO_Msk _U_(0x44) /**< (HSTPIPIFR_ISO) Register Mask */
+
+/* BLK mode */
+#define HSTPIPIFR_BLK_TXSTPIS_Pos 2 /**< (HSTPIPIFR) Transmitted SETUP Interrupt Set Position */
+#define HSTPIPIFR_BLK_TXSTPIS (_U_(0x1) << HSTPIPIFR_BLK_TXSTPIS_Pos) /**< (HSTPIPIFR) Transmitted SETUP Interrupt Set Mask */
+#define HSTPIPIFR_BLK_RXSTALLDIS_Pos 6 /**< (HSTPIPIFR) Received STALLed Interrupt Set Position */
+#define HSTPIPIFR_BLK_RXSTALLDIS (_U_(0x1) << HSTPIPIFR_BLK_RXSTALLDIS_Pos) /**< (HSTPIPIFR) Received STALLed Interrupt Set Mask */
+#define HSTPIPIFR_BLK_Msk _U_(0x44) /**< (HSTPIPIFR_BLK) Register Mask */
+
+/* INTRPT mode */
+#define HSTPIPIFR_INTRPT_UNDERFIS_Pos 2 /**< (HSTPIPIFR) Underflow Interrupt Set Position */
+#define HSTPIPIFR_INTRPT_UNDERFIS (_U_(0x1) << HSTPIPIFR_INTRPT_UNDERFIS_Pos) /**< (HSTPIPIFR) Underflow Interrupt Set Mask */
+#define HSTPIPIFR_INTRPT_RXSTALLDIS_Pos 6 /**< (HSTPIPIFR) Received STALLed Interrupt Set Position */
+#define HSTPIPIFR_INTRPT_RXSTALLDIS (_U_(0x1) << HSTPIPIFR_INTRPT_RXSTALLDIS_Pos) /**< (HSTPIPIFR) Received STALLed Interrupt Set Mask */
+#define HSTPIPIFR_INTRPT_Msk _U_(0x44) /**< (HSTPIPIFR_INTRPT) Register Mask */
+
+
+/* -------- HSTPIPIMR : (USBHS Offset: 0x5c0) (R/ 32) Host Pipe Mask Register -------- */
+
+#define HSTPIPIMR_OFFSET (0x5C0) /**< (HSTPIPIMR) Host Pipe Mask Register Offset */
+
+#define HSTPIPIMR_RXINE_Pos 0 /**< (HSTPIPIMR) Received IN Data Interrupt Enable Position */
+#define HSTPIPIMR_RXINE (_U_(0x1) << HSTPIPIMR_RXINE_Pos) /**< (HSTPIPIMR) Received IN Data Interrupt Enable Mask */
+#define HSTPIPIMR_TXOUTE_Pos 1 /**< (HSTPIPIMR) Transmitted OUT Data Interrupt Enable Position */
+#define HSTPIPIMR_TXOUTE (_U_(0x1) << HSTPIPIMR_TXOUTE_Pos) /**< (HSTPIPIMR) Transmitted OUT Data Interrupt Enable Mask */
+#define HSTPIPIMR_PERRE_Pos 3 /**< (HSTPIPIMR) Pipe Error Interrupt Enable Position */
+#define HSTPIPIMR_PERRE (_U_(0x1) << HSTPIPIMR_PERRE_Pos) /**< (HSTPIPIMR) Pipe Error Interrupt Enable Mask */
+#define HSTPIPIMR_NAKEDE_Pos 4 /**< (HSTPIPIMR) NAKed Interrupt Enable Position */
+#define HSTPIPIMR_NAKEDE (_U_(0x1) << HSTPIPIMR_NAKEDE_Pos) /**< (HSTPIPIMR) NAKed Interrupt Enable Mask */
+#define HSTPIPIMR_OVERFIE_Pos 5 /**< (HSTPIPIMR) Overflow Interrupt Enable Position */
+#define HSTPIPIMR_OVERFIE (_U_(0x1) << HSTPIPIMR_OVERFIE_Pos) /**< (HSTPIPIMR) Overflow Interrupt Enable Mask */
+#define HSTPIPIMR_SHORTPACKETIE_Pos 7 /**< (HSTPIPIMR) Short Packet Interrupt Enable Position */
+#define HSTPIPIMR_SHORTPACKETIE (_U_(0x1) << HSTPIPIMR_SHORTPACKETIE_Pos) /**< (HSTPIPIMR) Short Packet Interrupt Enable Mask */
+#define HSTPIPIMR_NBUSYBKE_Pos 12 /**< (HSTPIPIMR) Number of Busy Banks Interrupt Enable Position */
+#define HSTPIPIMR_NBUSYBKE (_U_(0x1) << HSTPIPIMR_NBUSYBKE_Pos) /**< (HSTPIPIMR) Number of Busy Banks Interrupt Enable Mask */
+#define HSTPIPIMR_FIFOCON_Pos 14 /**< (HSTPIPIMR) FIFO Control Position */
+#define HSTPIPIMR_FIFOCON (_U_(0x1) << HSTPIPIMR_FIFOCON_Pos) /**< (HSTPIPIMR) FIFO Control Mask */
+#define HSTPIPIMR_PDISHDMA_Pos 16 /**< (HSTPIPIMR) Pipe Interrupts Disable HDMA Request Enable Position */
+#define HSTPIPIMR_PDISHDMA (_U_(0x1) << HSTPIPIMR_PDISHDMA_Pos) /**< (HSTPIPIMR) Pipe Interrupts Disable HDMA Request Enable Mask */
+#define HSTPIPIMR_PFREEZE_Pos 17 /**< (HSTPIPIMR) Pipe Freeze Position */
+#define HSTPIPIMR_PFREEZE (_U_(0x1) << HSTPIPIMR_PFREEZE_Pos) /**< (HSTPIPIMR) Pipe Freeze Mask */
+#define HSTPIPIMR_RSTDT_Pos 18 /**< (HSTPIPIMR) Reset Data Toggle Position */
+#define HSTPIPIMR_RSTDT (_U_(0x1) << HSTPIPIMR_RSTDT_Pos) /**< (HSTPIPIMR) Reset Data Toggle Mask */
+#define HSTPIPIMR_Msk _U_(0x750BB) /**< (HSTPIPIMR) Register Mask */
+
+/* CTRL mode */
+#define HSTPIPIMR_CTRL_TXSTPE_Pos 2 /**< (HSTPIPIMR) Transmitted SETUP Interrupt Enable Position */
+#define HSTPIPIMR_CTRL_TXSTPE (_U_(0x1) << HSTPIPIMR_CTRL_TXSTPE_Pos) /**< (HSTPIPIMR) Transmitted SETUP Interrupt Enable Mask */
+#define HSTPIPIMR_CTRL_RXSTALLDE_Pos 6 /**< (HSTPIPIMR) Received STALLed Interrupt Enable Position */
+#define HSTPIPIMR_CTRL_RXSTALLDE (_U_(0x1) << HSTPIPIMR_CTRL_RXSTALLDE_Pos) /**< (HSTPIPIMR) Received STALLed Interrupt Enable Mask */
+#define HSTPIPIMR_CTRL_Msk _U_(0x44) /**< (HSTPIPIMR_CTRL) Register Mask */
+
+/* ISO mode */
+#define HSTPIPIMR_ISO_UNDERFIE_Pos 2 /**< (HSTPIPIMR) Underflow Interrupt Enable Position */
+#define HSTPIPIMR_ISO_UNDERFIE (_U_(0x1) << HSTPIPIMR_ISO_UNDERFIE_Pos) /**< (HSTPIPIMR) Underflow Interrupt Enable Mask */
+#define HSTPIPIMR_ISO_CRCERRE_Pos 6 /**< (HSTPIPIMR) CRC Error Interrupt Enable Position */
+#define HSTPIPIMR_ISO_CRCERRE (_U_(0x1) << HSTPIPIMR_ISO_CRCERRE_Pos) /**< (HSTPIPIMR) CRC Error Interrupt Enable Mask */
+#define HSTPIPIMR_ISO_Msk _U_(0x44) /**< (HSTPIPIMR_ISO) Register Mask */
+
+/* BLK mode */
+#define HSTPIPIMR_BLK_TXSTPE_Pos 2 /**< (HSTPIPIMR) Transmitted SETUP Interrupt Enable Position */
+#define HSTPIPIMR_BLK_TXSTPE (_U_(0x1) << HSTPIPIMR_BLK_TXSTPE_Pos) /**< (HSTPIPIMR) Transmitted SETUP Interrupt Enable Mask */
+#define HSTPIPIMR_BLK_RXSTALLDE_Pos 6 /**< (HSTPIPIMR) Received STALLed Interrupt Enable Position */
+#define HSTPIPIMR_BLK_RXSTALLDE (_U_(0x1) << HSTPIPIMR_BLK_RXSTALLDE_Pos) /**< (HSTPIPIMR) Received STALLed Interrupt Enable Mask */
+#define HSTPIPIMR_BLK_Msk _U_(0x44) /**< (HSTPIPIMR_BLK) Register Mask */
+
+/* INTRPT mode */
+#define HSTPIPIMR_INTRPT_UNDERFIE_Pos 2 /**< (HSTPIPIMR) Underflow Interrupt Enable Position */
+#define HSTPIPIMR_INTRPT_UNDERFIE (_U_(0x1) << HSTPIPIMR_INTRPT_UNDERFIE_Pos) /**< (HSTPIPIMR) Underflow Interrupt Enable Mask */
+#define HSTPIPIMR_INTRPT_RXSTALLDE_Pos 6 /**< (HSTPIPIMR) Received STALLed Interrupt Enable Position */
+#define HSTPIPIMR_INTRPT_RXSTALLDE (_U_(0x1) << HSTPIPIMR_INTRPT_RXSTALLDE_Pos) /**< (HSTPIPIMR) Received STALLed Interrupt Enable Mask */
+#define HSTPIPIMR_INTRPT_Msk _U_(0x44) /**< (HSTPIPIMR_INTRPT) Register Mask */
+
+
+/* -------- HSTPIPIER : (USBHS Offset: 0x5f0) (/W 32) Host Pipe Enable Register -------- */
+
+#define HSTPIPIER_OFFSET (0x5F0) /**< (HSTPIPIER) Host Pipe Enable Register Offset */
+
+#define HSTPIPIER_RXINES_Pos 0 /**< (HSTPIPIER) Received IN Data Interrupt Enable Position */
+#define HSTPIPIER_RXINES (_U_(0x1) << HSTPIPIER_RXINES_Pos) /**< (HSTPIPIER) Received IN Data Interrupt Enable Mask */
+#define HSTPIPIER_TXOUTES_Pos 1 /**< (HSTPIPIER) Transmitted OUT Data Interrupt Enable Position */
+#define HSTPIPIER_TXOUTES (_U_(0x1) << HSTPIPIER_TXOUTES_Pos) /**< (HSTPIPIER) Transmitted OUT Data Interrupt Enable Mask */
+#define HSTPIPIER_PERRES_Pos 3 /**< (HSTPIPIER) Pipe Error Interrupt Enable Position */
+#define HSTPIPIER_PERRES (_U_(0x1) << HSTPIPIER_PERRES_Pos) /**< (HSTPIPIER) Pipe Error Interrupt Enable Mask */
+#define HSTPIPIER_NAKEDES_Pos 4 /**< (HSTPIPIER) NAKed Interrupt Enable Position */
+#define HSTPIPIER_NAKEDES (_U_(0x1) << HSTPIPIER_NAKEDES_Pos) /**< (HSTPIPIER) NAKed Interrupt Enable Mask */
+#define HSTPIPIER_OVERFIES_Pos 5 /**< (HSTPIPIER) Overflow Interrupt Enable Position */
+#define HSTPIPIER_OVERFIES (_U_(0x1) << HSTPIPIER_OVERFIES_Pos) /**< (HSTPIPIER) Overflow Interrupt Enable Mask */
+#define HSTPIPIER_SHORTPACKETIES_Pos 7 /**< (HSTPIPIER) Short Packet Interrupt Enable Position */
+#define HSTPIPIER_SHORTPACKETIES (_U_(0x1) << HSTPIPIER_SHORTPACKETIES_Pos) /**< (HSTPIPIER) Short Packet Interrupt Enable Mask */
+#define HSTPIPIER_NBUSYBKES_Pos 12 /**< (HSTPIPIER) Number of Busy Banks Enable Position */
+#define HSTPIPIER_NBUSYBKES (_U_(0x1) << HSTPIPIER_NBUSYBKES_Pos) /**< (HSTPIPIER) Number of Busy Banks Enable Mask */
+#define HSTPIPIER_PDISHDMAS_Pos 16 /**< (HSTPIPIER) Pipe Interrupts Disable HDMA Request Enable Position */
+#define HSTPIPIER_PDISHDMAS (_U_(0x1) << HSTPIPIER_PDISHDMAS_Pos) /**< (HSTPIPIER) Pipe Interrupts Disable HDMA Request Enable Mask */
+#define HSTPIPIER_PFREEZES_Pos 17 /**< (HSTPIPIER) Pipe Freeze Enable Position */
+#define HSTPIPIER_PFREEZES (_U_(0x1) << HSTPIPIER_PFREEZES_Pos) /**< (HSTPIPIER) Pipe Freeze Enable Mask */
+#define HSTPIPIER_RSTDTS_Pos 18 /**< (HSTPIPIER) Reset Data Toggle Enable Position */
+#define HSTPIPIER_RSTDTS (_U_(0x1) << HSTPIPIER_RSTDTS_Pos) /**< (HSTPIPIER) Reset Data Toggle Enable Mask */
+#define HSTPIPIER_Msk _U_(0x710BB) /**< (HSTPIPIER) Register Mask */
+
+/* CTRL mode */
+#define HSTPIPIER_CTRL_TXSTPES_Pos 2 /**< (HSTPIPIER) Transmitted SETUP Interrupt Enable Position */
+#define HSTPIPIER_CTRL_TXSTPES (_U_(0x1) << HSTPIPIER_CTRL_TXSTPES_Pos) /**< (HSTPIPIER) Transmitted SETUP Interrupt Enable Mask */
+#define HSTPIPIER_CTRL_RXSTALLDES_Pos 6 /**< (HSTPIPIER) Received STALLed Interrupt Enable Position */
+#define HSTPIPIER_CTRL_RXSTALLDES (_U_(0x1) << HSTPIPIER_CTRL_RXSTALLDES_Pos) /**< (HSTPIPIER) Received STALLed Interrupt Enable Mask */
+#define HSTPIPIER_CTRL_Msk _U_(0x44) /**< (HSTPIPIER_CTRL) Register Mask */
+
+/* ISO mode */
+#define HSTPIPIER_ISO_UNDERFIES_Pos 2 /**< (HSTPIPIER) Underflow Interrupt Enable Position */
+#define HSTPIPIER_ISO_UNDERFIES (_U_(0x1) << HSTPIPIER_ISO_UNDERFIES_Pos) /**< (HSTPIPIER) Underflow Interrupt Enable Mask */
+#define HSTPIPIER_ISO_CRCERRES_Pos 6 /**< (HSTPIPIER) CRC Error Interrupt Enable Position */
+#define HSTPIPIER_ISO_CRCERRES (_U_(0x1) << HSTPIPIER_ISO_CRCERRES_Pos) /**< (HSTPIPIER) CRC Error Interrupt Enable Mask */
+#define HSTPIPIER_ISO_Msk _U_(0x44) /**< (HSTPIPIER_ISO) Register Mask */
+
+/* BLK mode */
+#define HSTPIPIER_BLK_TXSTPES_Pos 2 /**< (HSTPIPIER) Transmitted SETUP Interrupt Enable Position */
+#define HSTPIPIER_BLK_TXSTPES (_U_(0x1) << HSTPIPIER_BLK_TXSTPES_Pos) /**< (HSTPIPIER) Transmitted SETUP Interrupt Enable Mask */
+#define HSTPIPIER_BLK_RXSTALLDES_Pos 6 /**< (HSTPIPIER) Received STALLed Interrupt Enable Position */
+#define HSTPIPIER_BLK_RXSTALLDES (_U_(0x1) << HSTPIPIER_BLK_RXSTALLDES_Pos) /**< (HSTPIPIER) Received STALLed Interrupt Enable Mask */
+#define HSTPIPIER_BLK_Msk _U_(0x44) /**< (HSTPIPIER_BLK) Register Mask */
+
+/* INTRPT mode */
+#define HSTPIPIER_INTRPT_UNDERFIES_Pos 2 /**< (HSTPIPIER) Underflow Interrupt Enable Position */
+#define HSTPIPIER_INTRPT_UNDERFIES (_U_(0x1) << HSTPIPIER_INTRPT_UNDERFIES_Pos) /**< (HSTPIPIER) Underflow Interrupt Enable Mask */
+#define HSTPIPIER_INTRPT_RXSTALLDES_Pos 6 /**< (HSTPIPIER) Received STALLed Interrupt Enable Position */
+#define HSTPIPIER_INTRPT_RXSTALLDES (_U_(0x1) << HSTPIPIER_INTRPT_RXSTALLDES_Pos) /**< (HSTPIPIER) Received STALLed Interrupt Enable Mask */
+#define HSTPIPIER_INTRPT_Msk _U_(0x44) /**< (HSTPIPIER_INTRPT) Register Mask */
+
+
+/* -------- HSTPIPIDR : (USBHS Offset: 0x620) (/W 32) Host Pipe Disable Register -------- */
+
+#define HSTPIPIDR_OFFSET (0x620) /**< (HSTPIPIDR) Host Pipe Disable Register Offset */
+
+#define HSTPIPIDR_RXINEC_Pos 0 /**< (HSTPIPIDR) Received IN Data Interrupt Disable Position */
+#define HSTPIPIDR_RXINEC (_U_(0x1) << HSTPIPIDR_RXINEC_Pos) /**< (HSTPIPIDR) Received IN Data Interrupt Disable Mask */
+#define HSTPIPIDR_TXOUTEC_Pos 1 /**< (HSTPIPIDR) Transmitted OUT Data Interrupt Disable Position */
+#define HSTPIPIDR_TXOUTEC (_U_(0x1) << HSTPIPIDR_TXOUTEC_Pos) /**< (HSTPIPIDR) Transmitted OUT Data Interrupt Disable Mask */
+#define HSTPIPIDR_PERREC_Pos 3 /**< (HSTPIPIDR) Pipe Error Interrupt Disable Position */
+#define HSTPIPIDR_PERREC (_U_(0x1) << HSTPIPIDR_PERREC_Pos) /**< (HSTPIPIDR) Pipe Error Interrupt Disable Mask */
+#define HSTPIPIDR_NAKEDEC_Pos 4 /**< (HSTPIPIDR) NAKed Interrupt Disable Position */
+#define HSTPIPIDR_NAKEDEC (_U_(0x1) << HSTPIPIDR_NAKEDEC_Pos) /**< (HSTPIPIDR) NAKed Interrupt Disable Mask */
+#define HSTPIPIDR_OVERFIEC_Pos 5 /**< (HSTPIPIDR) Overflow Interrupt Disable Position */
+#define HSTPIPIDR_OVERFIEC (_U_(0x1) << HSTPIPIDR_OVERFIEC_Pos) /**< (HSTPIPIDR) Overflow Interrupt Disable Mask */
+#define HSTPIPIDR_SHORTPACKETIEC_Pos 7 /**< (HSTPIPIDR) Short Packet Interrupt Disable Position */
+#define HSTPIPIDR_SHORTPACKETIEC (_U_(0x1) << HSTPIPIDR_SHORTPACKETIEC_Pos) /**< (HSTPIPIDR) Short Packet Interrupt Disable Mask */
+#define HSTPIPIDR_NBUSYBKEC_Pos 12 /**< (HSTPIPIDR) Number of Busy Banks Disable Position */
+#define HSTPIPIDR_NBUSYBKEC (_U_(0x1) << HSTPIPIDR_NBUSYBKEC_Pos) /**< (HSTPIPIDR) Number of Busy Banks Disable Mask */
+#define HSTPIPIDR_FIFOCONC_Pos 14 /**< (HSTPIPIDR) FIFO Control Disable Position */
+#define HSTPIPIDR_FIFOCONC (_U_(0x1) << HSTPIPIDR_FIFOCONC_Pos) /**< (HSTPIPIDR) FIFO Control Disable Mask */
+#define HSTPIPIDR_PDISHDMAC_Pos 16 /**< (HSTPIPIDR) Pipe Interrupts Disable HDMA Request Disable Position */
+#define HSTPIPIDR_PDISHDMAC (_U_(0x1) << HSTPIPIDR_PDISHDMAC_Pos) /**< (HSTPIPIDR) Pipe Interrupts Disable HDMA Request Disable Mask */
+#define HSTPIPIDR_PFREEZEC_Pos 17 /**< (HSTPIPIDR) Pipe Freeze Disable Position */
+#define HSTPIPIDR_PFREEZEC (_U_(0x1) << HSTPIPIDR_PFREEZEC_Pos) /**< (HSTPIPIDR) Pipe Freeze Disable Mask */
+#define HSTPIPIDR_Msk _U_(0x350BB) /**< (HSTPIPIDR) Register Mask */
+
+/* CTRL mode */
+#define HSTPIPIDR_CTRL_TXSTPEC_Pos 2 /**< (HSTPIPIDR) Transmitted SETUP Interrupt Disable Position */
+#define HSTPIPIDR_CTRL_TXSTPEC (_U_(0x1) << HSTPIPIDR_CTRL_TXSTPEC_Pos) /**< (HSTPIPIDR) Transmitted SETUP Interrupt Disable Mask */
+#define HSTPIPIDR_CTRL_RXSTALLDEC_Pos 6 /**< (HSTPIPIDR) Received STALLed Interrupt Disable Position */
+#define HSTPIPIDR_CTRL_RXSTALLDEC (_U_(0x1) << HSTPIPIDR_CTRL_RXSTALLDEC_Pos) /**< (HSTPIPIDR) Received STALLed Interrupt Disable Mask */
+#define HSTPIPIDR_CTRL_Msk _U_(0x44) /**< (HSTPIPIDR_CTRL) Register Mask */
+
+/* ISO mode */
+#define HSTPIPIDR_ISO_UNDERFIEC_Pos 2 /**< (HSTPIPIDR) Underflow Interrupt Disable Position */
+#define HSTPIPIDR_ISO_UNDERFIEC (_U_(0x1) << HSTPIPIDR_ISO_UNDERFIEC_Pos) /**< (HSTPIPIDR) Underflow Interrupt Disable Mask */
+#define HSTPIPIDR_ISO_CRCERREC_Pos 6 /**< (HSTPIPIDR) CRC Error Interrupt Disable Position */
+#define HSTPIPIDR_ISO_CRCERREC (_U_(0x1) << HSTPIPIDR_ISO_CRCERREC_Pos) /**< (HSTPIPIDR) CRC Error Interrupt Disable Mask */
+#define HSTPIPIDR_ISO_Msk _U_(0x44) /**< (HSTPIPIDR_ISO) Register Mask */
+
+/* BLK mode */
+#define HSTPIPIDR_BLK_TXSTPEC_Pos 2 /**< (HSTPIPIDR) Transmitted SETUP Interrupt Disable Position */
+#define HSTPIPIDR_BLK_TXSTPEC (_U_(0x1) << HSTPIPIDR_BLK_TXSTPEC_Pos) /**< (HSTPIPIDR) Transmitted SETUP Interrupt Disable Mask */
+#define HSTPIPIDR_BLK_RXSTALLDEC_Pos 6 /**< (HSTPIPIDR) Received STALLed Interrupt Disable Position */
+#define HSTPIPIDR_BLK_RXSTALLDEC (_U_(0x1) << HSTPIPIDR_BLK_RXSTALLDEC_Pos) /**< (HSTPIPIDR) Received STALLed Interrupt Disable Mask */
+#define HSTPIPIDR_BLK_Msk _U_(0x44) /**< (HSTPIPIDR_BLK) Register Mask */
+
+/* INTRPT mode */
+#define HSTPIPIDR_INTRPT_UNDERFIEC_Pos 2 /**< (HSTPIPIDR) Underflow Interrupt Disable Position */
+#define HSTPIPIDR_INTRPT_UNDERFIEC (_U_(0x1) << HSTPIPIDR_INTRPT_UNDERFIEC_Pos) /**< (HSTPIPIDR) Underflow Interrupt Disable Mask */
+#define HSTPIPIDR_INTRPT_RXSTALLDEC_Pos 6 /**< (HSTPIPIDR) Received STALLed Interrupt Disable Position */
+#define HSTPIPIDR_INTRPT_RXSTALLDEC (_U_(0x1) << HSTPIPIDR_INTRPT_RXSTALLDEC_Pos) /**< (HSTPIPIDR) Received STALLed Interrupt Disable Mask */
+#define HSTPIPIDR_INTRPT_Msk _U_(0x44) /**< (HSTPIPIDR_INTRPT) Register Mask */
+
+
+/* -------- HSTPIPINRQ : (USBHS Offset: 0x650) (R/W 32) Host Pipe IN Request Register -------- */
+
+#define HSTPIPINRQ_OFFSET (0x650) /**< (HSTPIPINRQ) Host Pipe IN Request Register Offset */
+
+#define HSTPIPINRQ_INRQ_Pos 0 /**< (HSTPIPINRQ) IN Request Number before Freeze Position */
+#define HSTPIPINRQ_INRQ (_U_(0xFF) << HSTPIPINRQ_INRQ_Pos) /**< (HSTPIPINRQ) IN Request Number before Freeze Mask */
+#define HSTPIPINRQ_INMODE_Pos 8 /**< (HSTPIPINRQ) IN Request Mode Position */
+#define HSTPIPINRQ_INMODE (_U_(0x1) << HSTPIPINRQ_INMODE_Pos) /**< (HSTPIPINRQ) IN Request Mode Mask */
+#define HSTPIPINRQ_Msk _U_(0x1FF) /**< (HSTPIPINRQ) Register Mask */
+
+
+/* -------- HSTPIPERR : (USBHS Offset: 0x680) (R/W 32) Host Pipe Error Register -------- */
+
+#define HSTPIPERR_OFFSET (0x680) /**< (HSTPIPERR) Host Pipe Error Register Offset */
+
+#define HSTPIPERR_DATATGL_Pos 0 /**< (HSTPIPERR) Data Toggle Error Position */
+#define HSTPIPERR_DATATGL (_U_(0x1) << HSTPIPERR_DATATGL_Pos) /**< (HSTPIPERR) Data Toggle Error Mask */
+#define HSTPIPERR_DATAPID_Pos 1 /**< (HSTPIPERR) Data PID Error Position */
+#define HSTPIPERR_DATAPID (_U_(0x1) << HSTPIPERR_DATAPID_Pos) /**< (HSTPIPERR) Data PID Error Mask */
+#define HSTPIPERR_PID_Pos 2 /**< (HSTPIPERR) Data PID Error Position */
+#define HSTPIPERR_PID (_U_(0x1) << HSTPIPERR_PID_Pos) /**< (HSTPIPERR) Data PID Error Mask */
+#define HSTPIPERR_TIMEOUT_Pos 3 /**< (HSTPIPERR) Time-Out Error Position */
+#define HSTPIPERR_TIMEOUT (_U_(0x1) << HSTPIPERR_TIMEOUT_Pos) /**< (HSTPIPERR) Time-Out Error Mask */
+#define HSTPIPERR_CRC16_Pos 4 /**< (HSTPIPERR) CRC16 Error Position */
+#define HSTPIPERR_CRC16 (_U_(0x1) << HSTPIPERR_CRC16_Pos) /**< (HSTPIPERR) CRC16 Error Mask */
+#define HSTPIPERR_COUNTER_Pos 5 /**< (HSTPIPERR) Error Counter Position */
+#define HSTPIPERR_COUNTER (_U_(0x3) << HSTPIPERR_COUNTER_Pos) /**< (HSTPIPERR) Error Counter Mask */
+#define HSTPIPERR_Msk _U_(0x7F) /**< (HSTPIPERR) Register Mask */
+
+#define HSTPIPERR_CRC_Pos 4 /**< (HSTPIPERR Position) CRCx6 Error */
+#define HSTPIPERR_CRC (_U_(0x1) << HSTPIPERR_CRC_Pos) /**< (HSTPIPERR Mask) CRC */
+
+/* -------- CTRL : (USBHS Offset: 0x800) (R/W 32) General Control Register -------- */
+
+#define CTRL_OFFSET (0x800) /**< (CTRL) General Control Register Offset */
+
+#define CTRL_RDERRE_Pos 4 /**< (CTRL) Remote Device Connection Error Interrupt Enable Position */
+#define CTRL_RDERRE (_U_(0x1) << CTRL_RDERRE_Pos) /**< (CTRL) Remote Device Connection Error Interrupt Enable Mask */
+#define CTRL_VBUSHWC_Pos 8 /**< (CTRL) VBUS Hardware Control Position */
+#define CTRL_VBUSHWC (_U_(0x1) << CTRL_VBUSHWC_Pos) /**< (CTRL) VBUS Hardware Control Mask */
+#define CTRL_FRZCLK_Pos 14 /**< (CTRL) Freeze USB Clock Position */
+#define CTRL_FRZCLK (_U_(0x1) << CTRL_FRZCLK_Pos) /**< (CTRL) Freeze USB Clock Mask */
+#define CTRL_USBE_Pos 15 /**< (CTRL) USBHS Enable Position */
+#define CTRL_USBE (_U_(0x1) << CTRL_USBE_Pos) /**< (CTRL) USBHS Enable Mask */
+#define CTRL_UID_Pos 24 /**< (CTRL) UID Pin Enable Position */
+#define CTRL_UID (_U_(0x1) << CTRL_UID_Pos) /**< (CTRL) UID Pin Enable Mask */
+#define CTRL_UIMOD_Pos 25 /**< (CTRL) USBHS Mode Position */
+#define CTRL_UIMOD (_U_(0x1) << CTRL_UIMOD_Pos) /**< (CTRL) USBHS Mode Mask */
+#define CTRL_UIMOD_HOST_Val _U_(0x0) /**< (CTRL) The module is in USB Host mode. */
+#define CTRL_UIMOD_DEVICE_Val _U_(0x1) /**< (CTRL) The module is in USB Device mode. */
+#define CTRL_UIMOD_HOST (CTRL_UIMOD_HOST_Val << CTRL_UIMOD_Pos) /**< (CTRL) The module is in USB Host mode. Position */
+#define CTRL_UIMOD_DEVICE (CTRL_UIMOD_DEVICE_Val << CTRL_UIMOD_Pos) /**< (CTRL) The module is in USB Device mode. Position */
+#define CTRL_Msk _U_(0x300C110) /**< (CTRL) Register Mask */
+
+
+/* -------- SR : (USBHS Offset: 0x804) (R/ 32) General Status Register -------- */
+
+#define SR_OFFSET (0x804) /**< (SR) General Status Register Offset */
+
+#define SR_RDERRI_Pos 4 /**< (SR) Remote Device Connection Error Interrupt (Host mode only) Position */
+#define SR_RDERRI (_U_(0x1) << SR_RDERRI_Pos) /**< (SR) Remote Device Connection Error Interrupt (Host mode only) Mask */
+#define SR_SPEED_Pos 12 /**< (SR) Speed Status (Device mode only) Position */
+#define SR_SPEED (_U_(0x3) << SR_SPEED_Pos) /**< (SR) Speed Status (Device mode only) Mask */
+#define SR_SPEED_FULL_SPEED_Val _U_(0x0) /**< (SR) Full-Speed mode */
+#define SR_SPEED_HIGH_SPEED_Val _U_(0x1) /**< (SR) High-Speed mode */
+#define SR_SPEED_LOW_SPEED_Val _U_(0x2) /**< (SR) Low-Speed mode */
+#define SR_SPEED_FULL_SPEED (SR_SPEED_FULL_SPEED_Val << SR_SPEED_Pos) /**< (SR) Full-Speed mode Position */
+#define SR_SPEED_HIGH_SPEED (SR_SPEED_HIGH_SPEED_Val << SR_SPEED_Pos) /**< (SR) High-Speed mode Position */
+#define SR_SPEED_LOW_SPEED (SR_SPEED_LOW_SPEED_Val << SR_SPEED_Pos) /**< (SR) Low-Speed mode Position */
+#define SR_CLKUSABLE_Pos 14 /**< (SR) UTMI Clock Usable Position */
+#define SR_CLKUSABLE (_U_(0x1) << SR_CLKUSABLE_Pos) /**< (SR) UTMI Clock Usable Mask */
+#define SR_Msk _U_(0x7010) /**< (SR) Register Mask */
+
+
+/* -------- SCR : (USBHS Offset: 0x808) (/W 32) General Status Clear Register -------- */
+
+#define SCR_OFFSET (0x808) /**< (SCR) General Status Clear Register Offset */
+
+#define SCR_RDERRIC_Pos 4 /**< (SCR) Remote Device Connection Error Interrupt Clear Position */
+#define SCR_RDERRIC (_U_(0x1) << SCR_RDERRIC_Pos) /**< (SCR) Remote Device Connection Error Interrupt Clear Mask */
+#define SCR_Msk _U_(0x10) /**< (SCR) Register Mask */
+
+
+/* -------- SFR : (USBHS Offset: 0x80c) (/W 32) General Status Set Register -------- */
+
+#define SFR_OFFSET (0x80C) /**< (SFR) General Status Set Register Offset */
+
+#define SFR_RDERRIS_Pos 4 /**< (SFR) Remote Device Connection Error Interrupt Set Position */
+#define SFR_RDERRIS (_U_(0x1) << SFR_RDERRIS_Pos) /**< (SFR) Remote Device Connection Error Interrupt Set Mask */
+#define SFR_VBUSRQS_Pos 9 /**< (SFR) VBUS Request Set Position */
+#define SFR_VBUSRQS (_U_(0x1) << SFR_VBUSRQS_Pos) /**< (SFR) VBUS Request Set Mask */
+#define SFR_Msk _U_(0x210) /**< (SFR) Register Mask */
+
+
+/** \brief DEVDMA hardware registers */
+typedef struct
+{
+ __IO uint32_t DEVDMANXTDSC; /**< (DEVDMA Offset: 0x00) Device DMA Channel Next Descriptor Address Register */
+ __IO uint32_t DEVDMAADDRESS; /**< (DEVDMA Offset: 0x04) Device DMA Channel Address Register */
+ __IO uint32_t DEVDMACONTROL; /**< (DEVDMA Offset: 0x08) Device DMA Channel Control Register */
+ __IO uint32_t DEVDMASTATUS; /**< (DEVDMA Offset: 0x0C) Device DMA Channel Status Register */
+} devdma_t;
+
+/** \brief HSTDMA hardware registers */
+typedef struct
+{
+ __IO uint32_t HSTDMANXTDSC; /**< (HSTDMA Offset: 0x00) Host DMA Channel Next Descriptor Address Register */
+ __IO uint32_t HSTDMAADDRESS; /**< (HSTDMA Offset: 0x04) Host DMA Channel Address Register */
+ __IO uint32_t HSTDMACONTROL; /**< (HSTDMA Offset: 0x08) Host DMA Channel Control Register */
+ __IO uint32_t HSTDMASTATUS; /**< (HSTDMA Offset: 0x0C) Host DMA Channel Status Register */
+} hstdma_t;
+
+/** \brief USBHS hardware registers */
+typedef struct
+{
+ __IO uint32_t DEVCTRL; /**< (USBHS Offset: 0x00) Device General Control Register */
+ __I uint32_t DEVISR; /**< (USBHS Offset: 0x04) Device Global Interrupt Status Register */
+ __O uint32_t DEVICR; /**< (USBHS Offset: 0x08) Device Global Interrupt Clear Register */
+ __O uint32_t DEVIFR; /**< (USBHS Offset: 0x0C) Device Global Interrupt Set Register */
+ __I uint32_t DEVIMR; /**< (USBHS Offset: 0x10) Device Global Interrupt Mask Register */
+ __O uint32_t DEVIDR; /**< (USBHS Offset: 0x14) Device Global Interrupt Disable Register */
+ __O uint32_t DEVIER; /**< (USBHS Offset: 0x18) Device Global Interrupt Enable Register */
+ __IO uint32_t DEVEPT; /**< (USBHS Offset: 0x1C) Device Endpoint Register */
+ __I uint32_t DEVFNUM; /**< (USBHS Offset: 0x20) Device Frame Number Register */
+ __I uint8_t Reserved1[220];
+ __IO uint32_t DEVEPTCFG[10]; /**< (USBHS Offset: 0x100) Device Endpoint Configuration Register */
+ __I uint8_t Reserved2[8];
+ __I uint32_t DEVEPTISR[10]; /**< (USBHS Offset: 0x130) Device Endpoint Interrupt Status Register */
+ __I uint8_t Reserved3[8];
+ __O uint32_t DEVEPTICR[10]; /**< (USBHS Offset: 0x160) Device Endpoint Interrupt Clear Register */
+ __I uint8_t Reserved4[8];
+ __O uint32_t DEVEPTIFR[10]; /**< (USBHS Offset: 0x190) Device Endpoint Interrupt Set Register */
+ __I uint8_t Reserved5[8];
+ __I uint32_t DEVEPTIMR[10]; /**< (USBHS Offset: 0x1C0) Device Endpoint Interrupt Mask Register */
+ __I uint8_t Reserved6[8];
+ __O uint32_t DEVEPTIER[10]; /**< (USBHS Offset: 0x1F0) Device Endpoint Interrupt Enable Register */
+ __I uint8_t Reserved7[8];
+ __O uint32_t DEVEPTIDR[10]; /**< (USBHS Offset: 0x220) Device Endpoint Interrupt Disable Register */
+ __I uint8_t Reserved8[200];
+ devdma_t DEVDMA[7]; /**< Offset: 0x310 Device DMA Channel Next Descriptor Address Register */
+ __I uint8_t Reserved9[128];
+ __IO uint32_t HSTCTRL; /**< (USBHS Offset: 0x400) Host General Control Register */
+ __I uint32_t HSTISR; /**< (USBHS Offset: 0x404) Host Global Interrupt Status Register */
+ __O uint32_t HSTICR; /**< (USBHS Offset: 0x408) Host Global Interrupt Clear Register */
+ __O uint32_t HSTIFR; /**< (USBHS Offset: 0x40C) Host Global Interrupt Set Register */
+ __I uint32_t HSTIMR; /**< (USBHS Offset: 0x410) Host Global Interrupt Mask Register */
+ __O uint32_t HSTIDR; /**< (USBHS Offset: 0x414) Host Global Interrupt Disable Register */
+ __O uint32_t HSTIER; /**< (USBHS Offset: 0x418) Host Global Interrupt Enable Register */
+ __IO uint32_t HSTPIP; /**< (USBHS Offset: 0x41C) Host Pipe Register */
+ __IO uint32_t HSTFNUM; /**< (USBHS Offset: 0x420) Host Frame Number Register */
+ __IO uint32_t HSTADDR1; /**< (USBHS Offset: 0x424) Host Address 1 Register */
+ __IO uint32_t HSTADDR2; /**< (USBHS Offset: 0x428) Host Address 2 Register */
+ __IO uint32_t HSTADDR3; /**< (USBHS Offset: 0x42C) Host Address 3 Register */
+ __I uint8_t Reserved10[208];
+ __IO uint32_t HSTPIPCFG[10]; /**< (USBHS Offset: 0x500) Host Pipe Configuration Register */
+ __I uint8_t Reserved11[8];
+ __I uint32_t HSTPIPISR[10]; /**< (USBHS Offset: 0x530) Host Pipe Status Register */
+ __I uint8_t Reserved12[8];
+ __O uint32_t HSTPIPICR[10]; /**< (USBHS Offset: 0x560) Host Pipe Clear Register */
+ __I uint8_t Reserved13[8];
+ __O uint32_t HSTPIPIFR[10]; /**< (USBHS Offset: 0x590) Host Pipe Set Register */
+ __I uint8_t Reserved14[8];
+ __I uint32_t HSTPIPIMR[10]; /**< (USBHS Offset: 0x5C0) Host Pipe Mask Register */
+ __I uint8_t Reserved15[8];
+ __O uint32_t HSTPIPIER[10]; /**< (USBHS Offset: 0x5F0) Host Pipe Enable Register */
+ __I uint8_t Reserved16[8];
+ __O uint32_t HSTPIPIDR[10]; /**< (USBHS Offset: 0x620) Host Pipe Disable Register */
+ __I uint8_t Reserved17[8];
+ __IO uint32_t HSTPIPINRQ[10]; /**< (USBHS Offset: 0x650) Host Pipe IN Request Register */
+ __I uint8_t Reserved18[8];
+ __IO uint32_t HSTPIPERR[10]; /**< (USBHS Offset: 0x680) Host Pipe Error Register */
+ __I uint8_t Reserved19[104];
+ hstdma_t HSTDMA[7]; /**< Offset: 0x710 Host DMA Channel Next Descriptor Address Register */
+ __I uint8_t Reserved20[128];
+ __IO uint32_t CTRL; /**< (USBHS Offset: 0x800) General Control Register */
+ __I uint32_t SR; /**< (USBHS Offset: 0x804) General Status Register */
+ __O uint32_t SCR; /**< (USBHS Offset: 0x808) General Status Clear Register */
+ __O uint32_t SFR; /**< (USBHS Offset: 0x80C) General Status Set Register */
+} dcd_registers_t;
+
+#define USB_REG ((dcd_registers_t *)0x40038000U) /**< \brief (USBHS) Base Address */
+
+#define EP_MAX 10
+
+#define FIFO_RAM_ADDR 0xA0100000u
+
+// Errata: The DMA feature is not available for Pipe/Endpoint 7
+#define EP_DMA_SUPPORT(epnum) (epnum >= 1 && epnum <= 6)
+
+#else // TODO : SAM3U
+
+
+#endif
+
+#endif /* _COMMON_USB_REGS_H_ */
diff --git a/src/portable/microchip/samx7x/dcd_samx7x.c b/src/portable/microchip/samx7x/dcd_samx7x.c
new file mode 100644
index 000000000..9586df84d
--- /dev/null
+++ b/src/portable/microchip/samx7x/dcd_samx7x.c
@@ -0,0 +1,776 @@
+/*
+* The MIT License (MIT)
+*
+* Copyright (c) 2018, hathach (tinyusb.org)
+* Copyright (c) 2021, HiFiPhile
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*
+* This file is part of the TinyUSB stack.
+*/
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMX7X
+
+#include "device/dcd.h"
+#include "sam.h"
+#include "common_usb_regs.h"
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
+// We disable SOF for now until needed later on
+#ifndef USE_SOF
+# define USE_SOF 0
+#endif
+
+// Dual bank can improve performance, but need 2 times bigger packet buffer
+// As SAM7x has only 4KB packet buffer, use with caution !
+// Enable in FS mode as packets are smaller
+#ifndef USE_DUAL_BANK
+# if TUD_OPT_HIGH_SPEED
+# define USE_DUAL_BANK 0
+# else
+# define USE_DUAL_BANK 1
+# endif
+#endif
+
+#define EP_GET_FIFO_PTR(ep, scale) (((TU_XSTRCAT(TU_STRCAT(uint, scale),_t) (*)[0x8000 / ((scale) / 8)])FIFO_RAM_ADDR)[(ep)])
+
+// DMA Channel Transfer Descriptor
+typedef struct {
+ volatile uint32_t next_desc;
+ volatile uint32_t buff_addr;
+ volatile uint32_t chnl_ctrl;
+ uint32_t padding;
+} dma_desc_t;
+
+// Transfer control context
+typedef struct {
+ uint8_t * buffer;
+ uint16_t total_len;
+ uint16_t queued_len;
+ uint16_t max_packet_size;
+ uint8_t interval;
+ tu_fifo_t * fifo;
+} xfer_ctl_t;
+
+static tusb_speed_t get_speed(void);
+static void dcd_transmit_packet(xfer_ctl_t * xfer, uint8_t ep_ix);
+
+// DMA descriptors shouldn't be placed in ITCM !
+CFG_TUD_MEM_SECTION static dma_desc_t dma_desc[6];
+
+static xfer_ctl_t xfer_status[EP_MAX];
+
+static const tusb_desc_endpoint_t ep0_desc =
+{
+ .bEndpointAddress = 0x00,
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
+};
+
+TU_ATTR_ALWAYS_INLINE static inline void CleanInValidateCache(uint32_t *addr, int32_t size)
+{
+ if (SCB->CCR & SCB_CCR_DC_Msk)
+ {
+ SCB_CleanInvalidateDCache_by_Addr(addr, size);
+ }
+ else
+ {
+ __DSB();
+ __ISB();
+ }
+}
+//------------------------------------------------------------------
+// Device API
+//------------------------------------------------------------------
+
+// Initialize controller to device mode
+void dcd_init (uint8_t rhport)
+{
+ dcd_connect(rhport);
+}
+
+// Enable device interrupt
+void dcd_int_enable (uint8_t rhport)
+{
+ (void) rhport;
+ NVIC_EnableIRQ((IRQn_Type) ID_USBHS);
+}
+
+// Disable device interrupt
+void dcd_int_disable (uint8_t rhport)
+{
+ (void) rhport;
+ NVIC_DisableIRQ((IRQn_Type) ID_USBHS);
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
+{
+ (void) dev_addr;
+ // DCD can only set address after status for this request is complete
+ // do it at dcd_edpt0_status_complete()
+
+ // Response with zlp status
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+// Wake up host
+void dcd_remote_wakeup (uint8_t rhport)
+{
+ (void) rhport;
+ USB_REG->DEVCTRL |= DEVCTRL_RMWKUP;
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ (void) rhport;
+ dcd_int_disable(rhport);
+ // Enable the USB controller in device mode
+ USB_REG->CTRL = CTRL_UIMOD | CTRL_USBE;
+ while (!(USB_REG->SR & SR_CLKUSABLE));
+#if TUD_OPT_HIGH_SPEED
+ USB_REG->DEVCTRL &= ~DEVCTRL_SPDCONF;
+#else
+ USB_REG->DEVCTRL |= DEVCTRL_SPDCONF_LOW_POWER;
+#endif
+ // Enable the End Of Reset, Suspend & Wakeup interrupts
+ USB_REG->DEVIER = (DEVIER_EORSTES | DEVIER_SUSPES | DEVIER_WAKEUPES);
+#if USE_SOF
+ USB_REG->DEVIER = DEVIER_SOFES;
+#endif
+ // Clear the End Of Reset, SOF & Wakeup interrupts
+ USB_REG->DEVICR = (DEVICR_EORSTC | DEVICR_SOFC | DEVICR_WAKEUPC);
+ // Manually set the Suspend Interrupt
+ USB_REG->DEVIFR |= DEVIFR_SUSPS;
+ // Ack the Wakeup Interrupt
+ USB_REG->DEVICR = DEVICR_WAKEUPC;
+ // Attach the device
+ USB_REG->DEVCTRL &= ~DEVCTRL_DETACH;
+ // Freeze USB clock
+ USB_REG->CTRL |= CTRL_FRZCLK;
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ (void) rhport;
+ dcd_int_disable(rhport);
+ // Disable all endpoints
+ USB_REG->DEVEPT &= ~(0x3FF << DEVEPT_EPEN0_Pos);
+ // Unfreeze USB clock
+ USB_REG->CTRL &= ~CTRL_FRZCLK;
+ while (!(USB_REG->SR & SR_CLKUSABLE));
+ // Clear all the pending interrupts
+ USB_REG->DEVICR = DEVICR_Msk;
+ // Disable all interrupts
+ USB_REG->DEVIDR = DEVIDR_Msk;
+ // Detach the device
+ USB_REG->DEVCTRL |= DEVCTRL_DETACH;
+ // Disable the device address
+ USB_REG->DEVCTRL &=~(DEVCTRL_ADDEN | DEVCTRL_UADD);
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+static tusb_speed_t get_speed(void)
+{
+ switch (USB_REG->SR & SR_SPEED) {
+ case SR_SPEED_FULL_SPEED:
+ default:
+ return TUSB_SPEED_FULL;
+ case SR_SPEED_HIGH_SPEED:
+ return TUSB_SPEED_HIGH;
+ case SR_SPEED_LOW_SPEED:
+ return TUSB_SPEED_LOW;
+ }
+}
+
+static void dcd_ep_handler(uint8_t ep_ix)
+{
+ uint32_t int_status = USB_REG->DEVEPTISR[ep_ix];
+ int_status &= USB_REG->DEVEPTIMR[ep_ix];
+
+ uint16_t count = (USB_REG->DEVEPTISR[ep_ix] &
+ DEVEPTISR_BYCT) >> DEVEPTISR_BYCT_Pos;
+ xfer_ctl_t *xfer = &xfer_status[ep_ix];
+
+ if (ep_ix == 0U)
+ {
+ static uint8_t ctrl_dir;
+
+ if (int_status & DEVEPTISR_CTRL_RXSTPI)
+ {
+ ctrl_dir = (USB_REG->DEVEPTISR[0] & DEVEPTISR_CTRL_CTRLDIR) >> DEVEPTISR_CTRL_CTRLDIR_Pos;
+ // Setup packet should always be 8 bytes. If not, ignore it, and try again.
+ if (count == 8)
+ {
+ uint8_t *ptr = EP_GET_FIFO_PTR(0,8);
+ dcd_event_setup_received(0, ptr, true);
+ }
+ // Ack and disable SETUP interrupt
+ USB_REG->DEVEPTICR[0] = DEVEPTICR_CTRL_RXSTPIC;
+ USB_REG->DEVEPTIDR[0] = DEVEPTIDR_CTRL_RXSTPEC;
+ }
+ if (int_status & DEVEPTISR_RXOUTI)
+ {
+ uint8_t *ptr = EP_GET_FIFO_PTR(0,8);
+
+ if (count && xfer->total_len)
+ {
+ uint16_t remain = xfer->total_len - xfer->queued_len;
+ if (count > remain)
+ {
+ count = remain;
+ }
+ if (xfer->buffer)
+ {
+ memcpy(xfer->buffer + xfer->queued_len, ptr, count);
+ } else
+ {
+ tu_fifo_write_n(xfer->fifo, ptr, count);
+ }
+ xfer->queued_len = (uint16_t)(xfer->queued_len + count);
+ }
+ // Acknowledge the interrupt
+ USB_REG->DEVEPTICR[0] = DEVEPTICR_RXOUTIC;
+ if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len))
+ {
+ // RX COMPLETE
+ dcd_event_xfer_complete(0, 0, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+ // Disable the interrupt
+ USB_REG->DEVEPTIDR[0] = DEVEPTIDR_RXOUTEC;
+ // Re-enable SETUP interrupt
+ if (ctrl_dir == 1)
+ {
+ USB_REG->DEVEPTIER[0] = DEVEPTIER_CTRL_RXSTPES;
+ }
+ }
+ }
+ if (int_status & DEVEPTISR_TXINI)
+ {
+ // Disable the interrupt
+ USB_REG->DEVEPTIDR[0] = DEVEPTIDR_TXINEC;
+ if ((xfer->total_len != xfer->queued_len))
+ {
+ // TX not complete
+ dcd_transmit_packet(xfer, 0);
+ } else
+ {
+ // TX complete
+ dcd_event_xfer_complete(0, 0x80 + 0, xfer->total_len, XFER_RESULT_SUCCESS, true);
+ // Re-enable SETUP interrupt
+ if (ctrl_dir == 0)
+ {
+ USB_REG->DEVEPTIER[0] = DEVEPTIER_CTRL_RXSTPES;
+ }
+ }
+ }
+ } else
+ {
+ if (int_status & DEVEPTISR_RXOUTI)
+ {
+ if (count && xfer->total_len)
+ {
+ uint16_t remain = xfer->total_len - xfer->queued_len;
+ if (count > remain)
+ {
+ count = remain;
+ }
+ uint8_t *ptr = EP_GET_FIFO_PTR(ep_ix,8);
+ if (xfer->buffer)
+ {
+ memcpy(xfer->buffer + xfer->queued_len, ptr, count);
+ } else {
+ tu_fifo_write_n(xfer->fifo, ptr, count);
+ }
+ xfer->queued_len = (uint16_t)(xfer->queued_len + count);
+ }
+ // Clear the FIFO control flag to receive more data.
+ USB_REG->DEVEPTIDR[ep_ix] = DEVEPTIDR_FIFOCONC;
+ // Acknowledge the interrupt
+ USB_REG->DEVEPTICR[ep_ix] = DEVEPTICR_RXOUTIC;
+ if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len))
+ {
+ // RX COMPLETE
+ dcd_event_xfer_complete(0, ep_ix, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+ // Disable the interrupt
+ USB_REG->DEVEPTIDR[ep_ix] = DEVEPTIDR_RXOUTEC;
+ // Though the host could still send, we don't know.
+ }
+ }
+ if (int_status & DEVEPTISR_TXINI)
+ {
+ // Acknowledge the interrupt
+ USB_REG->DEVEPTICR[ep_ix] = DEVEPTICR_TXINIC;
+ if ((xfer->total_len != xfer->queued_len))
+ {
+ // TX not complete
+ dcd_transmit_packet(xfer, ep_ix);
+ } else
+ {
+ // TX complete
+ dcd_event_xfer_complete(0, 0x80 + ep_ix, xfer->total_len, XFER_RESULT_SUCCESS, true);
+ // Disable the interrupt
+ USB_REG->DEVEPTIDR[ep_ix] = DEVEPTIDR_TXINEC;
+ }
+ }
+ }
+}
+
+static void dcd_dma_handler(uint8_t ep_ix)
+{
+ uint32_t status = USB_REG->DEVDMA[ep_ix - 1].DEVDMASTATUS;
+ if (status & DEVDMASTATUS_CHANN_ENB)
+ {
+ return; // Ignore EOT_STA interrupt
+ }
+ // Disable DMA interrupt
+ USB_REG->DEVIDR = DEVIDR_DMA_1 << (ep_ix - 1);
+
+ xfer_ctl_t *xfer = &xfer_status[ep_ix];
+ uint16_t count = xfer->total_len - ((status & DEVDMASTATUS_BUFF_COUNT) >> DEVDMASTATUS_BUFF_COUNT_Pos);
+ if(USB_REG->DEVEPTCFG[ep_ix] & DEVEPTCFG_EPDIR)
+ {
+ dcd_event_xfer_complete(0, 0x80 + ep_ix, count, XFER_RESULT_SUCCESS, true);
+ } else
+ {
+ dcd_event_xfer_complete(0, ep_ix, count, XFER_RESULT_SUCCESS, true);
+ }
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+ (void) rhport;
+ uint32_t int_status = USB_REG->DEVISR;
+ int_status &= USB_REG->DEVIMR;
+ // End of reset interrupt
+ if (int_status & DEVISR_EORST)
+ {
+ // Unfreeze USB clock
+ USB_REG->CTRL &= ~CTRL_FRZCLK;
+ while(!(USB_REG->SR & SR_CLKUSABLE));
+ // Reset all endpoints
+ for (int ep_ix = 1; ep_ix < EP_MAX; ep_ix++)
+ {
+ USB_REG->DEVEPT |= 1 << (DEVEPT_EPRST0_Pos + ep_ix);
+ USB_REG->DEVEPT &=~(1 << (DEVEPT_EPRST0_Pos + ep_ix));
+ }
+ dcd_edpt_open (0, &ep0_desc);
+ USB_REG->DEVICR = DEVICR_EORSTC;
+ USB_REG->DEVICR = DEVICR_WAKEUPC;
+ USB_REG->DEVICR = DEVICR_SUSPC;
+ USB_REG->DEVIER = DEVIER_SUSPES;
+
+ dcd_event_bus_reset(rhport, get_speed(), true);
+ }
+ // End of Wakeup interrupt
+ if (int_status & DEVISR_WAKEUP)
+ {
+ USB_REG->CTRL &= ~CTRL_FRZCLK;
+ while (!(USB_REG->SR & SR_CLKUSABLE));
+ USB_REG->DEVICR = DEVICR_WAKEUPC;
+ USB_REG->DEVIDR = DEVIDR_WAKEUPEC;
+ USB_REG->DEVIER = DEVIER_SUSPES;
+
+ dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+ }
+ // Suspend interrupt
+ if (int_status & DEVISR_SUSP)
+ {
+ // Unfreeze USB clock
+ USB_REG->CTRL &= ~CTRL_FRZCLK;
+ while (!(USB_REG->SR & SR_CLKUSABLE));
+ USB_REG->DEVICR = DEVICR_SUSPC;
+ USB_REG->DEVIDR = DEVIDR_SUSPEC;
+ USB_REG->DEVIER = DEVIER_WAKEUPES;
+ USB_REG->CTRL |= CTRL_FRZCLK;
+
+ dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+ }
+#if USE_SOF
+ if(int_status & DEVISR_SOF)
+ {
+ USB_REG->DEVICR = DEVICR_SOFC;
+
+ dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+ }
+#endif
+ // Endpoints interrupt
+ for (int ep_ix = 0; ep_ix < EP_MAX; ep_ix++)
+ {
+ if (int_status & (DEVISR_PEP_0 << ep_ix))
+ {
+ dcd_ep_handler(ep_ix);
+ }
+ }
+ // Endpoints DMA interrupt
+ for (int ep_ix = 0; ep_ix < EP_MAX; ep_ix++)
+ {
+ if (EP_DMA_SUPPORT(ep_ix))
+ {
+ if (int_status & (DEVISR_DMA_1 << (ep_ix - 1)))
+ {
+ dcd_dma_handler(ep_ix);
+ }
+ }
+ }
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+// Invoked when a control transfer's status stage is complete.
+// May help DCD to prepare for next control transfer, this API is optional.
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
+{
+ (void) rhport;
+
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
+ request->bRequest == TUSB_REQ_SET_ADDRESS )
+ {
+ uint8_t const dev_addr = (uint8_t) request->wValue;
+
+ USB_REG->DEVCTRL |= dev_addr | DEVCTRL_ADDEN;
+ }
+}
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void) rhport;
+ uint8_t const epnum = tu_edpt_number(ep_desc->bEndpointAddress);
+ uint8_t const dir = tu_edpt_dir(ep_desc->bEndpointAddress);
+ uint16_t const epMaxPktSize = tu_edpt_packet_size(ep_desc);
+ tusb_xfer_type_t const eptype = (tusb_xfer_type_t)ep_desc->bmAttributes.xfer;
+ uint8_t fifoSize = 0; // FIFO size
+ uint16_t defaultEndpointSize = 8; // Default size of Endpoint
+ // Find upper 2 power number of epMaxPktSize
+ if (epMaxPktSize)
+ {
+ while (defaultEndpointSize < epMaxPktSize)
+ {
+ fifoSize++;
+ defaultEndpointSize <<= 1;
+ }
+ }
+ xfer_status[epnum].max_packet_size = epMaxPktSize;
+
+ USB_REG->DEVEPT |= 1 << (DEVEPT_EPRST0_Pos + epnum);
+ USB_REG->DEVEPT &=~(1 << (DEVEPT_EPRST0_Pos + epnum));
+
+ if (epnum == 0)
+ {
+ // Enable the control endpoint - Endpoint 0
+ USB_REG->DEVEPT |= DEVEPT_EPEN0;
+ // Configure the Endpoint 0 configuration register
+ USB_REG->DEVEPTCFG[0] =
+ (
+ (fifoSize << DEVEPTCFG_EPSIZE_Pos) |
+ (TUSB_XFER_CONTROL << DEVEPTCFG_EPTYPE_Pos) |
+ (DEVEPTCFG_EPBK_1_BANK << DEVEPTCFG_EPBK_Pos) |
+ DEVEPTCFG_ALLOC
+ );
+ USB_REG->DEVEPTIER[0] = DEVEPTIER_RSTDTS;
+ USB_REG->DEVEPTIDR[0] = DEVEPTIDR_CTRL_STALLRQC;
+ if (DEVEPTISR_CFGOK == (USB_REG->DEVEPTISR[0] & DEVEPTISR_CFGOK))
+ {
+ // Endpoint configuration is successful
+ USB_REG->DEVEPTIER[0] = DEVEPTIER_CTRL_RXSTPES;
+ // Enable Endpoint 0 Interrupts
+ USB_REG->DEVIER = DEVIER_PEP_0;
+ return true;
+ } else
+ {
+ // Endpoint configuration is not successful
+ return false;
+ }
+ } else
+ {
+ // Enable the endpoint
+ USB_REG->DEVEPT |= ((0x01 << epnum) << DEVEPT_EPEN0_Pos);
+ // Set up the maxpacket size, fifo start address fifosize
+ // and enable the interrupt. CLear the data toggle.
+ // AUTOSW is needed for DMA ack !
+ USB_REG->DEVEPTCFG[epnum] =
+ (
+ (fifoSize << DEVEPTCFG_EPSIZE_Pos) |
+ (eptype << DEVEPTCFG_EPTYPE_Pos) |
+ (DEVEPTCFG_EPBK_1_BANK << DEVEPTCFG_EPBK_Pos) |
+ DEVEPTCFG_AUTOSW |
+ ((dir & 0x01) << DEVEPTCFG_EPDIR_Pos)
+ );
+ if (eptype == TUSB_XFER_ISOCHRONOUS)
+ {
+ USB_REG->DEVEPTCFG[epnum] |= DEVEPTCFG_NBTRANS_1_TRANS;
+ }
+#if USE_DUAL_BANK
+ if (eptype == TUSB_XFER_ISOCHRONOUS || eptype == TUSB_XFER_BULK)
+ {
+ USB_REG->DEVEPTCFG[epnum] |= DEVEPTCFG_EPBK_2_BANK;
+ }
+#endif
+ USB_REG->DEVEPTCFG[epnum] |= DEVEPTCFG_ALLOC;
+ USB_REG->DEVEPTIER[epnum] = DEVEPTIER_RSTDTS;
+ USB_REG->DEVEPTIDR[epnum] = DEVEPTIDR_CTRL_STALLRQC;
+ if (DEVEPTISR_CFGOK == (USB_REG->DEVEPTISR[epnum] & DEVEPTISR_CFGOK))
+ {
+ USB_REG->DEVIER = ((0x01 << epnum) << DEVIER_PEP_0_Pos);
+ return true;
+ } else
+ {
+ // Endpoint configuration is not successful
+ return false;
+ }
+ }
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+
+ // Disable endpoint interrupt
+ USB_REG->DEVIDR = 1 << (DEVIDR_PEP_0_Pos + epnum);
+ // Disable EP
+ USB_REG->DEVEPT &=~(1 << (DEVEPT_EPEN0_Pos + epnum));
+}
+
+static void dcd_transmit_packet(xfer_ctl_t * xfer, uint8_t ep_ix)
+{
+ uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len);
+ if (len)
+ {
+ if (len > xfer->max_packet_size)
+ {
+ len = xfer->max_packet_size;
+ }
+ uint8_t *ptr = EP_GET_FIFO_PTR(ep_ix,8);
+ if(xfer->buffer)
+ {
+ memcpy(ptr, xfer->buffer + xfer->queued_len, len);
+ }
+ else
+ {
+ tu_fifo_read_n(xfer->fifo, ptr, len);
+ }
+ __DSB();
+ __ISB();
+ xfer->queued_len = (uint16_t)(xfer->queued_len + len);
+ }
+ if (ep_ix == 0U)
+ {
+ // Control endpoint: clear the interrupt flag to send the data
+ USB_REG->DEVEPTICR[0] = DEVEPTICR_TXINIC;
+ } else
+ {
+ // Other endpoint types: clear the FIFO control flag to send the data
+ USB_REG->DEVEPTIDR[ep_ix] = DEVEPTIDR_FIFOCONC;
+ }
+ USB_REG->DEVEPTIER[ep_ix] = DEVEPTIER_TXINES;
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ (void) rhport;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ xfer_ctl_t * xfer = &xfer_status[epnum];
+
+ xfer->buffer = buffer;
+ xfer->total_len = total_bytes;
+ xfer->queued_len = 0;
+ xfer->fifo = NULL;
+
+ if (EP_DMA_SUPPORT(epnum) && total_bytes != 0)
+ {
+ // Force the CPU to flush the buffer. We increase the size by 32 because the call aligns the
+ // address to 32-byte boundaries.
+ CleanInValidateCache((uint32_t*) tu_align((uint32_t) buffer, 4), total_bytes + 31);
+ uint32_t udd_dma_ctrl = total_bytes << DEVDMACONTROL_BUFF_LENGTH_Pos;
+ if (dir == TUSB_DIR_OUT)
+ {
+ udd_dma_ctrl |= DEVDMACONTROL_END_TR_IT | DEVDMACONTROL_END_TR_EN;
+ } else {
+ udd_dma_ctrl |= DEVDMACONTROL_END_B_EN;
+ }
+ USB_REG->DEVDMA[epnum - 1].DEVDMAADDRESS = (uint32_t)buffer;
+ udd_dma_ctrl |= DEVDMACONTROL_END_BUFFIT | DEVDMACONTROL_CHANN_ENB;
+ // Disable IRQs to have a short sequence
+ // between read of EOT_STA and DMA enable
+ uint32_t irq_state = __get_PRIMASK();
+ __disable_irq();
+ if (!(USB_REG->DEVDMA[epnum - 1].DEVDMASTATUS & DEVDMASTATUS_END_TR_ST))
+ {
+ USB_REG->DEVDMA[epnum - 1].DEVDMACONTROL = udd_dma_ctrl;
+ USB_REG->DEVIER = DEVIER_DMA_1 << (epnum - 1);
+ __set_PRIMASK(irq_state);
+ return true;
+ }
+ __set_PRIMASK(irq_state);
+
+ // Here a ZLP has been received
+ // and the DMA transfer must be not started.
+ // It is the end of transfer
+ return false;
+ } else
+ {
+ if (dir == TUSB_DIR_OUT)
+ {
+ USB_REG->DEVEPTIER[epnum] = DEVEPTIER_RXOUTES;
+ } else
+ {
+ dcd_transmit_packet(xfer,epnum);
+ }
+ }
+ return true;
+}
+
+// The number of bytes has to be given explicitly to allow more flexible control of how many
+// bytes should be written and second to keep the return value free to give back a boolean
+// success message. If total_bytes is too big, the FIFO will copy only what is available
+// into the USB buffer!
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+ (void) rhport;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ xfer_ctl_t * xfer = &xfer_status[epnum];
+ if(epnum == 0x80)
+ xfer = &xfer_status[EP_MAX];
+
+ xfer->buffer = NULL;
+ xfer->total_len = total_bytes;
+ xfer->queued_len = 0;
+ xfer->fifo = ff;
+
+ if (EP_DMA_SUPPORT(epnum) && total_bytes != 0)
+ {
+ tu_fifo_buffer_info_t info;
+ uint32_t udd_dma_ctrl_lin = DEVDMACONTROL_CHANN_ENB;
+ uint32_t udd_dma_ctrl_wrap = DEVDMACONTROL_CHANN_ENB | DEVDMACONTROL_END_BUFFIT;
+ if (dir == TUSB_DIR_OUT)
+ {
+ tu_fifo_get_write_info(ff, &info);
+ udd_dma_ctrl_lin |= DEVDMACONTROL_END_TR_IT | DEVDMACONTROL_END_TR_EN;
+ udd_dma_ctrl_wrap |= DEVDMACONTROL_END_TR_IT | DEVDMACONTROL_END_TR_EN;
+ } else {
+ tu_fifo_get_read_info(ff, &info);
+ if(info.len_wrap == 0)
+ {
+ udd_dma_ctrl_lin |= DEVDMACONTROL_END_B_EN;
+ }
+ udd_dma_ctrl_wrap |= DEVDMACONTROL_END_B_EN;
+ }
+
+ // Clean invalidate cache of linear part
+ CleanInValidateCache((uint32_t*) tu_align((uint32_t) info.ptr_lin, 4), info.len_lin + 31);
+
+ USB_REG->DEVDMA[epnum - 1].DEVDMAADDRESS = (uint32_t)info.ptr_lin;
+ if (info.len_wrap)
+ {
+ // Clean invalidate cache of wrapped part
+ CleanInValidateCache((uint32_t*) tu_align((uint32_t) info.ptr_wrap, 4), info.len_wrap + 31);
+
+ dma_desc[epnum - 1].next_desc = 0;
+ dma_desc[epnum - 1].buff_addr = (uint32_t)info.ptr_wrap;
+ dma_desc[epnum - 1].chnl_ctrl =
+ udd_dma_ctrl_wrap | (info.len_wrap << DEVDMACONTROL_BUFF_LENGTH_Pos);
+ // Clean cache of wrapped DMA descriptor
+ CleanInValidateCache((uint32_t*)&dma_desc[epnum - 1], sizeof(dma_desc_t));
+
+ udd_dma_ctrl_lin |= DEVDMASTATUS_DESC_LDST;
+ USB_REG->DEVDMA[epnum - 1].DEVDMANXTDSC = (uint32_t)&dma_desc[epnum - 1];
+ } else {
+ udd_dma_ctrl_lin |= DEVDMACONTROL_END_BUFFIT;
+ }
+ udd_dma_ctrl_lin |= (info.len_lin << DEVDMACONTROL_BUFF_LENGTH_Pos);
+ // Disable IRQs to have a short sequence
+ // between read of EOT_STA and DMA enable
+ uint32_t irq_state = __get_PRIMASK();
+ __disable_irq();
+ if (!(USB_REG->DEVDMA[epnum - 1].DEVDMASTATUS & DEVDMASTATUS_END_TR_ST))
+ {
+ USB_REG->DEVDMA[epnum - 1].DEVDMACONTROL = udd_dma_ctrl_lin;
+ USB_REG->DEVIER = DEVIER_DMA_1 << (epnum - 1);
+ __set_PRIMASK(irq_state);
+ return true;
+ }
+ __set_PRIMASK(irq_state);
+
+ // Here a ZLP has been received
+ // and the DMA transfer must be not started.
+ // It is the end of transfer
+ return false;
+ } else
+ {
+ if (dir == TUSB_DIR_OUT)
+ {
+ USB_REG->DEVEPTIER[epnum] = DEVEPTIER_RXOUTES;
+ } else
+ {
+ dcd_transmit_packet(xfer,epnum);
+ }
+ }
+ return true;
+}
+
+// Stall endpoint
+void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ USB_REG->DEVEPTIER[epnum] = DEVEPTIER_CTRL_STALLRQS;
+ // Re-enable SETUP interrupt
+ if (epnum == 0)
+ {
+ USB_REG->DEVEPTIER[0] = DEVEPTIER_CTRL_RXSTPES;
+ }
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ USB_REG->DEVEPTIDR[epnum] = DEVEPTIDR_CTRL_STALLRQC;
+ USB_REG->DEVEPTIER[epnum] = HSTPIPIER_RSTDTS;
+}
+
+#endif
diff --git a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
new file mode 100644
index 000000000..d5c0daaeb
--- /dev/null
+++ b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
@@ -0,0 +1,496 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 SE TEAM
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MM32F327X )
+
+#include "reg_usb_otg_fs.h"
+#include "mm32_device.h"
+#include "hal_conf.h"
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+ TOK_PID_OUT = 0x1u,
+ TOK_PID_IN = 0x9u,
+ TOK_PID_SETUP = 0xDu,
+};
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t head;
+ struct {
+ union {
+ struct {
+ uint16_t : 2;
+ uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ uint16_t own : 1;
+ uint16_t : 8;
+ };
+ struct {
+ uint16_t : 2;
+ uint16_t bdt_stall: 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ uint16_t : 10;
+ };
+ };
+ uint16_t bc : 10;
+ uint16_t : 6;
+ };
+ };
+ uint8_t *addr;
+}buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" );
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t state;
+ struct {
+ uint32_t max_packet_size :11;
+ uint32_t : 5;
+ uint32_t odd : 1;
+ uint32_t :15;
+ };
+ };
+ uint16_t length;
+ uint16_t remaining;
+}endpoint_state_t;
+
+TU_VERIFY_STATIC( sizeof(endpoint_state_t) == 8, "size is not correct" );
+
+typedef struct
+{
+ union {
+ /* [#EP][OUT,IN][EVEN,ODD] */
+ buffer_descriptor_t bdt[16][2][2];
+ uint16_t bda[512];
+ };
+ TU_ATTR_ALIGNED(4) union {
+ endpoint_state_t endpoint[16][2];
+ endpoint_state_t endpoint_unified[16 * 2];
+ };
+ uint8_t setup_packet[8];
+ uint8_t addr;
+}dcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+// BDT(Buffer Descriptor Table) must be 256-byte aligned
+CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
+
+TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
+
+static void prepare_next_setup_packet(uint8_t rhport)
+{
+ const unsigned out_odd = _dcd.endpoint[0][0].odd;
+ const unsigned in_odd = _dcd.endpoint[0][1].odd;
+ if (_dcd.bdt[0][0][out_odd].own) {
+ TU_LOG1("DCD fail to prepare the next SETUP %d %d\r\n", out_odd, in_odd);
+ return;
+ }
+ _dcd.bdt[0][0][out_odd].data = 0;
+ _dcd.bdt[0][0][out_odd ^ 1].data = 1;
+ _dcd.bdt[0][1][in_odd].data = 1;
+ _dcd.bdt[0][1][in_odd ^ 1].data = 0;
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT),
+ _dcd.setup_packet, sizeof(_dcd.setup_packet));
+}
+
+static void process_stall(uint8_t rhport)
+{
+ if (USB_OTG_FS->EP_CTL[0] & USB_ENDPT_EPSTALL_MASK) {
+ /* clear stall condition of the control pipe */
+ prepare_next_setup_packet(rhport);
+ USB_OTG_FS->EP_CTL[0] &= ~USB_ENDPT_EPSTALL_MASK;
+ }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+ const unsigned s = USB_OTG_FS->STAT;
+ USB_OTG_FS->INT_STAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
+ buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s];
+ endpoint_state_t *ep = &_dcd.endpoint_unified[s >> 3];
+ unsigned odd = (s & USB_STAT_ODD_MASK) ? 1 : 0;
+
+ /* fetch pid before discarded by the next steps */
+ const unsigned pid = bd->tok_pid;
+ /* reset values for a next transfer */
+ bd->bdt_stall = 0;
+ bd->dts = 1;
+ bd->ninc = 0;
+ bd->keep = 0;
+ /* update the odd variable to prepare for the next transfer */
+ ep->odd = odd ^ 1;
+ if (pid == TOK_PID_SETUP) {
+ dcd_event_setup_received(rhport, bd->addr, true);
+ USB_OTG_FS->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
+ return;
+ }
+ if (s >> 4) {
+ TU_LOG1("TKDNE %x\r\n", s);
+ }
+
+ const unsigned bc = bd->bc;
+ const unsigned remaining = ep->remaining - bc;
+ if (remaining && bc == ep->max_packet_size) {
+ /* continue the transferring consecutive data */
+ ep->remaining = remaining;
+ const int next_remaining = remaining - ep->max_packet_size;
+ if (next_remaining > 0) {
+ /* prepare to the after next transfer */
+ bd->addr += ep->max_packet_size * 2;
+ bd->bc = next_remaining > ep->max_packet_size ? ep->max_packet_size: next_remaining;
+ __DSB();
+ bd->own = 1; /* the own bit must set after addr */
+ }
+ return;
+ }
+ const unsigned length = ep->length;
+ dcd_event_xfer_complete(rhport,
+ ((s & USB_STAT_TX_MASK) << 4) | (s >> USB_STAT_ENDP_SHIFT),
+ length - remaining, XFER_RESULT_SUCCESS, true);
+ if (0 == (s & USB_STAT_ENDP_MASK) && 0 == length) {
+ /* After completion a ZLP of control transfer,
+ * it prepares for the next steup transfer. */
+ if (_dcd.addr) {
+ /* When the transfer was the SetAddress,
+ * the device address should be updated here. */
+ USB_OTG_FS->ADDR = _dcd.addr;
+ _dcd.addr = 0;
+ }
+ prepare_next_setup_packet(rhport);
+ }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+ USB_OTG_FS->CTL |= USB_CTL_ODDRST_MASK;
+ USB_OTG_FS->ADDR = 0;
+ USB_OTG_FS->INT_ENB = (USB_OTG_FS->INT_ENB & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
+
+ USB_OTG_FS->EP_CTL[0] = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+ for (unsigned i = 1; i < 16; ++i) {
+ USB_OTG_FS->EP_CTL[i] = 0;
+ }
+ buffer_descriptor_t *bd = _dcd.bdt[0][0];
+ for (unsigned i = 0; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+ bd->head = 0;
+ }
+ const endpoint_state_t ep0 = {
+ .max_packet_size = CFG_TUD_ENDPOINT0_SIZE,
+ .odd = 0,
+ .length = 0,
+ .remaining = 0,
+ };
+ _dcd.endpoint[0][0] = ep0;
+ _dcd.endpoint[0][1] = ep0;
+ tu_memclr(_dcd.endpoint[1], sizeof(_dcd.endpoint) - sizeof(_dcd.endpoint[0]));
+ _dcd.addr = 0;
+ prepare_next_setup_packet(rhport);
+ USB_OTG_FS->CTL &= ~USB_CTL_ODDRST_MASK;
+ dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+}
+
+static void process_bus_inactive(uint8_t rhport)
+{
+ (void) rhport;
+ const unsigned inten = USB_OTG_FS->INT_ENB;
+ USB_OTG_FS->INT_ENB = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK;
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+}
+
+static void process_bus_active(uint8_t rhport)
+{
+ (void) rhport;
+ const unsigned inten = USB_OTG_FS->INT_ENB;
+ USB_OTG_FS->INT_ENB = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+ (void) rhport;
+
+ tu_memclr(&_dcd, sizeof(_dcd));
+ USB_OTG_FS->BDT_PAGE_01 = (uint8_t)((uintptr_t)_dcd.bdt >> 8);
+ USB_OTG_FS->BDT_PAGE_02 = (uint8_t)((uintptr_t)_dcd.bdt >> 16);
+ USB_OTG_FS->BDT_PAGE_03 = (uint8_t)((uintptr_t)_dcd.bdt >> 24);
+
+ dcd_connect(rhport);
+ NVIC_ClearPendingIRQ(USB_FS_IRQn);
+}
+#define USB_DEVICE_INTERRUPT_PRIORITY (3U)
+void dcd_int_enable(uint8_t rhport)
+{
+ uint8_t irqNumber;
+ irqNumber = USB_FS_IRQn;
+ (void) rhport;
+ USB_OTG_FS->INT_ENB = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK |
+ USB_INTEN_SLEEPEN_MASK | USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
+ NVIC_SetPriority((IRQn_Type)irqNumber, USB_DEVICE_INTERRUPT_PRIORITY);
+ NVIC_EnableIRQ(USB_FS_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ (void) rhport;
+ NVIC_DisableIRQ(USB_FS_IRQn);
+ USB_OTG_FS->INT_ENB = 0;
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ (void) rhport;
+ _dcd.addr = dev_addr & 0x7F;
+ /* Response with status first before changing device address */
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+#ifdef __GNUC__ // caused by extra declaration of SystemCoreClock in freeRTOSConfig.h
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+extern u32 SystemCoreClock;
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void) rhport;
+ unsigned cnt = SystemCoreClock / 100;
+ USB_OTG_FS->CTL |= USB_CTL_RESUME_MASK;
+ while (cnt--) __NOP();
+ USB_OTG_FS->CTL &= ~USB_CTL_RESUME_MASK;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ (void) rhport;
+ USB_OTG_FS->CTL |= USB_CTL_USBENSOFEN_MASK;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ (void) rhport;
+ USB_OTG_FS->CTL = 0;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void) rhport;
+
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = ep_addr & 0xFu;
+ const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ const unsigned odd = ep->odd;
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0];
+
+ /* No support for control transfer */
+ TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL));
+
+ ep->max_packet_size = tu_edpt_packet_size(ep_desc);
+ unsigned val = USB_ENDPT_EPCTLDIS_MASK;
+ val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? USB_ENDPT_EPHSHK_MASK: 0;
+ val |= dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+ USB_OTG_FS->EP_CTL[epn] |= val;
+
+ if (xfer != TUSB_XFER_ISOCHRONOUS) {
+ bd[odd].dts = 1;
+ bd[odd].data = 0;
+ bd[odd ^ 1].dts = 1;
+ bd[odd ^ 1].data = 1;
+ }
+
+ return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+
+ const unsigned epn = ep_addr & 0xFu;
+ const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0];
+ const unsigned msk = dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+ USB_OTG_FS->EP_CTL[epn] &= ~msk;
+ ep->max_packet_size = 0;
+ ep->length = 0;
+ ep->remaining = 0;
+ bd->head = 0;
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+ (void) rhport;
+ NVIC_DisableIRQ(USB_FS_IRQn);
+ const unsigned epn = ep_addr & 0xFu;
+ const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd];
+
+ if (bd->own) {
+ TU_LOG1("DCD XFER fail %x %d %lx %lx\r\n", ep_addr, total_bytes, ep->state, bd->head);
+ return false; /* The last transfer has not completed */
+ }
+ ep->length = total_bytes;
+ ep->remaining = total_bytes;
+
+ const unsigned mps = ep->max_packet_size;
+ if (total_bytes > mps) {
+ buffer_descriptor_t *next = ep->odd ? bd - 1: bd + 1;
+ /* When total_bytes is greater than the max packet size,
+ * it prepares to the next transfer to avoid NAK in advance. */
+ next->bc = total_bytes >= 2 * mps ? mps: total_bytes - mps;
+ next->addr = buffer + mps;
+ next->own = 1;
+ }
+ bd->bc = total_bytes >= mps ? mps: total_bytes;
+ bd->addr = buffer;
+ __DSB();
+ bd->own = 1; /* the own bit must set after addr */
+ NVIC_EnableIRQ(USB_FS_IRQn);
+ return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ const unsigned epn = ep_addr & 0xFu;
+ if (0 == epn) {
+ USB_OTG_FS->EP_CTL[epn] |= USB_ENDPT_EPSTALL_MASK;
+ } else {
+ const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+ bd[0].bdt_stall = 1;
+ bd[1].bdt_stall = 1;
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ const unsigned epn = ep_addr & 0xFu;
+ const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+ const unsigned odd = _dcd.endpoint[epn][dir].odd;
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+
+ bd[odd ^ 1].own = 0;
+ bd[odd ^ 1].data = 1;
+ bd[odd ^ 1].bdt_stall = 0;
+ bd[odd].own = 0;
+ bd[odd].data = 0;
+ bd[odd].bdt_stall = 0;
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void dcd_int_handler(uint8_t rhport)
+{
+ (void) rhport;
+
+ uint32_t is = USB_OTG_FS->INT_STAT;
+ uint32_t msk = USB_OTG_FS->INT_ENB;
+ USB_OTG_FS->INT_STAT = is & ~msk;
+ is &= msk;
+ if (is & USB_ISTAT_ERROR_MASK) {
+ /* TODO: */
+ uint32_t es = USB_OTG_FS->ERR_STAT;
+ USB_OTG_FS->ERR_STAT = es;
+ USB_OTG_FS->INT_STAT = is; /* discard any pending events */
+ return;
+ }
+
+ if (is & USB_ISTAT_USBRST_MASK) {
+ USB_OTG_FS->INT_STAT = is; /* discard any pending events */
+ process_bus_reset(rhport);
+ return;
+ }
+ if (is & USB_ISTAT_SLEEP_MASK) {
+ USB_OTG_FS->INT_STAT = USB_ISTAT_SLEEP_MASK;
+ process_bus_inactive(rhport);
+ return;
+ }
+ if (is & USB_ISTAT_RESUME_MASK) {
+ USB_OTG_FS->INT_STAT = USB_ISTAT_RESUME_MASK;
+ process_bus_active(rhport);
+ return;
+ }
+ if (is & USB_ISTAT_SOFTOK_MASK) {
+ USB_OTG_FS->INT_STAT = USB_ISTAT_SOFTOK_MASK;
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ return;
+ }
+ if (is & USB_ISTAT_STALL_MASK) {
+ USB_OTG_FS->INT_STAT = USB_ISTAT_STALL_MASK;
+ process_stall(rhport);
+ return;
+ }
+ if (is & USB_ISTAT_TOKDNE_MASK) {
+ process_tokdne(rhport);
+ return;
+ }
+}
+
+#endif
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 977ec6cdb..2fe721d6b 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -26,48 +26,85 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_NRF5X
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_NRF5X
+
+#include <stdatomic.h>
+
+// Suppress warning caused by nrfx driver
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#pragma GCC diagnostic ignored "-Wcast-align"
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
#include "nrf.h"
#include "nrf_clock.h"
-#include "nrf_power.h"
#include "nrfx_usbd_errata.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
#include "device/dcd.h"
// TODO remove later
#include "device/usbd.h"
#include "device/usbd_pvt.h" // to use defer function helper
+#if CFG_TUSB_OS == OPT_OS_MYNEWT
+#include "mcu/mcu.h"
+#endif
+
+/* Try to detect nrfx version if not configured with CFG_TUD_NRF_NRFX_VERSION
+ * nrfx v1 and v2 are concurrently developed. There is no NRFX_VERSION only MDK VERSION which is as follows:
+ * - v3.0.0: 8.53.1 (conflict with v2.11.0), v3.1.0: 8.55.0 ...
+ * - v2.11.0: 8.53.1, v2.6.0: 8.44.1, v2.5.0: 8.40.2, v2.4.0: 8.37.0, v2.3.0: 8.35.0, v2.2.0: 8.32.1, v2.1.0: 8.30.2, v2.0.0: 8.29.0
+ * - v1.9.0: 8.40.3, v1.8.6: 8.35.0 (conflict with v2.3.0), v1.8.5: 8.32.3, v1.8.4: 8.32.1 (conflict with v2.2.0),
+ * v1.8.2: 8.32.1 (conflict with v2.2.0), v1.8.1: 8.27.1
+ * Therefore the check for v1 would be:
+ * - MDK < 8.29.0 (v2.0), MDK == 8.32.3, 8.40.3
+ * - in case of conflict User of those version must upgrade to other 1.x version or set CFG_TUD_NRF_NRFX_VERSION
+*/
+#ifndef CFG_TUD_NRF_NRFX_VERSION
+ #define _MDK_VERSION (10000*MDK_MAJOR_VERSION + 100*MDK_MINOR_VERSION + MDK_MICRO_VERSION)
+
+ #if _MDK_VERSION < 82900 || _MDK_VERSION == 83203 || _MDK_VERSION == 84003
+ // nrfx <= 1.8.1, or 1.8.5 or 1.9.0
+ #define CFG_TUD_NRF_NRFX_VERSION 1
+ #else
+ #define CFG_TUD_NRF_NRFX_VERSION 2
+ #endif
+#endif
+
/*------------------------------------------------------------------*/
/* MACRO TYPEDEF CONSTANT ENUM
*------------------------------------------------------------------*/
-enum
-{
+enum {
// Max allowed by USB specs
- MAX_PACKET_SIZE = 64,
+ MAX_PACKET_SIZE = 64,
// Mask of all END event (IN & OUT) for all endpoints. ENDEPIN0-7, ENDEPOUT0-7, ENDISOIN, ENDISOOUT
EDPT_END_ALL_MASK = (0xff << USBD_INTEN_ENDEPIN0_Pos) | (0xff << USBD_INTEN_ENDEPOUT0_Pos) |
USBD_INTENCLR_ENDISOIN_Msk | USBD_INTEN_ENDISOOUT_Msk
};
-enum
-{
- EP_ISO_NUM = 8, // Endpoint number is fixed (8) for ISOOUT and ISOIN
+enum {
+ EP_ISO_NUM = 8, // Endpoint number is fixed (8) for ISOOUT and ISOIN
EP_CBI_COUNT = 8 // Control Bulk Interrupt endpoints count
};
// Transfer Descriptor
-typedef struct
-{
+typedef struct {
uint8_t* buffer;
uint16_t total_len;
volatile uint16_t actual_len;
- uint16_t mps; // max packet size
+ uint16_t mps; // max packet size
// nRF will auto accept OUT packet after DMA is done
// indicate packet is already ACK
volatile bool data_received;
+ volatile bool started;
// Set to true when data was transferred from RAM to ISO IN output buffer.
// New data can be put in ISO IN output buffer after SOF.
@@ -76,169 +113,136 @@ typedef struct
} xfer_td_t;
// Data for managing dcd
-static struct
-{
+static struct {
// All 8 endpoints including control IN & OUT (offset 1)
// +1 for ISO endpoints
xfer_td_t xfer[EP_CBI_COUNT + 1][2];
- // Number of pending DMA that is started but not handled yet by dcd_int_handler().
- // Since nRF can only carry one DMA can run at a time, this value is normally be either 0 or 1.
- // However, in critical section with interrupt disabled, the DMA can be finished and added up
- // until handled by dcd_init_handler() when exiting critical section.
- volatile uint8_t dma_pending;
-}_dcd;
+ // nRF can only carry one DMA at a time, this is used to guard the access to EasyDMA
+ atomic_flag dma_running;
+} _dcd;
/*------------------------------------------------------------------*/
/* Control / Bulk / Interrupt (CBI) Transfer
*------------------------------------------------------------------*/
-// NVIC_GetEnableIRQ is only available in CMSIS v5
-#ifndef NVIC_GetEnableIRQ
-static inline uint32_t NVIC_GetEnableIRQ(IRQn_Type IRQn)
-{
- if ((int32_t)(IRQn) >= 0)
- {
- return((uint32_t)(((NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));
- }
- else
- {
- return(0U);
- }
+// check if we are in ISR
+TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void) {
+ return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) ? true : false;
}
-#endif
// helper to start DMA
-static void edpt_dma_start(volatile uint32_t* reg_startep)
-{
- // Only one dma can be active
- if ( _dcd.dma_pending )
- {
- if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk)
- {
- // Called within ISR, use usbd task to defer later
- usbd_defer_func( (osal_task_func_t) edpt_dma_start, (void*) reg_startep, true );
- return;
- }
- else
- {
- if ( __get_PRIMASK() || !NVIC_GetEnableIRQ(USBD_IRQn) )
- {
- // Called in critical section with interrupt disabled. We have to manually check
- // for the DMA complete by comparing current pending DMA with number of ENDED Events
- uint32_t ended = 0;
-
- while ( _dcd.dma_pending > ((uint8_t) ended) )
- {
- ended = NRF_USBD->EVENTS_ENDISOIN + NRF_USBD->EVENTS_ENDISOOUT;
+static void start_dma(volatile uint32_t* reg_startep) {
+ (*reg_startep) = 1;
+ __ISB();
+ __DSB();
- for (uint8_t i=0; i<EP_CBI_COUNT; i++)
- {
- ended += NRF_USBD->EVENTS_ENDEPIN[i] + NRF_USBD->EVENTS_ENDEPOUT[i];
- }
- }
- }else
- {
- // Called in non-critical thread-mode, should be 99% of the time.
- // Should be safe to blocking wait until previous DMA transfer complete
- while ( _dcd.dma_pending ) { }
- }
- }
+ // TASKS_EP0STATUS, TASKS_EP0RCVOUT seem to need EasyDMA to be available
+ // However these don't trigger any DMA transfer and got ENDED event subsequently
+ // Therefore dma_pending is corrected right away
+ if ((reg_startep == &NRF_USBD->TASKS_EP0STATUS) || (reg_startep == &NRF_USBD->TASKS_EP0RCVOUT)) {
+ atomic_flag_clear(&_dcd.dma_running);
}
+}
- _dcd.dma_pending++;
-
- (*reg_startep) = 1;
- __ISB(); __DSB();
+static void edpt_dma_start(volatile uint32_t* reg_startep) {
+ if (atomic_flag_test_and_set(&_dcd.dma_running)) {
+ usbd_defer_func((osal_task_func_t)(uintptr_t ) edpt_dma_start, (void*) (uintptr_t) reg_startep, true);
+ } else {
+ start_dma(reg_startep);
+ }
}
// DMA is complete
-static void edpt_dma_end(void)
-{
- TU_ASSERT(_dcd.dma_pending, );
- _dcd.dma_pending = 0;
+static void edpt_dma_end(void) {
+ atomic_flag_clear(&_dcd.dma_running);
}
// helper getting td
-static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir)
-{
+static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir) {
return &_dcd.xfer[epnum][dir];
}
+static void xact_out_dma(uint8_t epnum);
+
+// Function wraps xact_out_dma which wants uint8_t while usbd_defer_func wants void (*)(void *)
+static void xact_out_dma_wrapper(void* epnum) {
+ xact_out_dma((uint8_t) ((uintptr_t) epnum));
+}
+
// Start DMA to move data from Endpoint -> RAM
-static void xact_out_dma(uint8_t epnum)
-{
+static void xact_out_dma(uint8_t epnum) {
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
uint32_t xact_len;
- if (epnum == EP_ISO_NUM)
- {
+ // DMA can't be active during read of SIZE.EPOUT or SIZE.ISOOUT, so try to lock,
+ // If already running defer call regardless if it was called from ISR or task,
+ if (atomic_flag_test_and_set(&_dcd.dma_running)) {
+ usbd_defer_func((osal_task_func_t) xact_out_dma_wrapper, (void*) (uint32_t) epnum, is_in_isr());
+ return;
+ }
+ if (epnum == EP_ISO_NUM) {
xact_len = NRF_USBD->SIZE.ISOOUT;
// If ZERO bit is set, ignore ISOOUT length
- if (xact_len & USBD_SIZE_ISOOUT_ZERO_Msk) xact_len = 0;
- else
- {
- // Trigger DMA move data from Endpoint -> SRAM
- NRF_USBD->ISOOUT.PTR = (uint32_t) xfer->buffer;
- NRF_USBD->ISOOUT.MAXCNT = xact_len;
+ if (xact_len & USBD_SIZE_ISOOUT_ZERO_Msk) {
+ xact_len = 0;
+ atomic_flag_clear(&_dcd.dma_running);
+ } else {
+ if (xfer->started) {
+ // Trigger DMA move data from Endpoint -> SRAM
+ NRF_USBD->ISOOUT.PTR = (uint32_t) xfer->buffer;
+ NRF_USBD->ISOOUT.MAXCNT = xact_len;
- edpt_dma_start(&NRF_USBD->TASKS_STARTISOOUT);
+ start_dma(&NRF_USBD->TASKS_STARTISOOUT);
+ } else {
+ atomic_flag_clear(&_dcd.dma_running);
+ }
}
- }
- else
- {
- xact_len = (uint8_t)NRF_USBD->SIZE.EPOUT[epnum];
+ } else {
+ // limit xact len to remaining length
+ xact_len = tu_min16((uint16_t) NRF_USBD->SIZE.EPOUT[epnum], xfer->total_len - xfer->actual_len);
// Trigger DMA move data from Endpoint -> SRAM
NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
- edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
+ start_dma(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
}
-
- xfer->buffer += xact_len;
- xfer->actual_len += xact_len;
}
// Prepare for a CBI transaction IN, call at the start
// it start DMA to transfer data from RAM -> Endpoint
-static void xact_in_dma(uint8_t epnum)
-{
+static void xact_in_dma(uint8_t epnum) {
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
// Each transaction is up to Max Packet Size
uint16_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps);
- NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer;
+ NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer;
NRF_USBD->EPIN[epnum].MAXCNT = xact_len;
- xfer->buffer += xact_len;
-
edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]);
}
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
-void dcd_init (uint8_t rhport)
-{
+void dcd_init(uint8_t rhport) {
+ TU_LOG2("dcd init\r\n");
(void) rhport;
}
-void dcd_int_enable(uint8_t rhport)
-{
+void dcd_int_enable(uint8_t rhport) {
(void) rhport;
NVIC_EnableIRQ(USBD_IRQn);
}
-void dcd_int_disable(uint8_t rhport)
-{
+void dcd_int_disable(uint8_t rhport) {
(void) rhport;
NVIC_DisableIRQ(USBD_IRQn);
}
-void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
-{
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
(void) rhport;
(void) dev_addr;
// Set Address is automatically update by hw controller, nothing to do
@@ -253,24 +257,16 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
NRF_USBD->INTENSET = USBD_INTEN_USBEVENT_Msk;
}
-void dcd_remote_wakeup(uint8_t rhport)
-{
+void dcd_remote_wakeup(uint8_t rhport) {
(void) rhport;
// Bring controller out of low power mode
+ // will start wakeup when USBWUALLOWED is set
NRF_USBD->LOWPOWER = 0;
-
- // Initiate RESUME signal
- NRF_USBD->DPDMVALUE = USBD_DPDMVALUE_STATE_Resume;
- NRF_USBD->TASKS_DPDMDRIVE = 1;
-
- // TODO There is no USBEVENT Resume interrupt
- // We may manually raise DCD_EVENT_RESUME event here
}
// disconnect by disabling internal pull-up resistor on D+/D-
-void dcd_disconnect(uint8_t rhport)
-{
+void dcd_disconnect(uint8_t rhport) {
(void) rhport;
NRF_USBD->USBPULLUP = 0;
@@ -280,167 +276,193 @@ void dcd_disconnect(uint8_t rhport)
}
// connect by enabling internal pull-up resistor on D+/D-
-void dcd_connect(uint8_t rhport)
-{
+void dcd_connect(uint8_t rhport) {
(void) rhport;
NRF_USBD->USBPULLUP = 1;
}
+void dcd_sof_enable(uint8_t rhport, bool en) {
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
-bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
-{
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
(void) rhport;
- uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
+ uint8_t const ep_addr = desc_edpt->bEndpointAddress;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- _dcd.xfer[epnum][dir].mps = desc_edpt->wMaxPacketSize.size;
+ _dcd.xfer[epnum][dir].mps = tu_edpt_packet_size(desc_edpt);
- if (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS)
- {
- if (dir == TUSB_DIR_OUT)
- {
+ if (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) {
+ if (dir == TUSB_DIR_OUT) {
NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum);
NRF_USBD->EPOUTEN |= TU_BIT(epnum);
// Write any value to SIZE register will allow nRF to ACK/accept data
NRF_USBD->SIZE.EPOUT[epnum] = 0;
- }else
- {
+ } else {
NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
- NRF_USBD->EPINEN |= TU_BIT(epnum);
+ NRF_USBD->EPINEN |= TU_BIT(epnum);
}
- }
- else
- {
+ // clear stall and reset DataToggle
+ NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
+ NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr;
+ } else {
TU_ASSERT(epnum == EP_ISO_NUM);
- if (dir == TUSB_DIR_OUT)
- {
+ if (dir == TUSB_DIR_OUT) {
// SPLIT ISO buffer when ISO IN endpoint is already opened.
if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN;
+
// Clear old events
NRF_USBD->EVENTS_ENDISOOUT = 0;
+
// Clear SOF event in case interrupt was not enabled yet.
if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0;
+
// Enable SOF and ISOOUT interrupts, and ISOOUT endpoint.
NRF_USBD->INTENSET = USBD_INTENSET_ENDISOOUT_Msk | USBD_INTENSET_SOF_Msk;
NRF_USBD->EPOUTEN |= USBD_EPOUTEN_ISOOUT_Msk;
- }
- else
- {
+ } else {
NRF_USBD->EVENTS_ENDISOIN = 0;
+
// SPLIT ISO buffer when ISO OUT endpoint is already opened.
if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN;
+
// Clear SOF event in case interrupt was not enabled yet.
if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0;
+
// Enable SOF and ISOIN interrupts, and ISOIN endpoint.
NRF_USBD->INTENSET = USBD_INTENSET_ENDISOIN_Msk | USBD_INTENSET_SOF_Msk;
- NRF_USBD->EPINEN |= USBD_EPINEN_ISOIN_Msk;
+ NRF_USBD->EPINEN |= USBD_EPINEN_ISOIN_Msk;
}
}
- __ISB(); __DSB();
+
+ __ISB();
+ __DSB();
return true;
}
-void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
-{
+void dcd_edpt_close_all(uint8_t rhport) {
+ // disable interrupt to prevent race condition
+ dcd_int_disable(rhport);
+
+ // disable all non-control (bulk + interrupt) endpoints
+ for (uint8_t ep = 1; ep < EP_CBI_COUNT; ep++) {
+ NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + ep) | TU_BIT(USBD_INTEN_ENDEPIN0_Pos + ep);
+
+ NRF_USBD->TASKS_STARTEPIN[ep] = 0;
+ NRF_USBD->TASKS_STARTEPOUT[ep] = 0;
+
+ tu_memclr(_dcd.xfer[ep], 2 * sizeof(xfer_td_t));
+ }
+
+ // disable both ISO
+ NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk | USBD_INTENCLR_ENDISOOUT_Msk | USBD_INTENCLR_ENDISOIN_Msk;
+ NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir;
+
+ NRF_USBD->TASKS_STARTISOIN = 0;
+ NRF_USBD->TASKS_STARTISOOUT = 0;
+
+ tu_memclr(_dcd.xfer[EP_ISO_NUM], 2 * sizeof(xfer_td_t));
+
+ // de-activate all non-control
+ NRF_USBD->EPOUTEN = 1UL;
+ NRF_USBD->EPINEN = 1UL;
+
+ dcd_int_enable(rhport);
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- if (epnum != EP_ISO_NUM)
- {
+ if (epnum != EP_ISO_NUM) {
// CBI
- if (dir == TUSB_DIR_OUT)
- {
+ if (dir == TUSB_DIR_OUT) {
NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum);
NRF_USBD->EPOUTEN &= ~TU_BIT(epnum);
- }
- else
- {
+ } else {
NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
NRF_USBD->EPINEN &= ~TU_BIT(epnum);
}
- }
- else
- {
+ } else {
_dcd.xfer[EP_ISO_NUM][dir].mps = 0;
// ISO
- if (dir == TUSB_DIR_OUT)
- {
+ if (dir == TUSB_DIR_OUT) {
NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOOUT_Msk;
NRF_USBD->EPOUTEN &= ~USBD_EPOUTEN_ISOOUT_Msk;
NRF_USBD->EVENTS_ENDISOOUT = 0;
- }
- else
- {
+ } else {
NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOIN_Msk;
NRF_USBD->EPINEN &= ~USBD_EPINEN_ISOIN_Msk;
}
// One of the ISO endpoints closed, no need to split buffers any more.
NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir;
// When both ISO endpoint are close there is no need for SOF any more.
- if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps + _dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps == 0) NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
+ if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps + _dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps == 0)
+ NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
}
- __ISB(); __DSB();
+ _dcd.xfer[epnum][dir].started = false;
+ __ISB();
+ __DSB();
}
-bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
-{
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
xfer_td_t* xfer = get_td(epnum, dir);
- xfer->buffer = buffer;
- xfer->total_len = total_bytes;
+ TU_ASSERT(!xfer->started);
+ xfer->buffer = buffer;
+ xfer->total_len = total_bytes;
xfer->actual_len = 0;
// Control endpoint with zero-length packet and opposite direction to 1st request byte --> status stage
bool const control_status = (epnum == 0 && total_bytes == 0 && dir != tu_edpt_dir(NRF_USBD->BMREQUESTTYPE));
- if ( control_status )
- {
- // Status Phase also requires Easy DMA has to be available as well !!!!
- // However TASKS_EP0STATUS doesn't trigger any DMA transfer and got ENDED event subsequently
- // Therefore dma_running state will be corrected right away
+ if (control_status) {
+ // Status Phase also requires EasyDMA has to be available as well !!!!
edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS);
- if (_dcd.dma_pending) _dcd.dma_pending--; // correct the dma_running++ in dma start
// The nRF doesn't interrupt on status transmit so we queue up a success response.
- dcd_event_xfer_complete(0, ep_addr, 0, XFER_RESULT_SUCCESS, false);
- }
- else if ( dir == TUSB_DIR_OUT )
- {
- if ( epnum == 0 )
- {
- // Accept next Control Out packet
- NRF_USBD->TASKS_EP0RCVOUT = 1;
- }else
- {
- if ( xfer->data_received )
- {
- // Data may already be received previously
- xfer->data_received = false;
-
+ dcd_event_xfer_complete(0, ep_addr, 0, XFER_RESULT_SUCCESS, is_in_isr());
+ } else if (dir == TUSB_DIR_OUT) {
+ xfer->started = true;
+ if (epnum == 0) {
+ // Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
+ edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
+ } else {
+ // started just set, it could start DMA transfer if interrupt was trigger after this line
+ // code only needs to start transfer (from Endpoint to RAM) when data_received was set
+ // before started was set. If started is NOT set but data_received is, it means that
+ // current transfer was already finished and next data is already present in endpoint and
+ // can be consumed by future transfer
+ __ISB();
+ __DSB();
+ if (xfer->data_received && xfer->started) {
+ // Data is already received previously
// start DMA to copy to SRAM
+ xfer->data_received = false;
xact_out_dma(epnum);
- }
- else
- {
+ } else {
// nRF auto accept next Bulk/Interrupt OUT packet
// nothing to do
}
}
- }
- else
- {
+ } else {
// Start DMA to copy data from RAM -> Endpoint
xact_in_dma(epnum);
}
@@ -448,93 +470,111 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
return true;
}
-void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
-{
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
(void) rhport;
+
uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ xfer_td_t* xfer = get_td(epnum, dir);
- if ( epnum == 0 )
- {
+ if (epnum == 0) {
NRF_USBD->TASKS_EP0STALL = 1;
- }else if (epnum != EP_ISO_NUM)
- {
+ } else if (epnum != EP_ISO_NUM) {
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_Stall << USBD_EPSTALL_STALL_Pos) | ep_addr;
+
+ // Note: nRF can auto ACK packet OUT before get stalled.
+ // There maybe data in endpoint fifo already, we need to pull it out
+ if ((dir == TUSB_DIR_OUT) && xfer->data_received) {
+ xfer->data_received = false;
+ xact_out_dma(epnum);
+ }
}
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
}
-void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
-{
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if ( epnum != 0 && epnum != EP_ISO_NUM )
- {
- // clear stall
- NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ if (epnum != 0 && epnum != EP_ISO_NUM) {
// reset data toggle to DATA0
+ // First write this register with VALUE=Nop to select the endpoint, then either read it to get the status from
+ // VALUE, or write it again with VALUE=Data0 or Data1
+ NRF_USBD->DTOGGLE = ep_addr;
NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr;
+ // clear stall
+ NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
+
// Write any value to SIZE register will allow nRF to ACK/accept data
- // Drop any pending data
if (dir == TUSB_DIR_OUT) NRF_USBD->SIZE.EPOUT[epnum] = 0;
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
}
}
/*------------------------------------------------------------------*/
/* Interrupt Handler
*------------------------------------------------------------------*/
-void bus_reset(void)
-{
- for(int i=0; i<8; i++)
- {
+void bus_reset(void) {
+ // 6.35.6 USB controller automatically disabled all endpoints (except control)
+ NRF_USBD->EPOUTEN = 1UL;
+ NRF_USBD->EPINEN = 1UL;
+
+ for (int i = 0; i < 8; i++) {
NRF_USBD->TASKS_STARTEPIN[i] = 0;
NRF_USBD->TASKS_STARTEPOUT[i] = 0;
}
- NRF_USBD->TASKS_STARTISOIN = 0;
+ NRF_USBD->TASKS_STARTISOIN = 0;
NRF_USBD->TASKS_STARTISOOUT = 0;
+ // Clear USB Event Interrupt
+ NRF_USBD->EVENTS_USBEVENT = 0;
+ NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE;
+
+ // Reset interrupt
+ NRF_USBD->INTENCLR = NRF_USBD->INTEN;
+ NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_USBEVENT_Msk | USBD_INTEN_EPDATA_Msk |
+ USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk |
+ USBD_INTEN_ENDEPOUT0_Msk;
+
tu_varclr(&_dcd);
_dcd.xfer[0][TUSB_DIR_IN].mps = MAX_PACKET_SIZE;
_dcd.xfer[0][TUSB_DIR_OUT].mps = MAX_PACKET_SIZE;
}
-void dcd_int_handler(uint8_t rhport)
-{
+void dcd_int_handler(uint8_t rhport) {
(void) rhport;
- uint32_t const inten = NRF_USBD->INTEN;
+ uint32_t const inten = NRF_USBD->INTEN;
uint32_t int_status = 0;
volatile uint32_t* regevt = &NRF_USBD->EVENTS_USBRESET;
- for(uint8_t i=0; i<USBD_INTEN_EPDATA_Pos+1; i++)
- {
- if ( tu_bit_test(inten, i) && regevt[i] )
- {
+ for (uint8_t i = 0; i < USBD_INTEN_EPDATA_Pos + 1; i++) {
+ if (tu_bit_test(inten, i) && regevt[i]) {
int_status |= TU_BIT(i);
// event clear
regevt[i] = 0;
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
}
}
- if ( int_status & USBD_INTEN_USBRESET_Msk )
- {
+ if (int_status & USBD_INTEN_USBRESET_Msk) {
bus_reset();
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
}
// ISOIN: Data was moved to endpoint buffer, client will be notified in SOF
- if ( int_status & USBD_INTEN_ENDISOIN_Msk )
- {
+ if (int_status & USBD_INTEN_ENDISOIN_Msk) {
xfer_td_t* xfer = get_td(EP_ISO_NUM, TUSB_DIR_IN);
xfer->actual_len = NRF_USBD->ISOIN.AMOUNT;
@@ -543,70 +583,97 @@ void dcd_int_handler(uint8_t rhport)
xfer->iso_in_transfer_ready = true;
}
- if ( int_status & USBD_INTEN_SOF_Msk )
- {
+ if (int_status & USBD_INTEN_SOF_Msk) {
+ bool iso_enabled = false;
+
// ISOOUT: Transfer data gathered in previous frame from buffer to RAM
- if (NRF_USBD->EPOUTEN & USBD_EPOUTEN_ISOOUT_Msk)
- {
- xact_out_dma(EP_ISO_NUM);
+ if (NRF_USBD->EPOUTEN & USBD_EPOUTEN_ISOOUT_Msk) {
+ iso_enabled = true;
+ // Transfer from endpoint to RAM only if data is not corrupted
+ if ((int_status & USBD_INTEN_USBEVENT_Msk) == 0 ||
+ (NRF_USBD->EVENTCAUSE & USBD_EVENTCAUSE_ISOOUTCRC_Msk) == 0) {
+ xact_out_dma(EP_ISO_NUM);
+ }
}
+
// ISOIN: Notify client that data was transferred
- xfer_td_t* xfer = get_td(EP_ISO_NUM, TUSB_DIR_IN);
- if ( xfer->iso_in_transfer_ready )
- {
- xfer->iso_in_transfer_ready = false;
- dcd_event_xfer_complete(0, EP_ISO_NUM | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true);
+ if (NRF_USBD->EPINEN & USBD_EPINEN_ISOIN_Msk) {
+ iso_enabled = true;
+
+ xfer_td_t* xfer = get_td(EP_ISO_NUM, TUSB_DIR_IN);
+ if (xfer->iso_in_transfer_ready) {
+ xfer->iso_in_transfer_ready = false;
+ dcd_event_xfer_complete(0, EP_ISO_NUM | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true);
+ }
+ }
+
+ if (!iso_enabled) {
+ // ISO endpoint is not used, SOF is only enabled one-time for remote wakeup
+ // so we disable it now
+ NRF_USBD->INTENCLR = USBD_INTENSET_SOF_Msk;
}
+
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
}
- if ( int_status & USBD_INTEN_USBEVENT_Msk )
- {
- uint32_t const evt_cause = NRF_USBD->EVENTCAUSE & (USBD_EVENTCAUSE_SUSPEND_Msk | USBD_EVENTCAUSE_RESUME_Msk);
- NRF_USBD->EVENTCAUSE = evt_cause; // clear interrupt
+ if (int_status & USBD_INTEN_USBEVENT_Msk) {
+ TU_LOG(3, "EVENTCAUSE = 0x%04" PRIX32 "\r\n", NRF_USBD->EVENTCAUSE);
- if ( evt_cause & USBD_EVENTCAUSE_SUSPEND_Msk )
- {
- dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+ enum {
+ EVT_CAUSE_MASK = USBD_EVENTCAUSE_SUSPEND_Msk | USBD_EVENTCAUSE_RESUME_Msk | USBD_EVENTCAUSE_USBWUALLOWED_Msk |
+ USBD_EVENTCAUSE_ISOOUTCRC_Msk
+ };
+ uint32_t const evt_cause = NRF_USBD->EVENTCAUSE & EVT_CAUSE_MASK;
+ NRF_USBD->EVENTCAUSE = evt_cause; // clear interrupt
+ if (evt_cause & USBD_EVENTCAUSE_SUSPEND_Msk) {
// Put controller into low power mode
+ // Leave HFXO disable to application, since it may be used by other peripherals
NRF_USBD->LOWPOWER = 1;
- // Leave HFXO disable to application, since it may be used by other
+ dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
}
- if ( evt_cause & USBD_EVENTCAUSE_RESUME_Msk )
- {
- dcd_event_bus_signal(0, DCD_EVENT_RESUME , true);
+ if (evt_cause & USBD_EVENTCAUSE_USBWUALLOWED_Msk) {
+ // USB is out of low power mode, and wakeup is allowed
+ // Initiate RESUME signal
+ NRF_USBD->DPDMVALUE = USBD_DPDMVALUE_STATE_Resume;
+ NRF_USBD->TASKS_DPDMDRIVE = 1;
+
+ // There is no Resume interrupt for remote wakeup, enable SOF for to report bus ready state
+ // Clear SOF event in case interrupt was not enabled yet.
+ if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0;
+ NRF_USBD->INTENSET = USBD_INTENSET_SOF_Msk;
}
- }
- if ( int_status & EDPT_END_ALL_MASK )
- {
- // DMA complete move data from SRAM -> Endpoint
- edpt_dma_end();
+ if (evt_cause & USBD_EVENTCAUSE_RESUME_Msk) {
+ dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+ }
}
-
+
// Setup tokens are specific to the Control endpoint.
- if ( int_status & USBD_INTEN_EP0SETUP_Msk )
- {
- uint8_t const setup[8] =
- {
- NRF_USBD->BMREQUESTTYPE , NRF_USBD->BREQUEST, NRF_USBD->WVALUEL , NRF_USBD->WVALUEH,
- NRF_USBD->WINDEXL , NRF_USBD->WINDEXH , NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH
+ if (int_status & USBD_INTEN_EP0SETUP_Msk) {
+ uint8_t const setup[8] = {
+ NRF_USBD->BMREQUESTTYPE, NRF_USBD->BREQUEST, NRF_USBD->WVALUEL, NRF_USBD->WVALUEH,
+ NRF_USBD->WINDEXL, NRF_USBD->WINDEXH, NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH
};
// nrf5x hw auto handle set address, there is no need to inform usb stack
- tusb_control_request_t const * request = (tusb_control_request_t const *) setup;
+ tusb_control_request_t const* request = (tusb_control_request_t const*) setup;
- if ( !(TUSB_REQ_RCPT_DEVICE == request->bmRequestType_bit.recipient &&
- TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type &&
- TUSB_REQ_SET_ADDRESS == request->bRequest) )
- {
+ if (!(TUSB_REQ_RCPT_DEVICE == request->bmRequestType_bit.recipient &&
+ TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type &&
+ TUSB_REQ_SET_ADDRESS == request->bRequest)) {
dcd_event_setup_received(0, setup, true);
}
}
+ if (int_status & EDPT_END_ALL_MASK) {
+ // DMA complete move data from SRAM <-> Endpoint
+ // Must before endpoint transfer handling
+ edpt_dma_end();
+ }
+
//--------------------------------------------------------------------+
/* Control/Bulk/Interrupt (CBI) Transfer
*
@@ -618,7 +685,7 @@ void dcd_int_handler(uint8_t rhport)
* - Host -> Endpoint
* EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPOUT[i]
* to start DMA. For Bulk/Interrupt, this step can occur automatically (without sw),
- * which means data may or may not be ready (data_received flag).
+ * which means data may or may not be ready (out_received flag).
* - Endpoint -> RAM
* ENDEPOUT[i] interrupted, transaction complete, sw prepare next transaction
*
@@ -643,28 +710,27 @@ void dcd_int_handler(uint8_t rhport)
* len if Host decides to sent fewer bytes, it this case transaction is also
* complete and next transfer is not initiated here like for CBI.
*/
- for(uint8_t epnum=0; epnum<EP_CBI_COUNT+1; epnum++)
- {
- if ( tu_bit_test(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum))
- {
+ for (uint8_t epnum = 0; epnum < EP_CBI_COUNT + 1; epnum++) {
+ if (tu_bit_test(int_status, USBD_INTEN_ENDEPOUT0_Pos + epnum)) {
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
- uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
+ uint16_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
+
+ xfer->buffer += xact_len;
+ xfer->actual_len += xact_len;
// Transfer complete if transaction len < Max Packet Size or total len is transferred
- if ( (epnum != EP_ISO_NUM) && (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) )
- {
- if ( epnum == 0 )
- {
- // Accept next Control Out packet
- NRF_USBD->TASKS_EP0RCVOUT = 1;
- }else
- {
+ if ((epnum != EP_ISO_NUM) && (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len)) {
+ if (epnum == 0) {
+ // Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
+ edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
+ } else {
// nRF auto accept next Bulk/Interrupt OUT packet
// nothing to do
}
- }else
- {
+ } else {
+ TU_ASSERT(xfer->started,);
xfer->total_len = xfer->actual_len;
+ xfer->started = false;
// CBI OUT complete
dcd_event_xfer_complete(0, epnum, xfer->actual_len, XFER_RESULT_SUCCESS, true);
@@ -675,11 +741,11 @@ void dcd_int_handler(uint8_t rhport)
}
// Endpoint <-> Host ( In & OUT )
- if ( int_status & (USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0DATADONE_Msk) )
- {
+ if (int_status & (USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0DATADONE_Msk)) {
uint32_t data_status = NRF_USBD->EPDATASTATUS;
NRF_USBD->EPDATASTATUS = data_status;
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
// EP0DATADONE is set with either Control Out on IN Data
// Since EPDATASTATUS cannot be used to determine whether it is control OUT or IN.
@@ -688,20 +754,18 @@ void dcd_int_handler(uint8_t rhport)
bool const is_control_out = (int_status & USBD_INTEN_EP0DATADONE_Msk) && !(NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK);
// CBI In: Endpoint -> Host (transaction complete)
- for(uint8_t epnum=0; epnum<EP_CBI_COUNT; epnum++)
- {
- if ( tu_bit_test(data_status, epnum) || (epnum == 0 && is_control_in) )
- {
+ for (uint8_t epnum = 0; epnum < EP_CBI_COUNT; epnum++) {
+ if (tu_bit_test(data_status, epnum) || (epnum == 0 && is_control_in)) {
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
+ uint8_t const xact_len = NRF_USBD->EPIN[epnum].AMOUNT;
- xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT;
+ xfer->buffer += xact_len;
+ xfer->actual_len += xact_len;
- if ( xfer->actual_len < xfer->total_len )
- {
+ if (xfer->actual_len < xfer->total_len) {
// Start DMA to copy next data packet
xact_in_dma(epnum);
- } else
- {
+ } else {
// CBI IN complete
dcd_event_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true);
}
@@ -709,17 +773,13 @@ void dcd_int_handler(uint8_t rhport)
}
// CBI OUT: Host -> Endpoint
- for(uint8_t epnum=0; epnum<EP_CBI_COUNT; epnum++)
- {
- if ( tu_bit_test(data_status, 16+epnum) || (epnum == 0 && is_control_out) )
- {
+ for (uint8_t epnum = 0; epnum < EP_CBI_COUNT; epnum++) {
+ if (tu_bit_test(data_status, 16 + epnum) || (epnum == 0 && is_control_out)) {
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
- if (xfer->actual_len < xfer->total_len)
- {
+ if (xfer->started && xfer->actual_len < xfer->total_len) {
xact_out_dma(epnum);
- }else
- {
+ } else {
// Data overflow !!! Nah, nRF will auto accept next Bulk/Interrupt OUT packet
// Mark this endpoint with data received
xfer->data_received = true;
@@ -743,64 +803,80 @@ void dcd_int_handler(uint8_t rhport)
#define SD_MAGIC_NUMBER 0x51B1E5DB
#endif
-static inline bool is_sd_existed(void)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool is_sd_existed(void) {
return *((uint32_t*)(SOFTDEVICE_INFO_STRUCT_ADDRESS+4)) == SD_MAGIC_NUMBER;
}
// check if SD is existed and enabled
-static inline bool is_sd_enabled(void)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool is_sd_enabled(void) {
if ( !is_sd_existed() ) return false;
-
uint8_t sd_en = false;
(void) sd_softdevice_is_enabled(&sd_en);
return sd_en;
}
#endif
-static bool hfclk_running(void)
-{
+static bool hfclk_running(void) {
#ifdef SOFTDEVICE_PRESENT
- if ( is_sd_enabled() )
- {
- uint32_t is_running;
+ if ( is_sd_enabled() ) {
+ uint32_t is_running = 0;
(void) sd_clock_hfclk_is_running(&is_running);
return (is_running ? true : false);
}
#endif
+#if CFG_TUD_NRF_NRFX_VERSION == 1
+ return nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY);
+#else
return nrf_clock_hf_is_running(NRF_CLOCK, NRF_CLOCK_HFCLK_HIGH_ACCURACY);
+#endif
}
-static void hfclk_enable(void)
-{
+static void hfclk_enable(void) {
+#if CFG_TUSB_OS == OPT_OS_MYNEWT
+ usb_clock_request();
+ return;
+#else
+
// already running, nothing to do
- if ( hfclk_running() ) return;
+ if (hfclk_running()) return;
#ifdef SOFTDEVICE_PRESENT
- if ( is_sd_enabled() )
- {
+ if ( is_sd_enabled() ) {
(void)sd_clock_hfclk_request();
return;
}
#endif
+#if CFG_TUD_NRF_NRFX_VERSION == 1
+ nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
+ nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTART);
+#else
nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
+#endif
+#endif
}
-static void hfclk_disable(void)
-{
+static void hfclk_disable(void) {
+#if CFG_TUSB_OS == OPT_OS_MYNEWT
+ usb_clock_release();
+ return;
+#else
+
#ifdef SOFTDEVICE_PRESENT
- if ( is_sd_enabled() )
- {
+ if ( is_sd_enabled() ) {
(void)sd_clock_hfclk_release();
return;
}
#endif
+#if CFG_TUD_NRF_NRFX_VERSION == 1
+ nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTOP);
+#else
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP);
+#endif
+#endif
}
// Power & Clock Peripheral on nRF5x to manage USB
@@ -813,8 +889,7 @@ static void hfclk_disable(void)
// Therefore this function must be called to handle USB power event by
// - nrfx_power_usbevt_init() : if Softdevice is not used or enabled
// - SoftDevice SOC event : if SD is used and enabled
-void tusb_hal_nrf_power_event (uint32_t event)
-{
+void tusb_hal_nrf_power_event(uint32_t event) {
// Value is chosen to be as same as NRFX_POWER_USB_EVT_* in nrfx_power.h
enum {
USB_EVT_DETECTED = 0,
@@ -822,145 +897,137 @@ void tusb_hal_nrf_power_event (uint32_t event)
USB_EVT_READY = 2
};
- switch ( event )
- {
- case USB_EVT_DETECTED:
- TU_LOG2("Power USB Detect\r\n");
+#if CFG_TUSB_DEBUG >= 2
+ const char* const power_evt_str[] = {"Detected", "Removed", "Ready"};
+ TU_LOG(2, "Power USB event: %s\r\n", power_evt_str[event]);
+#endif
- if ( !NRF_USBD->ENABLE )
- {
- /* Prepare for READY event receiving */
+ switch (event) {
+ case USB_EVT_DETECTED:
+ if (!NRF_USBD->ENABLE) {
+ // Prepare for receiving READY event: disable interrupt since we will blocking wait
+ NRF_USBD->INTENCLR = USBD_INTEN_USBEVENT_Msk;
NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk;
- __ISB(); __DSB(); // for sync
+ __ISB();
+ __DSB(); // for sync
-#ifdef NRF52_SERIES
+#ifdef NRF52_SERIES // NRF53 does not need this errata
// ERRATA 171, 187, 166
- if ( nrfx_usbd_errata_187() )
- {
+ if (nrfx_usbd_errata_187()) {
// CRITICAL_REGION_ENTER();
- if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
- {
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- *((volatile uint32_t *) (0x4006ED14)) = 0x00000003;
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- }
- else
- {
- *((volatile uint32_t *) (0x4006ED14)) = 0x00000003;
+ if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ *((volatile uint32_t*) (0x4006ED14)) = 0x00000003;
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ } else {
+ *((volatile uint32_t*) (0x4006ED14)) = 0x00000003;
}
// CRITICAL_REGION_EXIT();
}
- if ( nrfx_usbd_errata_171() )
- {
+ if (nrfx_usbd_errata_171()) {
// CRITICAL_REGION_ENTER();
- if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
- {
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- *((volatile uint32_t *) (0x4006EC14)) = 0x000000C0;
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- }
- else
- {
- *((volatile uint32_t *) (0x4006EC14)) = 0x000000C0;
+ if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ *((volatile uint32_t*) (0x4006EC14)) = 0x000000C0;
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ } else {
+ *((volatile uint32_t*) (0x4006EC14)) = 0x000000C0;
}
// CRITICAL_REGION_EXIT();
}
#endif
- /* Enable the peripheral */
+ // Enable the peripheral (will cause Ready event)
NRF_USBD->ENABLE = 1;
- __ISB(); __DSB(); // for sync
+ __ISB();
+ __DSB(); // for sync
// Enable HFCLK
hfclk_enable();
}
- break;
+ break;
case USB_EVT_READY:
- TU_LOG2("Power USB Ready\r\n");
-
// Skip if pull-up is enabled and HCLK is already running.
// Application probably call this more than necessary.
- if ( NRF_USBD->USBPULLUP && hfclk_running() ) break;
+ if (NRF_USBD->USBPULLUP && hfclk_running()) break;
- /* Waiting for USBD peripheral enabled */
- while ( !(USBD_EVENTCAUSE_READY_Msk & NRF_USBD->EVENTCAUSE) ) { }
+ // Waiting for USBD peripheral enabled
+ while (!(USBD_EVENTCAUSE_READY_Msk & NRF_USBD->EVENTCAUSE)) {}
NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk;
- __ISB(); __DSB(); // for sync
+ __ISB();
+ __DSB(); // for sync
#ifdef NRF52_SERIES
- if ( nrfx_usbd_errata_171() )
- {
+ if (nrfx_usbd_errata_171()) {
// CRITICAL_REGION_ENTER();
- if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
- {
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- *((volatile uint32_t *) (0x4006EC14)) = 0x00000000;
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- }
- else
- {
- *((volatile uint32_t *) (0x4006EC14)) = 0x00000000;
+ if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ *((volatile uint32_t*) (0x4006EC14)) = 0x00000000;
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ } else {
+ *((volatile uint32_t*) (0x4006EC14)) = 0x00000000;
}
// CRITICAL_REGION_EXIT();
}
- if ( nrfx_usbd_errata_187() )
- {
+ if (nrfx_usbd_errata_187()) {
// CRITICAL_REGION_ENTER();
- if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
- {
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- *((volatile uint32_t *) (0x4006ED14)) = 0x00000000;
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- }
- else
- {
- *((volatile uint32_t *) (0x4006ED14)) = 0x00000000;
+ if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ *((volatile uint32_t*) (0x4006ED14)) = 0x00000000;
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ } else {
+ *((volatile uint32_t*) (0x4006ED14)) = 0x00000000;
}
// CRITICAL_REGION_EXIT();
}
- if ( nrfx_usbd_errata_166() )
- {
- *((volatile uint32_t *) (NRF_USBD_BASE + 0x800)) = 0x7E3;
- *((volatile uint32_t *) (NRF_USBD_BASE + 0x804)) = 0x40;
+ if (nrfx_usbd_errata_166()) {
+ *((volatile uint32_t*) (NRF_USBD_BASE + 0x800)) = 0x7E3;
+ *((volatile uint32_t*) (NRF_USBD_BASE + 0x804)) = 0x40;
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
}
#endif
// ISO buffer Lower half for IN, upper half for OUT
NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN;
- // Enable interrupt
- NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_EPDATA_Msk |
- USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk | USBD_INTEN_ENDEPOUT0_Msk;
+ // Enable bus-reset interrupt
+ NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk;
// Enable interrupt, priorities should be set by application
NVIC_ClearPendingIRQ(USBD_IRQn);
- NVIC_EnableIRQ(USBD_IRQn);
+
+ // Don't enable USBD interrupt yet, if dcd_init() did not finish yet
+ // Interrupt will be enabled by tud_init(), when USB stack is ready
+ // to handle interrupts.
+ if (tud_inited()) {
+ NVIC_EnableIRQ(USBD_IRQn);
+ }
// Wait for HFCLK
- while ( !hfclk_running() ) { }
+ while (!hfclk_running()) {}
// Enable pull up
NRF_USBD->USBPULLUP = 1;
- __ISB(); __DSB(); // for sync
- break;
+ __ISB();
+ __DSB(); // for sync
+ break;
case USB_EVT_REMOVED:
- TU_LOG2("Power USB Removed\r\n");
- if ( NRF_USBD->ENABLE )
- {
+ if (NRF_USBD->ENABLE) {
// Abort all transfers
// Disable pull up
NRF_USBD->USBPULLUP = 0;
- __ISB(); __DSB(); // for sync
+ __ISB();
+ __DSB(); // for sync
// Disable Interrupt
NVIC_DisableIRQ(USBD_IRQn);
@@ -969,15 +1036,17 @@ void tusb_hal_nrf_power_event (uint32_t event)
NRF_USBD->INTENCLR = NRF_USBD->INTEN;
NRF_USBD->ENABLE = 0;
- __ISB(); __DSB(); // for sync
+ __ISB();
+ __DSB(); // for sync
hfclk_disable();
- dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) ? true : false);
+ dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, is_in_isr());
}
- break;
+ break;
- default: break;
+ default:
+ break;
}
}
diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c
index 047fa3fa6..fb12122e0 100644
--- a/src/portable/nuvoton/nuc120/dcd_nuc120.c
+++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c
@@ -27,15 +27,15 @@
/*
Theory of operation:
- The NUC100/NUC120 USBD peripheral has six "EP"s, but each is simplex,
- so two collectively (peripheral nomenclature of "EP0" and "EP1") are needed to
- implement USB EP0. PERIPH_EP0 and PERIPH_EP1 are used by this driver for
+ The NUC100/NUC120 USBD peripheral has six "EP"s, but each is simplex,
+ so two collectively (peripheral nomenclature of "EP0" and "EP1") are needed to
+ implement USB EP0. PERIPH_EP0 and PERIPH_EP1 are used by this driver for
EP0_IN and EP0_OUT respectively. This leaves up to four for user usage.
*/
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC120)
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC120)
#include "device/dcd.h"
#include "NUC100Series.h"
@@ -99,6 +99,11 @@ static void usb_detach(void)
USBD->DRVSE0 |= USBD_DRVSE0_DRVSE0_Msk;
}
+static inline void usb_memcpy(uint8_t *dest, uint8_t *src, uint16_t size)
+{
+ while(size--) *dest++ = *src++;
+}
+
static void usb_control_send_zlp(void)
{
USBD->EP[PERIPH_EP0].CFG |= USBD_CFG_DSQ_SYNC_Msk;
@@ -151,7 +156,8 @@ static void dcd_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep)
else
#endif
{
- memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now);
+ // USB SRAM seems to only support byte access and memcpy could possibly do it by words
+ usb_memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now);
}
ep->MXPLD = bytes_now;
@@ -245,8 +251,8 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
/* mine the data for the information we need */
int const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
- int const size = p_endpoint_desc->wMaxPacketSize.size;
- tusb_xfer_type_t const type = p_endpoint_desc->bmAttributes.xfer;
+ int const size = tu_edpt_packet_size(p_endpoint_desc);
+ tusb_xfer_type_t const type = (tusb_xfer_type_t) p_endpoint_desc->bmAttributes.xfer;
struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
/* allocate buffer from USB RAM */
@@ -267,6 +273,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
(void) rhport;
@@ -439,7 +451,8 @@ void dcd_int_handler(uint8_t rhport)
else
#endif
{
- memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes);
+ // USB SRAM seems to only support byte access and memcpy could possibly do it by words
+ usb_memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes);
xfer->data_ptr += available_bytes;
}
@@ -484,4 +497,12 @@ void dcd_connect(uint8_t rhport)
usb_attach();
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
#endif
diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c
index 37b7b0106..873b1b7ef 100644
--- a/src/portable/nuvoton/nuc121/dcd_nuc121.c
+++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c
@@ -27,19 +27,25 @@
/*
Theory of operation:
- The NUC121/NUC125/NUC126 USBD peripheral has eight "EP"s, but each is simplex,
- so two collectively (peripheral nomenclature of "EP0" and "EP1") are needed to
- implement USB EP0. PERIPH_EP0 and PERIPH_EP1 are used by this driver for
+ The NUC121/NUC125/NUC126 USBD peripheral has eight "EP"s, but each is simplex,
+ so two collectively (peripheral nomenclature of "EP0" and "EP1") are needed to
+ implement USB EP0. PERIPH_EP0 and PERIPH_EP1 are used by this driver for
EP0_IN and EP0_OUT respectively. This leaves up to six for user usage.
*/
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && ( (CFG_TUSB_MCU == OPT_MCU_NUC121) || (CFG_TUSB_MCU == OPT_MCU_NUC126) )
+#if CFG_TUD_ENABLED && ( (CFG_TUSB_MCU == OPT_MCU_NUC121) || (CFG_TUSB_MCU == OPT_MCU_NUC126) )
#include "device/dcd.h"
#include "NuMicro.h"
+// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
+// We disable SOF for now until needed later on
+#ifndef USE_SOF
+# define USE_SOF 0
+#endif
+
/* allocation of USBD RAM for Setup, EP0_IN, and and EP_OUT */
#define PERIPH_SETUP_BUF_BASE 0
#define PERIPH_SETUP_BUF_LEN 8
@@ -65,9 +71,6 @@ enum ep_enum
PERIPH_MAX_EP,
};
-/* set by dcd_set_address() */
-static volatile uint8_t assigned_address;
-
/* reset by dcd_init(), this is used by dcd_edpt_open() to assign USBD peripheral buffer addresses */
static uint32_t bufseg_addr;
@@ -101,6 +104,11 @@ static void usb_detach(void)
USBD->SE0 |= USBD_SE0_SE0_Msk;
}
+static inline void usb_memcpy(uint8_t *dest, uint8_t *src, uint16_t size)
+{
+ while(size--) *dest++ = *src++;
+}
+
static void usb_control_send_zlp(void)
{
USBD->EP[PERIPH_EP0].CFG |= USBD_CFG_DSQSYNC_Msk;
@@ -153,7 +161,8 @@ static void dcd_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep)
else
#endif
{
- memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now);
+ // USB SRAM seems to only support byte access and memcpy could possibly do it by words
+ usb_memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now);
}
ep->MXPLD = bytes_now;
@@ -191,7 +200,10 @@ static void bus_reset(void)
}
/* centralized location for USBD interrupt enable bit mask */
-static const uint32_t enabled_irqs = USBD_INTSTS_VBDETIF_Msk | USBD_INTSTS_BUSIF_Msk | USBD_INTSTS_SETUP_Msk | USBD_INTSTS_USBIF_Msk | USBD_INTSTS_SOFIF_Msk;
+enum {
+ ENABLED_IRQS = USBD_INTSTS_VBDETIF_Msk | USBD_INTSTS_BUSIF_Msk | USBD_INTSTS_SETUP_Msk |
+ USBD_INTSTS_USBIF_Msk | (USE_SOF ? USBD_INTSTS_SOFIF_Msk : 0)
+};
/*
NUC121/NUC125/NUC126 TinyUSB API driver implementation
@@ -213,8 +225,8 @@ void dcd_init(uint8_t rhport)
usb_attach();
- USBD->INTSTS = enabled_irqs;
- USBD->INTEN = enabled_irqs;
+ USBD->INTSTS = ENABLED_IRQS;
+ USBD->INTEN = ENABLED_IRQS;
}
void dcd_int_enable(uint8_t rhport)
@@ -232,14 +244,30 @@ void dcd_int_disable(uint8_t rhport)
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
{
(void) rhport;
+ (void) dev_addr;
usb_control_send_zlp(); /* SET_ADDRESS is the one exception where TinyUSB doesn't use dcd_edpt_xfer() to generate a ZLP */
- assigned_address = dev_addr;
+
+ // DCD can only set address after status for this request is complete.
+ // do it at dcd_edpt0_status_complete()
+}
+
+static void remote_wakeup_delay(void)
+{
+ // try to delay for 1 ms
+ uint32_t count = SystemCoreClock / 1000;
+ while(count--) __NOP();
}
void dcd_remote_wakeup(uint8_t rhport)
{
(void) rhport;
- USBD->ATTR = USBD_ATTR_RWAKEUP_Msk;
+ // Enable PHY before sending Resume('K') state
+ USBD->ATTR |= USBD_ATTR_PHYEN_Msk;
+ USBD->ATTR |= USBD_ATTR_RWAKEUP_Msk;
+
+ // Per specs: remote wakeup signal bit must be clear within 1-15ms
+ remote_wakeup_delay();
+ USBD->ATTR &=~USBD_ATTR_RWAKEUP_Msk;
}
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
@@ -251,8 +279,8 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
/* mine the data for the information we need */
int const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
- int const size = p_endpoint_desc->wMaxPacketSize.size;
- tusb_xfer_type_t const type = p_endpoint_desc->bmAttributes.xfer;
+ int const size = tu_edpt_packet_size(p_endpoint_desc);
+ tusb_xfer_type_t const type = (tusb_xfer_type_t) p_endpoint_desc->bmAttributes.xfer;
struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
/* allocate buffer from USB RAM */
@@ -273,6 +301,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
(void) rhport;
@@ -345,14 +379,16 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
USBD_EP_T *ep = ep_entry(ep_addr, false);
- ep->CFG |= USBD_CFG_CSTALL_Msk;
+ ep->CFG = (ep->CFG & ~USBD_CFG_DSQSYNC_Msk) | USBD_CFG_CSTALL_Msk;
}
void dcd_int_handler(uint8_t rhport)
{
(void) rhport;
- uint32_t status = USBD->INTSTS;
+ // Mask non-enabled irqs, ex. SOF
+ uint32_t status = USBD->INTSTS & (ENABLED_IRQS | 0xffffff00);
+
#ifdef SUPPORT_LPM
uint32_t state = USBD->ATTR & 0x300f;
#else
@@ -414,9 +450,6 @@ void dcd_int_handler(uint8_t rhport)
{
if (status & USBD_INTSTS_EPEVT0_Msk) /* PERIPH_EP0 (EP0_IN) event: this is treated separately from the rest */
{
- /* given ACK from host has happened, we can now set the address (if not already done) */
- if((USBD->FADDR != assigned_address) && (USBD->FADDR == 0)) USBD->FADDR = assigned_address;
-
uint16_t const available_bytes = USBD->EP[PERIPH_EP0].MXPLD;
active_ep0_xfer = (available_bytes == xfer_table[PERIPH_EP0].max_packet_size);
@@ -450,7 +483,8 @@ void dcd_int_handler(uint8_t rhport)
else
#endif
{
- memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes);
+ // USB SRAM seems to only support byte access and memcpy could possibly do it by words
+ usb_memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes);
xfer->data_ptr += available_bytes;
}
@@ -485,7 +519,24 @@ void dcd_int_handler(uint8_t rhport)
}
/* acknowledge all interrupts */
- USBD->INTSTS = status & enabled_irqs;
+ USBD->INTSTS = status & ENABLED_IRQS;
+}
+
+// Invoked when a control transfer's status stage is complete.
+// May help DCD to prepare for next control transfer, this API is optional.
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
+{
+ (void) rhport;
+
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
+ request->bRequest == TUSB_REQ_SET_ADDRESS )
+ {
+ uint8_t const dev_addr = (uint8_t) request->wValue;
+
+ // Setting new address after the whole request is complete
+ USBD->FADDR = dev_addr;
+ }
}
void dcd_disconnect(uint8_t rhport)
@@ -500,4 +551,12 @@ void dcd_connect(uint8_t rhport)
usb_attach();
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
#endif
diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c
index 4e633086d..3a92c9794 100644
--- a/src/portable/nuvoton/nuc505/dcd_nuc505.c
+++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c
@@ -27,15 +27,15 @@
/*
Theory of operation:
- The NUC505 USBD peripheral has twelve "EP"s, where each is simplex, in addition
+ The NUC505 USBD peripheral has twelve "EP"s, where each is simplex, in addition
to dedicated support for the control endpoint (EP0). The non-user endpoints
- are referred to as "user" EPs in this code, and follow the datasheet
+ are referred to as "user" EPs in this code, and follow the datasheet
nomenclature of EPA through EPL.
*/
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC505)
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC505)
#include "device/dcd.h"
#include "NUC505Series.h"
@@ -144,7 +144,9 @@ static USBD_EP_T *ep_entry(uint8_t ep_addr, bool add)
enum ep_enum ep_index;
struct xfer_ctl_t *xfer;
- for (ep_index = PERIPH_EPA, xfer = &xfer_table[PERIPH_EPA], ep = USBD->EP; ep_index < PERIPH_MAX_EP; ep_index++, xfer++, ep++)
+ for (ep_index = PERIPH_EPA, xfer = &xfer_table[PERIPH_EPA], ep = USBD->EP;
+ ep_index < PERIPH_MAX_EP;
+ ep_index++, xfer++, ep++)
{
if (add)
{
@@ -179,7 +181,7 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep)
ep->EPINTEN = USBD_EPINTEN_TXPKIEN_Msk;
}
- /* provided buffers are thankfully 32-bit aligned, allowing most data to be transfered as 32-bit */
+ /* provided buffers are thankfully 32-bit aligned, allowing most data to be transferred as 32-bit */
#if 0 // TODO support dcd_edpt_xfer_fifo API
if (xfer->ff)
{
@@ -325,7 +327,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
/* mine the data for the information we need */
int const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
- int const size = p_endpoint_desc->wMaxPacketSize.size;
+ int const size = tu_edpt_packet_size(p_endpoint_desc);
tusb_xfer_type_t const type = p_endpoint_desc->bmAttributes.xfer;
struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
@@ -353,6 +355,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
(void) rhport;
@@ -381,7 +389,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to
while (total_bytes < USBD->CEPRXCNT);
for (int count = 0; count < total_bytes; count++)
*buffer++ = USBD->CEPDAT_BYTE;
-
+
dcd_event_xfer_complete(0, ep_addr, total_bytes, XFER_RESULT_SUCCESS, true);
}
}
@@ -390,6 +398,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to
/* mine the data for the information we need */
tusb_dir_t dir = tu_edpt_dir(ep_addr);
USBD_EP_T *ep = ep_entry(ep_addr, false);
+ TU_ASSERT(ep);
struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
/* store away the information we'll needing now and later */
@@ -451,6 +460,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
if (tu_edpt_number(ep_addr))
{
USBD_EP_T *ep = ep_entry(ep_addr, false);
+ TU_ASSERT(ep, );
ep->EPRSPCTL = (ep->EPRSPCTL & 0xf7) | USBD_EPRSPCTL_HALT_Msk;
}
else
@@ -466,6 +476,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
if (tu_edpt_number(ep_addr))
{
USBD_EP_T *ep = ep_entry(ep_addr, false);
+ TU_ASSERT(ep, );
ep->EPRSPCTL = USBD_EPRSPCTL_TOGGLE_Msk;
}
}
@@ -709,4 +720,12 @@ void dcd_connect(uint8_t rhport)
usb_attach();
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
#endif
diff --git a/src/portable/nxp/khci/dcd_khci.c b/src/portable/nxp/khci/dcd_khci.c
index 519b8fb7b..dc71117b3 100644
--- a/src/portable/nxp/khci/dcd_khci.c
+++ b/src/portable/nxp/khci/dcd_khci.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Koji Kitayama
@@ -26,10 +26,14 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX )
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_CHIPIDEA_FS)
-#include "fsl_device_registers.h"
-#define KHCI USB0
+#ifdef TUP_USBIP_CHIPIDEA_FS_KINETIS
+ #include "fsl_device_registers.h"
+ #define KHCI USB0
+#else
+ #error "MCU is not supported"
+#endif
#include "device/dcd.h"
@@ -50,23 +54,23 @@ typedef struct TU_ATTR_PACKED
struct {
union {
struct {
- uint16_t : 2;
- uint16_t tok_pid : 4;
- uint16_t data : 1;
- uint16_t own : 1;
- uint16_t : 8;
+ uint16_t : 2;
+ __IO uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ __IO uint16_t own : 1;
+ uint16_t : 8;
};
struct {
- uint16_t : 2;
- uint16_t bdt_stall: 1;
- uint16_t dts : 1;
- uint16_t ninc : 1;
- uint16_t keep : 1;
- uint16_t : 10;
+ uint16_t : 2;
+ uint16_t bdt_stall : 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ uint16_t : 10;
};
};
- uint16_t bc : 10;
- uint16_t : 6;
+ __IO uint16_t bc : 10;
+ uint16_t : 6;
};
};
uint8_t *addr;
@@ -110,7 +114,7 @@ typedef struct
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
// BDT(Buffer Descriptor Table) must be 256-byte aligned
-CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
+CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
@@ -118,10 +122,8 @@ static void prepare_next_setup_packet(uint8_t rhport)
{
const unsigned out_odd = _dcd.endpoint[0][0].odd;
const unsigned in_odd = _dcd.endpoint[0][1].odd;
- if (_dcd.bdt[0][0][out_odd].own) {
- TU_LOG1("DCD fail to prepare the next SETUP %d %d\r\n", out_odd, in_odd);
- return;
- }
+ TU_ASSERT(0 == _dcd.bdt[0][0][out_odd].own, );
+
_dcd.bdt[0][0][out_odd].data = 0;
_dcd.bdt[0][0][out_odd ^ 1].data = 1;
_dcd.bdt[0][1][in_odd].data = 1;
@@ -132,10 +134,16 @@ static void prepare_next_setup_packet(uint8_t rhport)
static void process_stall(uint8_t rhport)
{
- if (KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_EPSTALL_MASK) {
- /* clear stall condition of the control pipe */
- prepare_next_setup_packet(rhport);
- KHCI->ENDPOINT[0].ENDPT &= ~USB_ENDPT_EPSTALL_MASK;
+ for (int i = 0; i < 16; ++i) {
+ unsigned const endpt = KHCI->ENDPOINT[i].ENDPT;
+
+ if (endpt & USB_ENDPT_EPSTALL_MASK) {
+ // prepare next setup if endpoint0
+ if ( i == 0 ) prepare_next_setup_packet(rhport);
+
+ // clear stall bit
+ KHCI->ENDPOINT[i].ENDPT = endpt & ~USB_ENDPT_EPSTALL_MASK;
+ }
}
}
@@ -143,12 +151,17 @@ static void process_tokdne(uint8_t rhport)
{
const unsigned s = KHCI->STAT;
KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
+
+ uint8_t const epnum = (s >> USB_STAT_ENDP_SHIFT);
+ uint8_t const dir = (s & USB_STAT_TX_MASK) >> USB_STAT_TX_SHIFT;
+ unsigned const odd = (s & USB_STAT_ODD_MASK) ? 1 : 0;
+
buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s];
endpoint_state_t *ep = &_dcd.endpoint_unified[s >> 3];
- unsigned odd = (s & USB_STAT_ODD_MASK) ? 1 : 0;
/* fetch pid before discarded by the next steps */
const unsigned pid = bd->tok_pid;
+
/* reset values for a next transfer */
bd->bdt_stall = 0;
bd->dts = 1;
@@ -161,9 +174,6 @@ static void process_tokdne(uint8_t rhport)
KHCI->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
return;
}
- if (s >> 4) {
- TU_LOG1("TKDNE %x\r\n", s);
- }
const unsigned bc = bd->bc;
const unsigned remaining = ep->remaining - bc;
@@ -182,9 +192,9 @@ static void process_tokdne(uint8_t rhport)
}
const unsigned length = ep->length;
dcd_event_xfer_complete(rhport,
- ((s & USB_STAT_TX_MASK) << 4) | (s >> USB_STAT_ENDP_SHIFT),
+ tu_edpt_addr(epnum, dir),
length - remaining, XFER_RESULT_SUCCESS, true);
- if (0 == (s & USB_STAT_ENDP_MASK) && 0 == length) {
+ if (0 == epnum && 0 == length) {
/* After completion a ZLP of control transfer,
* it prepares for the next steup transfer. */
if (_dcd.addr) {
@@ -202,7 +212,8 @@ static void process_bus_reset(uint8_t rhport)
KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
KHCI->CTL |= USB_CTL_ODDRST_MASK;
KHCI->ADDR = 0;
- KHCI->INTEN = (KHCI->INTEN & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
+ KHCI->INTEN = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK | USB_INTEN_SLEEPEN_MASK |
+ USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
KHCI->ENDPOINT[0].ENDPT = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
for (unsigned i = 1; i < 16; ++i) {
@@ -227,21 +238,27 @@ static void process_bus_reset(uint8_t rhport)
dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
}
-static void process_bus_inactive(uint8_t rhport)
+static void process_bus_sleep(uint8_t rhport)
{
- (void) rhport;
+ // Enable resume & disable suspend interrupt
const unsigned inten = KHCI->INTEN;
+
KHCI->INTEN = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK;
+ KHCI->USBTRC0 |= USB_USBTRC0_USBRESMEN_MASK;
KHCI->USBCTRL |= USB_USBCTRL_SUSP_MASK;
+
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
}
-static void process_bus_active(uint8_t rhport)
+static void process_bus_resume(uint8_t rhport)
{
- (void) rhport;
- KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+ // Enable suspend & disable resume interrupt
const unsigned inten = KHCI->INTEN;
+
+ KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; // will also clear USB_USBTRC0_USB_RESUME_INT_MASK
+ KHCI->USBTRC0 &= ~USB_USBTRC0_USBRESMEN_MASK;
KHCI->INTEN = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
+
dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
}
@@ -252,14 +269,29 @@ void dcd_init(uint8_t rhport)
{
(void) rhport;
+ // save crystal-less setting (if available)
+ #if defined(FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED) && FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED == 1
+ uint32_t clk_recover_irc_en = KHCI->CLK_RECOVER_IRC_EN;
+ uint32_t clk_recover_ctrl = KHCI->CLK_RECOVER_CTRL;
+ #endif
+
KHCI->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
while (KHCI->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+
+ // restore crystal-less setting (if available)
+ #if defined(FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED) && FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED == 1
+ KHCI->CLK_RECOVER_IRC_EN = clk_recover_irc_en;
+ KHCI->CLK_RECOVER_CTRL |= clk_recover_ctrl;
+ #endif
+
tu_memclr(&_dcd, sizeof(_dcd));
KHCI->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */
KHCI->BDTPAGE1 = (uint8_t)((uintptr_t)_dcd.bdt >> 8);
KHCI->BDTPAGE2 = (uint8_t)((uintptr_t)_dcd.bdt >> 16);
KHCI->BDTPAGE3 = (uint8_t)((uintptr_t)_dcd.bdt >> 24);
+ KHCI->INTEN = USB_INTEN_USBRSTEN_MASK;
+
dcd_connect(rhport);
NVIC_ClearPendingIRQ(USB0_IRQn);
}
@@ -267,8 +299,6 @@ void dcd_init(uint8_t rhport)
void dcd_int_enable(uint8_t rhport)
{
(void) rhport;
- KHCI->INTEN = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK |
- USB_INTEN_SLEEPEN_MASK | USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
NVIC_EnableIRQ(USB0_IRQn);
}
@@ -276,12 +306,10 @@ void dcd_int_disable(uint8_t rhport)
{
(void) rhport;
NVIC_DisableIRQ(USB0_IRQn);
- KHCI->INTEN = 0;
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
{
- (void) rhport;
_dcd.addr = dev_addr & 0x7F;
/* Response with status first before changing device address */
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
@@ -290,9 +318,12 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
void dcd_remote_wakeup(uint8_t rhport)
{
(void) rhport;
- unsigned cnt = SystemCoreClock / 100;
+
KHCI->CTL |= USB_CTL_RESUME_MASK;
+
+ unsigned cnt = SystemCoreClock / 1000;
while (cnt--) __NOP();
+
KHCI->CTL &= ~USB_CTL_RESUME_MASK;
}
@@ -311,6 +342,14 @@ void dcd_disconnect(uint8_t rhport)
KHCI->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -319,17 +358,17 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
(void) rhport;
const unsigned ep_addr = ep_desc->bEndpointAddress;
- const unsigned epn = ep_addr & 0xFu;
- const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
const unsigned xfer = ep_desc->bmAttributes.xfer;
endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
const unsigned odd = ep->odd;
- buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0];
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
/* No support for control transfer */
TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL));
- ep->max_packet_size = ep_desc->wMaxPacketSize.size;
+ ep->max_packet_size = tu_edpt_packet_size(ep_desc);
unsigned val = USB_ENDPT_EPCTLDIS_MASK;
val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? USB_ENDPT_EPHSHK_MASK: 0;
val |= dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
@@ -345,35 +384,60 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
return true;
}
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ (void) rhport;
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ for (unsigned i = 1; i < 16; ++i) {
+ KHCI->ENDPOINT[i].ENDPT = 0;
+ }
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ buffer_descriptor_t *bd = _dcd.bdt[1][0];
+ for (unsigned i = 2; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+ bd->head = 0;
+ }
+ endpoint_state_t *ep = &_dcd.endpoint[1][0];
+ for (unsigned i = 2; i < sizeof(_dcd.endpoint)/sizeof(*ep); ++i, ++ep) {
+ /* Clear except the odd */
+ ep->max_packet_size = 0;
+ ep->length = 0;
+ ep->remaining = 0;
+ }
+}
+
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
- const unsigned epn = ep_addr & 0xFu;
- const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
- buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0];
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
const unsigned msk = dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
KHCI->ENDPOINT[epn].ENDPT &= ~msk;
ep->max_packet_size = 0;
ep->length = 0;
ep->remaining = 0;
- bd->head = 0;
+ bd[0].head = 0;
+ bd[1].head = 0;
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
}
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
{
(void) rhport;
- NVIC_DisableIRQ(USB0_IRQn);
- const unsigned epn = ep_addr & 0xFu;
- const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd];
+ TU_ASSERT(0 == bd->own);
+
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
- if (bd->own) {
- TU_LOG1("DCD XFER fail %x %d %lx %lx\r\n", ep_addr, total_bytes, ep->state, bd->head);
- return false; /* The last transfer has not completed */
- }
ep->length = total_bytes;
ep->remaining = total_bytes;
@@ -386,42 +450,69 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
next->addr = buffer + mps;
next->own = 1;
}
- bd->bc = total_bytes >= mps ? mps: total_bytes;
- bd->addr = buffer;
+ bd->bc = total_bytes >= mps ? mps: total_bytes;
+ bd->addr = buffer;
__DSB();
- bd->own = 1; /* the own bit must set after addr */
- NVIC_EnableIRQ(USB0_IRQn);
+ bd->own = 1; /* This bit must be set last */
+
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
return true;
}
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
- const unsigned epn = ep_addr & 0xFu;
+ const unsigned epn = tu_edpt_number(ep_addr);
+
if (0 == epn) {
KHCI->ENDPOINT[epn].ENDPT |= USB_ENDPT_EPSTALL_MASK;
} else {
- const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
- buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
- bd[0].bdt_stall = 1;
- bd[1].bdt_stall = 1;
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned odd = _dcd.endpoint[epn][dir].odd;
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][odd];
+ TU_ASSERT(0 == bd->own,);
+
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+
+ bd->bdt_stall = 1;
+ __DSB();
+ bd->own = 1; /* This bit must be set last */
+
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
}
}
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
- const unsigned epn = ep_addr & 0xFu;
- const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ TU_VERIFY(epn,);
+ const unsigned dir = tu_edpt_dir(ep_addr);
const unsigned odd = _dcd.endpoint[epn][dir].odd;
buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+ TU_VERIFY(bd[odd].own,);
+
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+
+ bd[odd].own = 0;
+ __DSB();
+
+ // clear stall
+ bd[odd].bdt_stall = 0;
+
+ // Reset data toggle
+ bd[odd ].data = 0;
+ bd[odd ^ 1].data = 1;
+
+ // We already cleared this in ISR, but just clear it here to be safe
+ const unsigned endpt = KHCI->ENDPOINT[epn].ENDPT;
+ if (endpt & USB_ENDPT_EPSTALL_MASK) {
+ KHCI->ENDPOINT[epn].ENDPT = endpt & ~USB_ENDPT_EPSTALL_MASK;
+ }
- bd[odd ^ 1].own = 0;
- bd[odd ^ 1].data = 1;
- bd[odd ^ 1].bdt_stall = 0;
- bd[odd].own = 0;
- bd[odd].data = 0;
- bd[odd].bdt_stall = 0;
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
}
//--------------------------------------------------------------------+
@@ -429,48 +520,59 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
//--------------------------------------------------------------------+
void dcd_int_handler(uint8_t rhport)
{
- (void) rhport;
-
uint32_t is = KHCI->ISTAT;
uint32_t msk = KHCI->INTEN;
+
+ // clear non-enabled interrupts
KHCI->ISTAT = is & ~msk;
is &= msk;
+
if (is & USB_ISTAT_ERROR_MASK) {
/* TODO: */
uint32_t es = KHCI->ERRSTAT;
KHCI->ERRSTAT = es;
KHCI->ISTAT = is; /* discard any pending events */
- return;
}
if (is & USB_ISTAT_USBRST_MASK) {
KHCI->ISTAT = is; /* discard any pending events */
process_bus_reset(rhport);
- return;
}
+
if (is & USB_ISTAT_SLEEP_MASK) {
+ // TU_LOG2("Suspend: "); TU_LOG2_HEX(is);
+
+ // Note Host usually has extra delay after bus reset (without SOF), which could falsely
+ // detected as Sleep event. Though usbd has debouncing logic so we are good
KHCI->ISTAT = USB_ISTAT_SLEEP_MASK;
- process_bus_inactive(rhport);
- return;
+ process_bus_sleep(rhport);
}
+
+#if 0 // ISTAT_RESUME never trigger, probably for host mode ?
if (is & USB_ISTAT_RESUME_MASK) {
+ // TU_LOG2("ISTAT Resume: "); TU_LOG2_HEX(is);
KHCI->ISTAT = USB_ISTAT_RESUME_MASK;
- process_bus_active(rhport);
- return;
+ process_bus_resume(rhport);
}
+#endif
+
+ if (KHCI->USBTRC0 & USB_USBTRC0_USB_RESUME_INT_MASK) {
+ // TU_LOG2("USBTRC0 Resume: "); TU_LOG2_HEX(is); TU_LOG2_HEX(KHCI->USBTRC0);
+ process_bus_resume(rhport);
+ }
+
if (is & USB_ISTAT_SOFTOK_MASK) {
KHCI->ISTAT = USB_ISTAT_SOFTOK_MASK;
dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
- return;
}
+
if (is & USB_ISTAT_STALL_MASK) {
KHCI->ISTAT = USB_ISTAT_STALL_MASK;
process_stall(rhport);
- return;
}
+
if (is & USB_ISTAT_TOKDNE_MASK) {
process_tokdne(rhport);
- return;
}
}
diff --git a/src/portable/nxp/khci/hcd_khci.c b/src/portable/nxp/khci/hcd_khci.c
new file mode 100644
index 000000000..57684b259
--- /dev/null
+++ b/src/portable/nxp/khci/hcd_khci.c
@@ -0,0 +1,641 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji Kitayama
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && defined(TUP_USBIP_CHIPIDEA_FS)
+
+#ifdef TUP_USBIP_CHIPIDEA_FS_KINETIS
+ #include "fsl_device_registers.h"
+ #define KHCI USB0
+#else
+ #error "MCU is not supported"
+#endif
+
+#include "host/hcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+ TOK_PID_OUT = 0x1u,
+ TOK_PID_IN = 0x9u,
+ TOK_PID_SETUP = 0xDu,
+ TOK_PID_DATA0 = 0x3u,
+ TOK_PID_DATA1 = 0xbu,
+ TOK_PID_ACK = 0x2u,
+ TOK_PID_STALL = 0xeu,
+ TOK_PID_NAK = 0xau,
+ TOK_PID_BUSTO = 0x0u,
+ TOK_PID_ERR = 0xfu,
+};
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t head;
+ struct {
+ union {
+ struct {
+ uint16_t : 2;
+ __IO uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ __IO uint16_t own : 1;
+ uint16_t : 8;
+ };
+ struct {
+ uint16_t : 2;
+ uint16_t bdt_stall : 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ uint16_t : 10;
+ };
+ };
+ __IO uint16_t bc : 10;
+ uint16_t : 6;
+ };
+ };
+ uint8_t *addr;
+}buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" );
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t state;
+ struct {
+ uint32_t pipenum:16;
+ uint32_t odd : 1;
+ uint32_t : 0;
+ };
+ };
+ uint8_t *buffer;
+ uint16_t length;
+ uint16_t remaining;
+} endpoint_state_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ uint8_t dev_addr;
+ uint8_t ep_addr;
+ uint16_t max_packet_size;
+ union {
+ uint8_t flags;
+ struct {
+ uint8_t data : 1;
+ uint8_t xfer : 2;
+ uint8_t : 0;
+ };
+ };
+ uint8_t *buffer;
+ uint16_t length;
+ uint16_t remaining;
+} pipe_state_t;
+
+
+typedef struct
+{
+ union {
+ /* [OUT,IN][EVEN,ODD] */
+ buffer_descriptor_t bdt[2][2];
+ uint16_t bda[2*2];
+ };
+ endpoint_state_t endpoint[2];
+ pipe_state_t pipe[CFG_TUH_ENDPOINT_MAX * 2];
+ uint32_t in_progress; /* Bitmap. Each bit indicates that a transfer of the corresponding pipe is in progress */
+ uint32_t pending; /* Bitmap. Each bit indicates that a transfer of the corresponding pipe will be resume the next frame */
+ bool need_reset; /* The device has not been reset after connection. */
+} hcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+// BDT(Buffer Descriptor Table) must be 256-byte aligned
+CFG_TUH_MEM_SECTION TU_ATTR_ALIGNED(512) static hcd_data_t _hcd;
+//CFG_TUH_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _rx_buf[1024];
+
+int find_pipe(uint8_t dev_addr, uint8_t ep_addr)
+{
+ /* Find the target pipe */
+ int num;
+ for (num = 0; num < CFG_TUH_ENDPOINT_MAX * 2; ++num) {
+ pipe_state_t *p = &_hcd.pipe[num];
+ if ((p->dev_addr == dev_addr) && (p->ep_addr == ep_addr))
+ return num;
+ }
+ return -1;
+}
+
+static int prepare_packets(int pipenum)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ unsigned const dir_tx = tu_edpt_dir(pipe->ep_addr) ? 0 : 1;
+ endpoint_state_t *ep = &_hcd.endpoint[dir_tx];
+ unsigned const odd = ep->odd;
+ buffer_descriptor_t *bd = _hcd.bdt[dir_tx];
+ TU_ASSERT(0 == bd[odd].own, -1);
+
+ // TU_LOG1(" %p dir %d odd %d data %d\r\n", &bd[odd], dir_tx, odd, pipe->data);
+
+ ep->pipenum = pipenum;
+
+ bd[odd ].data = pipe->data;
+ bd[odd ^ 1].data = pipe->data ^ 1;
+ bd[odd ^ 1].own = 0;
+ /* reset values for a next transfer */
+
+ int num_tokens = 0; /* The number of prepared packets */
+ unsigned const mps = pipe->max_packet_size;
+ unsigned const rem = pipe->remaining;
+ if (rem > mps) {
+ /* When total_bytes is greater than the max packet size,
+ * it prepares to the next transfer to avoid NAK in advance. */
+ bd[odd ^ 1].bc = rem >= 2 * mps ? mps: rem - mps;
+ bd[odd ^ 1].addr = pipe->buffer + mps;
+ bd[odd ^ 1].own = 1;
+ if (dir_tx) ++num_tokens;
+ }
+ bd[odd].bc = rem >= mps ? mps: rem;
+ bd[odd].addr = pipe->buffer;
+ __DSB();
+ bd[odd].own = 1; /* This bit must be set last */
+ ++num_tokens;
+ return num_tokens;
+}
+
+static int select_next_pipenum(int pipenum)
+{
+ unsigned wip = _hcd.in_progress & ~_hcd.pending;
+ if (!wip) return -1;
+ unsigned msk = TU_GENMASK(31, pipenum);
+ int next = __builtin_ctz(wip & msk);
+ if (next) return next;
+ msk = TU_GENMASK(pipenum, 0);
+ next = __builtin_ctz(wip & msk);
+ return next;
+}
+
+/* When transfer is completed, return true. */
+static bool continue_transfer(int pipenum, buffer_descriptor_t *bd)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ unsigned const bc = bd->bc;
+ unsigned const rem = pipe->remaining - bc;
+
+ pipe->remaining = rem;
+ if (rem && bc == pipe->max_packet_size) {
+ int const next_rem = rem - pipe->max_packet_size;
+ if (next_rem > 0) {
+ /* Prepare to the after next transfer */
+ bd->addr += pipe->max_packet_size * 2;
+ bd->bc = next_rem > pipe->max_packet_size ? pipe->max_packet_size: next_rem;
+ __DSB();
+ bd->own = 1; /* This bit must be set last */
+ while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+ KHCI->TOKEN = KHCI->TOKEN; /* Queue the same token as the last */
+ } else if (TUSB_DIR_IN == tu_edpt_dir(pipe->ep_addr)) { /* IN */
+ while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+ KHCI->TOKEN = KHCI->TOKEN;
+ }
+ return true;
+ }
+ pipe->data = bd->data ^ 1;
+ return false;
+}
+
+static bool resume_transfer(int pipenum)
+{
+ int num_tokens = prepare_packets(pipenum);
+ TU_ASSERT(0 <= num_tokens);
+
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+
+ unsigned flags = KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_HOSTWOHUB_MASK;
+ flags |= USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+ switch (pipe->xfer) {
+ case TUSB_XFER_CONTROL:
+ flags |= USB_ENDPT_EPHSHK_MASK;
+ break;
+ case TUSB_XFER_ISOCHRONOUS:
+ flags |= USB_ENDPT_EPCTLDIS_MASK | USB_ENDPT_RETRYDIS_MASK;
+ break;
+ default:
+ flags |= USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPCTLDIS_MASK | USB_ENDPT_RETRYDIS_MASK;
+ break;
+ }
+ // TU_LOG1(" resume pipenum %d flags %x\r\n", pipenum, flags);
+
+ KHCI->ENDPOINT[0].ENDPT = flags;
+ KHCI->ADDR = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | pipe->dev_addr;
+
+ unsigned const token = tu_edpt_number(pipe->ep_addr) |
+ ((tu_edpt_dir(pipe->ep_addr) ? TOK_PID_IN: TOK_PID_OUT) << USB_TOKEN_TOKENPID_SHIFT);
+ do {
+ while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+ KHCI->TOKEN = token;
+ } while (--num_tokens);
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ return true;
+}
+
+static void suspend_transfer(int pipenum, buffer_descriptor_t *bd)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ pipe->buffer = bd->addr;
+ pipe->data = bd->data ^ 1;
+ if ((TUSB_XFER_INTERRUPT == pipe->xfer) ||
+ (TUSB_XFER_BULK == pipe->xfer)) {
+ _hcd.pending |= TU_BIT(pipenum);
+ KHCI->INTEN |= USB_ISTAT_SOFTOK_MASK;
+ }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+ (void)rhport;
+ const unsigned s = KHCI->STAT;
+ KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
+ uint8_t const dir_in = (s & USB_STAT_TX_MASK) ? TUSB_DIR_OUT: TUSB_DIR_IN;
+ unsigned const odd = (s & USB_STAT_ODD_MASK) ? 1 : 0;
+
+ buffer_descriptor_t *bd = (buffer_descriptor_t *)&_hcd.bda[s];
+ endpoint_state_t *ep = &_hcd.endpoint[s >> 3];
+
+ /* fetch status before discarded by the next steps */
+ const unsigned pid = bd->tok_pid;
+
+ /* reset values for a next transfer */
+ bd->bdt_stall = 0;
+ bd->dts = 1;
+ bd->ninc = 0;
+ bd->keep = 0;
+ /* Update the odd variable to prepare for the next transfer */
+ ep->odd = odd ^ 1;
+
+ int pipenum = ep->pipenum;
+ int next_pipenum;
+ // TU_LOG1("TOKDNE %x PID %x pipe %d\r\n", s, pid, pipenum);
+
+ xfer_result_t result;
+ switch (pid) {
+ default:
+ if (continue_transfer(pipenum, bd))
+ return;
+ result = XFER_RESULT_SUCCESS;
+ break;
+ case TOK_PID_NAK:
+ suspend_transfer(pipenum, bd);
+ next_pipenum = select_next_pipenum(pipenum);
+ if (0 <= next_pipenum)
+ resume_transfer(next_pipenum);
+ return;
+ case TOK_PID_STALL:
+ result = XFER_RESULT_STALLED;
+ break;
+ case TOK_PID_ERR: /* mismatch toggle bit */
+ case TOK_PID_BUSTO:
+ result = XFER_RESULT_FAILED;
+ break;
+ }
+ _hcd.in_progress &= ~TU_BIT(pipenum);
+ pipe_state_t *pipe = &_hcd.pipe[ep->pipenum];
+ hcd_event_xfer_complete(pipe->dev_addr,
+ tu_edpt_addr(KHCI->TOKEN & USB_TOKEN_TOKENENDPT_MASK, dir_in),
+ pipe->length - pipe->remaining,
+ result, true);
+ next_pipenum = select_next_pipenum(pipenum);
+ if (0 <= next_pipenum)
+ resume_transfer(next_pipenum);
+}
+
+static void process_attach(uint8_t rhport)
+{
+ unsigned ctl = KHCI->CTL;
+ if (!(ctl & USB_CTL_JSTATE_MASK)) {
+ /* The attached device is a low speed device. */
+ KHCI->ADDR = USB_ADDR_LSEN_MASK;
+ KHCI->ENDPOINT[0].ENDPT = USB_ENDPT_HOSTWOHUB_MASK;
+ }
+ hcd_event_device_attach(rhport, true);
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+ KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK;
+ KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+ KHCI->CTL &= ~USB_CTL_USBENSOFEN_MASK;
+ KHCI->ADDR = 0;
+ KHCI->ENDPOINT[0].ENDPT = 0;
+
+ hcd_event_device_remove(rhport, true);
+
+ _hcd.in_progress = 0;
+ _hcd.pending = 0;
+ buffer_descriptor_t *bd = &_hcd.bdt[0][0];
+ for (unsigned i = 0; i < 2; ++i, ++bd) {
+ bd->head = 0;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* Host API
+ *------------------------------------------------------------------*/
+bool hcd_init(uint8_t rhport)
+{
+ (void)rhport;
+
+ KHCI->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
+ while (KHCI->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+
+ tu_memclr(&_hcd, sizeof(_hcd));
+ KHCI->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */
+ KHCI->BDTPAGE1 = (uint8_t)((uintptr_t)_hcd.bdt >> 8);
+ KHCI->BDTPAGE2 = (uint8_t)((uintptr_t)_hcd.bdt >> 16);
+ KHCI->BDTPAGE3 = (uint8_t)((uintptr_t)_hcd.bdt >> 24);
+
+ KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+ KHCI->CTL |= USB_CTL_ODDRST_MASK;
+ for (unsigned i = 0; i < 16; ++i) {
+ KHCI->ENDPOINT[i].ENDPT = 0;
+ }
+ KHCI->CTL &= ~USB_CTL_ODDRST_MASK;
+
+ KHCI->SOFTHLD = 74; /* for 64-byte packets */
+ // KHCI->SOFTHLD = 144; /* for low speed 8-byte packets */
+ KHCI->CTL = USB_CTL_HOSTMODEEN_MASK | USB_CTL_SE0_MASK;
+ KHCI->USBCTRL = USB_USBCTRL_PDE_MASK;
+
+ NVIC_ClearPendingIRQ(USB0_IRQn);
+ KHCI->INTEN = USB_INTEN_ATTACHEN_MASK | USB_INTEN_TOKDNEEN_MASK |
+ USB_INTEN_USBRSTEN_MASK | USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
+ KHCI->ERREN = 0xff;
+
+ return true;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_DisableIRQ(USB0_IRQn);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void)rhport;
+ /* The device must be reset at least once after connection
+ * in order to start the frame counter. */
+ if (_hcd.need_reset) hcd_port_reset(rhport);
+ uint32_t frmnum = KHCI->FRMNUML;
+ frmnum |= KHCI->FRMNUMH << 8u;
+ return frmnum;
+}
+
+/*--------------------------------------------------------------------+
+ * Port API
+ *--------------------------------------------------------------------+ */
+bool hcd_port_connect_status(uint8_t rhport)
+{
+ (void)rhport;
+ if (KHCI->ISTAT & USB_ISTAT_ATTACH_MASK)
+ return true;
+ return false;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+ (void)rhport;
+ KHCI->CTL &= ~USB_CTL_USBENSOFEN_MASK;
+ KHCI->CTL |= USB_CTL_RESET_MASK;
+ unsigned cnt = SystemCoreClock / 100;
+ while (cnt--) __NOP();
+ KHCI->CTL &= ~USB_CTL_RESET_MASK;
+ KHCI->CTL |= USB_CTL_USBENSOFEN_MASK;
+ _hcd.need_reset = false;
+}
+
+void hcd_port_reset_end(uint8_t rhport) {
+ (void) rhport;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+ (void)rhport;
+ tusb_speed_t speed = TUSB_SPEED_FULL;
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ if (KHCI->ADDR & USB_ADDR_LSEN_MASK)
+ speed = TUSB_SPEED_LOW;
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ return speed;
+}
+
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ pipe_state_t *p = &_hcd.pipe[0];
+ pipe_state_t *end = &_hcd.pipe[CFG_TUH_ENDPOINT_MAX * 2];
+ for (;p != end; ++p) {
+ if (p->dev_addr == dev_addr)
+ tu_memclr(p, sizeof(*p));
+ }
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+//--------------------------------------------------------------------+
+// Endpoints API
+//--------------------------------------------------------------------+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ (void)rhport;
+ // TU_LOG1("SETUP %u\r\n", dev_addr);
+ TU_ASSERT(0 == (_hcd.in_progress & TU_BIT(0)));
+
+ int pipenum = find_pipe(dev_addr, 0);
+ if (pipenum < 0) return false;
+
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ pipe[0].data = 0;
+ pipe[0].buffer = (uint8_t*)(uintptr_t)setup_packet;
+ pipe[0].length = 8;
+ pipe[0].remaining = 8;
+ pipe[1].data = 1;
+
+ if (1 != prepare_packets(pipenum))
+ return false;
+
+ _hcd.in_progress |= TU_BIT(pipenum);
+
+ unsigned hostwohub = KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_HOSTWOHUB_MASK;
+ KHCI->ENDPOINT[0].ENDPT = hostwohub |
+ USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+ KHCI->ADDR = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | dev_addr;
+ while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+ KHCI->TOKEN = (TOK_PID_SETUP << USB_TOKEN_TOKENPID_SHIFT);
+ return true;
+}
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void)rhport;
+ uint8_t const ep_addr = ep_desc->bEndpointAddress;
+ // TU_LOG1("O %u %x\r\n", dev_addr, ep_addr);
+ /* Find a free pipe */
+ pipe_state_t *p = &_hcd.pipe[0];
+ pipe_state_t *end = &_hcd.pipe[CFG_TUH_ENDPOINT_MAX * 2];
+ if (dev_addr || ep_addr) {
+ p += 2;
+ for (; p < end && (p->dev_addr || p->ep_addr); ++p) ;
+ if (p == end) return false;
+ }
+ p->dev_addr = dev_addr;
+ p->ep_addr = ep_addr;
+ p->max_packet_size = ep_desc->wMaxPacketSize;
+ p->xfer = ep_desc->bmAttributes.xfer;
+ p->data = 0;
+ if (!ep_addr) {
+ /* Open one more pipe for Control IN transfer */
+ TU_ASSERT(TUSB_XFER_CONTROL == p->xfer);
+ pipe_state_t *q = p + 1;
+ TU_ASSERT(!q->dev_addr && !q->ep_addr);
+ q->dev_addr = dev_addr;
+ q->ep_addr = tu_edpt_addr(0, TUSB_DIR_IN);
+ q->max_packet_size = ep_desc->wMaxPacketSize;
+ q->xfer = ep_desc->bmAttributes.xfer;
+ q->data = 1;
+ }
+ return true;
+}
+
+/* The address of buffer must be aligned to 4 byte boundary. And it must be at least 4 bytes long.
+ * DMA writes data in 4 byte unit */
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
+{
+ (void)rhport;
+ // TU_LOG1("X %u %x %x %d\r\n", dev_addr, ep_addr, (uintptr_t)buffer, buflen);
+
+ int pipenum = find_pipe(dev_addr, ep_addr);
+ TU_ASSERT(0 <= pipenum);
+
+ TU_ASSERT(0 == (_hcd.in_progress & TU_BIT(pipenum)));
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ pipe->buffer = buffer;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ _hcd.in_progress |= TU_BIT(pipenum);
+ _hcd.pending |= TU_BIT(pipenum); /* Send at the next Frame */
+ KHCI->INTEN |= USB_ISTAT_SOFTOK_MASK;
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ return true;
+}
+
+bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+ // TODO not implemented yet
+ return false;
+}
+
+bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ if (!tu_edpt_number(ep_addr)) return true;
+ int num = find_pipe(dev_addr, ep_addr);
+ if (num < 0) return false;
+ pipe_state_t *p = &_hcd.pipe[num];
+ p->data = 0; /* Reset data toggle */
+ return true;
+}
+
+/*--------------------------------------------------------------------+
+ * ISR
+ *--------------------------------------------------------------------+*/
+void hcd_int_handler(uint8_t rhport, bool in_isr)
+{
+ (void) in_isr;
+ uint32_t is = KHCI->ISTAT;
+ uint32_t msk = KHCI->INTEN;
+
+ // TU_LOG1("S %lx\r\n", is);
+
+ /* clear disabled interrupts */
+ KHCI->ISTAT = (is & ~msk & ~USB_ISTAT_TOKDNE_MASK) | USB_ISTAT_SOFTOK_MASK;
+ is &= msk;
+
+ if (is & USB_ISTAT_ERROR_MASK) {
+ unsigned err = KHCI->ERRSTAT;
+ if (err) {
+ TU_LOG1(" ERR %x\r\n", err);
+ KHCI->ERRSTAT = err;
+ } else {
+ KHCI->INTEN &= ~USB_ISTAT_ERROR_MASK;
+ }
+ }
+
+ if (is & USB_ISTAT_USBRST_MASK) {
+ KHCI->INTEN = (msk & ~USB_INTEN_USBRSTEN_MASK) | USB_INTEN_ATTACHEN_MASK;
+ process_bus_reset(rhport);
+ return;
+ }
+ if (is & USB_ISTAT_ATTACH_MASK) {
+ KHCI->INTEN = (msk & ~USB_INTEN_ATTACHEN_MASK) | USB_INTEN_USBRSTEN_MASK;
+ _hcd.need_reset = true;
+ process_attach(rhport);
+ return;
+ }
+ if (is & USB_ISTAT_STALL_MASK) {
+ KHCI->ISTAT = USB_ISTAT_STALL_MASK;
+ }
+ if (is & USB_ISTAT_SOFTOK_MASK) {
+ msk &= ~USB_ISTAT_SOFTOK_MASK;
+ KHCI->INTEN = msk;
+ if (_hcd.pending) {
+ int pipenum = __builtin_ctz(_hcd.pending);
+ _hcd.pending = 0;
+ if (!(is & USB_ISTAT_TOKDNE_MASK))
+ resume_transfer(pipenum);
+ }
+ }
+ if (is & USB_ISTAT_TOKDNE_MASK) {
+ process_tokdne(rhport);
+ }
+}
+
+#endif
diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
index 519d09151..b880c2870 100644
--- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
+++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && \
+#if CFG_TUD_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
#include "device/dcd.h"
@@ -92,7 +92,7 @@ typedef struct
} dcd_data_t;
-CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(128) static dcd_data_t _dcd;
+CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(128) static dcd_data_t _dcd;
//--------------------------------------------------------------------+
@@ -228,6 +228,14 @@ void dcd_disconnect(uint8_t rhport)
sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 0);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// CONTROL HELPER
//--------------------------------------------------------------------+
@@ -311,14 +319,15 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
}
//------------- Realize Endpoint with Max Packet Size -------------//
- set_ep_size(ep_id, p_endpoint_desc->wMaxPacketSize.size);
+ const uint16_t ep_size = tu_edpt_packet_size(p_endpoint_desc);
+ set_ep_size(ep_id, ep_size);
//------------- first DD prepare -------------//
dma_desc_t* const dd = &_dcd.dd[ep_id];
tu_memclr(dd, sizeof(dma_desc_t));
dd->isochronous = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
- dd->max_packet_size = p_endpoint_desc->wMaxPacketSize.size;
+ dd->max_packet_size = ep_size;
dd->retired = 1; // invalid at first
sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS + ep_id, 1, 0); // clear all endpoint status
@@ -326,6 +335,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.h b/src/portable/nxp/lpc17_40/dcd_lpc17_40.h
index 07daa32e4..654b80866 100644
--- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.h
+++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
diff --git a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
index 1c1faed94..372dcf51f 100644
--- a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
+++ b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019, Ha Thach (tinyusb.org)
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && \
+#if CFG_TUH_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
#include "chip.h"
@@ -44,4 +44,3 @@ void hcd_int_disable(uint8_t rhport)
}
#endif
-
diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
index 4392d1882..cc18cf59b 100644
--- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
+++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -34,20 +34,26 @@
* - LPC54114
* - LPC55s69
*/
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_LPC11UXX || \
- CFG_TUSB_MCU == OPT_MCU_LPC13XX || \
- CFG_TUSB_MCU == OPT_MCU_LPC15XX || \
- CFG_TUSB_MCU == OPT_MCU_LPC51UXX || \
- CFG_TUSB_MCU == OPT_MCU_LPC54XXX || \
- CFG_TUSB_MCU == OPT_MCU_LPC55XX)
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_IP3511)
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
-#if CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13XX || CFG_TUSB_MCU == OPT_MCU_LPC15XX
+#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX)
// LPCOpen
+ #ifdef __GNUC__
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
+ #pragma GCC diagnostic ignored "-Wstrict-prototypes"
+ #endif
+
#include "chip.h"
+
+ #ifdef __GNUC__
+ #pragma GCC diagnostic pop
+ #endif
+
#else
// SDK
#include "fsl_device_registers.h"
@@ -78,8 +84,10 @@ typedef struct {
// Max nbytes for each control/bulk/interrupt transfer
enum {
- NBYTES_CBI_FULLSPEED_MAX = 64,
- NBYTES_CBI_HIGHSPEED_MAX = 32767 // can be up to all 15-bit, but only tested with 4096
+ NBYTES_ISO_FS_MAX = 1023, // FS ISO
+ NBYTES_ISO_HS_MAX = 1024, // HS ISO
+ NBYTES_CBI_FS_MAX = 64, // FS control/bulk/interrupt. TODO some FS can do burst with higher size e.g 1024. Need to test
+ NBYTES_CBI_HS_MAX = 32767 // can be up to all 15-bit, but only tested with 4096
};
enum {
@@ -88,30 +96,42 @@ enum {
};
enum {
- CMDSTAT_DEVICE_ADDR_MASK = TU_BIT(7 )-1,
- CMDSTAT_DEVICE_ENABLE_MASK = TU_BIT(7 ),
- CMDSTAT_SETUP_RECEIVED_MASK = TU_BIT(8 ),
- CMDSTAT_DEVICE_CONNECT_MASK = TU_BIT(16), // reflect the soft-connect only, does not reflect the actual attached state
- CMDSTAT_DEVICE_SUSPEND_MASK = TU_BIT(17),
- // 23-22 is link speed (only available for HighSpeed port)
- CMDSTAT_CONNECT_CHANGE_MASK = TU_BIT(24),
- CMDSTAT_SUSPEND_CHANGE_MASK = TU_BIT(25),
- CMDSTAT_RESET_CHANGE_MASK = TU_BIT(26),
- CMDSTAT_VBUS_DEBOUNCED_MASK = TU_BIT(28),
+ DEVCMDSTAT_DEVICE_ADDR_MASK = TU_BIT(7 )-1,
+ DEVCMDSTAT_DEVICE_ENABLE_MASK = TU_BIT(7 ),
+ DEVCMDSTAT_SETUP_RECEIVED_MASK = TU_BIT(8 ),
+ DEVCMDSTAT_DEVICE_CONNECT_MASK = TU_BIT(16), // reflect the soft-connect only, does not reflect the actual attached state
+ DEVCMDSTAT_DEVICE_SUSPEND_MASK = TU_BIT(17),
+ // 23-22 is link speed (only available for HighSpeed port)
+ DEVCMDSTAT_CONNECT_CHANGE_MASK = TU_BIT(24),
+ DEVCMDSTAT_SUSPEND_CHANGE_MASK = TU_BIT(25),
+ DEVCMDSTAT_RESET_CHANGE_MASK = TU_BIT(26),
+ DEVCMDSTAT_VBUS_DEBOUNCED_MASK = TU_BIT(28),
};
enum {
- CMDSTAT_SPEED_SHIFT = 22
+ DEVCMDSTAT_SPEED_SHIFT = 22
};
//--------------------------------------------------------------------+
// Endpoint Command/Status List
//--------------------------------------------------------------------+
+// EP Command/Status field definition
+enum {
+ EPCS_TYPE = TU_BIT(26),
+ EPCS_RF_TV = TU_BIT(27),
+ EPCS_TOGGLE_RESET = TU_BIT(28),
+ EPCS_STALL = TU_BIT(29),
+ EPCS_DISABLED = TU_BIT(30),
+ EPCS_ACTIVE = TU_BIT(31),
+};
+
// Endpoint Command/Status
typedef union TU_ATTR_PACKED
{
// Full and High speed has different bit layout for buffer_offset and nbytes
+ // TODO FS/HS layout depends on the max speed of controller e.g
+ // lpc55s69 PORT0 is only FS but actually has the same layout as HS on port1
// Buffer (aligned 64) = DATABUFSTART [31:22] | buffer_offset [21:6]
volatile struct {
@@ -129,13 +149,13 @@ typedef union TU_ATTR_PACKED
volatile struct {
uint32_t TU_RESERVED : 26;
- uint32_t is_iso : 1 ;
- uint32_t toggle_mode : 1 ;
+ uint32_t type : 1 ;
+ uint32_t rf_tv : 1 ; // rate feedback or toggle value
uint32_t toggle_reset : 1 ;
uint32_t stall : 1 ;
uint32_t disable : 1 ;
uint32_t active : 1 ;
- };
+ } cmd_sts;
}ep_cmd_sts_t;
TU_VERIFY_STATIC( sizeof(ep_cmd_sts_t) == 4, "size is not correct" );
@@ -172,8 +192,12 @@ typedef struct
// EP list must be 256-byte aligned
// Some MCU controller may require this variable to be placed in specific SRAM region.
// For example: LPC55s69 port1 Highspeed must be USB_RAM (0x40100000)
-// Use CFG_TUSB_MEM_SECTION to place it accordingly.
-CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd;
+// Use CFG_TUD_MEM_SECTION to place it accordingly.
+CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd;
+
+// Dummy buffer to fix ZLPs overwriting the buffer (probably an USB/DMA controller bug)
+// TODO find way to save memory
+CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(64) static uint8_t dummy[8];
//--------------------------------------------------------------------+
// Multiple Controllers
@@ -181,60 +205,102 @@ CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd;
typedef struct
{
- dcd_registers_t* regs; // registers
- const tusb_speed_t max_speed; // max link speed
- const IRQn_Type irqnum; // IRQ number
- const uint8_t ep_pairs; // Max bi-directional Endpoints
+ dcd_registers_t* regs; // registers
+ const bool is_highspeed; // max link speed
+ const IRQn_Type irqnum; // IRQ number
+ const uint8_t ep_pairs; // Max bi-directional Endpoints
}dcd_controller_t;
#ifdef INCLUDE_FSL_DEVICE_REGISTERS
-static const dcd_controller_t _dcd_controller[] =
-{
- { .regs = (dcd_registers_t*) USB0_BASE , .max_speed = TUSB_SPEED_FULL, .irqnum = USB0_IRQn, .ep_pairs = FSL_FEATURE_USB_EP_NUM },
+static const dcd_controller_t _dcd_controller[] = {
+ { .regs = (dcd_registers_t*) USB0_BASE , .is_highspeed = false, .irqnum = USB0_IRQn, .ep_pairs = FSL_FEATURE_USB_EP_NUM },
#if defined(FSL_FEATURE_SOC_USBHSD_COUNT) && FSL_FEATURE_SOC_USBHSD_COUNT
- { .regs = (dcd_registers_t*) USBHSD_BASE, .max_speed = TUSB_SPEED_HIGH, .irqnum = USB1_IRQn, .ep_pairs = FSL_FEATURE_USBHSD_EP_NUM }
+ { .regs = (dcd_registers_t*) USBHSD_BASE, .is_highspeed = true, .irqnum = USB1_IRQn, .ep_pairs = FSL_FEATURE_USBHSD_EP_NUM }
#endif
};
#else
-static const dcd_controller_t _dcd_controller[] =
-{
- { .regs = (dcd_registers_t*) LPC_USB0_BASE, .max_speed = TUSB_SPEED_FULL, .irqnum = USB0_IRQn, .ep_pairs = 5 },
+static const dcd_controller_t _dcd_controller[] = {
+ { .regs = (dcd_registers_t*) LPC_USB0_BASE, .is_highspeed = false, .irqnum = USB0_IRQn, .ep_pairs = 5 },
};
#endif
+#if defined(FSL_FEATURE_SOC_USBHSD_COUNT) && FSL_FEATURE_SOC_USBHSD_COUNT
+ #define IP3511_HAS_HIGHSPEED
+#endif
+
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
-static inline uint16_t get_buf_offset(void const * buffer)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint16_t get_buf_offset(void const * buffer) {
uint32_t addr = (uint32_t) buffer;
TU_ASSERT( (addr & 0x3f) == 0, 0 );
return ( (addr >> 6) & 0xFFFFUL ) ;
}
-static inline uint8_t ep_addr2id(uint8_t ep_addr)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint8_t ep_addr2id(uint8_t ep_addr) {
return 2*(ep_addr & 0x0F) + ((ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0);
}
+TU_ATTR_ALWAYS_INLINE static inline bool ep_is_iso(ep_cmd_sts_t* ep_cs, bool is_highspeed) {
+ return is_highspeed ? (ep_cs[0].cmd_sts.type && !ep_cs[0].cmd_sts.rf_tv) : ep_cs->cmd_sts.type;
+}
+
+TU_ATTR_ALWAYS_INLINE TU_ATTR_UNUSED static inline bool ep_is_bulk(ep_cmd_sts_t* ep_cs) {
+ return (ep_cs[0].cmd_sts.type == 0) && (ep_cs[0].cmd_sts.rf_tv == 0);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline ep_cmd_sts_t* get_ep_cs(uint8_t ep_id) {
+ return _dcd.ep[ep_id];
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool rhport_is_highspeed(uint8_t rhport) {
+ return _dcd_controller[rhport].is_highspeed;
+}
+
//--------------------------------------------------------------------+
// CONTROLLER API
//--------------------------------------------------------------------+
+
+static void prepare_setup_packet(uint8_t rhport) {
+ uint16_t const buf_offset = get_buf_offset(_dcd.setup_packet);
+ if ( _dcd_controller[rhport].is_highspeed ) {
+ _dcd.ep[0][1].buffer_hs.offset = buf_offset;
+ } else {
+ _dcd.ep[0][1].buffer_fs.offset = buf_offset;
+ }
+}
+
+static void edpt_reset(uint8_t rhport, uint8_t ep_id)
+{
+ (void) rhport;
+ tu_memclr(&_dcd.ep[ep_id], sizeof(_dcd.ep[ep_id]));
+}
+
+static void edpt_reset_all(uint8_t rhport)
+{
+ for (uint8_t ep_id = 0; ep_id < 2*_dcd_controller[rhport].ep_pairs; ++ep_id)
+ {
+ edpt_reset(rhport, ep_id);
+ }
+ prepare_setup_packet(rhport);
+}
void dcd_init(uint8_t rhport)
{
+ edpt_reset_all(rhport);
+
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
dcd_reg->EPLISTSTART = (uint32_t) _dcd.ep;
dcd_reg->DATABUFSTART = tu_align((uint32_t) &_dcd, TU_BIT(22)); // 22-bit alignment
dcd_reg->INTSTAT |= dcd_reg->INTSTAT; // clear all pending interrupt
dcd_reg->INTEN = INT_DEVICE_STATUS_MASK;
- dcd_reg->DEVCMDSTAT |= CMDSTAT_DEVICE_ENABLE_MASK | CMDSTAT_DEVICE_CONNECT_MASK |
- CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
+ dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_DEVICE_ENABLE_MASK | DEVCMDSTAT_DEVICE_CONNECT_MASK |
+ DEVCMDSTAT_RESET_CHANGE_MASK | DEVCMDSTAT_CONNECT_CHANGE_MASK | DEVCMDSTAT_SUSPEND_CHANGE_MASK;
NVIC_ClearPendingIRQ(_dcd_controller[rhport].irqnum);
}
@@ -256,7 +322,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
// Response with status first before changing device address
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
- dcd_reg->DEVCMDSTAT &= ~CMDSTAT_DEVICE_ADDR_MASK;
+ dcd_reg->DEVCMDSTAT &= ~DEVCMDSTAT_DEVICE_ADDR_MASK;
dcd_reg->DEVCMDSTAT |= dev_addr;
}
@@ -268,13 +334,21 @@ void dcd_remote_wakeup(uint8_t rhport)
void dcd_connect(uint8_t rhport)
{
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->DEVCMDSTAT |= CMDSTAT_DEVICE_CONNECT_MASK;
+ dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_DEVICE_CONNECT_MASK;
}
void dcd_disconnect(uint8_t rhport)
{
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->DEVCMDSTAT &= ~CMDSTAT_DEVICE_CONNECT_MASK;
+ dcd_reg->DEVCMDSTAT &= ~DEVCMDSTAT_DEVICE_CONNECT_MASK;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
}
//--------------------------------------------------------------------+
@@ -286,7 +360,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
// TODO cannot able to STALL Control OUT endpoint !!!!! FIXME try some walk-around
uint8_t const ep_id = ep_addr2id(ep_addr);
- _dcd.ep[ep_id][0].stall = 1;
+ _dcd.ep[ep_id][0].cmd_sts.stall = 1;
}
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
@@ -295,26 +369,41 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
uint8_t const ep_id = ep_addr2id(ep_addr);
- _dcd.ep[ep_id][0].stall = 0;
- _dcd.ep[ep_id][0].toggle_reset = 1;
- _dcd.ep[ep_id][0].toggle_mode = 0;
+ _dcd.ep[ep_id][0].cmd_sts.stall = 0;
+ _dcd.ep[ep_id][0].cmd_sts.toggle_reset = 1;
+ _dcd.ep[ep_id][0].cmd_sts.rf_tv = 0;
}
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
{
- (void) rhport;
-
- // TODO not support ISO yet
- TU_VERIFY(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
-
//------------- Prepare Queue Head -------------//
uint8_t ep_id = ep_addr2id(p_endpoint_desc->bEndpointAddress);
+ ep_cmd_sts_t* ep_cs = get_ep_cs(ep_id);
// Check if endpoint is available
- TU_ASSERT( _dcd.ep[ep_id][0].disable && _dcd.ep[ep_id][1].disable );
+ TU_ASSERT( ep_cs[0].cmd_sts.disable && ep_cs[1].cmd_sts.disable );
- tu_memclr(_dcd.ep[ep_id], 2*sizeof(ep_cmd_sts_t));
- _dcd.ep[ep_id][0].is_iso = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS);
+ edpt_reset(rhport, ep_id);
+
+ switch (p_endpoint_desc->bmAttributes.xfer) {
+ case TUSB_XFER_ISOCHRONOUS:
+ ep_cs[0].cmd_sts.type = 1;
+ break;
+
+ case TUSB_XFER_INTERRUPT:
+ // What is interrupt endpoint in rate feedback mode ?
+ if ( rhport_is_highspeed(rhport) ) {
+ ep_cs[0].cmd_sts.type = 1;
+ ep_cs[0].cmd_sts.rf_tv = 1;
+ }
+ break;
+
+ case TUSB_XFER_BULK:
+ // nothing to do both type and rf_tv are 0
+ break;
+
+ default: break;
+ }
// Enable EP interrupt
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
@@ -323,45 +412,65 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
-static void prepare_setup_packet(uint8_t rhport)
+void dcd_edpt_close_all (uint8_t rhport)
{
- if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
+ for (uint8_t ep_id = 0; ep_id < 2*_dcd_controller[rhport].ep_pairs; ++ep_id)
{
- _dcd.ep[0][1].buffer_fs.offset = get_buf_offset(_dcd.setup_packet);;
- }else
- {
- _dcd.ep[0][1].buffer_hs.offset = get_buf_offset(_dcd.setup_packet);;
+ _dcd.ep[ep_id][0].cmd_sts.active = _dcd.ep[ep_id][0].cmd_sts.active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual)
+ _dcd.ep[ep_id][0].cmd_sts.disable = _dcd.ep[ep_id][1].cmd_sts.disable = 1;
}
}
-static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, uint16_t total_bytes)
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
+ (void) rhport;
+
+ uint8_t ep_id = ep_addr2id(ep_addr);
+ _dcd.ep[ep_id][0].cmd_sts.active = _dcd.ep[ep_id][0].cmd_sts.active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual)
+ _dcd.ep[ep_id][0].cmd_sts.disable = _dcd.ep[ep_id][1].cmd_sts.disable = 1;
+}
+
+static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, uint16_t total_bytes) {
uint16_t nbytes;
+ ep_cmd_sts_t* ep_cs = get_ep_cs(ep_id);
- if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
- {
- // TODO ISO FullSpeed can have up to 1023 bytes
- nbytes = tu_min16(total_bytes, NBYTES_CBI_FULLSPEED_MAX);
- _dcd.ep[ep_id][0].buffer_fs.offset = buf_offset;
- _dcd.ep[ep_id][0].buffer_fs.nbytes = nbytes;
- }else
- {
- nbytes = tu_min16(total_bytes, NBYTES_CBI_HIGHSPEED_MAX);
- _dcd.ep[ep_id][0].buffer_hs.offset = buf_offset;
- _dcd.ep[ep_id][0].buffer_hs.nbytes = nbytes;
+ const bool is_iso = ep_is_iso(ep_cs, _dcd_controller[rhport].is_highspeed);
+
+ if ( rhport_is_highspeed(rhport) ) {
+ nbytes = tu_min16(total_bytes, is_iso ? NBYTES_ISO_HS_MAX : NBYTES_CBI_HS_MAX);
+ #if TU_CHECK_MCU(OPT_MCU_LPC54)
+ // LPC54 Errata USB.1: In USB high-speed device mode, the NBytes field does not decrement after BULK OUT transfer.
+ // Suggested Work-around: Program the NByte to the max packet size (512)
+ // Actual Work-around: round up NByte to multiple of 4.
+ // Note: this can cause buffer overflowed and corrupt data if host send more data than total_bytes
+ if ( (ep_id > 1) && (ep_id & 0x01) == 0 && ep_is_bulk(ep_cs) ) {
+ if ( nbytes & 0x03 ) {
+ nbytes = tu_align4(nbytes) + 4;
+ }
+ }
+ #endif
+
+ ep_cs[0].buffer_hs.offset = buf_offset;
+ ep_cs[0].buffer_hs.nbytes = nbytes;
+ }else {
+ nbytes = tu_min16(total_bytes, is_iso ? NBYTES_ISO_FS_MAX : NBYTES_CBI_FS_MAX);
+ ep_cs[0].buffer_fs.offset = buf_offset;
+ ep_cs[0].buffer_fs.nbytes = nbytes;
}
_dcd.dma[ep_id].nbytes = nbytes;
-
- _dcd.ep[ep_id][0].active = 1;
+ ep_cs[0].cmd_sts.active = 1;
}
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
-{
- (void) rhport;
-
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
uint8_t const ep_id = ep_addr2id(ep_addr);
+ if (!buffer || total_bytes == 0) {
+ // Although having no data, ZLPs can cause buffer overwritten to zeroes. Probably due to USB/DMA controller side
+ // effect/bug. Assigned buffer offset to (valid) dummy to prevent overwriting to DATABUFSTART
+ buffer = (uint8_t *) (uint32_t) dummy;
+ }
+
tu_memclr(&_dcd.dma[ep_id], sizeof(xfer_dma_t));
_dcd.dma[ep_id].total_bytes = total_bytes;
@@ -376,15 +485,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
static void bus_reset(uint8_t rhport)
{
tu_memclr(&_dcd, sizeof(dcd_data_t));
+ edpt_reset_all(rhport);
- // disable all non-control endpoints on bus reset
- for(uint8_t ep_id = 2; ep_id < 2*MAX_EP_PAIRS; ep_id++)
+ // disable all endpoints as specified by LPC55S69 UM Table 778
+ for(uint8_t ep_id = 0; ep_id < 2*MAX_EP_PAIRS; ep_id++)
{
- _dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1;
+ _dcd.ep[ep_id][0].cmd_sts.disable = _dcd.ep[ep_id][1].cmd_sts.disable = 1;
}
- prepare_setup_packet(rhport);
-
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
dcd_reg->EPINUSE = 0;
@@ -392,50 +500,49 @@ static void bus_reset(uint8_t rhport)
dcd_reg->EPSKIP = 0xFFFFFFFF;
dcd_reg->INTSTAT = dcd_reg->INTSTAT; // clear all pending interrupt
- dcd_reg->DEVCMDSTAT |= CMDSTAT_SETUP_RECEIVED_MASK; // clear setup received interrupt
+ dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_SETUP_RECEIVED_MASK; // clear setup received interrupt
dcd_reg->INTEN = INT_DEVICE_STATUS_MASK | TU_BIT(0) | TU_BIT(1); // enable device status & control endpoints
}
-static void process_xfer_isr(uint8_t rhport, uint32_t int_status)
-{
+static void process_xfer_isr(uint8_t rhport, uint32_t int_status) {
uint8_t const max_ep = 2*_dcd_controller[rhport].ep_pairs;
- for(uint8_t ep_id = 0; ep_id < max_ep; ep_id++ )
- {
- if ( tu_bit_test(int_status, ep_id) )
- {
+ for(uint8_t ep_id = 0; ep_id < max_ep; ep_id++ ) {
+ if ( tu_bit_test(int_status, ep_id) ) {
ep_cmd_sts_t * ep_cs = &_dcd.ep[ep_id][0];
xfer_dma_t* xfer_dma = &_dcd.dma[ep_id];
- if ( ep_id == 0 || ep_id == 1)
- {
+ if ( ep_id <= 1 ) {
// For control endpoint, we need to manually clear Active bit
- ep_cs->active = 0;
+ ep_cs->cmd_sts.active = 0;
}
uint16_t buf_offset;
uint16_t buf_nbytes;
- if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL)
- {
- buf_offset = ep_cs->buffer_fs.offset;
- buf_nbytes = ep_cs->buffer_fs.nbytes;
- }else
- {
+ if ( rhport_is_highspeed(rhport) ) {
buf_offset = ep_cs->buffer_hs.offset;
buf_nbytes = ep_cs->buffer_hs.nbytes;
+
+ #if TU_CHECK_MCU(OPT_MCU_LPC54)
+ // LPC54 Errata USB.2: In USB high-speed device mode, the NBytes field is not correct after BULK IN transfer
+ // There is no work-around. For EP in transfer, the NByte value can be ignored after a packet is transmitted.
+ if ( (ep_id > 1) && (ep_id & 0x01) == 1 && ep_is_bulk(ep_cs) ) {
+ buf_nbytes = 0;
+ }
+ #endif
+ } else {
+ buf_offset = ep_cs->buffer_fs.offset;
+ buf_nbytes = ep_cs->buffer_fs.nbytes;
}
xfer_dma->xferred_bytes += xfer_dma->nbytes - buf_nbytes;
- if ( (buf_nbytes == 0) && (xfer_dma->total_bytes > xfer_dma->xferred_bytes) )
- {
+ if ( (buf_nbytes == 0) && (xfer_dma->total_bytes > xfer_dma->xferred_bytes) ) {
// There is more data to transfer
// buff_offset has been already increased by hw to correct value for next transfer
prepare_ep_xfer(rhport, ep_id, buf_offset, xfer_dma->total_bytes - xfer_dma->xferred_bytes);
- }
- else
- {
+ } else {
// for detecting ZLP
xfer_dma->total_bytes = xfer_dma->xferred_bytes;
@@ -462,19 +569,16 @@ void dcd_int_handler(uint8_t rhport)
//------------- Device Status -------------//
if ( int_status & INT_DEVICE_STATUS_MASK )
{
- dcd_reg->DEVCMDSTAT |= CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
+ dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_RESET_CHANGE_MASK | DEVCMDSTAT_CONNECT_CHANGE_MASK | DEVCMDSTAT_SUSPEND_CHANGE_MASK;
- if ( cmd_stat & CMDSTAT_RESET_CHANGE_MASK) // bus reset
+ if ( cmd_stat & DEVCMDSTAT_RESET_CHANGE_MASK) // bus reset
{
bus_reset(rhport);
tusb_speed_t speed = TUSB_SPEED_FULL;
-
- if (_dcd_controller[rhport].max_speed == TUSB_SPEED_HIGH)
- {
+ if ( _dcd_controller[rhport].is_highspeed ) {
// 0 : reserved, 1 : full, 2 : high, 3: super
- if ( 2 == ((cmd_stat >> CMDSTAT_SPEED_SHIFT) & 0x3UL) )
- {
+ if ( 2 == ((cmd_stat >> DEVCMDSTAT_SPEED_SHIFT) & 0x3UL) ) {
speed= TUSB_SPEED_HIGH;
}
}
@@ -482,43 +586,35 @@ void dcd_int_handler(uint8_t rhport)
dcd_event_bus_reset(rhport, speed, true);
}
- if (cmd_stat & CMDSTAT_CONNECT_CHANGE_MASK)
+ if (cmd_stat & DEVCMDSTAT_CONNECT_CHANGE_MASK)
{
// device disconnect
- if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
+ if (cmd_stat & DEVCMDSTAT_DEVICE_ADDR_MASK)
{
// debouncing as this can be set when device is powering
dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
}
}
- // TODO support suspend & resume
- if (cmd_stat & CMDSTAT_SUSPEND_CHANGE_MASK)
+ if (cmd_stat & DEVCMDSTAT_SUSPEND_CHANGE_MASK)
{
- if (cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK)
- { // suspend signal, bus idle for more than 3ms
- // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
- if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
- }
+ // suspend signal, bus idle for more than 3ms
+ // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
+ if (cmd_stat & DEVCMDSTAT_DEVICE_ADDR_MASK)
+ {
+ dcd_event_bus_signal(rhport, (cmd_stat & DEVCMDSTAT_DEVICE_SUSPEND_MASK) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME, true);
}
}
-// else
-// { // resume signal
-// dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
-// }
-// }
}
// Setup Receive
- if ( tu_bit_test(int_status, 0) && (cmd_stat & CMDSTAT_SETUP_RECEIVED_MASK) )
+ if ( tu_bit_test(int_status, 0) && (cmd_stat & DEVCMDSTAT_SETUP_RECEIVED_MASK) )
{
// Follow UM flowchart to clear Active & Stall on both Control IN/OUT endpoints
- _dcd.ep[0][0].active = _dcd.ep[1][0].active = 0;
- _dcd.ep[0][0].stall = _dcd.ep[1][0].stall = 0;
+ _dcd.ep[0][0].cmd_sts.active = _dcd.ep[1][0].cmd_sts.active = 0;
+ _dcd.ep[0][0].cmd_sts.stall = _dcd.ep[1][0].cmd_sts.stall = 0;
- dcd_reg->DEVCMDSTAT |= CMDSTAT_SETUP_RECEIVED_MASK;
+ dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_SETUP_RECEIVED_MASK;
dcd_event_setup_received(rhport, _dcd.setup_packet, true);
@@ -534,4 +630,3 @@ void dcd_int_handler(uint8_t rhport)
}
#endif
-
diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c
deleted file mode 100644
index eeab3f487..000000000
--- a/src/portable/nxp/transdimension/dcd_transdimension.c
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-#include "tusb_option.h"
-
-#if TUSB_OPT_DEVICE_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX)
-
-//--------------------------------------------------------------------+
-// INCLUDE
-//--------------------------------------------------------------------+
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
- #include "fsl_device_registers.h"
- #define INCLUDE_FSL_DEVICE_REGISTERS
-#else
- // LPCOpen for 18xx & 43xx
- #include "chip.h"
-#endif
-
-#include "common/tusb_common.h"
-#include "device/dcd.h"
-#include "common_transdimension.h"
-
-#if defined(__CORTEX_M) && __CORTEX_M == 7 && __DCACHE_PRESENT == 1
- #define CleanInvalidateDCache_by_Addr SCB_CleanInvalidateDCache_by_Addr
-#else
- #define CleanInvalidateDCache_by_Addr(_addr, _dsize)
-#endif
-
-//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF
-//--------------------------------------------------------------------+
-
-// ENDPTCTRL
-enum {
- ENDPTCTRL_STALL = TU_BIT(0),
- ENDPTCTRL_TOGGLE_INHIBIT = TU_BIT(5), ///< used for test only
- ENDPTCTRL_TOGGLE_RESET = TU_BIT(6),
- ENDPTCTRL_ENABLE = TU_BIT(7)
-};
-
-// USBSTS, USBINTR
-enum {
- INTR_USB = TU_BIT(0),
- INTR_ERROR = TU_BIT(1),
- INTR_PORT_CHANGE = TU_BIT(2),
- INTR_RESET = TU_BIT(6),
- INTR_SOF = TU_BIT(7),
- INTR_SUSPEND = TU_BIT(8),
- INTR_NAK = TU_BIT(16)
-};
-
-// Queue Transfer Descriptor
-typedef struct
-{
- // Word 0: Next QTD Pointer
- uint32_t next; ///< Next link pointer This field contains the physical memory address of the next dTD to be processed
-
- // Word 1: qTQ Token
- uint32_t : 3 ;
- volatile uint32_t xact_err : 1 ;
- uint32_t : 1 ;
- volatile uint32_t buffer_err : 1 ;
- volatile uint32_t halted : 1 ;
- volatile uint32_t active : 1 ;
- uint32_t : 2 ;
- uint32_t iso_mult_override : 2 ; ///< This field can be used for transmit ISOs to override the MULT field in the dQH. This field must be zero for all packet types that are not transmit-ISO.
- uint32_t : 3 ;
- uint32_t int_on_complete : 1 ;
- volatile uint32_t total_bytes : 15 ;
- uint32_t : 0 ;
-
- // Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page
- uint32_t buffer[5]; ///< buffer1 has frame_n for TODO Isochronous
-
- //------------- DCD Area -------------//
- uint16_t expected_bytes;
- uint8_t reserved[2];
-} dcd_qtd_t;
-
-TU_VERIFY_STATIC( sizeof(dcd_qtd_t) == 32, "size is not correct");
-
-// Queue Head
-typedef struct
-{
- // Word 0: Capabilities and Characteristics
- uint32_t : 15 ; ///< Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated by the USB variable length protocol where N is computed using Max_packet_length and the Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: Isochronous endpoints must set MULT = 01, 10, or 11 as needed.
- uint32_t int_on_setup : 1 ; ///< Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is set in response to a setup being received.
- uint32_t max_package_size : 11 ; ///< This directly corresponds to the maximum packet size of the associated endpoint (wMaxPacketSize)
- uint32_t : 2 ;
- uint32_t zero_length_termination : 1 ; ///< This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on transfers that are equal in length to a multiple Max_packet_length.
- uint32_t iso_mult : 2 ; ///<
- uint32_t : 0 ;
-
- // Word 1: Current qTD Pointer
- volatile uint32_t qtd_addr;
-
- // Word 2-9: Transfer Overlay
- volatile dcd_qtd_t qtd_overlay;
-
- // Word 10-11: Setup request (control OUT only)
- volatile tusb_control_request_t setup_request;
-
- //--------------------------------------------------------------------+
- /// Due to the fact QHD is 64 bytes aligned but occupies only 48 bytes
- /// thus there are 16 bytes padding free that we can make use of.
- //--------------------------------------------------------------------+
- uint8_t reserved[16];
-} dcd_qhd_t;
-
-TU_VERIFY_STATIC( sizeof(dcd_qhd_t) == 64, "size is not correct");
-
-//--------------------------------------------------------------------+
-// Variables
-//--------------------------------------------------------------------+
-
-typedef struct
-{
- dcd_registers_t* regs; // registers
- const IRQn_Type irqnum; // IRQ number
- const uint8_t ep_count; // Max bi-directional Endpoints
-}dcd_controller_t;
-
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
- // Each endpoint with direction (IN/OUT) occupies a queue head
- // Therefore QHD_MAX is 2 x max endpoint count
- #define QHD_MAX (8*2)
-
- static const dcd_controller_t _dcd_controller[] =
- {
- // RT1010 and RT1020 only has 1 USB controller
- #if FSL_FEATURE_SOC_USBHS_COUNT == 1
- { .regs = (dcd_registers_t*) USB_BASE , .irqnum = USB_OTG1_IRQn, .ep_count = 8 }
- #else
- { .regs = (dcd_registers_t*) USB1_BASE, .irqnum = USB_OTG1_IRQn, .ep_count = 8 },
- { .regs = (dcd_registers_t*) USB2_BASE, .irqnum = USB_OTG2_IRQn, .ep_count = 8 }
- #endif
- };
-
-#else
- #define QHD_MAX (6*2)
-
- static const dcd_controller_t _dcd_controller[] =
- {
- { .regs = (dcd_registers_t*) LPC_USB0_BASE, .irqnum = USB0_IRQn, .ep_count = 6 },
- { .regs = (dcd_registers_t*) LPC_USB1_BASE, .irqnum = USB1_IRQn, .ep_count = 4 }
- };
-#endif
-
-#define QTD_NEXT_INVALID 0x01
-
-typedef struct {
- // Must be at 2K alignment
- dcd_qhd_t qhd[QHD_MAX] TU_ATTR_ALIGNED(64);
- dcd_qtd_t qtd[QHD_MAX] TU_ATTR_ALIGNED(32); // for portability, TinyUSB only queue 1 TD for each Qhd
-}dcd_data_t;
-
-CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(2048)
-static dcd_data_t _dcd_data;
-
-//--------------------------------------------------------------------+
-// Controller API
-//--------------------------------------------------------------------+
-
-/// follows LPC43xx User Manual 23.10.3
-static void bus_reset(uint8_t rhport)
-{
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
-
- // The reset value for all endpoint types is the control endpoint. If one endpoint
- // direction is enabled and the paired endpoint of opposite direction is disabled, then the
- // endpoint type of the unused direction must be changed from the control type to any other
- // type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
- // for the data PID tracking on the active endpoint.
- for( int i=1; i < _dcd_controller[rhport].ep_count; i++)
- {
- dcd_reg->ENDPTCTRL[i] = (TUSB_XFER_BULK << 2) | (TUSB_XFER_BULK << 18);
- }
-
- //------------- Clear All Registers -------------//
- dcd_reg->ENDPTNAK = dcd_reg->ENDPTNAK;
- dcd_reg->ENDPTNAKEN = 0;
- dcd_reg->USBSTS = dcd_reg->USBSTS;
- dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;
- dcd_reg->ENDPTCOMPLETE = dcd_reg->ENDPTCOMPLETE;
-
- while (dcd_reg->ENDPTPRIME) {}
- dcd_reg->ENDPTFLUSH = 0xFFFFFFFF;
- while (dcd_reg->ENDPTFLUSH) {}
-
- // read reset bit in portsc
-
- //------------- Queue Head & Queue TD -------------//
- tu_memclr(&_dcd_data, sizeof(dcd_data_t));
-
- //------------- Set up Control Endpoints (0 OUT, 1 IN) -------------//
- _dcd_data.qhd[0].zero_length_termination = _dcd_data.qhd[1].zero_length_termination = 1;
- _dcd_data.qhd[0].max_package_size = _dcd_data.qhd[1].max_package_size = CFG_TUD_ENDPOINT0_SIZE;
- _dcd_data.qhd[0].qtd_overlay.next = _dcd_data.qhd[1].qtd_overlay.next = QTD_NEXT_INVALID;
-
- _dcd_data.qhd[0].int_on_setup = 1; // OUT only
-}
-
-void dcd_init(uint8_t rhport)
-{
- tu_memclr(&_dcd_data, sizeof(dcd_data_t));
-
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
-
- // Reset controller
- dcd_reg->USBCMD |= USBCMD_RESET;
- while( dcd_reg->USBCMD & USBCMD_RESET ) {}
-
- // Set mode to device, must be set immediately after reset
- dcd_reg->USBMODE = USBMODE_CM_DEVICE;
- dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION;
-
- // TODO Force fullspeed on non-highspeed port
- // dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED;
-
- CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
-
- dcd_reg->ENDPTLISTADDR = (uint32_t) _dcd_data.qhd; // Endpoint List Address has to be 2K alignment
- dcd_reg->USBSTS = dcd_reg->USBSTS;
- dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_RESET | INTR_SUSPEND /*| INTR_SOF*/;
-
- dcd_reg->USBCMD &= ~0x00FF0000; // Interrupt Threshold Interval = 0
- dcd_reg->USBCMD |= USBCMD_RUN_STOP; // Connect
-}
-
-void dcd_int_enable(uint8_t rhport)
-{
- NVIC_EnableIRQ(_dcd_controller[rhport].irqnum);
-}
-
-void dcd_int_disable(uint8_t rhport)
-{
- NVIC_DisableIRQ(_dcd_controller[rhport].irqnum);
-}
-
-void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
-{
- // Response with status first before changing device address
- dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
-
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24);
-}
-
-void dcd_remote_wakeup(uint8_t rhport)
-{
- (void) rhport;
-}
-
-void dcd_connect(uint8_t rhport)
-{
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->USBCMD |= USBCMD_RUN_STOP;
-}
-
-void dcd_disconnect(uint8_t rhport)
-{
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->USBCMD &= ~USBCMD_RUN_STOP;
-}
-
-//--------------------------------------------------------------------+
-// HELPER
-//--------------------------------------------------------------------+
-// index to bit position in register
-static inline uint8_t ep_idx2bit(uint8_t ep_idx)
-{
- return ep_idx/2 + ( (ep_idx%2) ? 16 : 0);
-}
-
-static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes)
-{
- tu_memclr(p_qtd, sizeof(dcd_qtd_t));
-
- p_qtd->next = QTD_NEXT_INVALID;
- p_qtd->active = 1;
- p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
-
- if (data_ptr != NULL)
- {
- p_qtd->buffer[0] = (uint32_t) data_ptr;
- for(uint8_t i=1; i<5; i++)
- {
- p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096;
- }
- }
-}
-
-//--------------------------------------------------------------------+
-// DCD Endpoint Port
-//--------------------------------------------------------------------+
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0);
-}
-
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- // data toggle also need to be reset
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << ( dir ? 16 : 0 );
- dcd_reg->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << ( dir ? 16 : 0));
-}
-
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
-{
- // TODO not support ISO yet
- TU_VERIFY ( p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
-
- uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
- uint8_t const ep_idx = 2*epnum + dir;
-
- // Must not exceed max endpoint number
- TU_ASSERT( epnum < _dcd_controller[rhport].ep_count );
-
- //------------- Prepare Queue Head -------------//
- dcd_qhd_t * p_qhd = &_dcd_data.qhd[ep_idx];
- tu_memclr(p_qhd, sizeof(dcd_qhd_t));
-
- p_qhd->zero_length_termination = 1;
- p_qhd->max_package_size = p_endpoint_desc->wMaxPacketSize.size;
- p_qhd->qtd_overlay.next = QTD_NEXT_INVALID;
-
- CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
-
- // Enable EP Control
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->ENDPTCTRL[epnum] |= ((p_endpoint_desc->bmAttributes.xfer << 2) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET) << (dir ? 16 : 0);
-
- return true;
-}
-
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
-{
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
- uint8_t const ep_idx = 2*epnum + dir;
-
- if ( epnum == 0 )
- {
- // follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism
- // wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out
- while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {}
- }
-
- dcd_qhd_t * p_qhd = &_dcd_data.qhd[ep_idx];
- dcd_qtd_t * p_qtd = &_dcd_data.qtd[ep_idx];
-
- // Force the CPU to flush the buffer. We increase the size by 32 because the call aligns the
- // address to 32-byte boundaries.
- // void* cast to suppress cast-align warning, buffer must be
- CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) buffer, 4), total_bytes + 31);
-
- //------------- Prepare qtd -------------//
- qtd_init(p_qtd, buffer, total_bytes);
- p_qtd->int_on_complete = true;
- p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd
-
- CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
-
- // start transfer
- dcd_reg->ENDPTPRIME = TU_BIT( ep_idx2bit(ep_idx) ) ;
-
- return true;
-}
-
-//--------------------------------------------------------------------+
-// ISR
-//--------------------------------------------------------------------+
-void dcd_int_handler(uint8_t rhport)
-{
- dcd_registers_t* const dcd_reg = _dcd_controller[rhport].regs;
-
- uint32_t const int_enable = dcd_reg->USBINTR;
- uint32_t const int_status = dcd_reg->USBSTS & int_enable;
- dcd_reg->USBSTS = int_status; // Acknowledge handled interrupt
-
- // disabled interrupt sources
- if (int_status == 0) return;
-
- if (int_status & INTR_RESET)
- {
- bus_reset(rhport);
- uint32_t speed = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS;
- dcd_event_bus_reset(rhport, (tusb_speed_t) speed, true);
- }
-
- if (int_status & INTR_SUSPEND)
- {
- if (dcd_reg->PORTSC1 & PORTSC1_SUSPEND)
- {
- // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
- if ((dcd_reg->DEVICEADDR >> 25) & 0x0f)
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
- }
- }
- }
-
- // Make sure we read the latest version of _dcd_data.
- CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
-
- // TODO disconnection does not generate interrupt !!!!!!
-// if (int_status & INTR_PORT_CHANGE)
-// {
-// if ( !(dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS) )
-// {
-// dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_UNPLUGGED };
-// dcd_event_handler(&event, true);
-// }
-// }
-
- if (int_status & INTR_USB)
- {
- uint32_t const edpt_complete = dcd_reg->ENDPTCOMPLETE;
- dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge
-
- if (dcd_reg->ENDPTSETUPSTAT)
- {
- //------------- Set up Received -------------//
- // 23.10.10.2 Operational model for setup transfers
- dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;// acknowledge
-
- dcd_event_setup_received(rhport, (uint8_t*) &_dcd_data.qhd[0].setup_request, true);
- }
-
- if ( edpt_complete )
- {
- for(uint8_t ep_idx = 0; ep_idx < QHD_MAX; ep_idx++)
- {
- if ( tu_bit_test(edpt_complete, ep_idx2bit(ep_idx)) )
- {
- // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set
- dcd_qtd_t * p_qtd = &_dcd_data.qtd[ep_idx];
-
- uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED :
- ( p_qtd->xact_err ||p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS;
-
- uint8_t const ep_addr = (ep_idx/2) | ( (ep_idx & 0x01) ? TUSB_DIR_IN_MASK : 0 );
- dcd_event_xfer_complete(rhport, ep_addr, p_qtd->expected_bytes - p_qtd->total_bytes, result, true); // only number of bytes in the IOC qtd
- }
- }
- }
- }
-
- if (int_status & INTR_SOF)
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
- }
-
- if (int_status & INTR_NAK) {}
- if (int_status & INTR_ERROR) TU_ASSERT(false, );
-}
-
-#endif
diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c
index dbd2cc793..c59d4755e 100644
--- a/src/portable/ohci/ohci.c
+++ b/src/portable/ohci/ohci.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -24,10 +24,13 @@
* This file is part of the TinyUSB stack.
*/
-#include <common/tusb_common.h>
+#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
+#if CFG_TUH_ENABLED && defined(TUP_USBIP_OHCI)
+
+#ifndef TUP_OHCI_RHPORTS
+#error OHCI is enabled, but TUP_OHCI_RHPORTS is not defined.
+#endif
//--------------------------------------------------------------------+
// INCLUDE
@@ -35,7 +38,6 @@
#include "osal/osal.h"
#include "host/hcd.h"
-#include "host/usbh_hcd.h"
#include "ohci.h"
// TODO remove
@@ -143,7 +145,7 @@ enum {
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
-CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static ohci_data_t ohci_data;
+CFG_TUH_MEM_SECTION TU_ATTR_ALIGNED(256) static ohci_data_t ohci_data;
static ohci_ed_t * const p_ed_head[] =
{
@@ -155,10 +157,26 @@ static ohci_ed_t * const p_ed_head[] =
static void ed_list_insert(ohci_ed_t * p_pre, ohci_ed_t * p_ed);
static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr);
+static gtd_extra_data_t *gtd_get_extra_data(ohci_gtd_t const * const gtd);
//--------------------------------------------------------------------+
// USBH-HCD API
//--------------------------------------------------------------------+
+
+// If your system requires separation of virtual and physical memory, implement
+// tusb_app_virt_to_phys and tusb_app_virt_to_phys in your application.
+TU_ATTR_ALWAYS_INLINE static inline void *_phys_addr(void *virtual_address)
+{
+ if (tusb_app_virt_to_phys) return tusb_app_virt_to_phys(virtual_address);
+ return virtual_address;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void *_virt_addr(void *physical_address)
+{
+ if (tusb_app_phys_to_virt) return tusb_app_phys_to_virt(physical_address);
+ return physical_address;
+}
+
// Initialization according to 5.1.1.4
bool hcd_init(uint8_t rhport)
{
@@ -167,22 +185,44 @@ bool hcd_init(uint8_t rhport)
//------------- Data Structure init -------------//
tu_memclr(&ohci_data, sizeof(ohci_data_t));
for(uint8_t i=0; i<32; i++)
- { // assign all interrupt pointes to period head ed
- ohci_data.hcca.interrupt_table[i] = (uint32_t) &ohci_data.period_head_ed;
+ { // assign all interrupt pointers to period head ed
+ ohci_data.hcca.interrupt_table[i] = (uint32_t) _phys_addr(&ohci_data.period_head_ed);
}
ohci_data.control[0].ed.skip = 1;
ohci_data.bulk_head_ed.skip = 1;
ohci_data.period_head_ed.skip = 1;
+ //If OHCI hardware is in SMM mode, gain ownership (Ref OHCI spec 5.1.1.3.3)
+ if (OHCI_REG->control_bit.interrupt_routing == 1)
+ {
+ OHCI_REG->command_status_bit.ownership_change_request = 1;
+ while (OHCI_REG->control_bit.interrupt_routing == 1) {}
+ }
+
+ //If OHCI hardware has come from warm-boot, signal resume (Ref OHCI spec 5.1.1.3.4)
+ else if (OHCI_REG->control_bit.hc_functional_state != OHCI_CONTROL_FUNCSTATE_RESET &&
+ OHCI_REG->control_bit.hc_functional_state != OHCI_CONTROL_FUNCSTATE_OPERATIONAL)
+ {
+ //Wait 20 ms. (Ref Usb spec 7.1.7.7)
+ OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_RESUME;
+
+#if CFG_TUSB_OS != OPT_OS_NONE
+ // os_none implement task delay using usb frame counter which is not started yet
+ // therefore cause infinite delay.
+ // TODO find a way to delay in case of os none e.g __nop
+ osal_task_delay(20);
+#endif
+ }
+
// reset controller
OHCI_REG->command_status_bit.controller_reset = 1;
while( OHCI_REG->command_status_bit.controller_reset ) {} // should not take longer than 10 us
//------------- init ohci registers -------------//
- OHCI_REG->control_head_ed = (uint32_t) &ohci_data.control[0].ed;
- OHCI_REG->bulk_head_ed = (uint32_t) &ohci_data.bulk_head_ed;
- OHCI_REG->hcca = (uint32_t) &ohci_data.hcca;
+ OHCI_REG->control_head_ed = (uint32_t) _phys_addr(&ohci_data.control[0].ed);
+ OHCI_REG->bulk_head_ed = (uint32_t) _phys_addr(&ohci_data.bulk_head_ed);
+ OHCI_REG->hcca = (uint32_t) _phys_addr(&ohci_data.hcca);
OHCI_REG->interrupt_disable = OHCI_REG->interrupt_enable; // disable all interrupts
OHCI_REG->interrupt_status = OHCI_REG->interrupt_status; // clear current set bits
@@ -190,15 +230,21 @@ bool hcd_init(uint8_t rhport)
OHCI_INT_UNRECOVERABLE_ERROR_MASK | OHCI_INT_FRAME_OVERFLOW_MASK | OHCI_INT_RHPORT_STATUS_CHANGE_MASK |
OHCI_INT_MASTER_ENABLE_MASK;
- OHCI_REG->control |= OHCI_CONTROL_CONTROL_BULK_RATIO | OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK |
+ OHCI_REG->control = OHCI_CONTROL_CONTROL_BULK_RATIO | OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK |
OHCI_CONTROL_LIST_BULK_ENABLE_MASK | OHCI_CONTROL_LIST_PERIODIC_ENABLE_MASK; // TODO Isochronous
OHCI_REG->frame_interval = (OHCI_FMINTERVAL_FSMPS << 16) | OHCI_FMINTERVAL_FI;
+ OHCI_REG->frame_interval ^= (1 << 31); //Must toggle when frame_interval is updated.
OHCI_REG->periodic_start = (OHCI_FMINTERVAL_FI * 9) / 10; // Periodic start is 90% of frame interval
OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_OPERATIONAL; // make HC's state to operational state TODO use this to suspend (save power)
OHCI_REG->rh_status_bit.local_power_status_change = 1; // set global power for ports
+#if CFG_TUSB_OS != OPT_OS_NONE
+ // TODO as above delay
+ osal_task_delay(OHCI_REG->rh_descriptorA_bit.power_on_to_good_time * 2); // Wait POTG after power up
+#endif
+
return true;
}
@@ -214,20 +260,22 @@ uint32_t hcd_frame_number(uint8_t rhport)
//--------------------------------------------------------------------+
void hcd_port_reset(uint8_t hostid)
{
- (void) hostid;
- OHCI_REG->rhport_status[0] = RHPORT_PORT_RESET_STATUS_MASK;
+ OHCI_REG->rhport_status[hostid] = RHPORT_PORT_RESET_STATUS_MASK;
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ (void) rhport;
}
bool hcd_port_connect_status(uint8_t hostid)
{
- (void) hostid;
- return OHCI_REG->rhport_status_bit[0].current_connect_status;
+ return OHCI_REG->rhport_status_bit[hostid].current_connect_status;
}
tusb_speed_t hcd_port_speed_get(uint8_t hostid)
{
- (void) hostid;
- return OHCI_REG->rhport_status_bit[0].low_speed_device_attached ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
+ return OHCI_REG->rhport_status_bit[hostid].low_speed_device_attached ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
}
// endpoints are tied to an address, which only reclaim after a long delay when enumerating
@@ -280,10 +328,13 @@ static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t
tu_memclr(p_ed, sizeof(ohci_ed_t));
}
+ hcd_devtree_info_t devtree_info;
+ hcd_devtree_get_info(dev_addr, &devtree_info);
+
p_ed->dev_addr = dev_addr;
p_ed->ep_number = ep_addr & 0x0F;
p_ed->pid = (xfer_type == TUSB_XFER_CONTROL) ? PID_FROM_TD : (tu_edpt_dir(ep_addr) ? PID_IN : PID_OUT);
- p_ed->speed = _usbh_devices[dev_addr].speed;
+ p_ed->speed = devtree_info.speed;
p_ed->is_iso = (xfer_type == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
p_ed->max_packet_size = ep_size;
@@ -291,19 +342,24 @@ static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t
p_ed->is_interrupt_xfer = (xfer_type == TUSB_XFER_INTERRUPT ? 1 : 0);
}
-static void gtd_init(ohci_gtd_t* p_td, uint8_t* data_ptr, uint16_t total_bytes)
-{
+static void gtd_init(ohci_gtd_t *p_td, uint8_t *data_ptr, uint16_t total_bytes) {
tu_memclr(p_td, sizeof(ohci_gtd_t));
- p_td->used = 1;
- p_td->expected_bytes = total_bytes;
+ p_td->used = 1;
+ gtd_get_extra_data(p_td)->expected_bytes = total_bytes;
+
+ p_td->buffer_rounding = 1; // less than queued length is not a error
+ p_td->delay_interrupt = OHCI_INT_ON_COMPLETE_NO;
+ p_td->condition_code = OHCI_CCODE_NOT_ACCESSED;
- p_td->buffer_rounding = 1; // less than queued length is not a error
- p_td->delay_interrupt = OHCI_INT_ON_COMPLETE_NO;
- p_td->condition_code = OHCI_CCODE_NOT_ACCESSED;
+ uint8_t *cbp = (uint8_t *) _phys_addr(data_ptr);
- p_td->current_buffer_pointer = data_ptr;
- p_td->buffer_end = total_bytes ? (data_ptr + total_bytes-1) : data_ptr;
+ p_td->current_buffer_pointer = cbp;
+ if ( total_bytes ) {
+ p_td->buffer_end = _phys_addr(data_ptr + total_bytes - 1);
+ } else {
+ p_td->buffer_end = cbp;
+ }
}
static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
@@ -312,7 +368,7 @@ static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
ohci_ed_t* ed_pool = ohci_data.ed_pool;
- for(uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
+ for(uint32_t i=0; i<ED_MAX; i++)
{
if ( (ed_pool[i].dev_addr == dev_addr) &&
ep_addr == tu_edpt_addr(ed_pool[i].ep_number, ed_pool[i].pid == PID_IN) )
@@ -328,7 +384,7 @@ static ohci_ed_t * ed_find_free(void)
{
ohci_ed_t* ed_pool = ohci_data.ed_pool;
- for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; i++)
+ for(uint8_t i = 0; i < ED_MAX; i++)
{
if ( !ed_pool[i].used ) return &ed_pool[i];
}
@@ -339,7 +395,7 @@ static ohci_ed_t * ed_find_free(void)
static void ed_list_insert(ohci_ed_t * p_pre, ohci_ed_t * p_ed)
{
p_ed->next = p_pre->next;
- p_pre->next = (uint32_t) p_ed;
+ p_pre->next = (uint32_t) _phys_addr(p_ed);
}
static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr)
@@ -348,26 +404,30 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr)
while( p_prev->next )
{
- ohci_ed_t* ed = (ohci_ed_t*) p_prev->next;
+ ohci_ed_t* ed = (ohci_ed_t*) _virt_addr((void *)p_prev->next);
if (ed->dev_addr == dev_addr)
{
- // unlink ed
+ // Prevent Host Controller from processing this ED while we remove it
+ ed->skip = 1;
+
+ // unlink ed, will also move up p_prev
p_prev->next = ed->next;
// point the removed ED's next pointer to list head to make sure HC can always safely move away from this ED
- ed->next = (uint32_t) p_head;
+ ed->next = (uint32_t) _phys_addr(p_head);
ed->used = 0;
+ ed->skip = 0;
+ }else
+ {
+ p_prev = (ohci_ed_t*) _virt_addr((void *)p_prev->next);
}
-
- // check next valid since we could remove it
- if (p_prev->next) p_prev = (ohci_ed_t*) p_prev->next;
}
}
static ohci_gtd_t * gtd_find_free(void)
{
- for(uint8_t i=0; i < HCD_MAX_XFER; i++)
+ for(uint8_t i=0; i < GTD_MAX; i++)
{
if ( !ohci_data.gtd_pool[i].used ) return &ohci_data.gtd_pool[i];
}
@@ -380,11 +440,11 @@ static void td_insert_to_ed(ohci_ed_t* p_ed, ohci_gtd_t * p_gtd)
// tail is always NULL
if ( tu_align16(p_ed->td_head.address) == 0 )
{ // TD queue is empty --> head = TD
- p_ed->td_head.address |= (uint32_t) p_gtd;
+ p_ed->td_head.address |= (uint32_t) _phys_addr(p_gtd);
}
else
{ // TODO currently only support queue up to 2 TD each endpoint at a time
- ((ohci_gtd_t*) tu_align16(p_ed->td_head.address))->next = (uint32_t) p_gtd;
+ ((ohci_gtd_t*) tu_align16((uint32_t)_virt_addr((void *)p_ed->td_head.address)))->next = (uint32_t) _phys_addr(p_gtd);
}
}
@@ -411,7 +471,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
}
TU_ASSERT(p_ed);
- ed_init( p_ed, dev_addr, ep_desc->wMaxPacketSize.size, ep_desc->bEndpointAddress,
+ ed_init( p_ed, dev_addr, tu_edpt_packet_size(ep_desc), ep_desc->bEndpointAddress,
ep_desc->bmAttributes.xfer, ep_desc->bInterval );
// control of dev0 is used as static async head
@@ -433,14 +493,14 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
ohci_ed_t* ed = &ohci_data.control[dev_addr].ed;
ohci_gtd_t *qtd = &ohci_data.control[dev_addr].gtd;
- gtd_init(qtd, (uint8_t*) setup_packet, 8);
+ gtd_init(qtd, (uint8_t*)(uintptr_t) setup_packet, 8);
qtd->index = dev_addr;
qtd->pid = PID_SETUP;
qtd->data_toggle = GTD_DT_DATA0;
- qtd->delay_interrupt = 0;
+ qtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
//------------- Attach TDs list to Control Endpoint -------------//
- ed->td_head.address = (uint32_t) qtd;
+ ed->td_head.address = (uint32_t) _phys_addr(qtd);
OHCI_REG->command_status_bit.control_list_filled = 1;
@@ -464,9 +524,9 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
gtd->index = dev_addr;
gtd->pid = dir ? PID_IN : PID_OUT;
gtd->data_toggle = GTD_DT_DATA1; // Both Data and Ack stage start with DATA1
- gtd->delay_interrupt = 0;
+ gtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
- ed->td_head.address = (uint32_t) gtd;
+ ed->td_head.address = (uint32_t) _phys_addr(gtd);
OHCI_REG->command_status_bit.control_list_filled = 1;
}else
@@ -478,7 +538,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
gtd_init(gtd, buffer, buflen);
gtd->index = ed-ohci_data.ed_pool;
- gtd->delay_interrupt = 0;
+ gtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
td_insert_to_ed(ed, gtd);
@@ -489,20 +549,16 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
return true;
}
-bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
-{
- ohci_ed_t const * const p_ed = ed_from_addr(dev_addr, ep_addr);
- return tu_align16(p_ed->td_head.address) != tu_align16(p_ed->td_tail);
-}
-
-bool hcd_edpt_stalled(uint8_t dev_addr, uint8_t ep_addr)
-{
- ohci_ed_t const * const p_ed = ed_from_addr(dev_addr, ep_addr);
- return p_ed->td_head.halted && p_ed->is_stalled;
+bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+ // TODO not implemented yet
+ return false;
}
-bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
-{
+bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
ohci_ed_t * const p_ed = ed_from_addr(dev_addr, ep_addr);
p_ed->is_stalled = 0;
@@ -526,16 +582,17 @@ static ohci_td_item_t* list_reverse(ohci_td_item_t* td_head)
while(td_head != NULL)
{
+ td_head = _virt_addr(td_head);
uint32_t next = td_head->next;
// make current's item become reverse's first item
td_head->next = (uint32_t) td_reverse_head;
- td_reverse_head = td_head;
+ td_reverse_head = _phys_addr(td_head);
td_head = (ohci_td_item_t*) next; // advance to next item
}
- return td_reverse_head;
+ return _virt_addr(td_reverse_head);
}
static inline bool gtd_is_control(ohci_gtd_t const * const p_qtd)
@@ -554,6 +611,15 @@ static inline ohci_ed_t* gtd_get_ed(ohci_gtd_t const * const p_qtd)
}
}
+static gtd_extra_data_t *gtd_get_extra_data(ohci_gtd_t const * const gtd) {
+ if ( gtd_is_control(gtd) ) {
+ uint8_t idx = ((uintptr_t)gtd - (uintptr_t)&ohci_data.control->gtd) / sizeof(ohci_data.control[0]);
+ return &ohci_data.gtd_extra_control[idx];
+ }else {
+ return &ohci_data.gtd_extra[gtd - ohci_data.gtd_pool];
+ }
+}
+
static inline uint32_t gtd_xfer_byte_left(uint32_t buffer_end, uint32_t current_buffer)
{
// 5.2.9 OHCI sample code
@@ -571,6 +637,7 @@ static void done_queue_isr(uint8_t hostid)
// done head is written in reversed order of completion --> need to reverse the done queue first
ohci_td_item_t* td_head = list_reverse ( (ohci_td_item_t*) tu_align16(ohci_data.hcca.done_head) );
+ ohci_data.hcca.done_head = 0;
while( td_head != NULL )
{
@@ -584,8 +651,7 @@ static void done_queue_isr(uint8_t hostid)
if ( (qtd->delay_interrupt == OHCI_INT_ON_COMPLETE_YES) || (event != XFER_RESULT_SUCCESS) )
{
ohci_ed_t * const ed = gtd_get_ed(qtd);
-
- uint32_t const xferred_bytes = qtd->expected_bytes - gtd_xfer_byte_left((uint32_t) qtd->buffer_end, (uint32_t) qtd->current_buffer_pointer);
+ uint32_t const xferred_bytes = gtd_get_extra_data(qtd)->expected_bytes - gtd_xfer_byte_left((uint32_t) qtd->buffer_end, (uint32_t) qtd->current_buffer_pointer);
// NOTE Assuming the current list is BULK and there is no other EDs in the list has queued TDs.
// When there is a error resulting this ED is halted, and this EP still has other queued TD
@@ -594,7 +660,7 @@ static void done_queue_isr(uint8_t hostid)
// --> HC will not process Control list (due to service ratio when Bulk list not empty)
// To walk-around this, the halted ED will have TailP = HeadP (empty list condition), when clearing halt
// the TailP must be set back to NULL for processing remaining TDs
- if ((event != XFER_RESULT_SUCCESS))
+ if (event != XFER_RESULT_SUCCESS)
{
ed->td_tail &= 0x0Ful;
ed->td_tail |= tu_align16(ed->td_head.address); // mark halted EP as empty queue
@@ -606,17 +672,21 @@ static void done_queue_isr(uint8_t hostid)
hcd_event_xfer_complete(ed->dev_addr, tu_edpt_addr(ed->ep_number, dir), xferred_bytes, event, true);
}
- td_head = (ohci_td_item_t*) td_head->next;
+ td_head = (ohci_td_item_t*) _virt_addr((void *)td_head->next);
}
}
-void hcd_int_handler(uint8_t hostid)
-{
+void hcd_int_handler(uint8_t hostid, bool in_isr) {
+ (void) in_isr;
+
uint32_t const int_en = OHCI_REG->interrupt_enable;
uint32_t const int_status = OHCI_REG->interrupt_status & int_en;
if (int_status == 0) return;
+ // Disable MIE as per OHCI spec 5.3
+ OHCI_REG->interrupt_disable = OHCI_INT_MASTER_ENABLE_MASK;
+
// Frame number overflow
if ( int_status & OHCI_INT_FRAME_OVERFLOW_MASK )
{
@@ -626,29 +696,30 @@ void hcd_int_handler(uint8_t hostid)
//------------- RootHub status -------------//
if ( int_status & OHCI_INT_RHPORT_STATUS_CHANGE_MASK )
{
- uint32_t const rhport_status = OHCI_REG->rhport_status[0] & RHPORT_ALL_CHANGE_MASK;
-
- // TODO dual port is not yet supported
- if ( rhport_status & RHPORT_CONNECT_STATUS_CHANGE_MASK )
+ for (int i = 0; i < TUP_OHCI_RHPORTS; i++)
{
- // TODO check if remote wake-up
- if ( OHCI_REG->rhport_status_bit[0].current_connect_status )
- {
- // TODO reset port immediately, without this controller will got 2-3 (debouncing connection status change)
- OHCI_REG->rhport_status[0] = RHPORT_PORT_RESET_STATUS_MASK;
- hcd_event_device_attach(hostid, true);
- }else
+ uint32_t const rhport_status = OHCI_REG->rhport_status[i] & RHPORT_ALL_CHANGE_MASK;
+ if ( rhport_status & RHPORT_CONNECT_STATUS_CHANGE_MASK )
{
- hcd_event_device_remove(hostid, true);
+ // TODO check if remote wake-up
+ if ( OHCI_REG->rhport_status_bit[i].current_connect_status )
+ {
+ // TODO reset port immediately, without this controller will got 2-3 (debouncing connection status change)
+ OHCI_REG->rhport_status[i] = RHPORT_PORT_RESET_STATUS_MASK;
+ hcd_event_device_attach(i, true);
+ }else
+ {
+ hcd_event_device_remove(i, true);
+ }
}
- }
- if ( rhport_status & RHPORT_PORT_SUSPEND_CHANGE_MASK)
- {
+ if ( rhport_status & RHPORT_PORT_SUSPEND_CHANGE_MASK)
+ {
- }
+ }
- OHCI_REG->rhport_status[0] = rhport_status; // acknowledge all interrupt
+ OHCI_REG->rhport_status[i] = rhport_status; // acknowledge all interrupt
+ }
}
//------------- Transfer Complete -------------//
@@ -658,6 +729,8 @@ void hcd_int_handler(uint8_t hostid)
}
OHCI_REG->interrupt_status = int_status; // Acknowledge handled interrupt
+
+ OHCI_REG->interrupt_enable = OHCI_INT_MASTER_ENABLE_MASK; // Enable MIE
}
//--------------------------------------------------------------------+
// HELPER
@@ -665,4 +738,3 @@ void hcd_int_handler(uint8_t hostid)
#endif
-
diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h
index 6a634592a..94bad5df7 100644
--- a/src/portable/ohci/ohci.h
+++ b/src/portable/ohci/ohci.h
@@ -34,7 +34,7 @@
//--------------------------------------------------------------------+
// OHCI CONFIGURATION & CONSTANTS
//--------------------------------------------------------------------+
-#define HOST_HCD_XFER_INTERRUPT // TODO interrupt is used widely, should always be enalbed
+#define HOST_HCD_XFER_INTERRUPT // TODO interrupt is used widely, should always be enabled
#define OHCI_PERIODIC_LIST (defined HOST_HCD_XFER_INTERRUPT || defined HOST_HCD_XFER_ISOCHRONOUS)
// TODO merge OHCI with EHCI
@@ -42,6 +42,12 @@ enum {
OHCI_MAX_ITD = 4
};
+#define ED_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX)
+#define GTD_MAX ED_MAX
+
+// tinyUSB's OHCI implementation caps number of EDs to 8 bits
+TU_VERIFY_STATIC (ED_MAX <= 256, "Reduce CFG_TUH_DEVICE_MAX or CFG_TUH_ENDPOINT_MAX");
+
//--------------------------------------------------------------------+
// OHCI Data Structure
//--------------------------------------------------------------------+
@@ -55,7 +61,9 @@ typedef struct {
TU_VERIFY_STATIC( sizeof(ohci_hcca_t) == 256, "size is not correct" );
-typedef struct {
+// common link item for gtd and itd for list travel
+// use as pointer only
+typedef struct TU_ATTR_ALIGNED(16) {
uint32_t reserved[2];
volatile uint32_t next;
uint32_t reserved2;
@@ -65,9 +73,8 @@ typedef struct TU_ATTR_ALIGNED(16)
{
// Word 0
uint32_t used : 1;
- uint32_t index : 4; // endpoint index the td belongs to, or device address in case of control xfer
- uint32_t expected_bytes : 13; // TODO available for hcd
-
+ uint32_t index : 8; // endpoint index the gtd belongs to, or device address in case of control xfer
+ uint32_t : 9; // can be used
uint32_t buffer_rounding : 1;
uint32_t pid : 2;
uint32_t delay_interrupt : 3;
@@ -76,7 +83,7 @@ typedef struct TU_ATTR_ALIGNED(16)
volatile uint32_t condition_code : 4;
// Word 1
- volatile uint8_t* current_buffer_pointer;
+ uint8_t* volatile current_buffer_pointer;
// Word 2 : next TD
volatile uint32_t next;
@@ -147,9 +154,12 @@ typedef struct TU_ATTR_ALIGNED(32)
TU_VERIFY_STATIC( sizeof(ochi_itd_t) == 32, "size is not correct" );
+typedef struct {
+ uint16_t expected_bytes; // up to 8192 bytes so max is 13 bits
+} gtd_extra_data_t;
+
// structure with member alignment required from large to small
-typedef struct TU_ATTR_ALIGNED(256)
-{
+typedef struct TU_ATTR_ALIGNED(256) {
ohci_hcca_t hcca;
ohci_ed_t bulk_head_ed; // static bulk head (dummy)
@@ -159,14 +169,17 @@ typedef struct TU_ATTR_ALIGNED(256)
struct {
ohci_ed_t ed;
ohci_gtd_t gtd;
- }control[CFG_TUSB_HOST_DEVICE_MAX+1];
+ } control[CFG_TUH_DEVICE_MAX + CFG_TUH_HUB + 1];
// ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32
- ohci_ed_t ed_pool[HCD_MAX_ENDPOINT];
- ohci_gtd_t gtd_pool[HCD_MAX_XFER];
+ ohci_ed_t ed_pool[ED_MAX];
+ ohci_gtd_t gtd_pool[GTD_MAX];
- volatile uint16_t frame_number_hi;
+ // extra data needed by TDs that can't fit in the TD struct
+ gtd_extra_data_t gtd_extra_control[CFG_TUH_DEVICE_MAX + CFG_TUH_HUB + 1];
+ gtd_extra_data_t gtd_extra[GTD_MAX];
+ volatile uint16_t frame_number_hi;
} ohci_data_t;
//--------------------------------------------------------------------+
@@ -227,8 +240,27 @@ typedef volatile struct
uint32_t periodic_start;
uint32_t lowspeed_threshold;
- uint32_t rh_descriptorA;
- uint32_t rh_descriptorB;
+ union {
+ uint32_t rh_descriptorA;
+ struct {
+ uint32_t number_downstream_ports : 8;
+ uint32_t power_switching_mode : 1;
+ uint32_t no_power_switching : 1;
+ uint32_t device_type : 1;
+ uint32_t overcurrent_protection_mode : 1;
+ uint32_t no_over_current_protection : 1;
+ uint32_t reserved : 11;
+ uint32_t power_on_to_good_time : 8;
+ } rh_descriptorA_bit;
+ };
+
+ union {
+ uint32_t rh_descriptorB;
+ struct {
+ uint32_t device_removable : 16;
+ uint32_t port_power_control_mask : 16;
+ } rh_descriptorB_bit;
+ };
union {
uint32_t rh_status;
@@ -245,7 +277,7 @@ typedef volatile struct
};
union {
- uint32_t rhport_status[2]; // TODO NXP OHCI controller only has 2 ports
+ uint32_t rhport_status[TUP_OHCI_RHPORTS];
struct {
uint32_t current_connect_status : 1;
uint32_t port_enable_status : 1;
@@ -262,11 +294,11 @@ typedef volatile struct
uint32_t port_over_current_indicator_change : 1;
uint32_t port_reset_status_change : 1;
uint32_t TU_RESERVED : 11;
- }rhport_status_bit[2];
+ }rhport_status_bit[TUP_OHCI_RHPORTS];
};
}ohci_registers_t;
-TU_VERIFY_STATIC( sizeof(ohci_registers_t) == 0x5c, "size is not correct");
+TU_VERIFY_STATIC( sizeof(ohci_registers_t) == (0x54 + (4 * TUP_OHCI_RHPORTS)), "size is not correct");
#ifdef __cplusplus
}
diff --git a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
new file mode 100644
index 000000000..e6daf6827
--- /dev/null
+++ b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
@@ -0,0 +1,210 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018, hathach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && CFG_TUD_RPI_PIO_USB
+
+#include "pico.h"
+#include "pio_usb.h"
+#include "pio_usb_ll.h"
+
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+#define RHPORT_OFFSET 1
+#define RHPORT_PIO(_x) ((_x)-RHPORT_OFFSET)
+
+//------------- -------------//
+static usb_device_t *usb_device = NULL;
+static usb_descriptor_buffers_t desc;
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+
+// Initialize controller to device mode
+void dcd_init (uint8_t rhport)
+{
+ (void) rhport;
+
+ static pio_usb_configuration_t config = PIO_USB_DEFAULT_CONFIG;
+ usb_device = pio_usb_device_init(&config, &desc);
+}
+
+// Enable device interrupt
+void dcd_int_enable (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Disable device interrupt
+void dcd_int_disable (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
+{
+ // must be called before queuing status
+ pio_usb_device_set_address(dev_addr);
+ dcd_edpt_xfer(rhport, 0x80, NULL, 0);
+}
+
+// Wake up host
+void dcd_remote_wakeup (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
+{
+ (void) rhport;
+ return pio_usb_device_endpoint_open((uint8_t const*) desc_ep);
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ (void) rhport;
+ endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr);
+ return pio_usb_ll_transfer_start(ep, buffer, total_bytes);
+}
+
+// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
+//bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+//{
+// (void) rhport;
+// (void) ep_addr;
+// (void) ff;
+// (void) total_bytes;
+// return false;
+//}
+
+// Stall endpoint
+void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr);
+ ep->has_transfer = false;
+ ep->stalled = true;
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr);
+ ep->data_id = 0;
+ ep->stalled = false;
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+static void __no_inline_not_in_flash_func(handle_endpoint_irq)(uint8_t tu_rhport, xfer_result_t result, volatile uint32_t* ep_reg)
+{
+ const uint32_t ep_all = *ep_reg;
+
+ for(uint8_t ep_idx = 0; ep_idx < PIO_USB_EP_POOL_CNT; ep_idx++)
+ {
+ uint32_t const mask = (1u << ep_idx);
+
+ if (ep_all & mask)
+ {
+ endpoint_t* ep = PIO_USB_ENDPOINT(ep_idx);
+ dcd_event_xfer_complete(tu_rhport, ep->ep_num, ep->actual_len, result, true);
+ }
+ }
+
+ // clear all
+ (*ep_reg) &= ~ep_all;
+}
+
+// IRQ Handler
+void __no_inline_not_in_flash_func(pio_usb_device_irq_handler)(uint8_t root_id)
+{
+ uint8_t const tu_rhport = root_id + 1;
+ root_port_t* rport = PIO_USB_ROOT_PORT(root_id);
+ uint32_t const ints = rport->ints;
+
+ if (ints & PIO_USB_INTS_RESET_END_BITS)
+ {
+ dcd_event_bus_reset(tu_rhport, TUSB_SPEED_FULL, true);
+ }
+
+ if (ints & PIO_USB_INTS_SETUP_REQ_BITS)
+ {
+ dcd_event_setup_received(tu_rhport, rport->setup_packet, true);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS )
+ {
+ handle_endpoint_irq(tu_rhport, XFER_RESULT_SUCCESS, &rport->ep_complete);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_STALLED_BITS )
+ {
+ handle_endpoint_irq(tu_rhport, XFER_RESULT_STALLED, &rport->ep_stalled);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_ERROR_BITS )
+ {
+ handle_endpoint_irq(tu_rhport, XFER_RESULT_FAILED, &rport->ep_error);
+ }
+
+ // clear all
+ rport->ints &= ~ints;
+}
+
+#endif
diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
new file mode 100644
index 000000000..f4de3c51d
--- /dev/null
+++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
@@ -0,0 +1,209 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && CFG_TUH_RPI_PIO_USB
+
+#include "pico.h"
+#include "pio_usb.h"
+#include "pio_usb_ll.h"
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "osal/osal.h"
+
+#include "host/hcd.h"
+#include "host/usbh.h"
+
+#define RHPORT_OFFSET 1
+#define RHPORT_PIO(_x) ((_x)-RHPORT_OFFSET)
+
+static pio_usb_configuration_t pio_host_cfg = PIO_USB_DEFAULT_CONFIG;
+
+//--------------------------------------------------------------------+
+// HCD API
+//--------------------------------------------------------------------+
+bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void *cfg_param) {
+ (void) rhport;
+ TU_VERIFY(cfg_id == TUH_CFGID_RPI_PIO_USB_CONFIGURATION);
+ memcpy(&pio_host_cfg, cfg_param, sizeof(pio_usb_configuration_t));
+ return true;
+}
+
+bool hcd_init(uint8_t rhport) {
+ (void) rhport;
+
+ // To run USB SOF interrupt in core1, call this init in core1
+ pio_usb_host_init(&pio_host_cfg);
+
+ return true;
+}
+
+void hcd_port_reset(uint8_t rhport) {
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ pio_usb_host_port_reset_start(pio_rhport);
+}
+
+void hcd_port_reset_end(uint8_t rhport) {
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ pio_usb_host_port_reset_end(pio_rhport);
+}
+
+bool hcd_port_connect_status(uint8_t rhport) {
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+
+ root_port_t *root = PIO_USB_ROOT_PORT(pio_rhport);
+ port_pin_status_t line_state = pio_usb_bus_get_line_state(root);
+
+ return line_state != PORT_PIN_SE0;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
+ // TODO determine link speed
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return PIO_USB_ROOT_PORT(pio_rhport)->is_fullspeed ? TUSB_SPEED_FULL : TUSB_SPEED_LOW;
+}
+
+// Close all opened endpoint belong to this device
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ pio_usb_host_close_device(pio_rhport, dev_addr);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport) {
+ (void) rhport;
+ return pio_usb_host_get_frame_number();
+}
+
+void hcd_int_enable(uint8_t rhport) {
+ (void) rhport;
+}
+
+void hcd_int_disable(uint8_t rhport) {
+ (void) rhport;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *desc_ep) {
+ hcd_devtree_info_t dev_tree;
+ hcd_devtree_get_info(dev_addr, &dev_tree);
+ bool const need_pre = (dev_tree.hub_addr && dev_tree.speed == TUSB_SPEED_LOW);
+
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_endpoint_open(pio_rhport, dev_addr, (uint8_t const *) desc_ep, need_pre);
+}
+
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) {
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_endpoint_transfer(pio_rhport, dev_addr, ep_addr, buffer, buflen);
+}
+
+bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_endpoint_abort_transfer(pio_rhport, dev_addr, ep_addr);
+}
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) {
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_send_setup(pio_rhport, dev_addr, setup_packet);
+}
+
+//bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
+//{
+// // EPX is shared, so multiple device addresses and endpoint addresses share that
+// // so if any transfer is active on epx, we are busy. Interrupt endpoints have their own
+// // EPX so ep->active will only be busy if there is a pending transfer on that interrupt endpoint
+// // on that device
+// pico_trace("hcd_edpt_busy dev addr %d ep_addr 0x%x\r\n", dev_addr, ep_addr);
+// struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
+// assert(ep);
+// bool busy = ep->active;
+// pico_trace("busy == %d\r\n", busy);
+// return busy;
+//}
+
+bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+
+ return true;
+}
+
+static void __no_inline_not_in_flash_func(handle_endpoint_irq)(root_port_t *rport, xfer_result_t result,
+ volatile uint32_t *ep_reg) {
+ (void) rport;
+ const uint32_t ep_all = *ep_reg;
+
+ for ( uint8_t ep_idx = 0; ep_idx < PIO_USB_EP_POOL_CNT; ep_idx++ ) {
+ uint32_t const mask = (1u << ep_idx);
+
+ if ( ep_all & mask ) {
+ endpoint_t * ep = PIO_USB_ENDPOINT(ep_idx);
+ hcd_event_xfer_complete(ep->dev_addr, ep->ep_num, ep->actual_len, result, true);
+ }
+ }
+
+ // clear all
+ (*ep_reg) &= ~ep_all;
+}
+
+// IRQ Handler
+void __no_inline_not_in_flash_func(pio_usb_host_irq_handler)(uint8_t root_id) {
+ uint8_t const tu_rhport = root_id + 1;
+ root_port_t *rport = PIO_USB_ROOT_PORT(root_id);
+ uint32_t const ints = rport->ints;
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS ) {
+ handle_endpoint_irq(rport, XFER_RESULT_SUCCESS, &rport->ep_complete);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_STALLED_BITS ) {
+ handle_endpoint_irq(rport, XFER_RESULT_STALLED, &rport->ep_stalled);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_ERROR_BITS ) {
+ handle_endpoint_irq(rport, XFER_RESULT_FAILED, &rport->ep_error);
+ }
+
+ if ( ints & PIO_USB_INTS_CONNECT_BITS ) {
+ hcd_event_device_attach(tu_rhport, true);
+ }
+
+ if ( ints & PIO_USB_INTS_DISCONNECT_BITS ) {
+ hcd_event_device_remove(tu_rhport, true);
+ }
+
+ // clear all
+ rport->ints &= ~ints;
+}
+
+#endif
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index 0048270a6..bc0deee32 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -26,9 +26,10 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_RP2040
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUD_RPI_PIO_USB
#include "pico.h"
+#include "hardware/sync.h"
#include "rp2040_usb.h"
#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
@@ -37,345 +38,319 @@
#include "device/dcd.h"
+// Current implementation force vbus detection as always present, causing device think it is always plugged into host.
+// Therefore it cannot detect disconnect event, mistaken it as suspend.
+// Note: won't work if change to 0 (for now)
+#define FORCE_VBUS_DETECT 1
+
/*------------------------------------------------------------------*/
/* Low level controller
*------------------------------------------------------------------*/
-#define usb_hw_set hw_set_alias(usb_hw)
-#define usb_hw_clear hw_clear_alias(usb_hw)
-
// Init these in dcd_init
-static uint8_t *next_buffer_ptr;
+static uint8_t* next_buffer_ptr;
// USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
-static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2] = {0};
+static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
-static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
-{
- return &hw_endpoints[num][dir];
+// SOF may be used by remote wakeup as RESUME, this indicate whether SOF is actually used by usbd
+static bool _sof_enable = false;
+
+TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir) {
+ return &hw_endpoints[num][dir];
}
-static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr)
-{
- uint8_t num = tu_edpt_number(ep_addr);
- tusb_dir_t dir = tu_edpt_dir(ep_addr);
- return hw_endpoint_get_by_num(num, dir);
+TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_addr(uint8_t ep_addr) {
+ uint8_t num = tu_edpt_number(ep_addr);
+ tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ return hw_endpoint_get_by_num(num, dir);
}
-static void _hw_endpoint_alloc(struct hw_endpoint *ep)
-{
- uint16_t size = tu_min16(64, ep->wMaxPacketSize);
+static void _hw_endpoint_alloc(struct hw_endpoint* ep, uint8_t transfer_type) {
+ // size must be multiple of 64
+ uint size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
- // Assumes single buffered for now
- ep->hw_data_buf = next_buffer_ptr;
- next_buffer_ptr += size;
- // Bits 0-5 are ignored by the controller so make sure these are 0
- if ((uintptr_t)next_buffer_ptr & 0b111111u)
- {
- // Round up to the next 64
- uint32_t fixptr = (uintptr_t)next_buffer_ptr;
- fixptr &= ~0b111111u;
- fixptr += 64;
- pico_info("Rounding non 64 byte boundary buffer up from %x to %x\n", (uintptr_t)next_buffer_ptr, fixptr);
- next_buffer_ptr = (uint8_t*)fixptr;
- }
- assert(((uintptr_t)next_buffer_ptr & 0b111111u) == 0);
- uint dpram_offset = hw_data_offset(ep->hw_data_buf);
- assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
+ // double buffered Bulk endpoint
+ if (transfer_type == TUSB_XFER_BULK) {
+ size *= 2u;
+ }
- pico_info("Alloced %d bytes at offset 0x%x (0x%p) for ep %d %s\n",
- size,
- dpram_offset,
- ep->hw_data_buf,
- ep->num,
- ep_dir_string[ep->in]);
+ ep->hw_data_buf = next_buffer_ptr;
+ next_buffer_ptr += size;
- // Fill in endpoint control register with buffer offset
- uint32_t reg = EP_CTRL_ENABLE_BITS
- | EP_CTRL_INTERRUPT_PER_BUFFER
- | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB)
- | dpram_offset;
+ assert(((uintptr_t) next_buffer_ptr & 0b111111u) == 0);
+ uint dpram_offset = hw_data_offset(ep->hw_data_buf);
+ hard_assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
- *ep->endpoint_control = reg;
-}
+ pico_info(" Allocated %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
-static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
-{
- const uint8_t num = tu_edpt_number(ep_addr);
- const tusb_dir_t dir = tu_edpt_dir(ep_addr);
- ep->ep_addr = ep_addr;
- // For device, IN is a tx transfer and OUT is an rx transfer
- ep->rx = (dir == TUSB_DIR_OUT);
- // Response to a setup packet on EP0 starts with pid of 1
- ep->next_pid = num == 0 ? 1u : 0u;
+ // Fill in endpoint control register with buffer offset
+ uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
- // Add some checks around the max packet size
- if (transfer_type == TUSB_XFER_ISOCHRONOUS)
- {
- if (wMaxPacketSize > USB_MAX_ISO_PACKET_SIZE)
- {
- panic("Isochronous wMaxPacketSize %d too large", wMaxPacketSize);
- }
- }
- else
- {
- if (wMaxPacketSize > USB_MAX_PACKET_SIZE)
- {
- panic("Isochronous wMaxPacketSize %d too large", wMaxPacketSize);
- }
- }
+ *ep->endpoint_control = reg;
+}
- ep->wMaxPacketSize = wMaxPacketSize;
- ep->transfer_type = transfer_type;
+static void _hw_endpoint_close(struct hw_endpoint* ep) {
+ // Clear hardware registers and then zero the struct
+ // Clears endpoint enable
+ *ep->endpoint_control = 0;
+ // Clears buffer available, etc
+ *ep->buffer_control = 0;
+ // Clear any endpoint state
+ memset(ep, 0, sizeof(struct hw_endpoint));
- // Every endpoint has a buffer control register in dpram
- if (dir == TUSB_DIR_IN)
- {
- ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in;
- }
- else
- {
- ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].out;
+ // Reclaim buffer space if all endpoints are closed
+ bool reclaim_buffers = true;
+ for (uint8_t i = 1; i < USB_MAX_ENDPOINTS; i++) {
+ if (hw_endpoint_get_by_num(i, TUSB_DIR_OUT)->hw_data_buf != NULL ||
+ hw_endpoint_get_by_num(i, TUSB_DIR_IN)->hw_data_buf != NULL) {
+ reclaim_buffers = false;
+ break;
}
+ }
+ if (reclaim_buffers) {
+ next_buffer_ptr = &usb_dpram->epx_data[0];
+ }
+}
- // Clear existing buffer control state
- *ep->buffer_control = 0;
+static void hw_endpoint_close(uint8_t ep_addr) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
+ _hw_endpoint_close(ep);
+}
- if (num == 0)
- {
- // EP0 has no endpoint control register because
- // the buffer offsets are fixed
- ep->endpoint_control = NULL;
+static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
- // Buffer offset is fixed
- ep->hw_data_buf = (uint8_t*)&usb_dpram->ep0_buf_a[0];
- }
- else
- {
- // Set the endpoint control register (starts at EP1, hence num-1)
- if (dir == TUSB_DIR_IN)
- {
- ep->endpoint_control = &usb_dpram->ep_ctrl[num-1].in;
- }
- else
- {
- ep->endpoint_control = &usb_dpram->ep_ctrl[num-1].out;
- }
+ const uint8_t num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
- // Now if it hasn't already been done
- //alloc a buffer and fill in endpoint control register
- if(!(ep->configured))
- {
- _hw_endpoint_alloc(ep);
- }
- }
+ ep->ep_addr = ep_addr;
- ep->configured = true;
-}
+ // For device, IN is a tx transfer and OUT is an rx transfer
+ ep->rx = (dir == TUSB_DIR_OUT);
-#if 0 // todo unused
-static void _hw_endpoint_close(struct hw_endpoint *ep)
-{
- // Clear hardware registers and then zero the struct
- // Clears endpoint enable
- *ep->endpoint_control = 0;
- // Clears buffer available, etc
- *ep->buffer_control = 0;
- // Clear any endpoint state
- memset(ep, 0, sizeof(struct hw_endpoint));
-}
+ ep->next_pid = 0u;
+ ep->wMaxPacketSize = wMaxPacketSize;
+ ep->transfer_type = transfer_type;
-static void hw_endpoint_close(uint8_t ep_addr)
-{
- struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
- _hw_endpoint_close(ep);
-}
-#endif
+ // Every endpoint has a buffer control register in dpram
+ if (dir == TUSB_DIR_IN) {
+ ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in;
+ } else {
+ ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].out;
+ }
-static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t bmAttributes)
-{
- struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
- _hw_endpoint_init(ep, ep_addr, wMaxPacketSize, bmAttributes);
-}
+ // Clear existing buffer control state
+ *ep->buffer_control = 0;
-static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool start)
-{
- struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
- _hw_endpoint_xfer(ep, buffer, total_bytes, start);
-}
+ if (num == 0) {
+ // EP0 has no endpoint control register because the buffer offsets are fixed
+ ep->endpoint_control = NULL;
-static void hw_handle_buff_status(void)
-{
- uint32_t remaining_buffers = usb_hw->buf_status;
- pico_trace("buf_status 0x%08x\n", remaining_buffers);
- uint bit = 1u;
- for (uint i = 0; remaining_buffers && i < USB_MAX_ENDPOINTS * 2; i++)
- {
- if (remaining_buffers & bit)
- {
- uint __unused which = (usb_hw->buf_cpu_should_handle & bit) ? 1 : 0;
- // Should be single buffered
- assert(which == 0);
- // clear this in advance
- usb_hw_clear->buf_status = bit;
- // IN transfer for even i, OUT transfer for odd i
- struct hw_endpoint *ep = hw_endpoint_get_by_num(i >> 1u, !(i & 1u));
- // Continue xfer
- bool done = _hw_endpoint_xfer_continue(ep);
- if (done)
- {
- // Notify
- dcd_event_xfer_complete(0, ep->ep_addr, ep->len, XFER_RESULT_SUCCESS, true);
- hw_endpoint_reset_transfer(ep);
- }
- remaining_buffers &= ~bit;
- }
- bit <<= 1u;
+ // Buffer offset is fixed (also double buffered)
+ ep->hw_data_buf = (uint8_t*) &usb_dpram->ep0_buf_a[0];
+ } else {
+ // Set the endpoint control register (starts at EP1, hence num-1)
+ if (dir == TUSB_DIR_IN) {
+ ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].in;
+ } else {
+ ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out;
}
-}
-static void reset_ep0(void)
-{
- // If we have finished this transfer on EP0 set pid back to 1 for next
- // setup transfer. Also clear a stall in case
- uint8_t addrs[] = {0x0, 0x80};
- for (uint i = 0 ; i < TU_ARRAY_SIZE(addrs); i++)
- {
- struct hw_endpoint *ep = hw_endpoint_get_by_addr(addrs[i]);
- ep->next_pid = 1u;
- ep->stalled = 0;
- }
+ // alloc a buffer and fill in endpoint control register
+ _hw_endpoint_alloc(ep, transfer_type);
+ }
}
-static void ep0_0len_status(void)
-{
- // Send 0len complete response on EP0 IN
- reset_ep0();
- hw_endpoint_xfer(0x80, NULL, 0, true);
+static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
+ hw_endpoint_xfer_start(ep, buffer, total_bytes);
}
-static void _hw_endpoint_stall(struct hw_endpoint *ep)
-{
- assert(!ep->stalled);
- if (tu_edpt_number(ep->ep_addr) == 0)
- {
- // A stall on EP0 has to be armed so it can be cleared on the next setup packet
- usb_hw_set->ep_stall_arm = (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
+static void __tusb_irq_path_func(hw_handle_buff_status)(void) {
+ uint32_t remaining_buffers = usb_hw->buf_status;
+ pico_trace("buf_status = 0x%08lx\r\n", remaining_buffers);
+ uint bit = 1u;
+ for (uint8_t i = 0; remaining_buffers && i < USB_MAX_ENDPOINTS * 2; i++) {
+ if (remaining_buffers & bit) {
+ // clear this in advance
+ usb_hw_clear->buf_status = bit;
+
+ // IN transfer for even i, OUT transfer for odd i
+ struct hw_endpoint* ep = hw_endpoint_get_by_num(i >> 1u, (i & 1u) ? TUSB_DIR_OUT : TUSB_DIR_IN);
+
+ // Continue xfer
+ bool done = hw_endpoint_xfer_continue(ep);
+ if (done) {
+ // Notify
+ dcd_event_xfer_complete(0, ep->ep_addr, ep->xferred_len, XFER_RESULT_SUCCESS, true);
+ hw_endpoint_reset_transfer(ep);
+ }
+ remaining_buffers &= ~bit;
}
- _hw_endpoint_buffer_control_set_mask32(ep, USB_BUF_CTRL_STALL);
- ep->stalled = true;
+ bit <<= 1u;
+ }
}
-static void hw_endpoint_stall(uint8_t ep_addr)
-{
- struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
- _hw_endpoint_stall(ep);
-}
+TU_ATTR_ALWAYS_INLINE static inline void reset_ep0(void) {
+ // If we have finished this transfer on EP0 set pid back to 1 for next
+ // setup transfer. Also clear a stall in case
+ for (uint8_t dir = 0; dir < 2; dir++) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_num(0, dir);
+ if (ep->active) {
+ // Abort any pending transfer from a prior control transfer per USB specs
+ // Due to Errata RP2040-E2: ABORT flag is only applicable for B2 and later (unusable for B0, B1).
+ // Which means we are not guaranteed to safely abort pending transfer on B0 and B1.
+ uint32_t const abort_mask = (dir ? USB_EP_ABORT_EP0_IN_BITS : USB_EP_ABORT_EP0_OUT_BITS);
+ if (rp2040_chip_version() >= 2) {
+ usb_hw_set->abort = abort_mask;
+ while ((usb_hw->abort_done & abort_mask) != abort_mask) {}
+ }
-static void _hw_endpoint_clear_stall(struct hw_endpoint *ep)
-{
- if (tu_edpt_number(ep->ep_addr) == 0)
- {
- // Probably already been cleared but no harm
- usb_hw_clear->ep_stall_arm = (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
+ _hw_endpoint_buffer_control_set_value32(ep, USB_BUF_CTRL_DATA1_PID | USB_BUF_CTRL_SEL);
+ hw_endpoint_reset_transfer(ep);
+
+ if (rp2040_chip_version() >= 2) {
+ usb_hw_clear->abort_done = abort_mask;
+ usb_hw_clear->abort = abort_mask;
+ }
}
- _hw_endpoint_buffer_control_clear_mask32(ep, USB_BUF_CTRL_STALL);
- ep->stalled = false;
+ ep->next_pid = 1u;
+ }
}
-static void hw_endpoint_clear_stall(uint8_t ep_addr)
-{
- struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
- _hw_endpoint_clear_stall(ep);
+static void __tusb_irq_path_func(reset_non_control_endpoints)(void) {
+ // Disable all non-control
+ for (uint8_t i = 0; i < USB_MAX_ENDPOINTS - 1; i++) {
+ usb_dpram->ep_ctrl[i].in = 0;
+ usb_dpram->ep_ctrl[i].out = 0;
+ }
+
+ // clear non-control hw endpoints
+ tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2 * sizeof(hw_endpoint_t));
+
+ // reclaim buffer space
+ next_buffer_ptr = &usb_dpram->epx_data[0];
}
-static void dcd_rp2040_irq(void)
-{
- uint32_t status = usb_hw->ints;
- uint32_t handled = 0;
+static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
+ uint32_t const status = usb_hw->ints;
+ uint32_t handled = 0;
- if (status & USB_INTS_SETUP_REQ_BITS)
- {
- handled |= USB_INTS_SETUP_REQ_BITS;
- uint8_t const *setup = (uint8_t const *)&usb_dpram->setup_packet;
- // Clear stall bits and reset pid
- reset_ep0();
- // Pass setup packet to tiny usb
- dcd_event_setup_received(0, setup, true);
- usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
- }
+ if (status & USB_INTF_DEV_SOF_BITS) {
+ bool keep_sof_alive = false;
- if (status & USB_INTS_BUFF_STATUS_BITS)
- {
- handled |= USB_INTS_BUFF_STATUS_BITS;
- hw_handle_buff_status();
- }
+ handled |= USB_INTF_DEV_SOF_BITS;
- // SE0 for 2 us or more, usually together with Bus Reset
- if (status & USB_INTS_DEV_CONN_DIS_BITS)
- {
- handled |= USB_INTS_DEV_CONN_DIS_BITS;
+#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+ // Errata 15 workaround for Device Bulk-In endpoint
+ e15_last_sof = time_us_32();
- if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS )
- {
- // Connected: nothing to do
- }else
- {
- // Disconnected
- dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
- }
+ for (uint8_t i = 0; i < USB_MAX_ENDPOINTS; i++) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_num(i, TUSB_DIR_IN);
- usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
- }
+ // Active Bulk IN endpoint requires SOF
+ if ((ep->transfer_type == TUSB_XFER_BULK) && ep->active) {
+ keep_sof_alive = true;
- // SE0 for 2.5 us or more
- if (status & USB_INTS_BUS_RESET_BITS)
- {
- pico_trace("BUS RESET\n");
- usb_hw->dev_addr_ctrl = 0;
- handled |= USB_INTS_BUS_RESET_BITS;
- dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
- usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
+ hw_endpoint_lock_update(ep, 1);
-#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
- // Only run enumeration walk-around if pull up is enabled
- if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS )
- {
- rp2040_usb_device_enumeration_fix();
+ // Deferred enable?
+ if (ep->pending) {
+ ep->pending = 0;
+ hw_endpoint_start_next_buffer(ep);
}
-#endif
+
+ hw_endpoint_lock_update(ep, -1);
+ }
}
+#endif
-#if 0
- // TODO Enable SUSPEND & RESUME interrupt and test later on with/without VBUS detection
+ // disable SOF interrupt if it is used for RESUME in remote wakeup
+ if (!keep_sof_alive && !_sof_enable) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
- /* Note from pico datasheet 4.1.2.6.4 (v1.2)
- * If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
- * the device is first connected but the bus is idle. The bus can be idle for a few ms before
- * the host begins sending start of frame packets. You will also see a suspend interrupt
- * when the device is disconnected if you do not have a VBUS detect circuit connected. This is
- * because without VBUS detection, it is impossible to tell the difference between
- * being disconnected and suspended.
- */
- if (status & USB_INTS_DEV_SUSPEND_BITS)
- {
- handled |= USB_INTS_DEV_SUSPEND_BITS;
- dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
- usb_hw_clear->sie_status = USB_SIE_STATUS_SUSPENDED_BITS;
- }
+ dcd_event_sof(0, usb_hw->sof_rd & USB_SOF_RD_BITS, true);
+ }
+
+ // xfer events are handled before setup req. So if a transfer completes immediately
+ // before closing the EP, the events will be delivered in same order.
+ if (status & USB_INTS_BUFF_STATUS_BITS) {
+ handled |= USB_INTS_BUFF_STATUS_BITS;
+ hw_handle_buff_status();
+ }
- if (status & USB_INTS_DEV_RESUME_FROM_HOST_BITS)
+ if (status & USB_INTS_SETUP_REQ_BITS) {
+ handled |= USB_INTS_SETUP_REQ_BITS;
+ uint8_t const* setup = remove_volatile_cast(uint8_t const*, &usb_dpram->setup_packet);
+
+ // reset pid to both 1 (data and ack)
+ reset_ep0();
+
+ // Pass setup packet to tiny usb
+ dcd_event_setup_received(0, setup, true);
+ usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
+ }
+
+#if FORCE_VBUS_DETECT == 0
+ // Since we force VBUS detect On, device will always think it is connected and
+ // couldn't distinguish between disconnect and suspend
+ if (status & USB_INTS_DEV_CONN_DIS_BITS)
+ {
+ handled |= USB_INTS_DEV_CONN_DIS_BITS;
+
+ if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS )
+ {
+ // Connected: nothing to do
+ }else
{
- handled |= USB_INTS_DEV_RESUME_FROM_HOST_BITS;
- dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
- usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
+ // Disconnected
+ dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
}
+
+ usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
+ }
#endif
- if (status ^ handled)
- {
- panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
- }
+ // SE0 for 2.5 us or more (will last at least 10ms)
+ if (status & USB_INTS_BUS_RESET_BITS) {
+ pico_trace("BUS RESET\r\n");
+
+ handled |= USB_INTS_BUS_RESET_BITS;
+
+ usb_hw->dev_addr_ctrl = 0;
+ reset_non_control_endpoints();
+ dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
+ usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
+
+#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
+ // Only run enumeration workaround if pull up is enabled
+ if (usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS) rp2040_usb_device_enumeration_fix();
+#endif
+ }
+
+ /* Note from pico datasheet 4.1.2.6.4 (v1.2)
+ * If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
+ * the device is first connected but the bus is idle. The bus can be idle for a few ms before
+ * the host begins sending start of frame packets. You will also see a suspend interrupt
+ * when the device is disconnected if you do not have a VBUS detect circuit connected. This is
+ * because without VBUS detection, it is impossible to tell the difference between
+ * being disconnected and suspended.
+ */
+ if (status & USB_INTS_DEV_SUSPEND_BITS) {
+ handled |= USB_INTS_DEV_SUSPEND_BITS;
+ dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+ usb_hw_clear->sie_status = USB_SIE_STATUS_SUSPENDED_BITS;
+ }
+
+ if (status & USB_INTS_DEV_RESUME_FROM_HOST_BITS) {
+ handled |= USB_INTS_DEV_RESUME_FROM_HOST_BITS;
+ dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+ usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
+ }
+
+ if (status ^ handled) {
+ panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
+ }
}
#define USB_INTS_ERROR_BITS ( \
@@ -388,144 +363,190 @@ static void dcd_rp2040_irq(void)
/*------------------------------------------------------------------*/
/* Controller API
*------------------------------------------------------------------*/
-void dcd_init (uint8_t rhport)
-{
- pico_trace("dcd_init %d\n", rhport);
- assert(rhport == 0);
- // Reset hardware to default state
- rp2040_usb_init();
+// older SDK
+#ifndef PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY
+#define PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY 0xff
+#endif
- irq_set_exclusive_handler(USBCTRL_IRQ, dcd_rp2040_irq);
- memset(hw_endpoints, 0, sizeof(hw_endpoints));
- next_buffer_ptr = &usb_dpram->epx_data[0];
+void dcd_init(uint8_t rhport) {
+ assert(rhport == 0);
+
+ TU_LOG(2, "Chip Version B%u\r\n", rp2040_chip_version());
- // EP0 always exists so init it now
- // EP0 OUT
- hw_endpoint_init(0x0, 64, 0);
- // EP0 IN
- hw_endpoint_init(0x80, 64, 0);
+ // Reset hardware to default state
+ rp2040_usb_init();
- // Initializes the USB peripheral for device mode and enables it.
- // Don't need to enable the pull up here. Force VBUS
- usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS;
+#if FORCE_VBUS_DETECT
+ // Force VBUS detect so the device thinks it is plugged into a host
+ usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
+#endif
+
+ irq_add_shared_handler(USBCTRL_IRQ, dcd_rp2040_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
+
+ // Init control endpoints
+ tu_memclr(hw_endpoints[0], 2 * sizeof(hw_endpoint_t));
+ hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
+ hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
+
+ // Init non-control endpoints
+ reset_non_control_endpoints();
+
+ // Initializes the USB peripheral for device mode and enables it.
+ // Don't need to enable the pull up here. Force VBUS
+ usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS;
+
+ // Enable individual controller IRQS here. Processor interrupt enable will be used
+ // for the global interrupt enable...
+ // Note: Force VBUS detect cause disconnection not detectable
+ usb_hw->sie_ctrl = USB_SIE_CTRL_EP0_INT_1BUF_BITS;
+ usb_hw->inte = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS |
+ USB_INTS_DEV_SUSPEND_BITS | USB_INTS_DEV_RESUME_FROM_HOST_BITS |
+ (FORCE_VBUS_DETECT ? 0 : USB_INTS_DEV_CONN_DIS_BITS);
+
+ dcd_connect(rhport);
+}
+
+bool dcd_deinit(uint8_t rhport) {
+ (void) rhport;
- // Enable individual controller IRQS here. Processor interrupt enable will be used
- // for the global interrupt enable...
- // TODO Enable SUSPEND & RESUME interrupt
- usb_hw->sie_ctrl = USB_SIE_CTRL_EP0_INT_1BUF_BITS;
- usb_hw->inte = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS |
- USB_INTS_DEV_CONN_DIS_BITS /* | USB_INTS_DEV_SUSPEND_BITS | USB_INTS_DEV_RESUME_FROM_HOST_BITS */ ;
+ reset_non_control_endpoints();
+ irq_remove_handler(USBCTRL_IRQ, dcd_rp2040_irq);
- dcd_connect(rhport);
+ // reset usb hardware into initial state
+ reset_block(RESETS_RESET_USBCTRL_BITS);
+ unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
+
+ return true;
}
-void dcd_int_enable(uint8_t rhport)
-{
- assert(rhport == 0);
- irq_set_enabled(USBCTRL_IRQ, true);
+void dcd_int_enable(__unused uint8_t rhport) {
+ assert(rhport == 0);
+ irq_set_enabled(USBCTRL_IRQ, true);
}
-void dcd_int_disable(uint8_t rhport)
-{
- assert(rhport == 0);
- irq_set_enabled(USBCTRL_IRQ, false);
+void dcd_int_disable(__unused uint8_t rhport) {
+ assert(rhport == 0);
+ irq_set_enabled(USBCTRL_IRQ, false);
}
-void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
-{
- pico_trace("dcd_set_address %d %d\n", rhport, dev_addr);
- assert(rhport == 0);
+void dcd_set_address(__unused uint8_t rhport, __unused uint8_t dev_addr) {
+ assert(rhport == 0);
- // Can't set device address in hardware until status xfer has complete
- ep0_0len_status();
+ // Can't set device address in hardware until status xfer has complete
+ // Send 0len complete response on EP0 IN
+ hw_endpoint_xfer(0x80, NULL, 0);
}
-void dcd_remote_wakeup(uint8_t rhport)
-{
- pico_info("dcd_remote_wakeup %d\n", rhport);
- assert(rhport == 0);
- usb_hw_set->sie_ctrl = USB_SIE_CTRL_RESUME_BITS;
+void dcd_remote_wakeup(__unused uint8_t rhport) {
+ pico_info("dcd_remote_wakeup %d\n", rhport);
+ assert(rhport == 0);
+
+ // since RESUME interrupt is not triggered if we are the one initiate
+ // briefly enable SOF to notify usbd when bus is ready
+ usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
+ usb_hw_set->sie_ctrl = USB_SIE_CTRL_RESUME_BITS;
}
// disconnect by disabling internal pull-up resistor on D+/D-
-void dcd_disconnect(uint8_t rhport)
-{
- pico_info("dcd_disconnect %d\n", rhport);
- assert(rhport == 0);
- usb_hw_clear->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
+void dcd_disconnect(__unused uint8_t rhport) {
+ (void) rhport;
+ usb_hw_clear->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
}
// connect by enabling internal pull-up resistor on D+/D-
-void dcd_connect(uint8_t rhport)
-{
- pico_info("dcd_connect %d\n", rhport);
- assert(rhport == 0);
- usb_hw_set->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
+void dcd_connect(__unused uint8_t rhport) {
+ (void) rhport;
+ usb_hw_set->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en) {
+ (void) rhport;
+
+ _sof_enable = en;
+
+ if (en) {
+ usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
+ }
+#if !TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+ else {
+ // Don't clear immediately if the SOF workaround is in use.
+ // The SOF handler will conditionally disable the interrupt.
+ usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
+ }
+#endif
}
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
-void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
-{
- pico_trace("dcd_edpt0_status_complete %d\n", rhport);
- assert(rhport == 0);
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
+ (void) rhport;
- if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
- request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
- request->bRequest == TUSB_REQ_SET_ADDRESS)
- {
- pico_trace("Set HW address %d\n", assigned_address);
- usb_hw->dev_addr_ctrl = (uint8_t) request->wValue;
- }
-
- reset_ep0();
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
+ request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ usb_hw->dev_addr_ctrl = (uint8_t) request->wValue;
+ }
}
-bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
-{
- pico_info("dcd_edpt_open %d %02x\n", rhport, desc_edpt->bEndpointAddress);
- assert(rhport == 0);
- hw_endpoint_init(desc_edpt->bEndpointAddress, desc_edpt->wMaxPacketSize.size, desc_edpt->bmAttributes.xfer);
- return true;
+bool dcd_edpt_open(__unused uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
+ assert(rhport == 0);
+ hw_endpoint_init(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), desc_edpt->bmAttributes.xfer);
+ return true;
}
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
-{
- assert(rhport == 0);
- // True means start new xfer
- hw_endpoint_xfer(ep_addr, buffer, total_bytes, true);
- return true;
+void dcd_edpt_close_all(uint8_t rhport) {
+ (void) rhport;
+
+ // may need to use EP Abort
+ reset_non_control_endpoints();
}
-void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
-{
- pico_trace("dcd_edpt_stall %d %02x\n", rhport, ep_addr);
- assert(rhport == 0);
- hw_endpoint_stall(ep_addr);
+bool dcd_edpt_xfer(__unused uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
+ assert(rhport == 0);
+ hw_endpoint_xfer(ep_addr, buffer, total_bytes);
+ return true;
}
-void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
-{
- pico_trace("dcd_edpt_clear_stall %d %02x\n", rhport, ep_addr);
- assert(rhport == 0);
- hw_endpoint_clear_stall(ep_addr);
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
+
+ if (tu_edpt_number(ep_addr) == 0) {
+ // A stall on EP0 has to be armed so it can be cleared on the next setup packet
+ usb_hw_set->ep_stall_arm = (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS
+ : USB_EP_STALL_ARM_EP0_OUT_BITS;
+ }
+
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
+
+ // stall and clear current pending buffer
+ // may need to use EP_ABORT
+ _hw_endpoint_buffer_control_set_value32(ep, USB_BUF_CTRL_STALL);
}
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
-void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
-{
- // usbd.c says: In progress transfers on this EP may be delivered after this call
- pico_trace("dcd_edpt_close %d %02x\n", rhport, ep_addr);
+ if (tu_edpt_number(ep_addr)) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
+
+ // clear stall also reset toggle to DATA0, ready for next transfer
+ ep->next_pid = 0;
+ _hw_endpoint_buffer_control_clear_mask32(ep, USB_BUF_CTRL_STALL);
+ }
+}
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
+ pico_trace("dcd_edpt_close %02x\r\n", ep_addr);
+ hw_endpoint_close(ep_addr);
}
-void dcd_int_handler(uint8_t rhport)
-{
- (void) rhport;
- dcd_rp2040_irq();
+void __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport) {
+ (void) rhport;
+ dcd_rp2040_irq();
}
#endif
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index 3c62b5732..222dbbbf0 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,7 +27,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && CFG_TUSB_MCU == OPT_MCU_RP2040
+#if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUH_RPI_PIO_USB && !CFG_TUH_MAX3421
#include "pico.h"
#include "rp2040_usb.h"
@@ -38,9 +39,9 @@
#include "host/hcd.h"
#include "host/usbh.h"
-#include "host/usbh_hcd.h"
-#define ROOT_PORT 0
+// port 0 is native USB port, other is counted as software PIO
+#define RHPORT_NATIVE 0
//--------------------------------------------------------------------+
// Low level rp2040 controller functions
@@ -52,315 +53,323 @@
static_assert(PICO_USB_HOST_INTERRUPT_ENDPOINTS <= USB_MAX_ENDPOINTS, "");
// Host mode uses one shared endpoint register for non-interrupt endpoint
-struct hw_endpoint eps[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS];
-#define epx (eps[0])
-
-#define usb_hw_set hw_set_alias(usb_hw)
-#define usb_hw_clear hw_clear_alias(usb_hw)
-
-// Used for hcd pipe busy.
-// todo still a bit wasteful
-// top bit set if valid
-uint8_t dev_ep_map[CFG_TUSB_HOST_DEVICE_MAX][1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS][2];
+static struct hw_endpoint ep_pool[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS];
+#define epx (ep_pool[0])
// Flags we set by default in sie_ctrl (we add other bits on top)
-static uint32_t sie_ctrl_base = USB_SIE_CTRL_SOF_EN_BITS |
- USB_SIE_CTRL_KEEP_ALIVE_EN_BITS |
- USB_SIE_CTRL_PULLDOWN_EN_BITS |
- USB_SIE_CTRL_EP0_INT_1BUF_BITS;
+enum {
+ SIE_CTRL_BASE = USB_SIE_CTRL_SOF_EN_BITS | USB_SIE_CTRL_KEEP_ALIVE_EN_BITS |
+ USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS
+};
static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
{
- uint8_t num = tu_edpt_number(ep_addr);
- if (num == 0) {
- return &epx;
- }
- uint8_t in = (ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0;
- uint mapping = dev_ep_map[dev_addr-1][num][in];
- pico_trace("Get dev addr %d ep %d = %d\n", dev_addr, ep_addr, mapping);
- return mapping >= 128 ? eps + (mapping & 0x7fu) : NULL;
-}
+ uint8_t num = tu_edpt_number(ep_addr);
+ if ( num == 0 ) return &epx;
-static void set_dev_ep(uint8_t dev_addr, uint8_t ep_addr, struct hw_endpoint *ep)
-{
- uint8_t num = tu_edpt_number(ep_addr);
- uint8_t in = (ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0;
- uint32_t index = ep - eps;
- hard_assert(index < TU_ARRAY_SIZE(eps));
- // todo revisit why dev_addr can be 0 here
- if (dev_addr) {
- dev_ep_map[dev_addr-1][num][in] = 128u | index;
- }
- pico_trace("Set dev addr %d ep %d = %d\n", dev_addr, ep_addr, index);
+ for ( uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++ )
+ {
+ struct hw_endpoint *ep = &ep_pool[i];
+ if ( ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr) ) return ep;
+ }
+
+ return NULL;
}
-static inline uint8_t dev_speed(void)
+TU_ATTR_ALWAYS_INLINE static inline uint8_t dev_speed(void)
{
- return (usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS) >> USB_SIE_STATUS_SPEED_LSB;
+ return (usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS) >> USB_SIE_STATUS_SPEED_LSB;
}
-static bool need_pre(uint8_t dev_addr)
+TU_ATTR_ALWAYS_INLINE static inline bool need_pre(uint8_t dev_addr)
{
- // If this device is different to the speed of the root device
- // (i.e. is a low speed device on a full speed hub) then need pre
- return hcd_port_speed_get(0) != tuh_device_get_speed(dev_addr);
+ // If this device is different to the speed of the root device
+ // (i.e. is a low speed device on a full speed hub) then need pre
+ return hcd_port_speed_get(0) != tuh_speed_get(dev_addr);
}
-static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result)
+static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_result_t xfer_result)
{
- // Mark transfer as done before we tell the tinyusb stack
- uint8_t dev_addr = ep->dev_addr;
- uint8_t ep_addr = ep->ep_addr;
- uint total_len = ep->total_len;
- hw_endpoint_reset_transfer(ep);
- hcd_event_xfer_complete(dev_addr, ep_addr, total_len, xfer_result, true);
+ // Mark transfer as done before we tell the tinyusb stack
+ uint8_t dev_addr = ep->dev_addr;
+ uint8_t ep_addr = ep->ep_addr;
+ uint xferred_len = ep->xferred_len;
+ hw_endpoint_reset_transfer(ep);
+ hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true);
}
-static void _handle_buff_status_bit(uint bit, struct hw_endpoint *ep)
+static void __tusb_irq_path_func(_handle_buff_status_bit)(uint bit, struct hw_endpoint *ep)
{
- usb_hw_clear->buf_status = bit;
- bool done = _hw_endpoint_xfer_continue(ep);
- if (done)
- {
- hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
- }
+ usb_hw_clear->buf_status = bit;
+ // EP may have been stalled?
+ assert(ep->active);
+ bool done = hw_endpoint_xfer_continue(ep);
+ if ( done )
+ {
+ hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
+ }
}
-static void hw_handle_buff_status(void)
+static void __tusb_irq_path_func(hw_handle_buff_status)(void)
{
- uint32_t remaining_buffers = usb_hw->buf_status;
- pico_trace("buf_status 0x%08x\n", remaining_buffers);
+ uint32_t remaining_buffers = usb_hw->buf_status;
+ pico_trace("buf_status 0x%08lx\n", remaining_buffers);
+
+ // Check EPX first
+ uint bit = 0b1;
+ if ( remaining_buffers & bit )
+ {
+ remaining_buffers &= ~bit;
+ struct hw_endpoint * ep = &epx;
- // Check EPX first
- uint bit = 0b1;
- if (remaining_buffers & bit)
+ uint32_t ep_ctrl = *ep->endpoint_control;
+ if ( ep_ctrl & EP_CTRL_DOUBLE_BUFFERED_BITS )
{
- remaining_buffers &= ~bit;
- struct hw_endpoint *ep = &epx;
- _handle_buff_status_bit(bit, ep);
+ TU_LOG(3, "Double Buffered: ");
}
-
- // Check interrupt endpoints
- for (uint i = 1; i <= USB_HOST_INTERRUPT_ENDPOINTS && remaining_buffers; i++)
+ else
{
- // EPX is bit 0
- // IEP1 is bit 2
- // IEP2 is bit 4
- // IEP3 is bit 6
- // etc
- bit = 1 << (i*2);
-
- if (remaining_buffers & bit)
- {
- remaining_buffers &= ~bit;
- _handle_buff_status_bit(bit, &eps[i]);
- }
+ TU_LOG(3, "Single Buffered: ");
}
+ TU_LOG_HEX(3, ep_ctrl);
+
+ _handle_buff_status_bit(bit, ep);
+ }
- if (remaining_buffers)
+ // Check "interrupt" (asynchronous) endpoints for both IN and OUT
+ for ( uint i = 1; i <= USB_HOST_INTERRUPT_ENDPOINTS && remaining_buffers; i++ )
+ {
+ // EPX is bit 0 & 1
+ // IEP1 IN is bit 2
+ // IEP1 OUT is bit 3
+ // IEP2 IN is bit 4
+ // IEP2 OUT is bit 5
+ // IEP3 IN is bit 6
+ // IEP3 OUT is bit 7
+ // etc
+ for ( uint j = 0; j < 2; j++ )
{
- panic("Unhandled buffer %d\n", remaining_buffers);
+ bit = 1 << (i * 2 + j);
+ if ( remaining_buffers & bit )
+ {
+ remaining_buffers &= ~bit;
+ _handle_buff_status_bit(bit, &ep_pool[i]);
+ }
}
+ }
+
+ if ( remaining_buffers )
+ {
+ panic("Unhandled buffer %d\n", remaining_buffers);
+ }
}
-static void hw_trans_complete(void)
+static void __tusb_irq_path_func(hw_trans_complete)(void)
{
+ if (usb_hw->sie_ctrl & USB_SIE_CTRL_SEND_SETUP_BITS)
+ {
+ pico_trace("Sent setup packet\n");
struct hw_endpoint *ep = &epx;
assert(ep->active);
+ // Set transferred length to 8 for a setup packet
+ ep->xferred_len = 8;
+ hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
+ }
+ else
+ {
+ // Don't care. Will handle this in buff status
+ return;
+ }
+}
- if (ep->sent_setup)
+static void __tusb_irq_path_func(hcd_rp2040_irq)(void)
+{
+ uint32_t status = usb_hw->ints;
+ uint32_t handled = 0;
+
+ if ( status & USB_INTS_HOST_CONN_DIS_BITS )
+ {
+ handled |= USB_INTS_HOST_CONN_DIS_BITS;
+
+ if ( dev_speed() )
{
- pico_trace("Sent setup packet\n");
- hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
+ hcd_event_device_attach(RHPORT_NATIVE, true);
}
else
{
- // Don't care. Will handle this in buff status
- return;
+ hcd_event_device_remove(RHPORT_NATIVE, true);
}
-}
-static void hcd_rp2040_irq(void)
-{
- uint32_t status = usb_hw->ints;
- uint32_t handled = 0;
+ // Clear speed change interrupt
+ usb_hw_clear->sie_status = USB_SIE_STATUS_SPEED_BITS;
+ }
- if (status & USB_INTS_HOST_CONN_DIS_BITS)
- {
- handled |= USB_INTS_HOST_CONN_DIS_BITS;
-
- if (dev_speed())
- {
- hcd_event_device_attach(ROOT_PORT, true);
- }
- else
- {
- hcd_event_device_remove(ROOT_PORT, true);
- }
+ if ( status & USB_INTS_STALL_BITS )
+ {
+ // We have rx'd a stall from the device
+ // NOTE THIS SHOULD HAVE PRIORITY OVER BUFF_STATUS
+ // AND TRANS_COMPLETE as the stall is an alternative response
+ // to one of those events
+ pico_trace("Stall REC\n");
+ handled |= USB_INTS_STALL_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_STALL_REC_BITS;
+ hw_xfer_complete(&epx, XFER_RESULT_STALLED);
+ }
- // Clear speed change interrupt
- usb_hw_clear->sie_status = USB_SIE_STATUS_SPEED_BITS;
- }
+ if ( status & USB_INTS_BUFF_STATUS_BITS )
+ {
+ handled |= USB_INTS_BUFF_STATUS_BITS;
+ TU_LOG(2, "Buffer complete\r\n");
+ hw_handle_buff_status();
+ }
- if (status & USB_INTS_TRANS_COMPLETE_BITS)
- {
- handled |= USB_INTS_TRANS_COMPLETE_BITS;
- usb_hw_clear->sie_status = USB_SIE_STATUS_TRANS_COMPLETE_BITS;
- hw_trans_complete();
- }
-
- if (status & USB_INTS_BUFF_STATUS_BITS)
- {
- handled |= USB_INTS_BUFF_STATUS_BITS;
- // print_bufctrl32(*epx.buffer_control);
- hw_handle_buff_status();
- }
+ if ( status & USB_INTS_TRANS_COMPLETE_BITS )
+ {
+ handled |= USB_INTS_TRANS_COMPLETE_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_TRANS_COMPLETE_BITS;
+ TU_LOG(2, "Transfer complete\r\n");
+ hw_trans_complete();
+ }
- if (status & USB_INTS_STALL_BITS)
- {
- // We have rx'd a stall from the device
- pico_trace("Stall REC\n");
- handled |= USB_INTS_STALL_BITS;
- usb_hw_clear->sie_status = USB_SIE_STATUS_STALL_REC_BITS;
- hw_xfer_complete(&epx, XFER_RESULT_STALLED);
- }
+ if ( status & USB_INTS_ERROR_RX_TIMEOUT_BITS )
+ {
+ handled |= USB_INTS_ERROR_RX_TIMEOUT_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_RX_TIMEOUT_BITS;
+ }
- if (status & USB_INTS_ERROR_RX_TIMEOUT_BITS)
- {
- handled |= USB_INTS_ERROR_RX_TIMEOUT_BITS;
- usb_hw_clear->sie_status = USB_SIE_STATUS_RX_TIMEOUT_BITS;
- }
+ if ( status & USB_INTS_ERROR_DATA_SEQ_BITS )
+ {
+ usb_hw_clear->sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS;
+ TU_LOG(3, " Seq Error: [0] = 0x%04u [1] = 0x%04x\r\n",
+ tu_u32_low16(*epx.buffer_control),
+ tu_u32_high16(*epx.buffer_control));
+ panic("Data Seq Error \n");
+ }
- if (status & USB_INTS_ERROR_DATA_SEQ_BITS)
- {
- usb_hw_clear->sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS;
- // print_bufctrl32(*epx.buffer_control);
- panic("Data Seq Error \n");
- }
+ if ( status ^ handled )
+ {
+ panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
+ }
+}
- if (status ^ handled)
- {
- panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
- }
+void __tusb_irq_path_func(hcd_int_handler)(uint8_t rhport, bool in_isr) {
+ (void) rhport;
+ (void) in_isr;
+ hcd_rp2040_irq();
}
static struct hw_endpoint *_next_free_interrupt_ep(void)
{
- struct hw_endpoint *ep = NULL;
- for (uint i = 1; i < TU_ARRAY_SIZE(eps); i++)
+ struct hw_endpoint * ep = NULL;
+ for ( uint i = 1; i < TU_ARRAY_SIZE(ep_pool); i++ )
+ {
+ ep = &ep_pool[i];
+ if ( !ep->configured )
{
- ep = &eps[i];
- if (!ep->configured)
- {
- // Will be configured by _hw_endpoint_init / _hw_endpoint_allocate
- ep->interrupt_num = i - 1;
- return ep;
- }
+ // Will be configured by _hw_endpoint_init / _hw_endpoint_allocate
+ ep->interrupt_num = (uint8_t) (i - 1);
+ return ep;
}
- return ep;
+ }
+ return ep;
}
static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
{
- struct hw_endpoint *ep = NULL;
- if (transfer_type == TUSB_XFER_INTERRUPT)
- {
- ep = _next_free_interrupt_ep();
- pico_info("Allocate interrupt ep %d\n", ep->interrupt_num);
- assert(ep);
- ep->buffer_control = &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl;
- ep->endpoint_control = &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl;
- // 0x180 for epx
- // 0x1c0 for intep0
- // 0x200 for intep1
- // etc
- ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 1)];
- }
- else
- {
- ep = &epx;
- ep->buffer_control = &usbh_dpram->epx_buf_ctrl;
- ep->endpoint_control = &usbh_dpram->epx_ctrl;
- ep->hw_data_buf = &usbh_dpram->epx_data[0];
- }
- return ep;
-}
+ struct hw_endpoint * ep = NULL;
-static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint wMaxPacketSize, uint8_t transfer_type, uint8_t bmInterval)
-{
- // Already has data buffer, endpoint control, and buffer control allocated at this point
- assert(ep->endpoint_control);
- assert(ep->buffer_control);
- assert(ep->hw_data_buf);
+ if ( transfer_type != TUSB_XFER_CONTROL )
+ {
+ // Note: even though datasheet name these "Interrupt" endpoints. These are actually
+ // "Asynchronous" endpoints and can be used for other type such as: Bulk (ISO need confirmation)
+ ep = _next_free_interrupt_ep();
+ pico_info("Allocate %s ep %d\n", tu_edpt_type_str(transfer_type), ep->interrupt_num);
+ assert(ep);
+ ep->buffer_control = &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl;
+ ep->endpoint_control = &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl;
+ // 0 for epx (double buffered): TODO increase to 1024 for ISO
+ // 2x64 for intep0
+ // 3x64 for intep1
+ // etc
+ ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 2)];
+ }
+ else
+ {
+ ep = &epx;
+ ep->buffer_control = &usbh_dpram->epx_buf_ctrl;
+ ep->endpoint_control = &usbh_dpram->epx_ctrl;
+ ep->hw_data_buf = &usbh_dpram->epx_data[0];
+ }
- uint8_t const num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+ return ep;
+}
- ep->ep_addr = ep_addr;
- ep->dev_addr = dev_addr;
+static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type, uint8_t bmInterval)
+{
+ // Already has data buffer, endpoint control, and buffer control allocated at this point
+ assert(ep->endpoint_control);
+ assert(ep->buffer_control);
+ assert(ep->hw_data_buf);
- // For host, IN to host == RX, anything else rx == false
- ep->rx = (dir == TUSB_DIR_IN);
+ uint8_t const num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- // Response to a setup packet on EP0 starts with pid of 1
- ep->next_pid = num == 0 ? 1u : 0u;
- ep->wMaxPacketSize = wMaxPacketSize;
- ep->transfer_type = transfer_type;
+ ep->ep_addr = ep_addr;
+ ep->dev_addr = dev_addr;
- pico_trace("hw_endpoint_init dev %d ep %d %s xfer %d\n", ep->dev_addr, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)], ep->transfer_type);
- pico_trace("dev %d ep %d %s setup buffer @ 0x%p\n", ep->dev_addr, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)], ep->hw_data_buf);
- uint dpram_offset = hw_data_offset(ep->hw_data_buf);
- // Bits 0-5 should be 0
- assert(!(dpram_offset & 0b111111));
+ // For host, IN to host == RX, anything else rx == false
+ ep->rx = (dir == TUSB_DIR_IN);
- // Fill in endpoint control register with buffer offset
- uint32_t ep_reg = EP_CTRL_ENABLE_BITS
- | EP_CTRL_INTERRUPT_PER_BUFFER
- | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB)
- | dpram_offset;
- ep_reg |= bmInterval ? (bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB : 0;
- *ep->endpoint_control = ep_reg;
- pico_trace("endpoint control (0x%p) <- 0x%x\n", ep->endpoint_control, ep_reg);
- ep->configured = true;
+ // Response to a setup packet on EP0 starts with pid of 1
+ ep->next_pid = (num == 0 ? 1u : 0u);
+ ep->wMaxPacketSize = wMaxPacketSize;
+ ep->transfer_type = transfer_type;
- if (bmInterval)
- {
- // This is an interrupt endpoint
- // so need to set up interrupt endpoint address control register with:
- // device address
- // endpoint number / direction
- // preamble
- uint32_t reg = dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB);
- // Assert the interrupt endpoint is IN_TO_HOST
- assert(dir == TUSB_DIR_IN);
+ pico_trace("hw_endpoint_init dev %d ep %02X xfer %d\n", ep->dev_addr, ep->ep_addr, ep->transfer_type);
+ pico_trace("dev %d ep %02X setup buffer @ 0x%p\n", ep->dev_addr, ep->ep_addr, ep->hw_data_buf);
+ uint dpram_offset = hw_data_offset(ep->hw_data_buf);
+ // Bits 0-5 should be 0
+ assert(!(dpram_offset & 0b111111));
- if (need_pre(dev_addr))
- {
- reg |= USB_ADDR_ENDP1_INTEP_PREAMBLE_BITS;
- }
- usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = reg;
+ // Fill in endpoint control register with buffer offset
+ uint32_t ep_reg = EP_CTRL_ENABLE_BITS
+ | EP_CTRL_INTERRUPT_PER_BUFFER
+ | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB)
+ | dpram_offset;
+ if ( bmInterval )
+ {
+ ep_reg |= (uint32_t) ((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB);
+ }
+ *ep->endpoint_control = ep_reg;
+ pico_trace("endpoint control (0x%p) <- 0x%lx\n", ep->endpoint_control, ep_reg);
+ ep->configured = true;
- // Finally, enable interrupt that endpoint
- usb_hw_set->int_ep_ctrl = 1 << (ep->interrupt_num + 1);
+ if ( ep != &epx )
+ {
+ // Endpoint has its own addr_endp and interrupt bits to be setup!
+ // This is an interrupt/async endpoint. so need to set up ADDR_ENDP register with:
+ // - device address
+ // - endpoint number / direction
+ // - preamble
+ uint32_t reg = (uint32_t) (dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB));
- // If it's an interrupt endpoint we need to set up the buffer control
- // register
+ if ( dir == TUSB_DIR_OUT )
+ {
+ reg |= USB_ADDR_ENDP1_INTEP_DIR_BITS;
+ }
+ if ( need_pre(dev_addr) )
+ {
+ reg |= USB_ADDR_ENDP1_INTEP_PREAMBLE_BITS;
}
-}
+ usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = reg;
-static void hw_endpoint_init(uint8_t dev_addr, const tusb_desc_endpoint_t *ep_desc)
-{
- // Allocated differently based on if it's an interrupt endpoint or not
- struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
- _hw_endpoint_init(ep,
- dev_addr,
- ep_desc->bEndpointAddress,
- ep_desc->wMaxPacketSize.size,
- ep_desc->bmAttributes.xfer,
- ep_desc->bInterval);
- // Map this struct to ep@device address
- set_dev_ep(dev_addr, ep_desc->bEndpointAddress, ep);
+ // Finally, enable interrupt that endpoint
+ usb_hw_set->int_ep_ctrl = 1 << (ep->interrupt_num + 1);
+
+ // If it's an interrupt endpoint we need to set up the buffer control
+ // register
+ }
}
//--------------------------------------------------------------------+
@@ -368,177 +377,269 @@ static void hw_endpoint_init(uint8_t dev_addr, const tusb_desc_endpoint_t *ep_de
//--------------------------------------------------------------------+
bool hcd_init(uint8_t rhport)
{
- pico_trace("hcd_init %d\n", rhport);
- assert(rhport == 0);
+ (void) rhport;
+ pico_trace("hcd_init %d\n", rhport);
+ assert(rhport == 0);
+
+ // Reset any previous state
+ rp2040_usb_init();
+
+ // Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En)
+ usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
- // Reset any previous state
- rp2040_usb_init();
+ // Remove shared irq if it was previously added so as not to fill up shared irq slots
+ irq_remove_handler(USBCTRL_IRQ, hcd_rp2040_irq);
- irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq);
+ irq_add_shared_handler(USBCTRL_IRQ, hcd_rp2040_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
- // clear epx and interrupt eps
- memset(&eps, 0, sizeof(eps));
+ // clear epx and interrupt eps
+ memset(&ep_pool, 0, sizeof(ep_pool));
- // Enable in host mode with SOF / Keep alive on
- usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS;
- usb_hw->sie_ctrl = sie_ctrl_base;
- usb_hw->inte = USB_INTE_BUFF_STATUS_BITS |
- USB_INTE_HOST_CONN_DIS_BITS |
- USB_INTE_HOST_RESUME_BITS |
- USB_INTE_STALL_BITS |
- USB_INTE_TRANS_COMPLETE_BITS |
- USB_INTE_ERROR_RX_TIMEOUT_BITS |
- USB_INTE_ERROR_DATA_SEQ_BITS ;
+ // Enable in host mode with SOF / Keep alive on
+ usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS;
+ usb_hw->sie_ctrl = SIE_CTRL_BASE;
+ usb_hw->inte = USB_INTE_BUFF_STATUS_BITS |
+ USB_INTE_HOST_CONN_DIS_BITS |
+ USB_INTE_HOST_RESUME_BITS |
+ USB_INTE_STALL_BITS |
+ USB_INTE_TRANS_COMPLETE_BITS |
+ USB_INTE_ERROR_RX_TIMEOUT_BITS |
+ USB_INTE_ERROR_DATA_SEQ_BITS ;
- return true;
+ return true;
+}
+
+bool hcd_deinit(uint8_t rhport) {
+ (void) rhport;
+
+ irq_remove_handler(USBCTRL_IRQ, hcd_rp2040_irq);
+ reset_block(RESETS_RESET_USBCTRL_BITS);
+ unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
+
+ return true;
}
void hcd_port_reset(uint8_t rhport)
{
- pico_trace("hcd_port_reset\n");
- assert(rhport == 0);
- // TODO: Nothing to do here yet. Perhaps need to reset some state?
+ (void) rhport;
+ pico_trace("hcd_port_reset\n");
+ assert(rhport == 0);
+ // TODO: Nothing to do here yet. Perhaps need to reset some state?
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ (void) rhport;
}
bool hcd_port_connect_status(uint8_t rhport)
{
- pico_trace("hcd_port_connect_status\n");
- assert(rhport == 0);
- return usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS;
+ (void) rhport;
+ pico_trace("hcd_port_connect_status\n");
+ assert(rhport == 0);
+ return usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS;
}
tusb_speed_t hcd_port_speed_get(uint8_t rhport)
{
- pico_trace("hcd_port_speed_get\n");
- assert(rhport == 0);
- // TODO: Should enumval this register
- switch (dev_speed())
- {
- case 1:
- return TUSB_SPEED_LOW;
- case 2:
- return TUSB_SPEED_FULL;
- default:
- panic("Invalid speed\n");
- }
+ (void) rhport;
+ assert(rhport == 0);
+
+ // TODO: Should enumval this register
+ switch ( dev_speed() )
+ {
+ case 1:
+ return TUSB_SPEED_LOW;
+ case 2:
+ return TUSB_SPEED_FULL;
+ default:
+ panic("Invalid speed\n");
+ // return TUSB_SPEED_INVALID;
+ }
}
// Close all opened endpoint belong to this device
void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
{
- pico_trace("hcd_device_close %d\n", dev_addr);
+ pico_trace("hcd_device_close %d\n", dev_addr);
+ (void) rhport;
+
+ if (dev_addr == 0) return;
+
+ for (size_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++)
+ {
+ hw_endpoint_t* ep = &ep_pool[i];
+
+ if (ep->dev_addr == dev_addr && ep->configured)
+ {
+ // in case it is an interrupt endpoint, disable it
+ usb_hw_clear->int_ep_ctrl = (1 << (ep->interrupt_num + 1));
+ usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = 0;
+
+ // unconfigure the endpoint
+ ep->configured = false;
+ *ep->endpoint_control = 0;
+ *ep->buffer_control = 0;
+ hw_endpoint_reset_transfer(ep);
+ }
+ }
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void) rhport;
+ return usb_hw->sof_rd;
}
void hcd_int_enable(uint8_t rhport)
{
- assert(rhport == 0);
- irq_set_enabled(USBCTRL_IRQ, true);
+ (void) rhport;
+ assert(rhport == 0);
+ irq_set_enabled(USBCTRL_IRQ, true);
}
void hcd_int_disable(uint8_t rhport)
{
- // todo we should check this is disabling from the correct core; note currently this is never called
- assert(rhport == 0);
- irq_set_enabled(USBCTRL_IRQ, false);
+ (void) rhport;
+ // todo we should check this is disabling from the correct core; note currently this is never called
+ assert(rhport == 0);
+ irq_set_enabled(USBCTRL_IRQ, false);
}
-bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
{
- pico_info("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen);
-
- // Get appropriate ep. Either EPX or interrupt endpoint
- struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
- assert(ep);
+ (void) rhport;
- if (ep_addr != ep->ep_addr)
- {
- // Direction has flipped so re init it but with same properties
- // TODO treat IN and OUT as invidual endpoints
- _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0);
- }
+ pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress);
- // True indicates this is the start of the transfer
- _hw_endpoint_xfer(ep, buffer, buflen, true);
+ // Allocated differently based on if it's an interrupt endpoint or not
+ struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
+ TU_ASSERT(ep);
- // If a normal transfer (non-interrupt) then initiate using
- // sie ctrl registers. Otherwise interrupt ep registers should
- // already be configured
- if (ep == &epx) {
- // That has set up buffer control, endpoint control etc
- // for host we have to initiate the transfer
- usb_hw->dev_addr_ctrl = dev_addr | (tu_edpt_number(ep_addr) << USB_ADDR_ENDP_ENDPOINT_LSB);
- uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | sie_ctrl_base;
- flags |= ep->rx ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS;
- // Set pre if we are a low speed device on full speed hub
- flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0;
- usb_hw->sie_ctrl = flags;
- }
+ _hw_endpoint_init(ep,
+ dev_addr,
+ ep_desc->bEndpointAddress,
+ tu_edpt_packet_size(ep_desc),
+ ep_desc->bmAttributes.xfer,
+ ep_desc->bInterval);
- return true;
+ return true;
}
-bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
{
- pico_info("hcd_setup_send dev_addr %d\n", dev_addr);
-
- // Copy data into setup packet buffer
- memcpy((void*)&usbh_dpram->setup_packet[0], setup_packet, 8);
+ (void) rhport;
+
+ pico_trace("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen);
+
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr);
+
+ // Get appropriate ep. Either EPX or interrupt endpoint
+ struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
+
+ TU_ASSERT(ep);
+
+ // EP should be inactive
+ assert(!ep->active);
+
+ // Control endpoint can change direction 0x00 <-> 0x80
+ if ( ep_addr != ep->ep_addr )
+ {
+ assert(ep_num == 0);
- // Configure EP0 struct with setup info for the trans complete
- struct hw_endpoint *ep = _hw_endpoint_allocate(0);
- // EP0 out
- _hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
- assert(ep->configured);
- ep->total_len = 8;
- ep->transfer_size = 8;
- ep->active = true;
- ep->sent_setup = true;
+ // Direction has flipped on endpoint control so re init it but with same properties
+ _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0);
+ }
- // Set device address
- usb_hw->dev_addr_ctrl = dev_addr;
- // Set pre if we are a low speed device on full speed hub
- uint32_t flags = sie_ctrl_base | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS;
- flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0;
+ // If a normal transfer (non-interrupt) then initiate using
+ // sie ctrl registers. Otherwise interrupt ep registers should
+ // already be configured
+ if ( ep == &epx )
+ {
+ hw_endpoint_xfer_start(ep, buffer, buflen);
+
+ // That has set up buffer control, endpoint control etc
+ // for host we have to initiate the transfer
+ usb_hw->dev_addr_ctrl = (uint32_t) (dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB));
+
+ uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | SIE_CTRL_BASE |
+ (ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS) |
+ (need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0);
+ // START_TRANS bit on SIE_CTRL seems to exhibit the same behavior as the AVAILABLE bit
+ // described in RP2040 Datasheet, release 2.1, section "4.1.2.5.1. Concurrent access".
+ // We write everything except the START_TRANS bit first, then wait some cycles.
+ usb_hw->sie_ctrl = flags & ~USB_SIE_CTRL_START_TRANS_BITS;
+ busy_wait_at_least_cycles(12);
usb_hw->sie_ctrl = flags;
- return true;
-}
+ }else
+ {
+ hw_endpoint_xfer_start(ep, buffer, buflen);
+ }
-uint32_t hcd_frame_number(uint8_t rhport)
-{
- return usb_hw->sof_rd;
+ return true;
}
-bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
-{
- pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress);
- hw_endpoint_init(dev_addr, ep_desc);
- return true;
+bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+ // TODO not implemented yet
+ return false;
}
-bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
{
- // EPX is shared, so multiple device addresses and endpoint addresses share that
- // so if any transfer is active on epx, we are busy. Interrupt endpoints have their own
- // EPX so ep->active will only be busy if there is a pending transfer on that interrupt endpoint
- // on that device
- pico_trace("hcd_edpt_busy dev addr %d ep_addr 0x%x\n", dev_addr, ep_addr);
- struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
- assert(ep);
- bool busy = ep->active;
- pico_trace("busy == %d\n", busy);
- return busy;
-}
+ (void) rhport;
-bool hcd_edpt_stalled(uint8_t dev_addr, uint8_t ep_addr)
-{
- panic("hcd_pipe_stalled");
- return false;
+ // Copy data into setup packet buffer
+ for ( uint8_t i = 0; i < 8; i++ )
+ {
+ usbh_dpram->setup_packet[i] = setup_packet[i];
+ }
+
+ // Configure EP0 struct with setup info for the trans complete
+ struct hw_endpoint * ep = _hw_endpoint_allocate(0);
+ TU_ASSERT(ep);
+
+ // EPX should be inactive
+ assert(!ep->active);
+
+ // EP0 out
+ _hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
+ assert(ep->configured);
+
+ ep->remaining_len = 8;
+ ep->active = true;
+
+ // Set device address
+ usb_hw->dev_addr_ctrl = dev_addr;
+
+ // Set pre if we are a low speed device on full speed hub
+ uint32_t const flags = SIE_CTRL_BASE | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS |
+ (need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0);
+
+ // START_TRANS bit on SIE_CTRL seems to exhibit the same behavior as the AVAILABLE bit
+ // described in RP2040 Datasheet, release 2.1, section "4.1.2.5.1. Concurrent access".
+ // We write everything except the START_TRANS bit first, then wait some cycles.
+ usb_hw->sie_ctrl = flags & ~USB_SIE_CTRL_START_TRANS_BITS;
+ busy_wait_at_least_cycles(12);
+ usb_hw->sie_ctrl = flags;
+
+ return true;
}
-bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
-{
- panic("hcd_clear_stall");
- return true;
+bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+
+ panic("hcd_clear_stall");
+ // return true;
}
#endif
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index a0263612f..1ca711c77 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -31,296 +32,344 @@
#include <stdlib.h>
#include "rp2040_usb.h"
-// Direction strings for debug
-const char *ep_dir_string[] = {
- "out",
- "in",
-};
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTOTYPE
+//--------------------------------------------------------------------+
+static void _hw_endpoint_xfer_sync(struct hw_endpoint* ep);
-static inline void _hw_endpoint_lock_update(struct hw_endpoint *ep, int delta) {
- // todo add critsec as necessary to prevent issues between worker and IRQ...
- // note that this is perhaps as simple as disabling IRQs because it would make
- // sense to have worker and IRQ on same core, however I think using critsec is about equivalent.
-}
+#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+ static bool e15_is_bulkin_ep(struct hw_endpoint* ep);
+ static bool e15_is_critical_frame_period(struct hw_endpoint* ep);
+#else
+ #define e15_is_bulkin_ep(x) (false)
+ #define e15_is_critical_frame_period(x) (false)
+#endif
-#if TUSB_OPT_HOST_ENABLED
-static inline void _hw_endpoint_update_last_buf(struct hw_endpoint *ep)
-{
- ep->last_buf = (ep->len + ep->transfer_size == ep->total_len);
+// if usb hardware is in host mode
+TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode(void) {
+ return (usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) ? true : false;
}
-#endif
-void rp2040_usb_init(void)
-{
- // Reset usb controller
- reset_block(RESETS_RESET_USBCTRL_BITS);
- unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
+//--------------------------------------------------------------------+
+// Implementation
+//--------------------------------------------------------------------+
- // Clear any previous state just in case
- memset(usb_hw, 0, sizeof(*usb_hw));
- memset(usb_dpram, 0, sizeof(*usb_dpram));
+void rp2040_usb_init(void) {
+ // Reset usb controller
+ reset_block(RESETS_RESET_USBCTRL_BITS);
+ unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
- // Mux the controller to the onboard usb phy
- usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
+#ifdef __GNUC__
+ // Clear any previous state just in case
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#if __GNUC__ > 6
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+#endif
+#endif
+ memset(usb_hw, 0, sizeof(*usb_hw));
+ memset(usb_dpram, 0, sizeof(*usb_dpram));
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
- // Force VBUS detect so the device thinks it is plugged into a host
- // TODO support VBUs detect
- usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
-}
+ // Mux the controller to the onboard usb phy
+ usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
-void hw_endpoint_reset_transfer(struct hw_endpoint *ep)
-{
- ep->stalled = false;
- ep->active = false;
-#if TUSB_OPT_HOST_ENABLED
- ep->sent_setup = false;
-#endif
- ep->total_len = 0;
- ep->len = 0;
- ep->transfer_size = 0;
- ep->user_buf = 0;
+ TU_LOG2_INT(sizeof(hw_endpoint_t));
}
-void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask) {
- uint32_t value = 0;
- if (and_mask) {
- value = *ep->buffer_control & and_mask;
- }
- if (or_mask) {
- value |= or_mask;
- if (or_mask & USB_BUF_CTRL_AVAIL) {
- if (*ep->buffer_control & USB_BUF_CTRL_AVAIL) {
- panic("ep %d %s was already available", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
- }
- *ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL;
- // 12 cycle delay.. (should be good for 48*12Mhz = 576Mhz)
- // Don't need delay in host mode as host is in charge
-#if !TUSB_OPT_HOST_ENABLED
- __asm volatile (
- "b 1f\n"
- "1: b 1f\n"
- "1: b 1f\n"
- "1: b 1f\n"
- "1: b 1f\n"
- "1: b 1f\n"
- "1:\n"
- : : : "memory");
-#endif
- }
- }
- *ep->buffer_control = value;
+void __tusb_irq_path_func(hw_endpoint_reset_transfer)(struct hw_endpoint* ep) {
+ ep->active = false;
+ ep->remaining_len = 0;
+ ep->xferred_len = 0;
+ ep->user_buf = 0;
}
-void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
-{
- // Prepare buffer control register value
- uint32_t val = ep->transfer_size | USB_BUF_CTRL_AVAIL;
+void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoint* ep, uint32_t and_mask,
+ uint32_t or_mask) {
+ uint32_t value = 0;
+
+ if (and_mask) {
+ value = *ep->buffer_control & and_mask;
+ }
- if (!ep->rx)
- {
- // Copy data from user buffer to hw buffer
- memcpy(ep->hw_data_buf, &ep->user_buf[ep->len], ep->transfer_size);
- // Mark as full
- val |= USB_BUF_CTRL_FULL;
+ if (or_mask) {
+ value |= or_mask;
+ if (or_mask & USB_BUF_CTRL_AVAIL) {
+ if (*ep->buffer_control & USB_BUF_CTRL_AVAIL) {
+ panic("ep %02X was already available", ep->ep_addr);
+ }
+ *ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL;
+ // 4.1.2.5.1 Con-current access: 12 cycles (should be good for 48*12Mhz = 576Mhz) after write to buffer control
+ // Don't need delay in host mode as host is in charge
+ if ( !is_host_mode()) {
+ busy_wait_at_least_cycles(12);
+ }
}
+ }
- // PID
- val |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
+ *ep->buffer_control = value;
+}
-#if TUSB_OPT_DEVICE_ENABLED
- ep->next_pid ^= 1u;
+// prepare buffer, return buffer control
+static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep, uint8_t buf_id) {
+ uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
+ ep->remaining_len = (uint16_t) (ep->remaining_len - buflen);
-#else
- // For Host (also device but since we dictate the endpoint size, following scenario does not occur)
- // Next PID depends on the number of packet in case wMaxPacketSize < 64 (e.g Interrupt Endpoint 8, or 12)
- // Special case with control status stage where PID is always DATA1
- if ( ep->transfer_size == 0 )
- {
- // ZLP also toggle data
- ep->next_pid ^= 1u;
- }else
- {
- uint32_t packet_count = 1 + ((ep->transfer_size - 1) / ep->wMaxPacketSize);
+ uint32_t buf_ctrl = buflen | USB_BUF_CTRL_AVAIL;
- if ( packet_count & 0x01 )
- {
- ep->next_pid ^= 1u;
- }
- }
-#endif
+ // PID
+ buf_ctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
+ ep->next_pid ^= 1u;
+ if (!ep->rx) {
+ // Copy data from user buffer to hw buffer
+ memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen);
+ ep->user_buf += buflen;
-#if TUSB_OPT_HOST_ENABLED
- // Is this the last buffer? Only really matters for host mode. Will trigger
- // the trans complete irq but also stop it polling. We only really care about
- // trans complete for setup packets being sent
- if (ep->last_buf)
- {
- pico_trace("Last buf (%d bytes left)\n", ep->transfer_size);
- val |= USB_BUF_CTRL_LAST;
- }
-#endif
+ // Mark as full
+ buf_ctrl |= USB_BUF_CTRL_FULL;
+ }
- // Finally, write to buffer_control which will trigger the transfer
- // the next time the controller polls this dpram address
- _hw_endpoint_buffer_control_set_value32(ep, val);
- pico_trace("buffer control (0x%p) <- 0x%x\n", ep->buffer_control, val);
- //print_bufctrl16(val);
+ // Is this the last buffer? Only really matters for host mode. Will trigger
+ // the trans complete irq but also stop it polling. We only really care about
+ // trans complete for setup packets being sent
+ if (ep->remaining_len == 0) {
+ buf_ctrl |= USB_BUF_CTRL_LAST;
+ }
+
+ if (buf_id) buf_ctrl = buf_ctrl << 16;
+
+ return buf_ctrl;
}
+// Prepare buffer control register value
+void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint* ep) {
+ uint32_t ep_ctrl = *ep->endpoint_control;
-void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len)
-{
- _hw_endpoint_lock_update(ep, 1);
- pico_trace("Start transfer of total len %d on ep %d %s\n", total_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
- if (ep->active)
- {
- // TODO: Is this acceptable for interrupt packets?
- pico_warn("WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
+ // always compute and start with buffer 0
+ uint32_t buf_ctrl = prepare_ep_buffer(ep, 0) | USB_BUF_CTRL_SEL;
- hw_endpoint_reset_transfer(ep);
- }
+ // For now: skip double buffered for OUT endpoint in Device mode, since
+ // host could send < 64 bytes and cause short packet on buffer0
+ // NOTE: this could happen to Host mode IN endpoint
+ // Also, Host mode "interrupt" endpoint hardware is only single buffered,
+ // NOTE2: Currently Host bulk is implemented using "interrupt" endpoint
+ bool const is_host = is_host_mode();
+ bool const force_single = (!is_host && !tu_edpt_dir(ep->ep_addr)) ||
+ (is_host && tu_edpt_number(ep->ep_addr) != 0);
- // Fill in info now that we're kicking off the hw
- ep->total_len = total_len;
- ep->len = 0;
+ if (ep->remaining_len && !force_single) {
+ // Use buffer 1 (double buffered) if there is still data
+ // TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt)
- // Limit by packet size but not less 64 (i.e low speed 8 bytes EP0)
- ep->transfer_size = tu_min16(total_len, tu_max16(64, ep->wMaxPacketSize));
+ buf_ctrl |= prepare_ep_buffer(ep, 1);
- ep->active = true;
- ep->user_buf = buffer;
-#if TUSB_OPT_HOST_ENABLED
- // Recalculate if this is the last buffer
- _hw_endpoint_update_last_buf(ep);
- ep->buf_sel = 0;
-#endif
+ // Set endpoint control double buffered bit if needed
+ ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER;
+ ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER;
+ } else {
+ // Single buffered since 1 is enough
+ ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
+ ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
+ }
- _hw_endpoint_start_next_buffer(ep);
- _hw_endpoint_lock_update(ep, -1);
+ *ep->endpoint_control = ep_ctrl;
+
+ TU_LOG(3, " Prepare BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
+
+ // Finally, write to buffer_control which will trigger the transfer
+ // the next time the controller polls this dpram address
+ _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl);
}
-void _hw_endpoint_xfer_sync(struct hw_endpoint *ep)
-{
- // Update hw endpoint struct with info from hardware
- // after a buff status interrupt
+void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t total_len) {
+ hw_endpoint_lock_update(ep, 1);
- // Get the buffer state and amount of bytes we have
- // transferred
- uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
- uint16_t transferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
+ if (ep->active) {
+ // TODO: Is this acceptable for interrupt packets?
+ TU_LOG(1, "WARN: starting new transfer on already active ep %02X\r\n", ep->ep_addr);
+ hw_endpoint_reset_transfer(ep);
+ }
-#if TUSB_OPT_HOST_ENABLED
- // RP2040-E4
- // tag::host_buf_sel_fix[]
- // TODO need changes to support double buffering
- if (ep->buf_sel == 1)
- {
- // Host can erroneously write status to top half of buf_ctrl register
- buf_ctrl = buf_ctrl >> 16;
+ // Fill in info now that we're kicking off the hw
+ ep->remaining_len = total_len;
+ ep->xferred_len = 0;
+ ep->active = true;
+ ep->user_buf = buffer;
- // update buf1 -> buf0 to prevent panic with "already available"
- *ep->buffer_control = buf_ctrl;
- }
- // Flip buf sel for host
- ep->buf_sel ^= 1u;
- // end::host_buf_sel_fix[]
-#endif
+ if (e15_is_bulkin_ep(ep)) {
+ usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
+ }
+
+ if (e15_is_critical_frame_period(ep)) {
+ ep->pending = 1;
+ } else {
+ hw_endpoint_start_next_buffer(ep);
+ }
+
+ hw_endpoint_lock_update(ep, -1);
+}
+
+// sync endpoint buffer and return transferred bytes
+static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint* ep, uint8_t buf_id) {
+ uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
+ if (buf_id) buf_ctrl = buf_ctrl >> 16;
- // We are continuing a transfer here. If we are TX, we have successfullly
+ uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
+
+ if (!ep->rx) {
+ // We are continuing a transfer here. If we are TX, we have successfully
// sent some data can increase the length we have sent
- if (!ep->rx)
- {
- assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
- pico_trace("tx %d bytes (buf_ctrl 0x%08x)\n", transferred_bytes, buf_ctrl);
- ep->len += transferred_bytes;
- }
- else
- {
- // If we are OUT we have recieved some data, so can increase the length
- // we have recieved AFTER we have copied it to the user buffer at the appropriate
- // offset
- pico_trace("rx %d bytes (buf_ctrl 0x%08x)\n", transferred_bytes, buf_ctrl);
- assert(buf_ctrl & USB_BUF_CTRL_FULL);
- memcpy(&ep->user_buf[ep->len], ep->hw_data_buf, transferred_bytes);
- ep->len += transferred_bytes;
- }
+ assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
- // Sometimes the host will send less data than we expect...
- // If this is a short out transfer update the total length of the transfer
- // to be the current length
- if ((ep->rx) && (transferred_bytes < ep->transfer_size))
- {
- pico_trace("Short rx transfer\n");
- // Reduce total length as this is last packet
- ep->total_len = ep->len;
- }
+ ep->xferred_len = (uint16_t) (ep->xferred_len + xferred_bytes);
+ } else {
+ // If we have received some data, so can increase the length
+ // we have received AFTER we have copied it to the user buffer at the appropriate offset
+ assert(buf_ctrl & USB_BUF_CTRL_FULL);
+
+ memcpy(ep->user_buf, ep->hw_data_buf + buf_id * 64, xferred_bytes);
+ ep->xferred_len = (uint16_t) (ep->xferred_len + xferred_bytes);
+ ep->user_buf += xferred_bytes;
+ }
+
+ // Short packet
+ if (xferred_bytes < ep->wMaxPacketSize) {
+ pico_trace(" Short packet on buffer %d with %u bytes\r\n", buf_id, xferred_bytes);
+ // Reduce total length as this is last packet
+ ep->remaining_len = 0;
+ }
+
+ return xferred_bytes;
}
-// Returns true if transfer is complete
-bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep)
-{
- _hw_endpoint_lock_update(ep, 1);
- // Part way through a transfer
- if (!ep->active)
- {
- panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string);
- }
+static void __tusb_irq_path_func(_hw_endpoint_xfer_sync)(struct hw_endpoint* ep) {
+ // Update hw endpoint struct with info from hardware
+ // after a buff status interrupt
- // Update EP struct from hardware state
- _hw_endpoint_xfer_sync(ep);
+ uint32_t __unused buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
+ TU_LOG(3, " Sync BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
- // Now we have synced our state with the hardware. Is there more data to transfer?
- // Limit by packet size but not less 64 (i.e low speed 8 bytes EP0)
- uint16_t remaining_bytes = ep->total_len - ep->len;
- ep->transfer_size = tu_min16(remaining_bytes, tu_max16(64, ep->wMaxPacketSize));
-#if TUSB_OPT_HOST_ENABLED
- _hw_endpoint_update_last_buf(ep);
-#endif
+ // always sync buffer 0
+ uint16_t buf0_bytes = sync_ep_buffer(ep, 0);
- // Can happen because of programmer error so check for it
- if (ep->len > ep->total_len)
- {
- panic("Transferred more data than expected");
- }
+ // sync buffer 1 if double buffered
+ if ((*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS) {
+ if (buf0_bytes == ep->wMaxPacketSize) {
+ // sync buffer 1 if not short packet
+ sync_ep_buffer(ep, 1);
+ } else {
+ // short packet on buffer 0
+ // TODO couldn't figure out how to handle this case which happen with net_lwip_webserver example
+ // At this time (currently trigger per 2 buffer), the buffer1 is probably filled with data from
+ // the next transfer (not current one). For now we disable double buffered for device OUT
+ // NOTE this could happen to Host IN
+#if 0
+ uint8_t const ep_num = tu_edpt_number(ep->ep_addr);
+ uint8_t const dir = (uint8_t) tu_edpt_dir(ep->ep_addr);
+ uint8_t const ep_id = 2*ep_num + (dir ? 0 : 1);
+
+ // abort queued transfer on buffer 1
+ usb_hw->abort |= TU_BIT(ep_id);
+
+ while ( !(usb_hw->abort_done & TU_BIT(ep_id)) ) {}
- // If we are done then notify tinyusb
- if (ep->len == ep->total_len)
- {
- pico_trace("Completed transfer of %d bytes on ep %d %s\n",
- ep->len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
- // Notify caller we are done so it can notify the tinyusb
- // stack
- _hw_endpoint_lock_update(ep, -1);
- return true;
+ uint32_t ep_ctrl = *ep->endpoint_control;
+ ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
+ ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
+
+ _hw_endpoint_buffer_control_set_value32(ep, 0);
+
+ usb_hw->abort &= ~TU_BIT(ep_id);
+
+ TU_LOG(3, "----SHORT PACKET buffer0 on EP %02X:\r\n", ep->ep_addr);
+ TU_LOG(3, " BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
+#endif
}
- else
- {
- _hw_endpoint_start_next_buffer(ep);
+ }
+}
+
+// Returns true if transfer is complete
+bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) {
+ hw_endpoint_lock_update(ep, 1);
+
+ // Part way through a transfer
+ if (!ep->active) {
+ panic("Can't continue xfer on inactive ep %02X", ep->ep_addr);
+ }
+
+ // Update EP struct from hardware state
+ _hw_endpoint_xfer_sync(ep);
+
+ // Now we have synced our state with the hardware. Is there more data to transfer?
+ // If we are done then notify tinyusb
+ if (ep->remaining_len == 0) {
+ pico_trace("Completed transfer of %d bytes on ep %02X\r\n", ep->xferred_len, ep->ep_addr);
+ // Notify caller we are done so it can notify the tinyusb stack
+ hw_endpoint_lock_update(ep, -1);
+ return true;
+ } else {
+ if (e15_is_critical_frame_period(ep)) {
+ ep->pending = 1;
+ } else {
+ hw_endpoint_start_next_buffer(ep);
}
+ }
- _hw_endpoint_lock_update(ep, -1);
- // More work to do
- return false;
+ hw_endpoint_lock_update(ep, -1);
+ // More work to do
+ return false;
}
-void _hw_endpoint_xfer(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len, bool start)
-{
- // Trace
- pico_trace("hw_endpoint_xfer ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
- pico_trace(" total_len %d, start=%d\n", total_len, start);
+//--------------------------------------------------------------------+
+// Errata 15
+//--------------------------------------------------------------------+
- assert(ep->configured);
+#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+/* Don't mark IN buffers as available during the last 200us of a full-speed
+ frame. This avoids a situation seen with the USB2.0 hub on a Raspberry
+ Pi 4 where a late IN token before the next full-speed SOF can cause port
+ babble and a corrupt ACK packet. The nature of the data corruption has a
+ chance to cause device lockup.
- if (start)
- {
- _hw_endpoint_xfer_start(ep, buffer, total_len);
- }
- else
- {
- _hw_endpoint_xfer_continue(ep);
- }
+ Use the next SOF to mark delayed buffers as available. This reduces
+ available Bulk IN bandwidth by approximately 20%, and requires that the
+ SOF interrupt is enabled while these transfers are ongoing.
+
+ Inherit the top-level enable from the corresponding Pico-SDK flag.
+ Applications that will not use the device in a situation where it could
+ be plugged into a Pi 4 or Pi 400 (for example, when directly connected
+ to a commodity hub or other host) can turn off the flag in the SDK.
+*/
+
+volatile uint32_t e15_last_sof = 0;
+
+// check if Errata 15 is needed for this endpoint i.e device bulk-in
+static bool __tusb_irq_path_func(e15_is_bulkin_ep)(struct hw_endpoint* ep) {
+ return (!is_host_mode() && tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN &&
+ ep->transfer_type == TUSB_XFER_BULK);
+}
+
+// check if we need to apply Errata 15 workaround : i.e
+// Endpoint is BULK IN and is currently in critical frame period i.e 20% of last usb frame
+static bool __tusb_irq_path_func(e15_is_critical_frame_period)(struct hw_endpoint* ep) {
+ TU_VERIFY(e15_is_bulkin_ep(ep));
+
+ /* Avoid the last 200us (uframe 6.5-7) of a frame, up to the EOF2 point.
+ * The device state machine cannot recover from receiving an incorrect PID
+ * when it is expecting an ACK.
+ */
+ uint32_t delta = time_us_32() - e15_last_sof;
+ if (delta < 800 || delta > 998) {
+ return false;
+ }
+ TU_LOG(3, "Avoiding sof %lu now %lu last %lu\r\n", (usb_hw->sof_rd + 1) & USB_SOF_RD_BITS, time_us_32(),
+ e15_last_sof);
+ return true;
}
+#endif // TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
#endif
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
index 32d20051f..d4d29a816 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.h
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -11,150 +11,133 @@
#include "hardware/structs/usb.h"
#include "hardware/irq.h"
#include "hardware/resets.h"
+#include "hardware/timer.h"
#if defined(PICO_RP2040_USB_DEVICE_ENUMERATION_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX)
#define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX PICO_RP2040_USB_DEVICE_ENUMERATION_FIX
#endif
+#if defined(PICO_RP2040_USB_DEVICE_UFRAME_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX)
+#define TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX PICO_RP2040_USB_DEVICE_UFRAME_FIX
+#endif
-#if false && !defined(NDEBUG)
-#define pico_trace(format,args...) printf(format, ## args)
-#else
-#define pico_trace(format,...) ((void)0)
+#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+#undef PICO_RP2040_USB_FAST_IRQ
+#define PICO_RP2040_USB_FAST_IRQ 1
#endif
-#if false && !defined(NDEBUG)
-#define pico_info(format,args...) printf(format, ## args)
-#else
-#define pico_info(format,...) ((void)0)
+#ifndef PICO_RP2040_USB_FAST_IRQ
+#define PICO_RP2040_USB_FAST_IRQ 0
#endif
-#if false && !defined(NDEBUG)
-#define pico_warn(format,args...) printf(format, ## args)
+#if PICO_RP2040_USB_FAST_IRQ
+#define __tusb_irq_path_func(x) __no_inline_not_in_flash_func(x)
#else
-#define pico_warn(format,...) ((void)0)
+#define __tusb_irq_path_func(x) x
#endif
+#define usb_hw_set ((usb_hw_t *) hw_set_alias_untyped(usb_hw))
+#define usb_hw_clear ((usb_hw_t *) hw_clear_alias_untyped(usb_hw))
+
+#define pico_info(...) TU_LOG(2, __VA_ARGS__)
+#define pico_trace(...) TU_LOG(3, __VA_ARGS__)
+
// Hardware information per endpoint
-struct hw_endpoint
+typedef struct hw_endpoint
{
// Is this a valid struct
bool configured;
-
+
// Transfer direction (i.e. IN is rx for host but tx for device)
// allows us to common up transfer functions
bool rx;
-
+
uint8_t ep_addr;
uint8_t next_pid;
// Endpoint control register
io_rw_32 *endpoint_control;
+
// Buffer control register
io_rw_32 *buffer_control;
// Buffer pointer in usb dpram
uint8_t *hw_data_buf;
- // Have we been stalled
- bool stalled;
-
- // Current transfer information
- bool active;
- uint16_t total_len;
- uint16_t len;
- // Amount of data with the hardware
- uint16_t transfer_size;
// User buffer in main memory
uint8_t *user_buf;
+ // Current transfer information
+ uint16_t remaining_len;
+ uint16_t xferred_len;
+
// Data needed from EP descriptor
uint16_t wMaxPacketSize;
+
+ // Endpoint is in use
+ bool active;
+
// Interrupt, bulk, etc
uint8_t transfer_type;
-
-#if TUSB_OPT_HOST_ENABLED
- // Only needed for host mode
- bool last_buf;
- // RP2040-E4: HOST BUG. Host will incorrect write status to top half of buffer
- // control register when doing transfers > 1 packet
- uint8_t buf_sel;
+
+ // Transfer scheduled but not active
+ uint8_t pending;
+
+#if CFG_TUH_ENABLED
// Only needed for host
uint8_t dev_addr;
- bool sent_setup;
+
// If interrupt endpoint
uint8_t interrupt_num;
#endif
-};
+
+} hw_endpoint_t;
+
+#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+extern volatile uint32_t e15_last_sof;
+#endif
void rp2040_usb_init(void);
+void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len);
+bool hw_endpoint_xfer_continue(struct hw_endpoint *ep);
void hw_endpoint_reset_transfer(struct hw_endpoint *ep);
-void _hw_endpoint_xfer(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len, bool start);
-void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep);
-void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len);
-void _hw_endpoint_xfer_sync(struct hw_endpoint *ep);
-bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep);
-void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask);
-static inline uint32_t _hw_endpoint_buffer_control_get_value32(struct hw_endpoint *ep) {
- return *ep->buffer_control;
-}
-static inline void _hw_endpoint_buffer_control_set_value32(struct hw_endpoint *ep, uint32_t value) {
- return _hw_endpoint_buffer_control_update32(ep, 0, value);
-}
-static inline void _hw_endpoint_buffer_control_set_mask32(struct hw_endpoint *ep, uint32_t value) {
- return _hw_endpoint_buffer_control_update32(ep, ~value, value);
-}
-static inline void _hw_endpoint_buffer_control_clear_mask32(struct hw_endpoint *ep, uint32_t value) {
- return _hw_endpoint_buffer_control_update32(ep, ~value, 0);
-}
+void hw_endpoint_start_next_buffer(struct hw_endpoint *ep);
-static inline uintptr_t hw_data_offset(uint8_t *buf)
-{
- // Remove usb base from buffer pointer
- return (uintptr_t)buf ^ (uintptr_t)usb_dpram;
+TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_lock_update(__unused struct hw_endpoint * ep, __unused int delta) {
+ // todo add critsec as necessary to prevent issues between worker and IRQ...
+ // note that this is perhaps as simple as disabling IRQs because it would make
+ // sense to have worker and IRQ on same core, however I think using critsec is about equivalent.
}
-extern const char *ep_dir_string[];
+void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask);
-typedef union TU_ATTR_PACKED
+TU_ATTR_ALWAYS_INLINE static inline uint32_t _hw_endpoint_buffer_control_get_value32 (struct hw_endpoint *ep)
{
- uint16_t u16;
- struct TU_ATTR_PACKED
- {
- uint16_t xfer_len : 10;
- uint16_t available : 1;
- uint16_t stall : 1;
- uint16_t reset_bufsel : 1;
- uint16_t data_toggle : 1;
- uint16_t last_buf : 1;
- uint16_t full : 1;
- };
-} rp2040_buffer_control_t;
-
-TU_VERIFY_STATIC(sizeof(rp2040_buffer_control_t) == 2, "size is not correct");
+ return *ep->buffer_control;
+}
-static inline void print_bufctrl16(uint32_t u16)
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_value32 (struct hw_endpoint *ep, uint32_t value)
{
- rp2040_buffer_control_t bufctrl;
-
- bufctrl.u16 = u16;
-
- TU_LOG(2, "len = %u, available = %u, stall = %u, reset = %u, toggle = %u, last = %u, full = %u\r\n",
- bufctrl.xfer_len, bufctrl.available, bufctrl.stall, bufctrl.reset_bufsel, bufctrl.data_toggle, bufctrl.last_buf, bufctrl.full);
+ _hw_endpoint_buffer_control_update32(ep, 0, value);
}
-static inline void print_bufctrl32(uint32_t u32)
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_mask32 (struct hw_endpoint *ep, uint32_t value)
{
- uint16_t u16;
+ _hw_endpoint_buffer_control_update32(ep, ~value, value);
+}
- u16 = u32 >> 16;
- TU_LOG(2, "Buffer Control 1 0x%x: ", u16);
- print_bufctrl16(u16);
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_clear_mask32 (struct hw_endpoint *ep, uint32_t value)
+{
+ _hw_endpoint_buffer_control_update32(ep, ~value, 0);
+}
- u16 = u32 & 0x0000ffff;
- TU_LOG(2, "Buffer Control 0 0x%x: ", u16);
- print_bufctrl16(u16);
+static inline uintptr_t hw_data_offset (uint8_t *buf)
+{
+ // Remove usb base from buffer pointer
+ return (uintptr_t) buf ^ (uintptr_t) usb_dpram;
}
+extern const char *ep_dir_string[];
+
#endif
diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c
new file mode 100644
index 000000000..50400d1f5
--- /dev/null
+++ b/src/portable/renesas/rusb2/dcd_rusb2.c
@@ -0,0 +1,1028 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Koji Kitayama
+ * Portions copyrighted (c) 2021 Roland Winistoerfer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_RUSB2)
+
+// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
+// We disable SOF for now until needed later on
+#define USE_SOF 0
+
+#include "device/dcd.h"
+#include "rusb2_type.h"
+
+#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
+ #include "rusb2_rx.h"
+#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
+ #include "rusb2_ra.h"
+ #if defined(RENESAS_CORTEX_M23)
+ #define D0FIFO CFIFO
+ #define D0FIFOSEL CFIFOSEL
+ #define D0FIFOSEL_b CFIFOSEL_b
+ #define D1FIFOSEL CFIFOSEL
+ #define D1FIFOSEL_b CFIFOSEL_b
+ #define D0FIFOCTR CFIFOCTR
+ #define D0FIFOCTR_b CFIFOCTR_b
+ #endif
+
+#else
+ #error "Unsupported MCU"
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
+enum {
+ PIPE_COUNT = 10,
+};
+
+typedef struct {
+ void *buf; /* the start address of a transfer data buffer */
+ uint16_t length; /* the number of bytes in the buffer */
+ uint16_t remaining; /* the number of bytes remaining in the buffer */
+
+ uint8_t ep; /* an assigned endpoint address */
+ uint8_t ff; /* `buf` is TU_FUFO or POD */
+} pipe_state_t;
+
+typedef struct
+{
+ pipe_state_t pipe[PIPE_COUNT];
+ uint8_t ep[2][16]; /* a lookup table for a pipe index from an endpoint address */
+} dcd_data_t;
+
+static dcd_data_t _dcd;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+
+
+// Transfer conditions specifiable for each pipe for most MCUs
+// - Pipe 0: Control transfer with 64-byte single buffer
+// - Pipes 1 and 2: Bulk or ISO
+// - Pipes 3 to 5: Bulk
+// - Pipes 6 to 9: Interrupt
+//
+// Note: for small mcu such as
+// - RA2A1: only pipe 4-7 are available, and no support for ISO
+static unsigned find_pipe(unsigned xfer_type) {
+ #if defined(BSP_MCU_GROUP_RA2A1)
+ const uint8_t pipe_idx_arr[4][2] = {
+ { 0, 0 }, // Control
+ { 0, 0 }, // Isochronous not supported
+ { 4, 5 }, // Bulk
+ { 6, 7 }, // Interrupt
+ };
+ #else
+ const uint8_t pipe_idx_arr[4][2] = {
+ { 0, 0 }, // Control
+ { 1, 2 }, // Isochronous
+ { 1, 5 }, // Bulk
+ { 6, 9 }, // Interrupt
+ };
+ #endif
+
+ // find backward since only pipe 1, 2 support ISO
+ const uint8_t idx_first = pipe_idx_arr[xfer_type][0];
+ const uint8_t idx_last = pipe_idx_arr[xfer_type][1];
+
+ for (int i = idx_last; i >= idx_first; i--) {
+ if (0 == _dcd.pipe[i].ep) return i;
+ }
+
+ return 0;
+}
+
+static volatile uint16_t* get_pipectr(rusb2_reg_t *rusb, unsigned num) {
+ if (num) {
+ return (volatile uint16_t*)&(rusb->PIPE_CTR[num - 1]);
+ } else {
+ return (volatile uint16_t*)&(rusb->DCPCTR);
+ }
+}
+
+static volatile reg_pipetre_t* get_pipetre(rusb2_reg_t *rusb, unsigned num) {
+ volatile reg_pipetre_t* tre = NULL;
+ if ((1 <= num) && (num <= 5)) {
+ tre = (volatile reg_pipetre_t*)&(rusb->PIPE_TR[num - 1].E);
+ }
+ return tre;
+}
+
+static volatile uint16_t* ep_addr_to_pipectr(uint8_t rhport, unsigned ep_addr) {
+ rusb2_reg_t *rusb = RUSB2_REG(rhport);
+ const unsigned epn = tu_edpt_number(ep_addr);
+
+ if (epn) {
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned num = _dcd.ep[dir][epn];
+ return get_pipectr(rusb, num);
+ } else {
+ return get_pipectr(rusb, 0);
+ }
+}
+
+static uint16_t edpt0_max_packet_size(rusb2_reg_t* rusb) {
+ return rusb->DCPMAXP_b.MXPS;
+}
+
+static uint16_t edpt_max_packet_size(rusb2_reg_t *rusb, unsigned num) {
+ rusb->PIPESEL = num;
+ return rusb->PIPEMAXP;
+}
+
+static inline void pipe_wait_for_ready(rusb2_reg_t * rusb, unsigned num) {
+ while ( rusb->D0FIFOSEL_b.CURPIPE != num ) {}
+ while ( !rusb->D0FIFOCTR_b.FRDY ) {}
+}
+
+//--------------------------------------------------------------------+
+// Pipe FIFO
+//--------------------------------------------------------------------+
+
+// Write data buffer --> hw fifo
+static void pipe_write_packet(rusb2_reg_t * rusb, void *buf, volatile void *fifo, unsigned len)
+{
+ (void) rusb;
+
+ volatile uint16_t *ff16;
+ volatile uint8_t *ff8;
+
+ // Highspeed FIFO is 32-bit
+ if ( rusb2_is_highspeed_reg(rusb) ) {
+ // TODO 32-bit access for better performance
+ ff16 = (volatile uint16_t*) ((uintptr_t) fifo+2);
+ ff8 = (volatile uint8_t *) ((uintptr_t) fifo+3);
+ }else {
+ ff16 = (volatile uint16_t*) fifo;
+ ff8 = ((volatile uint8_t*) fifo);
+ }
+
+ uint8_t const* buf8 = (uint8_t const*) buf;
+
+ while (len >= 2) {
+ *ff16 = tu_unaligned_read16(buf8);
+ buf8 += 2;
+ len -= 2;
+ }
+
+ if (len > 0) {
+ *ff8 = *buf8;
+ ++buf8;
+ }
+}
+
+// Read data buffer <-- hw fifo
+static void pipe_read_packet(rusb2_reg_t * rusb, void *buf, volatile void *fifo, unsigned len)
+{
+ (void) rusb;
+
+ // TODO 16/32-bit access for better performance
+
+ uint8_t *p = (uint8_t*)buf;
+ volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */
+ while (len--) *p++ = *reg;
+}
+
+// Write data sw fifo --> hw fifo
+static void pipe_write_packet_ff(rusb2_reg_t * rusb, tu_fifo_t *f, volatile void *fifo, uint16_t total_len) {
+ tu_fifo_buffer_info_t info;
+ tu_fifo_get_read_info(f, &info);
+
+ uint16_t count = tu_min16(total_len, info.len_lin);
+ pipe_write_packet(rusb, info.ptr_lin, fifo, count);
+
+ uint16_t rem = total_len - count;
+ if (rem) {
+ rem = tu_min16(rem, info.len_wrap);
+ pipe_write_packet(rusb, info.ptr_wrap, fifo, rem);
+ count += rem;
+ }
+
+ tu_fifo_advance_read_pointer(f, count);
+}
+
+// Read data sw fifo <-- hw fifo
+static void pipe_read_packet_ff(rusb2_reg_t * rusb, tu_fifo_t *f, volatile void *fifo, uint16_t total_len) {
+ tu_fifo_buffer_info_t info;
+ tu_fifo_get_write_info(f, &info);
+
+ uint16_t count = tu_min16(total_len, info.len_lin);
+ pipe_read_packet(rusb, info.ptr_lin, fifo, count);
+
+ uint16_t rem = total_len - count;
+ if (rem) {
+ rem = tu_min16(rem, info.len_wrap);
+ pipe_read_packet(rusb, info.ptr_wrap, fifo, rem);
+ count += rem;
+ }
+
+ tu_fifo_advance_write_pointer(f, count);
+}
+
+//--------------------------------------------------------------------+
+// Pipe Transfer
+//--------------------------------------------------------------------+
+
+static bool pipe0_xfer_in(rusb2_reg_t* rusb)
+{
+ pipe_state_t *pipe = &_dcd.pipe[0];
+ const unsigned rem = pipe->remaining;
+
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+
+ const uint16_t mps = edpt0_max_packet_size(rusb);
+ const uint16_t len = tu_min16(mps, rem);
+ void *buf = pipe->buf;
+
+ if (len) {
+ if (pipe->ff) {
+ pipe_write_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->CFIFO, len);
+ } else {
+ pipe_write_packet(rusb, buf, (volatile void*)&rusb->CFIFO, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ }
+
+ if (len < mps) {
+ rusb->CFIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
+ }
+
+ pipe->remaining = rem - len;
+ return false;
+}
+
+static bool pipe0_xfer_out(rusb2_reg_t* rusb)
+{
+ pipe_state_t *pipe = &_dcd.pipe[0];
+ const unsigned rem = pipe->remaining;
+
+ const uint16_t mps = edpt0_max_packet_size(rusb);
+ const uint16_t vld = rusb->CFIFOCTR_b.DTLN;
+ const uint16_t len = tu_min16(tu_min16(rem, mps), vld);
+ void *buf = pipe->buf;
+
+ if (len) {
+ if (pipe->ff) {
+ pipe_read_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->CFIFO, len);
+ } else {
+ pipe_read_packet(rusb, buf, (volatile void*)&rusb->CFIFO, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ }
+
+ if (len < mps) {
+ rusb->CFIFOCTR = RUSB2_CFIFOCTR_BCLR_Msk;
+ }
+
+ pipe->remaining = rem - len;
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return true;
+ }
+
+ return false;
+}
+
+static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num)
+{
+ pipe_state_t *pipe = &_dcd.pipe[num];
+ const unsigned rem = pipe->remaining;
+
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+
+ rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_16BIT | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
+ const uint16_t mps = edpt_max_packet_size(rusb, num);
+ pipe_wait_for_ready(rusb, num);
+ const uint16_t len = tu_min16(rem, mps);
+ void *buf = pipe->buf;
+
+ if (len) {
+ if (pipe->ff) {
+ pipe_write_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->D0FIFO, len);
+ } else {
+ pipe_write_packet(rusb, buf, (volatile void*)&rusb->D0FIFO, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ }
+
+ if (len < mps) {
+ rusb->D0FIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
+ }
+
+ rusb->D0FIFOSEL = 0;
+ while (rusb->D0FIFOSEL_b.CURPIPE) {} /* if CURPIPE bits changes, check written value */
+
+ pipe->remaining = rem - len;
+
+ return false;
+}
+
+static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
+{
+ pipe_state_t *pipe = &_dcd.pipe[num];
+ const uint16_t rem = pipe->remaining;
+
+ rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_8BIT;
+ const uint16_t mps = edpt_max_packet_size(rusb, num);
+ pipe_wait_for_ready(rusb, num);
+
+ const uint16_t vld = rusb->D0FIFOCTR_b.DTLN;
+ const uint16_t len = tu_min16(tu_min16(rem, mps), vld);
+ void *buf = pipe->buf;
+
+ if (len) {
+ if (pipe->ff) {
+ pipe_read_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->D0FIFO, len);
+ } else {
+ pipe_read_packet(rusb, buf, (volatile void*)&rusb->D0FIFO, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ }
+
+ if (len < mps) {
+ rusb->D0FIFOCTR = RUSB2_CFIFOCTR_BCLR_Msk;
+ }
+
+ rusb->D0FIFOSEL = 0;
+ while (rusb->D0FIFOSEL_b.CURPIPE) {} /* if CURPIPE bits changes, check written value */
+
+ pipe->remaining = rem - len;
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return NULL != buf;
+ }
+
+ return false;
+}
+
+static void process_setup_packet(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ if (0 == (rusb->INTSTS0 & RUSB2_INTSTS0_VALID_Msk)) return;
+
+ rusb->CFIFOCTR = RUSB2_CFIFOCTR_BCLR_Msk;
+ uint16_t setup_packet[4] = {
+ tu_htole16(rusb->USBREQ),
+ tu_htole16(rusb->USBVAL),
+ tu_htole16(rusb->USBINDX),
+ tu_htole16(rusb->USBLENG)
+ };
+
+ rusb->INTSTS0 = ~((uint16_t) RUSB2_INTSTS0_VALID_Msk);
+ dcd_event_setup_received(rhport, (const uint8_t*)&setup_packet[0], true);
+}
+
+static void process_status_completion(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ uint8_t ep_addr;
+ /* Check the data stage direction */
+ if (rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) {
+ /* IN transfer. */
+ ep_addr = tu_edpt_addr(0, TUSB_DIR_IN);
+ } else {
+ /* OUT transfer. */
+ ep_addr = tu_edpt_addr(0, TUSB_DIR_OUT);
+ }
+
+ dcd_event_xfer_complete(rhport, ep_addr, 0, XFER_RESULT_SUCCESS, true);
+}
+
+static bool process_pipe0_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes)
+{
+ /* configure fifo direction and access unit settings */
+ if ( ep_addr ) {
+ /* IN, 2 bytes */
+ rusb->CFIFOSEL = RUSB2_CFIFOSEL_ISEL_WRITE | RUSB2_FIFOSEL_MBW_16BIT |
+ (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
+ while ( !(rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) ) {}
+ } else {
+ /* OUT, a byte */
+ rusb->CFIFOSEL = RUSB2_FIFOSEL_MBW_8BIT;
+ while ( rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE ) {}
+ }
+
+ pipe_state_t *pipe = &_dcd.pipe[0];
+ pipe->ff = buffer_type;
+ pipe->length = total_bytes;
+ pipe->remaining = total_bytes;
+
+ if ( total_bytes ) {
+ pipe->buf = buffer;
+ if ( ep_addr ) {
+ /* IN */
+ TU_ASSERT(rusb->DCPCTR_b.BSTS && (rusb->USBREQ & 0x80));
+ pipe0_xfer_in(rusb);
+ }
+ rusb->DCPCTR = RUSB2_PIPE_CTR_PID_BUF;
+ } else {
+ /* ZLP */
+ pipe->buf = NULL;
+ rusb->DCPCTR = RUSB2_DCPCTR_CCPL_Msk | RUSB2_PIPE_CTR_PID_BUF;
+ }
+
+ return true;
+}
+
+static bool process_pipe_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned num = _dcd.ep[dir][epn];
+
+ TU_ASSERT(num);
+
+ pipe_state_t *pipe = &_dcd.pipe[num];
+ pipe->ff = buffer_type;
+ pipe->buf = buffer;
+ pipe->length = total_bytes;
+ pipe->remaining = total_bytes;
+
+ if (dir) {
+ /* IN */
+ if (total_bytes) {
+ pipe_xfer_in(rusb, num);
+ } else {
+ /* ZLP */
+ rusb->D0FIFOSEL = num;
+ pipe_wait_for_ready(rusb, num);
+ rusb->D0FIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
+ rusb->D0FIFOSEL = 0;
+ /* if CURPIPE bits changes, check written value */
+ while (rusb->D0FIFOSEL_b.CURPIPE) {}
+ }
+ } else {
+ // OUT
+ volatile reg_pipetre_t *pt = get_pipetre(rusb, num);
+
+ if (pt) {
+ const uint16_t mps = edpt_max_packet_size(rusb, num);
+ volatile uint16_t *ctr = get_pipectr(rusb, num);
+
+ if (*ctr & 0x3) *ctr = RUSB2_PIPE_CTR_PID_NAK;
+
+ pt->TRE = TU_BIT(8);
+ pt->TRN = (total_bytes + mps - 1) / mps;
+ pt->TRENB = 1;
+ *ctr = RUSB2_PIPE_CTR_PID_BUF;
+ }
+ }
+
+ // TU_LOG2("X %x %d %d\r\n", ep_addr, total_bytes, buffer_type);
+ return true;
+}
+
+static bool process_edpt_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ if (0 == epn) {
+ return process_pipe0_xfer(rusb, buffer_type, ep_addr, buffer, total_bytes);
+ } else {
+ return process_pipe_xfer(rusb, buffer_type, ep_addr, buffer, total_bytes);
+ }
+}
+
+static void process_pipe0_bemp(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ bool completed = pipe0_xfer_in(rusb);
+ if (completed) {
+ pipe_state_t *pipe = &_dcd.pipe[0];
+ dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_IN),
+ pipe->length, XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_pipe_brdy(uint8_t rhport, unsigned num)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ pipe_state_t *pipe = &_dcd.pipe[num];
+ const unsigned dir = tu_edpt_dir(pipe->ep);
+ bool completed;
+
+ if (dir) {
+ /* IN */
+ completed = pipe_xfer_in(rusb, num);
+ } else {
+ // OUT
+ if (num) {
+ completed = pipe_xfer_out(rusb, num);
+ } else {
+ completed = pipe0_xfer_out(rusb);
+ }
+ }
+ if (completed) {
+ dcd_event_xfer_complete(rhport, pipe->ep,
+ pipe->length - pipe->remaining,
+ XFER_RESULT_SUCCESS, true);
+ // TU_LOG1("C %d %d\r\n", num, pipe->length - pipe->remaining);
+ }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+
+ rusb->BEMPENB = 1;
+ rusb->BRDYENB = 1;
+ rusb->CFIFOCTR = RUSB2_CFIFOCTR_BCLR_Msk;
+
+ rusb->D0FIFOSEL = 0;
+ while (rusb->D0FIFOSEL_b.CURPIPE) {} /* if CURPIPE bits changes, check written value */
+
+ rusb->D1FIFOSEL = 0;
+ while (rusb->D1FIFOSEL_b.CURPIPE) {} /* if CURPIPE bits changes, check written value */
+
+ volatile uint16_t *ctr = (volatile uint16_t*)((uintptr_t) (&rusb->PIPE_CTR[0]));
+ volatile uint16_t *tre = (volatile uint16_t*)((uintptr_t) (&rusb->PIPE_TR[0].E));
+
+ for (int i = 1; i <= 5; ++i) {
+ rusb->PIPESEL = i;
+ rusb->PIPECFG = 0;
+ *ctr = RUSB2_PIPE_CTR_ACLRM_Msk;
+ *ctr = 0;
+ ++ctr;
+ *tre = TU_BIT(8);
+ tre += 2;
+ }
+
+ for (int i = 6; i <= 9; ++i) {
+ rusb->PIPESEL = i;
+ rusb->PIPECFG = 0;
+ *ctr = RUSB2_PIPE_CTR_ACLRM_Msk;
+ *ctr = 0;
+ ++ctr;
+ }
+ tu_varclr(&_dcd);
+
+ TU_LOG3("Bus reset, RHST = %u\r\n", rusb->DVSTCTR0_b.RHST);
+ tusb_speed_t speed;
+ switch(rusb->DVSTCTR0 & RUSB2_DVSTCTR0_RHST_Msk) {
+ case RUSB2_DVSTCTR0_RHST_LS:
+ speed = TUSB_SPEED_LOW;
+ break;
+
+ case RUSB2_DVSTCTR0_RHST_FS:
+ speed = TUSB_SPEED_FULL;
+ break;
+
+ case RUSB2_DVSTCTR0_RHST_HS:
+ speed = TUSB_SPEED_HIGH;
+ break;
+
+ default:
+ TU_ASSERT(false, );
+ }
+
+ dcd_event_bus_reset(rhport, speed, true);
+}
+
+static void process_set_address(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ const uint16_t addr = rusb->USBADDR_b.USBADDR;
+ if (!addr) return;
+
+ const tusb_control_request_t setup_packet = {
+#if defined(__CCRX__)
+ .bmRequestType = { 0 }, /* Note: CCRX needs the braces over this struct member */
+#else
+ .bmRequestType = 0,
+#endif
+ .bRequest = TUSB_REQ_SET_ADDRESS,
+ .wValue = addr,
+ .wIndex = 0,
+ .wLength = 0,
+ };
+
+ dcd_event_setup_received(rhport, (const uint8_t *) &setup_packet, true);
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+
+#if 0 // previously present in the rx driver before generalization
+static uint32_t disable_interrupt(void)
+{
+ uint32_t pswi;
+#if defined(__CCRX__)
+ pswi = get_psw() & 0x010000;
+ clrpsw_i();
+#else
+ pswi = __builtin_rx_mvfc(0) & 0x010000;
+ __builtin_rx_clrpsw('I');
+#endif
+ return pswi;
+}
+
+static void enable_interrupt(uint32_t pswi)
+{
+#if defined(__CCRX__)
+ set_psw(get_psw() | pswi);
+#else
+ __builtin_rx_mvtc(0, __builtin_rx_mvfc(0) | pswi);
+#endif
+}
+#endif
+
+void dcd_init(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ rusb2_module_start(rhport, true);
+
+#ifdef RUSB2_SUPPORT_HIGHSPEED
+ if ( rusb2_is_highspeed_rhport(rhport) ) {
+ rusb->SYSCFG_b.HSE = 1;
+
+ // leave CLKSEL as default (0x11) 24Mhz
+
+ // Power and reset UTMI Phy
+ uint16_t physet = (rusb->PHYSET | RUSB2_PHYSET_PLLRESET_Msk) & ~RUSB2_PHYSET_DIRPD_Msk;
+ rusb->PHYSET = physet;
+ R_BSP_SoftwareDelay((uint32_t) 1, BSP_DELAY_UNITS_MILLISECONDS);
+ rusb->PHYSET_b.PLLRESET = 0;
+
+ // set UTMI to operating mode and wait for PLL lock confirmation
+ rusb->LPSTS_b.SUSPENDM = 1;
+ while (!rusb->PLLSTA_b.PLLLOCK) {}
+
+ rusb->SYSCFG_b.DRPD = 0;
+ rusb->SYSCFG_b.USBE = 1;
+
+ // Set CPU bus wait time (fine tunne later)
+ // rusb2->BUSWAIT |= 0x0F00U;
+
+ rusb->PHYSET_b.REPSEL = 1;
+ } else
+#endif
+ {
+ rusb->SYSCFG_b.SCKE = 1;
+ while (!rusb->SYSCFG_b.SCKE) {}
+ rusb->SYSCFG_b.DRPD = 0;
+ rusb->SYSCFG_b.DCFM = 0;
+ rusb->SYSCFG_b.USBE = 1;
+
+ // MCU specific PHY init
+ rusb2_phy_init();
+
+ rusb->PHYSLEW = 0x5;
+ rusb->DPUSR0R_FS_b.FIXPHY0 = 0u; /* USB_BASE Transceiver Output fixed */
+ }
+
+ /* Setup default control pipe */
+ rusb->DCPMAXP_b.MXPS = 64;
+
+ rusb->INTSTS0 = 0;
+ rusb->INTENB0 = RUSB2_INTSTS0_VBINT_Msk | RUSB2_INTSTS0_BRDY_Msk | RUSB2_INTSTS0_BEMP_Msk |
+ RUSB2_INTSTS0_DVST_Msk | RUSB2_INTSTS0_CTRT_Msk | (USE_SOF ? RUSB2_INTSTS0_SOFR_Msk : 0) |
+ RUSB2_INTSTS0_RESM_Msk;
+ rusb->BEMPENB = 1;
+ rusb->BRDYENB = 1;
+
+ // If VBUS (detect) pin is not used, application need to call tud_connect() manually after tud_init()
+ if (rusb->INTSTS0_b.VBSTS) {
+ dcd_connect(rhport);
+ }
+}
+
+void dcd_int_enable(uint8_t rhport) {
+ rusb2_int_enable(rhport);
+}
+
+void dcd_int_disable(uint8_t rhport) {
+ rusb2_int_disable(rhport);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
+ (void) rhport;
+ (void) dev_addr;
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ rusb->DVSTCTR0_b.WKUP = 1;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+
+ if ( rusb2_is_highspeed_rhport(rhport)) {
+ rusb->SYSCFG_b.CNEN = 1;
+ }
+ rusb->SYSCFG_b.DPRPU = 1;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ rusb->SYSCFG_b.DPRPU = 0;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void)rhport;
+
+ rusb2_reg_t * rusb = RUSB2_REG(rhport);
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+
+ const unsigned mps = tu_edpt_packet_size(ep_desc);
+
+ if (xfer == TUSB_XFER_ISOCHRONOUS) {
+ // Fullspeed ISO is limit to 256 bytes
+ if ( !rusb2_is_highspeed_rhport(rhport) && mps > 256) {
+ return false;
+ }
+ }
+
+ const unsigned num = find_pipe(xfer);
+ TU_ASSERT(num);
+
+ _dcd.pipe[num].ep = ep_addr;
+ _dcd.ep[dir][epn] = num;
+
+ /* setup pipe */
+ dcd_int_disable(rhport);
+
+ if ( rusb2_is_highspeed_rhport(rhport) ) {
+ // FIXME shouldn't be after pipe selection and config, also the BUFNMB should be changed
+ // depending on the allocation scheme
+ rusb->PIPEBUF = 0x7C08;
+ }
+
+ rusb->PIPESEL = num;
+ rusb->PIPEMAXP = mps;
+ volatile uint16_t *ctr = get_pipectr(rusb, num);
+ *ctr = RUSB2_PIPE_CTR_ACLRM_Msk | RUSB2_PIPE_CTR_SQCLR_Msk;
+ *ctr = 0;
+ unsigned cfg = (dir << 4) | epn;
+
+ if (xfer == TUSB_XFER_BULK) {
+ cfg |= (RUSB2_PIPECFG_TYPE_BULK | RUSB2_PIPECFG_SHTNAK_Msk | RUSB2_PIPECFG_DBLB_Msk);
+ } else if (xfer == TUSB_XFER_INTERRUPT) {
+ cfg |= RUSB2_PIPECFG_TYPE_INT;
+ } else {
+ cfg |= (RUSB2_PIPECFG_TYPE_ISO | RUSB2_PIPECFG_DBLB_Msk);
+ }
+
+ rusb->PIPECFG = cfg;
+ rusb->BRDYSTS = 0x3FFu ^ TU_BIT(num);
+ rusb->BRDYENB |= TU_BIT(num);
+
+ if (dir || (xfer != TUSB_XFER_BULK)) {
+ *ctr = RUSB2_PIPE_CTR_PID_BUF;
+ }
+
+ // TU_LOG1("O %d %x %x\r\n", rusb->PIPESEL, rusb->PIPECFG, rusb->PIPEMAXP);
+ dcd_int_enable(rhport);
+
+ return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ unsigned i = TU_ARRAY_SIZE(_dcd.pipe);
+ dcd_int_disable(rhport);
+ while (--i) { /* Close all pipes except 0 */
+ const unsigned ep_addr = _dcd.pipe[i].ep;
+ if (!ep_addr) continue;
+ dcd_edpt_close(rhport, ep_addr);
+ }
+ dcd_int_enable(rhport);
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ rusb2_reg_t * rusb = RUSB2_REG(rhport);
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned num = _dcd.ep[dir][epn];
+
+ rusb->BRDYENB &= ~TU_BIT(num);
+ volatile uint16_t *ctr = get_pipectr(rusb, num);
+ *ctr = 0;
+ rusb->PIPESEL = num;
+ rusb->PIPECFG = 0;
+ _dcd.pipe[num].ep = 0;
+ _dcd.ep[dir][epn] = 0;
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+
+ dcd_int_disable(rhport);
+ bool r = process_edpt_xfer(rusb, 0, ep_addr, buffer, total_bytes);
+ dcd_int_enable(rhport);
+
+ return r;
+}
+
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+ // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
+ TU_ASSERT(ff->item_size == 1);
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+
+ dcd_int_disable(rhport);
+ bool r = process_edpt_xfer(rusb, 1, ep_addr, ff, total_bytes);
+ dcd_int_enable(rhport);
+
+ return r;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr);
+ if (!ctr) return;
+ dcd_int_disable(rhport);
+ const uint32_t pid = *ctr & 0x3;
+ *ctr = pid | RUSB2_PIPE_CTR_PID_STALL;
+ *ctr = RUSB2_PIPE_CTR_PID_STALL;
+ dcd_int_enable(rhport);
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ rusb2_reg_t * rusb = RUSB2_REG(rhport);
+ volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr);
+ if (!ctr) return;
+
+ dcd_int_disable(rhport);
+ *ctr = RUSB2_PIPE_CTR_SQCLR_Msk;
+
+ if (tu_edpt_dir(ep_addr)) { /* IN */
+ *ctr = RUSB2_PIPE_CTR_PID_BUF;
+ } else {
+ const unsigned num = _dcd.ep[0][tu_edpt_number(ep_addr)];
+ rusb->PIPESEL = num;
+ if (rusb->PIPECFG_b.TYPE != 1) {
+ *ctr = RUSB2_PIPE_CTR_PID_BUF;
+ }
+ }
+ dcd_int_enable(rhport);
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+
+#if defined(__CCRX__)
+TU_ATTR_ALWAYS_INLINE static inline unsigned __builtin_ctz(unsigned int value) {
+ unsigned int count = 0;
+ while ((value & 1) == 0) {
+ value >>= 1;
+ count++;
+ }
+ return count;
+}
+#endif
+
+void dcd_int_handler(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+
+ uint16_t is0 = rusb->INTSTS0;
+
+ /* clear active bits except VALID (don't write 0 to already cleared bits according to the HW manual) */
+ rusb->INTSTS0 = ~((RUSB2_INTSTS0_CTRT_Msk | RUSB2_INTSTS0_DVST_Msk | RUSB2_INTSTS0_SOFR_Msk |
+ RUSB2_INTSTS0_RESM_Msk | RUSB2_INTSTS0_VBINT_Msk) & is0) | RUSB2_INTSTS0_VALID_Msk;
+
+ // VBUS changes
+ if ( is0 & RUSB2_INTSTS0_VBINT_Msk ) {
+ if ( rusb->INTSTS0_b.VBSTS ) {
+ dcd_connect(rhport);
+ } else {
+ dcd_disconnect(rhport);
+ }
+ }
+
+ // Resumed
+ if ( is0 & RUSB2_INTSTS0_RESM_Msk ) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+#if (0 == USE_SOF)
+ rusb->INTENB0_b.SOFE = 0;
+#endif
+ }
+
+ // SOF received
+ if ( (is0 & RUSB2_INTSTS0_SOFR_Msk) && rusb->INTENB0_b.SOFE ) {
+ // USBD will exit suspended mode when SOF event is received
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+#if (0 == USE_SOF)
+ rusb->INTENB0_b.SOFE = 0;
+#endif
+ }
+
+ // Device state changes
+ if ( is0 & RUSB2_INTSTS0_DVST_Msk ) {
+ switch (is0 & RUSB2_INTSTS0_DVSQ_Msk) {
+ case RUSB2_INTSTS0_DVSQ_STATE_DEF:
+ process_bus_reset(rhport);
+ break;
+
+ case RUSB2_INTSTS0_DVSQ_STATE_ADDR:
+ process_set_address(rhport);
+ break;
+
+ case RUSB2_INTSTS0_DVSQ_STATE_SUSP0:
+ case RUSB2_INTSTS0_DVSQ_STATE_SUSP1:
+ case RUSB2_INTSTS0_DVSQ_STATE_SUSP2:
+ case RUSB2_INTSTS0_DVSQ_STATE_SUSP3:
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+#if (0 == USE_SOF)
+ rusb->INTENB0_b.SOFE = 1;
+#endif
+
+ default: break;
+ }
+ }
+
+// if ( is0 & RUSB2_INTSTS0_NRDY_Msk ) {
+// rusb->NRDYSTS = 0;
+// }
+
+ // Control transfer stage changes
+ if ( is0 & RUSB2_INTSTS0_CTRT_Msk ) {
+ if ( is0 & RUSB2_INTSTS0_CTSQ_CTRL_RDATA ) {
+ /* A setup packet has been received. */
+ process_setup_packet(rhport);
+ } else if ( 0 == (is0 & RUSB2_INTSTS0_CTSQ_Msk) ) {
+ /* A ZLP has been sent/received. */
+ process_status_completion(rhport);
+ }
+ }
+
+ // Buffer empty
+ if ( is0 & RUSB2_INTSTS0_BEMP_Msk ) {
+ const uint16_t s = rusb->BEMPSTS;
+ rusb->BEMPSTS = 0;
+ if ( s & 1 ) {
+ process_pipe0_bemp(rhport);
+ }
+ }
+
+ // Buffer ready
+ if ( is0 & RUSB2_INTSTS0_BRDY_Msk ) {
+ const unsigned m = rusb->BRDYENB;
+ unsigned s = rusb->BRDYSTS & m;
+ /* clear active bits (don't write 0 to already cleared bits according to the HW manual) */
+ rusb->BRDYSTS = ~s;
+ while (s) {
+ const unsigned num = __builtin_ctz(s);
+ process_pipe_brdy(rhport, num);
+ s &= ~TU_BIT(num);
+ }
+ }
+}
+
+#endif
diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c
new file mode 100644
index 000000000..f140da690
--- /dev/null
+++ b/src/portable/renesas/rusb2/hcd_rusb2.c
@@ -0,0 +1,844 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji Kitayama
+ * Portions copyrighted (c) 2021 Roland Winistoerfer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && defined(TUP_USBIP_RUSB2)
+
+#include "host/hcd.h"
+#include "rusb2_type.h"
+
+#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
+ #include "rusb2_rx.h"
+#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
+ #include "rusb2_ra.h"
+#else
+ #error "Unsupported MCU"
+#endif
+
+#define TU_RUSB2_HCD_DBG 2
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+enum {
+ PIPE_COUNT = 10,
+};
+
+TU_ATTR_PACKED_BEGIN
+TU_ATTR_BIT_FIELD_ORDER_BEGIN
+
+typedef union TU_ATTR_PACKED {
+ struct {
+ volatile uint16_t u8: 8;
+ volatile uint16_t : 0;
+ };
+ volatile uint16_t u16;
+} hw_fifo_t;
+
+typedef struct TU_ATTR_PACKED {
+ void *buf; /* the start address of a transfer data buffer */
+ uint16_t length; /* the number of bytes in the buffer */
+ uint16_t remaining; /* the number of bytes remaining in the buffer */
+ struct {
+ uint32_t ep : 8; /* an assigned endpoint address */
+ uint32_t dev : 8; /* an assigned device address */
+ uint32_t ff : 1; /* `buf` is TU_FUFO or POD */
+ uint32_t : 0;
+ };
+} pipe_state_t;
+
+TU_ATTR_PACKED_END // End of definition of packed structs (used by the CCRX toolchain)
+TU_ATTR_BIT_FIELD_ORDER_END
+
+typedef struct
+{
+ bool need_reset; /* The device has not been reset after connection. */
+ pipe_state_t pipe[PIPE_COUNT];
+ uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
+ uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
+} hcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+static hcd_data_t _hcd;
+
+// TODO merged with DCD
+// Transfer conditions specifiable for each pipe for most MCUs
+// - Pipe 0: Control transfer with 64-byte single buffer
+// - Pipes 1 and 2: Bulk or ISO
+// - Pipes 3 to 5: Bulk
+// - Pipes 6 to 9: Interrupt
+//
+// Note: for small mcu such as
+// - RA2A1: only pipe 4-7 are available, and no support for ISO
+static unsigned find_pipe(unsigned xfer_type) {
+ const uint8_t pipe_idx_arr[4][2] = {
+ { 0, 0 }, // Control
+ { 1, 2 }, // Isochronous
+ { 1, 5 }, // Bulk
+ { 6, 9 }, // Interrupt
+ };
+
+ // find backward since only pipe 1, 2 support ISO
+ const uint8_t idx_first = pipe_idx_arr[xfer_type][0];
+ const uint8_t idx_last = pipe_idx_arr[xfer_type][1];
+
+ for (int i = idx_last; i >= idx_first; i--) {
+ if (0 == _hcd.pipe[i].ep) return i;
+ }
+
+ return 0;
+}
+
+static volatile uint16_t* get_pipectr(rusb2_reg_t *rusb, unsigned num)
+{
+ if (num) {
+ return (volatile uint16_t*)&(rusb->PIPE_CTR[num - 1]);
+ } else {
+ return (volatile uint16_t*)&(rusb->DCPCTR);
+ }
+}
+
+static volatile reg_pipetre_t* get_pipetre(rusb2_reg_t *rusb, unsigned num)
+{
+ volatile reg_pipetre_t* tre = NULL;
+ if ((1 <= num) && (num <= 5)) {
+ tre = (volatile reg_pipetre_t*)&(rusb->PIPE_TR[num - 1].E);
+ }
+ return tre;
+}
+
+static volatile uint16_t* addr_to_pipectr(uint8_t rhport, uint8_t dev_addr, unsigned ep_addr)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ const unsigned epn = tu_edpt_number(ep_addr);
+
+ if (epn) {
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned num = _hcd.ep[dev_addr][dir_in][epn - 1];
+ return get_pipectr(rusb, num);
+ } else {
+ return get_pipectr(rusb, 0);
+ }
+}
+
+static uint16_t edpt0_max_packet_size(rusb2_reg_t* rusb)
+{
+ return rusb->DCPMAXP_b.MXPS;
+}
+
+static uint16_t edpt_max_packet_size(rusb2_reg_t *rusb, unsigned num)
+{
+ rusb->PIPESEL = num;
+ return rusb->PIPEMAXP_b.MXPS;
+}
+
+static inline void pipe_wait_for_ready(rusb2_reg_t* rusb, unsigned num)
+{
+ while (rusb->D0FIFOSEL_b.CURPIPE != num) ;
+ while (!rusb->D0FIFOCTR_b.FRDY) {}
+}
+
+static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ // NOTE: unlike DCD, Highspeed 32-bit FIFO does not need to adjust the fifo address
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 2) {
+ reg->u16 = *(const uint16_t *)addr;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ reg->u8 = *(const uint8_t *)addr;
+ ++addr;
+ }
+}
+
+static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ uint8_t *p = (uint8_t*)buf;
+ volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */
+ while (len--) *p++ = *reg;
+}
+
+static bool pipe0_xfer_in(rusb2_reg_t* rusb)
+{
+ pipe_state_t *pipe = &_hcd.pipe[0];
+ const unsigned rem = pipe->remaining;
+
+ const unsigned mps = edpt0_max_packet_size(rusb);
+ const unsigned vld = rusb->CFIFOCTR_b.DTLN;
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
+ pipe_read_packet(buf, (volatile void*)&rusb->CFIFO, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ if (len < mps) {
+ rusb->CFIFOCTR = RUSB2_CFIFOCTR_BCLR_Msk;
+ }
+ pipe->remaining = rem - len;
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return true;
+ }
+ rusb->DCPCTR = RUSB2_PIPE_CTR_PID_BUF;
+ return false;
+}
+
+static bool pipe0_xfer_out(rusb2_reg_t* rusb)
+{
+ pipe_state_t *pipe = &_hcd.pipe[0];
+ const unsigned rem = pipe->remaining;
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+ const unsigned mps = edpt0_max_packet_size(rusb);
+ const unsigned len = TU_MIN(mps, rem);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, (volatile void*)&rusb->CFIFO, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ if (len < mps) {
+ rusb->CFIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
+ }
+ pipe->remaining = rem - len;
+ return false;
+}
+
+static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num)
+{
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ const unsigned rem = pipe->remaining;
+
+ rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_8BIT;
+ const unsigned mps = edpt_max_packet_size(rusb, num);
+ pipe_wait_for_ready(rusb, num);
+ const unsigned vld = rusb->D0FIFOCTR_b.DTLN;
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_read_packet(buf, (volatile void*)&rusb->D0FIFO, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ if (len < mps) {
+ rusb->D0FIFOCTR = RUSB2_D0FIFOCTR_BCLR_Msk;
+ }
+ rusb->D0FIFOSEL = 0;
+ while (rusb->D0FIFOSEL_b.CURPIPE) ; /* if CURPIPE bits changes, check written value */
+ pipe->remaining = rem - len;
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return NULL != buf;
+ }
+ return false;
+}
+
+static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
+{
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ const unsigned rem = pipe->remaining;
+
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+
+ rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_16BIT | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
+ const unsigned mps = edpt_max_packet_size(rusb, num);
+ pipe_wait_for_ready(rusb, num);
+ const unsigned len = TU_MIN(rem, mps);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, (volatile void*)&rusb->D0FIFO, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ if (len < mps) {
+ rusb->D0FIFOCTR = RUSB2_D0FIFOCTR_BVAL_Msk;
+ }
+ rusb->D0FIFOSEL = 0;
+ while (rusb->D0FIFOSEL_b.CURPIPE) ; /* if CURPIPE bits changes, check written value */
+ pipe->remaining = rem - len;
+ return false;
+}
+
+static bool process_pipe0_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
+{
+ (void)dev_addr;
+
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+
+ /* configure fifo direction and access unit settings */
+ if (dir_in) { /* IN, a byte */
+ rusb->CFIFOSEL = RUSB2_FIFOSEL_MBW_8BIT;
+ while (rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) ;
+ } else { /* OUT, 2 bytes */
+ rusb->CFIFOSEL = RUSB2_CFIFOSEL_ISEL_WRITE | RUSB2_FIFOSEL_MBW_16BIT |
+ (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
+ while (!(rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE)) ;
+ }
+
+ pipe_state_t *pipe = &_hcd.pipe[0];
+ pipe->ep = ep_addr;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ if (buflen) {
+ pipe->buf = buffer;
+ if (!dir_in) { /* OUT */
+ TU_ASSERT(rusb->DCPCTR_b.BSTS && (rusb->USBREQ & 0x80));
+ pipe0_xfer_out(rusb);
+ }
+ } else { /* ZLP */
+ pipe->buf = NULL;
+ if (!dir_in) { /* OUT */
+ rusb->CFIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
+ }
+ if (dir_in == rusb->DCPCFG_b.DIR) {
+ TU_ASSERT(RUSB2_PIPE_CTR_PID_NAK == rusb->DCPCTR_b.PID);
+ rusb->DCPCTR_b.SQSET = 1;
+ rusb->DCPCFG_b.DIR = dir_in ^ 1;
+ }
+ }
+ rusb->DCPCTR = RUSB2_PIPE_CTR_PID_BUF;
+ return true;
+}
+
+static bool process_pipe_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, void *buffer, uint16_t buflen)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned num = _hcd.ep[dev_addr - 1][dir_in][epn - 1];
+
+ TU_ASSERT(num);
+
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ pipe->buf = buffer;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ if (!dir_in) { /* OUT */
+ if (buflen) {
+ pipe_xfer_out(rusb, num);
+ } else { /* ZLP */
+ rusb->D0FIFOSEL = num;
+ pipe_wait_for_ready(rusb, num);
+ rusb->D0FIFOCTR = RUSB2_D0FIFOCTR_BVAL_Msk;
+ rusb->D0FIFOSEL = 0;
+ while (rusb->D0FIFOSEL_b.CURPIPE) {} /* if CURPIPE bits changes, check written value */
+ }
+ } else {
+ volatile uint16_t *ctr = get_pipectr(rusb, num);
+ volatile reg_pipetre_t *pt = get_pipetre(rusb, num);
+ if (pt) {
+ const unsigned mps = edpt_max_packet_size(rusb, num);
+ if (*ctr & 0x3) *ctr = RUSB2_PIPE_CTR_PID_NAK;
+ pt->TRE = TU_BIT(8);
+ pt->TRN = (buflen + mps - 1) / mps;
+ pt->TRENB = 1;
+ }
+ *ctr = RUSB2_PIPE_CTR_PID_BUF;
+ }
+ return true;
+}
+
+static bool process_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ if (0 == epn) {
+ return process_pipe0_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
+ } else {
+ return process_pipe_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
+ }
+}
+
+static void process_pipe0_bemp(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ bool completed = pipe0_xfer_out(rusb);
+ if (completed) {
+ pipe_state_t *pipe = &_hcd.pipe[0];
+ hcd_event_xfer_complete(pipe->dev,
+ tu_edpt_addr(0, TUSB_DIR_OUT),
+ pipe->length - pipe->remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_pipe_nrdy(uint8_t rhport, unsigned num)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ xfer_result_t result;
+ uint16_t volatile *ctr = get_pipectr(rusb, num);
+ TU_LOG(TU_RUSB2_HCD_DBG, "NRDY %d %x\r\n", num, *ctr);
+ switch (*ctr & RUSB2_PIPE_CTR_PID_Msk) {
+ default: return;
+ case RUSB2_PIPE_CTR_PID_STALL: result = XFER_RESULT_STALLED; break;
+ case RUSB2_PIPE_CTR_PID_STALL2: result = XFER_RESULT_STALLED; break;
+ case RUSB2_PIPE_CTR_PID_NAK: result = XFER_RESULT_FAILED; break;
+ }
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ hcd_event_xfer_complete(pipe->dev, pipe->ep,
+ pipe->length - pipe->remaining,
+ result, true);
+}
+
+static void process_pipe_brdy(uint8_t rhport, unsigned num)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ const unsigned dir_in = tu_edpt_dir(pipe->ep);
+ bool completed;
+
+ if (dir_in) { /* IN */
+ if (num) {
+ completed = pipe_xfer_in(rusb, num);
+ } else {
+ completed = pipe0_xfer_in(rusb);
+ }
+ } else {
+ completed = pipe_xfer_out(rusb, num);
+ }
+ if (completed) {
+ hcd_event_xfer_complete(pipe->dev, pipe->ep,
+ pipe->length - pipe->remaining,
+ XFER_RESULT_SUCCESS, true);
+ TU_LOG(TU_RUSB2_HCD_DBG, "C %d %d\r\n", num, pipe->length - pipe->remaining);
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* Host API
+ *------------------------------------------------------------------*/
+
+#if 0 // previously present in the rx driver before generalization
+static uint32_t disable_interrupt(void)
+{
+ uint32_t pswi;
+#if defined(__CCRX__)
+ pswi = get_psw() & 0x010000;
+ clrpsw_i();
+#else
+ pswi = __builtin_rx_mvfc(0) & 0x010000;
+ __builtin_rx_clrpsw('I');
+#endif
+ return pswi;
+}
+
+static void enable_interrupt(uint32_t pswi)
+{
+#if defined(__CCRX__)
+ set_psw(get_psw() | pswi);
+#else
+ __builtin_rx_mvtc(0, __builtin_rx_mvfc(0) | pswi);
+#endif
+}
+#endif
+
+bool hcd_init(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ rusb2_module_start(rhport, true);
+
+#ifdef RUSB2_SUPPORT_HIGHSPEED
+ if (rusb2_is_highspeed_rhport(rhport) ) {
+ rusb->SYSCFG_b.HSE = 1;
+ rusb->PHYSET_b.HSEB = 0;
+ rusb->PHYSET_b.DIRPD = 0;
+ R_BSP_SoftwareDelay((uint32_t) 1, BSP_DELAY_UNITS_MILLISECONDS);
+ rusb->PHYSET_b.PLLRESET = 0;
+ rusb->LPSTS_b.SUSPENDM = 1;
+ while ( !rusb->PLLSTA_b.PLLLOCK );
+ rusb->SYSCFG_b.DRPD = 1;
+ rusb->SYSCFG_b.DCFM = 1;
+ rusb->SYSCFG_b.DPRPU = 0;
+ rusb->SYSCFG_b.CNEN = 1;
+ rusb->BUSWAIT |= 0x0F00U;
+ rusb->SOFCFG_b.INTL = 1;
+ rusb->DVSTCTR0_b.VBUSEN = 1;
+ rusb->CFIFOSEL_b.MBW = 1;
+ rusb->D0FIFOSEL_b.MBW = 1;
+ rusb->D1FIFOSEL_b.MBW = 1;
+ rusb->INTSTS0 = 0;
+ for ( volatile int i = 0; i < 30000; ++i );
+ rusb->SYSCFG_b.USBE = 1;
+ } else
+#endif
+ {
+ rusb->SYSCFG_b.SCKE = 1;
+ while ( !rusb->SYSCFG_b.SCKE ) {}
+ rusb->SYSCFG_b.DCFM = 1; // Host function
+ rusb->SYSCFG_b.DPRPU = 0; // Disable D+ pull up
+ rusb->SYSCFG_b.DRPD = 1; // Enable D+/D- pull down
+
+ rusb->DVSTCTR0_b.VBUSEN = 1;
+ for ( volatile int i = 0; i < 30000; ++i ) {} // FIXME do we need to wait here? how long ?
+ //R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
+ rusb->SYSCFG_b.USBE = 1;
+
+ // MCU specific PHY init
+ rusb2_phy_init();
+
+ rusb->PHYSLEW = 0x5;
+ rusb->DPUSR0R_FS_b.FIXPHY0 = 0u; /* Transceiver Output fixed */
+ }
+
+ /* Setup default control pipe */
+ rusb->DCPCFG = RUSB2_PIPECFG_SHTNAK_Msk;
+ rusb->DCPMAXP = 64;
+ rusb->INTENB0 = RUSB2_INTSTS0_BRDY_Msk | RUSB2_INTSTS0_NRDY_Msk | RUSB2_INTSTS0_BEMP_Msk;
+ rusb->INTENB1 = RUSB2_INTSTS1_SACK_Msk | RUSB2_INTSTS1_SIGN_Msk | RUSB2_INTSTS1_ATTCH_Msk | RUSB2_INTSTS1_DTCH_Msk;
+ rusb->BEMPENB = 1;
+ rusb->NRDYENB = 1;
+ rusb->BRDYENB = 1;
+
+ return true;
+}
+
+void hcd_int_enable(uint8_t rhport) {
+ rusb2_int_enable(rhport);
+}
+
+void hcd_int_disable(uint8_t rhport) {
+ rusb2_int_disable(rhport);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+
+ /* The device must be reset at least once after connection
+ * in order to start the frame counter. */
+ if (_hcd.need_reset) hcd_port_reset(rhport);
+ return rusb->FRMNUM_b.FRNM;
+}
+
+/*--------------------------------------------------------------------+
+ * Port API
+ *--------------------------------------------------------------------+*/
+bool hcd_port_connect_status(uint8_t rhport) {
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ return rusb->INTSTS1_b.ATTCH ? true : false;
+}
+
+void hcd_port_reset(uint8_t rhport) {
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
+ while (rusb->DCPCTR_b.PBUSY) {}
+
+ hcd_int_disable(rhport);
+ rusb->DVSTCTR0_b.UACT = 0;
+ if (rusb->DCPCTR_b.SUREQ) {
+ rusb->DCPCTR_b.SUREQCLR = 1;
+ }
+ hcd_int_enable(rhport);
+
+ /* Reset should be asserted 10-20ms. */
+ rusb->DVSTCTR0_b.USBRST = 1;
+ for (volatile int i = 0; i < 2400000; ++i) {}
+ rusb->DVSTCTR0_b.USBRST = 0;
+
+ rusb->DVSTCTR0_b.UACT = 1;
+ _hcd.need_reset = false;
+}
+
+void hcd_port_reset_end(uint8_t rhport) {
+ (void) rhport;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ switch (rusb->DVSTCTR0_b.RHST) {
+ case RUSB2_DVSTCTR0_RHST_HS: return TUSB_SPEED_HIGH;
+ case RUSB2_DVSTCTR0_RHST_FS: return TUSB_SPEED_FULL;
+ case RUSB2_DVSTCTR0_RHST_LS: return TUSB_SPEED_LOW;
+ default: return TUSB_SPEED_INVALID;
+ }
+}
+
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ uint16_t volatile *ctr;
+
+ TU_ASSERT(dev_addr < 6,); /* USBa can only handle addresses from 0 to 5. */
+ if (!dev_addr) return;
+
+ _hcd.ctl_mps[dev_addr] = 0;
+ uint8_t *ep = &_hcd.ep[dev_addr - 1][0][0];
+
+ for (int i = 0; i < 2 * 15; ++i, ++ep) {
+ unsigned num = *ep;
+ if (!num || (dev_addr != _hcd.pipe[num].dev)) continue;
+
+ ctr = (uint16_t volatile*)&rusb->PIPE_CTR[num - 1];
+ *ctr = 0;
+ rusb->NRDYENB &= ~TU_BIT(num);
+ rusb->BRDYENB &= ~TU_BIT(num);
+ rusb->PIPESEL = num;
+ rusb->PIPECFG = 0;
+ rusb->PIPEMAXP = 0;
+
+ _hcd.pipe[num].ep = 0;
+ _hcd.pipe[num].dev = 0;
+ *ep = 0;
+ }
+}
+
+/*--------------------------------------------------------------------+
+ * Endpoints API
+ *--------------------------------------------------------------------+*/
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ TU_ASSERT(dev_addr < 6); /* USBa can only handle addresses from 0 to 5. */
+
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ TU_LOG(TU_RUSB2_HCD_DBG, "S %d %x\r\n", dev_addr, rusb->DCPCTR);
+
+ TU_ASSERT(0 == rusb->DCPCTR_b.SUREQ);
+
+ rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
+
+ _hcd.pipe[0].buf = NULL;
+ _hcd.pipe[0].length = 8;
+ _hcd.pipe[0].remaining = 0;
+ _hcd.pipe[0].dev = dev_addr;
+
+ while (rusb->DCPCTR_b.PBUSY) ;
+ rusb->DCPMAXP = (dev_addr << 12) | _hcd.ctl_mps[dev_addr];
+
+ /* Set direction in advance for DATA stage */
+ uint8_t const bmRequesttype = setup_packet[0];
+ rusb->DCPCFG_b.DIR = tu_edpt_dir(bmRequesttype) ? 0: 1;
+
+ uint16_t const* p = (uint16_t const*)(uintptr_t)&setup_packet[0];
+ rusb->USBREQ = tu_htole16(p[0]);
+ rusb->USBVAL = p[1];
+ rusb->USBINDX = p[2];
+ rusb->USBLENG = p[3];
+
+ rusb->DCPCTR_b.SUREQ = 1;
+ return true;
+}
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *ep_desc)
+{
+ TU_ASSERT(dev_addr < 6); /* USBa can only handle addresses from 0 to 5. */
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned mps = tu_edpt_packet_size(ep_desc);
+
+ if (0 == epn) {
+ rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
+ hcd_devtree_info_t devtree;
+ hcd_devtree_get_info(dev_addr, &devtree);
+ uint16_t volatile *devadd = (uint16_t volatile *)(uintptr_t) &rusb->DEVADD[0];
+ devadd += dev_addr;
+ while (rusb->DCPCTR_b.PBUSY) {}
+ rusb->DCPMAXP = (dev_addr << 12) | mps;
+ *devadd = (TUSB_SPEED_FULL == devtree.speed) ? RUSB2_DEVADD_USBSPD_FS : RUSB2_DEVADD_USBSPD_LS;
+ _hcd.ctl_mps[dev_addr] = mps;
+ return true;
+ }
+
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ if (xfer == TUSB_XFER_ISOCHRONOUS && mps > 256) {
+ /* USBa supports up to 256 bytes */
+ return false;
+ }
+ const unsigned num = find_pipe(xfer);
+ if (!num) return false;
+
+ _hcd.pipe[num].dev = dev_addr;
+ _hcd.pipe[num].ep = ep_addr;
+ _hcd.ep[dev_addr - 1][dir_in][epn - 1] = num;
+
+ /* setup pipe */
+ hcd_int_disable(rhport);
+
+ rusb->PIPESEL = num;
+ rusb->PIPEMAXP = (dev_addr << 12) | mps;
+ volatile uint16_t *ctr = get_pipectr(rusb, num);
+ *ctr = RUSB2_PIPE_CTR_ACLRM_Msk | RUSB2_PIPE_CTR_SQCLR_Msk;
+ *ctr = 0;
+
+ unsigned cfg = ((1 ^ dir_in) << 4) | epn;
+ if (xfer == TUSB_XFER_BULK) {
+ cfg |= RUSB2_PIPECFG_TYPE_BULK | RUSB2_PIPECFG_SHTNAK_Msk | RUSB2_PIPECFG_DBLB_Msk;
+ } else if (xfer == TUSB_XFER_INTERRUPT) {
+ cfg |= RUSB2_PIPECFG_TYPE_INT;
+ } else {
+ cfg |= RUSB2_PIPECFG_TYPE_ISO | RUSB2_PIPECFG_DBLB_Msk;
+ }
+
+ rusb->PIPECFG = cfg;
+ rusb->BRDYSTS = 0x3FFu ^ TU_BIT(num);
+ rusb->NRDYENB |= TU_BIT(num);
+ rusb->BRDYENB |= TU_BIT(num);
+
+ if (!dir_in) {
+ *ctr = RUSB2_PIPE_CTR_PID_BUF;
+ }
+
+ hcd_int_enable(rhport);
+
+ return true;
+}
+
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ bool r;
+ hcd_int_disable(rhport);
+ TU_LOG(TU_RUSB2_HCD_DBG, "X %d %x %u\r\n", dev_addr, ep_addr, buflen);
+ r = process_edpt_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
+ hcd_int_enable(rhport);
+ return r;
+}
+
+bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+ // TODO not implemented yet
+ return false;
+}
+
+bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ uint16_t volatile *ctr = addr_to_pipectr(rhport, dev_addr, ep_addr);
+ TU_ASSERT(ctr);
+
+ const uint32_t pid = *ctr & 0x3;
+ if (pid & 2) {
+ *ctr = pid & 2;
+ *ctr = 0;
+ }
+ *ctr = RUSB2_PIPE_CTR_SQCLR_Msk;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ if (!epn) return true;
+
+ if (!tu_edpt_dir(ep_addr)) { /* OUT */
+ *ctr = RUSB2_PIPE_CTR_PID_BUF;
+ }
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+#if defined(__CCRX__)
+TU_ATTR_ALWAYS_INLINE static inline unsigned __builtin_ctz(unsigned int value) {
+ unsigned int count = 0;
+ while ((value & 1) == 0) {
+ value >>= 1;
+ count++;
+ }
+ return count;
+}
+#endif
+
+void hcd_int_handler(uint8_t rhport, bool in_isr) {
+ (void) in_isr;
+
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ unsigned is0 = rusb->INTSTS0;
+ unsigned is1 = rusb->INTSTS1;
+
+ /* clear active bits except VALID (don't write 0 to already cleared bits according to the HW manual) */
+ rusb->INTSTS1 = ~((RUSB2_INTSTS1_SACK_Msk | RUSB2_INTSTS1_SIGN_Msk | RUSB2_INTSTS1_ATTCH_Msk | RUSB2_INTSTS1_DTCH_Msk) & is1);
+ rusb->INTSTS0 = ~((RUSB2_INTSTS0_BRDY_Msk | RUSB2_INTSTS0_NRDY_Msk | RUSB2_INTSTS0_BEMP_Msk) & is0);
+
+ TU_LOG3("IS %04x %04x\r\n", is0, is1);
+ is1 &= rusb->INTENB1;
+ is0 &= rusb->INTENB0;
+
+ if (is1 & RUSB2_INTSTS1_SACK_Msk) {
+ /* Set DATA1 in advance for the next transfer. */
+ rusb->DCPCTR_b.SQSET = 1;
+ hcd_event_xfer_complete(rusb->DCPMAXP_b.DEVSEL, tu_edpt_addr(0, TUSB_DIR_OUT), 8, XFER_RESULT_SUCCESS, true);
+ }
+
+ if (is1 & RUSB2_INTSTS1_SIGN_Msk) {
+ hcd_event_xfer_complete(rusb->DCPMAXP_b.DEVSEL, tu_edpt_addr(0, TUSB_DIR_OUT), 8, XFER_RESULT_FAILED, true);
+ }
+
+ if (is1 & RUSB2_INTSTS1_ATTCH_Msk) {
+ rusb->DVSTCTR0_b.UACT = 1;
+ _hcd.need_reset = true;
+ rusb->INTENB1 = (rusb->INTENB1 & ~RUSB2_INTSTS1_ATTCH_Msk) | RUSB2_INTSTS1_DTCH_Msk;
+ hcd_event_device_attach(rhport, true);
+ }
+
+ if (is1 & RUSB2_INTSTS1_DTCH_Msk) {
+ rusb->DVSTCTR0_b.UACT = 0;
+ if (rusb->DCPCTR_b.SUREQ) {
+ rusb->DCPCTR_b.SUREQCLR = 1;
+ }
+ rusb->INTENB1 = (rusb->INTENB1 & ~RUSB2_INTSTS1_DTCH_Msk) | RUSB2_INTSTS1_ATTCH_Msk;
+ hcd_event_device_remove(rhport, true);
+ }
+
+ if (is0 & RUSB2_INTSTS0_BEMP_Msk) {
+ const unsigned s = rusb->BEMPSTS;
+ rusb->BEMPSTS = 0;
+ if (s & 1) {
+ process_pipe0_bemp(rhport);
+ }
+ }
+
+ if (is0 & RUSB2_INTSTS0_NRDY_Msk) {
+ const unsigned m = rusb->NRDYENB;
+ unsigned s = rusb->NRDYSTS & m;
+ rusb->NRDYSTS = ~s;
+ while (s) {
+ const unsigned num = __builtin_ctz(s);
+ process_pipe_nrdy(rhport, num);
+ s &= ~TU_BIT(num);
+ }
+ }
+ if (is0 & RUSB2_INTSTS0_BRDY_Msk) {
+ const unsigned m = rusb->BRDYENB;
+ unsigned s = rusb->BRDYSTS & m;
+ /* clear active bits (don't write 0 to already cleared bits according to the HW manual) */
+ rusb->BRDYSTS = ~s;
+ while (s) {
+ const unsigned num = __builtin_ctz(s);
+ process_pipe_brdy(rhport, num);
+ s &= ~TU_BIT(num);
+ }
+ }
+}
+
+#endif
diff --git a/src/portable/renesas/rusb2/rusb2_common.c b/src/portable/renesas/rusb2/rusb2_common.c
new file mode 100644
index 000000000..850060777
--- /dev/null
+++ b/src/portable/renesas/rusb2/rusb2_common.c
@@ -0,0 +1,61 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if defined(TUP_USBIP_RUSB2) && (CFG_TUH_ENABLED || CFG_TUD_ENABLED)
+
+#include "rusb2_type.h"
+
+#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
+#include "rusb2_rx.h"
+
+#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
+#include "rusb2_ra.h"
+
+// USBFS_INT_IRQn and USBHS_USB_INT_RESUME_IRQn are generated by FSP
+rusb2_controller_t rusb2_controller[] = {
+ { .reg_base = R_USB_FS0_BASE, .irqnum = USBFS_INT_IRQn },
+ #ifdef RUSB2_SUPPORT_HIGHSPEED
+ { .reg_base = R_USB_HS0_BASE, .irqnum = USBHS_USB_INT_RESUME_IRQn },
+ #endif
+};
+
+// Application API for setting IRQ number. May throw warnings for missing prototypes.
+void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum) {
+ rusb2_controller[rhport].irqnum = irqnum;
+}
+
+// void osal_task_delay(uint32_t msec) {
+// R_BSP_SoftwareDelay(msec, BSP_DELAY_UNITS_MILLISECONDS);
+// }
+
+#else
+ #error "Unsupported MCU"
+#endif
+
+
+#endif
diff --git a/src/portable/renesas/rusb2/rusb2_ra.h b/src/portable/renesas/rusb2/rusb2_ra.h
new file mode 100644
index 000000000..4774d2e2c
--- /dev/null
+++ b/src/portable/renesas/rusb2/rusb2_ra.h
@@ -0,0 +1,109 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Rafael Silva (@perigoso)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _RUSB2_RA_H_
+#define _RUSB2_RA_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#pragma GCC diagnostic ignored "-Wundef"
+
+// extra push due to https://github.com/renesas/fsp/pull/278
+#pragma GCC diagnostic push
+#endif
+
+/* renesas fsp api */
+#include "bsp_api.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+// IAR does not have __builtin_ctz
+#if defined(__ICCARM__)
+ #define __builtin_ctz(x) __iar_builtin_CLZ(__iar_builtin_RBIT(x))
+#endif
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+typedef struct {
+ uint32_t reg_base;
+ int32_t irqnum;
+}rusb2_controller_t;
+
+#if defined(BSP_MCU_GROUP_RA6M5) || defined(BSP_MCU_GROUP_RA6M3) || (BSP_CFG_MCU_PART_SERIES == 8)
+ #define RUSB2_SUPPORT_HIGHSPEED
+ #define RUSB2_CONTROLLER_COUNT 2
+
+ #define rusb2_is_highspeed_rhport(_p) (_p == 1)
+ #define rusb2_is_highspeed_reg(_reg) (_reg == RUSB2_REG(1))
+#else
+ #define RUSB2_CONTROLLER_COUNT 1
+
+ #define rusb2_is_highspeed_rhport(_p) (false)
+ #define rusb2_is_highspeed_reg(_reg) (false)
+#endif
+
+extern rusb2_controller_t rusb2_controller[];
+#define RUSB2_REG(_p) ((rusb2_reg_t*) rusb2_controller[_p].reg_base)
+
+//--------------------------------------------------------------------+
+// RUSB2 API
+//--------------------------------------------------------------------+
+
+TU_ATTR_ALWAYS_INLINE static inline void rusb2_module_start(uint8_t rhport, bool start) {
+ uint32_t const mask = 1U << (11+rhport);
+ if (start) {
+ R_MSTP->MSTPCRB &= ~mask;
+ }else {
+ R_MSTP->MSTPCRB |= mask;
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_enable(uint8_t rhport) {
+ NVIC_EnableIRQ(rusb2_controller[rhport].irqnum);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_disable(uint8_t rhport) {
+ NVIC_DisableIRQ(rusb2_controller[rhport].irqnum);
+}
+
+// MCU specific PHY init
+TU_ATTR_ALWAYS_INLINE static inline void rusb2_phy_init(void) {
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RUSB2_RA_H_ */
diff --git a/src/portable/renesas/rusb2/rusb2_rx.h b/src/portable/renesas/rusb2/rusb2_rx.h
new file mode 100644
index 000000000..7bf4be47e
--- /dev/null
+++ b/src/portable/renesas/rusb2/rusb2_rx.h
@@ -0,0 +1,94 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Koji Kitayama
+ * Portions copyrighted (c) 2021 Roland Winistoerfer
+ * Copyright (c) 2022 Rafael Silva (@perigoso)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _RUSB2_RX_H_
+#define _RUSB2_RX_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "iodefine.h"
+
+#define RUSB2_REG_BASE (0x000A0000)
+
+TU_ATTR_ALWAYS_INLINE static inline rusb2_reg_t* RUSB2_REG(uint8_t rhport) {
+ (void) rhport;
+ return (rusb2_reg_t *) RUSB2_REG_BASE;
+}
+
+
+#define rusb2_is_highspeed_rhport(_p) (false)
+#define rusb2_is_highspeed_reg(_reg) (false)
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+
+// Start/Stop MSTP TODO implement later
+TU_ATTR_ALWAYS_INLINE static inline void rusb2_module_start(uint8_t rhport, bool start) {
+ (void) rhport;
+ (void) start;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_enable(uint8_t rhport)
+{
+ (void) rhport;
+#if (CFG_TUSB_MCU == OPT_MCU_RX72N)
+ IEN(PERIB, INTB185) = 1;
+#else
+ IEN(USB0, USBI0) = 1;
+#endif
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_disable(uint8_t rhport)
+{
+ (void) rhport;
+#if (CFG_TUSB_MCU == OPT_MCU_RX72N)
+ IEN(PERIB, INTB185) = 0;
+#else
+ IEN(USB0, USBI0) = 0;
+#endif
+}
+
+// MCU specific PHY init
+TU_ATTR_ALWAYS_INLINE static inline void rusb2_phy_init(void)
+{
+#if (CFG_TUSB_MCU == OPT_MCU_RX72N)
+ IR(PERIB, INTB185) = 0;
+#else
+ IR(USB0, USBI0) = 0;
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RUSB2_RX_H_ */
diff --git a/src/portable/renesas/rusb2/rusb2_type.h b/src/portable/renesas/rusb2/rusb2_type.h
new file mode 100644
index 000000000..dd88f66a7
--- /dev/null
+++ b/src/portable/renesas/rusb2/rusb2_type.h
@@ -0,0 +1,1780 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Rafael Silva (@perigoso)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_RUSB2_TYPE_H_
+#define _TUSB_RUSB2_TYPE_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// CCRX specific attribute to generate a Code that Accesses Variables in the Declared Size
+#ifdef __CCRX__
+ #define _ccrx_evenaccess __evenaccess
+#else
+ #define _ccrx_evenaccess
+#endif
+
+/*--------------------------------------------------------------------*/
+/* Register Definitions */
+/*--------------------------------------------------------------------*/
+
+/* Start of definition of packed structs (used by the CCRX toolchain) */
+TU_ATTR_PACKED_BEGIN
+TU_ATTR_BIT_FIELD_ORDER_BEGIN
+
+// TODO same as RUSB2_PIPE_TR_t
+typedef struct TU_ATTR_PACKED _ccrx_evenaccess {
+ union {
+ struct {
+ uint16_t : 8;
+ uint16_t TRCLR: 1;
+ uint16_t TRENB: 1;
+ uint16_t : 0;
+ };
+ uint16_t TRE;
+ };
+ uint16_t TRN;
+} reg_pipetre_t;
+
+typedef struct {
+ union {
+ volatile uint16_t E; /* (@ 0x00000000) Pipe Transaction Counter Enable Register */
+
+ struct TU_ATTR_PACKED {
+ uint16_t : 8;
+ volatile uint16_t TRCLR : 1; /* [8..8] Transaction Counter Clear */
+ volatile uint16_t TRENB : 1; /* [9..9] Transaction Counter Enable */
+ uint16_t : 6;
+ } E_b;
+ };
+
+ union {
+ volatile uint16_t N; /* (@ 0x00000002) Pipe Transaction Counter Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t TRNCNT : 16; /* [15..0] Transaction Counter */
+ } N_b;
+ };
+} RUSB2_PIPE_TR_t; /* Size = 4 (0x4) */
+
+
+/* RUSB2 Registers Structure */
+typedef struct _ccrx_evenaccess {
+ union {
+ volatile uint16_t SYSCFG; /* (@ 0x00000000) System Configuration Control Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t USBE : 1; /* [0..0] USB Operation Enable */
+ uint16_t : 2;
+ volatile uint16_t DMRPU : 1; /* [3..3] D- Line Resistor Control */
+ volatile uint16_t DPRPU : 1; /* [4..4] D+ Line Resistor Control */
+ volatile uint16_t DRPD : 1; /* [5..5] D+/D- Line Resistor Control */
+ volatile uint16_t DCFM : 1; /* [6..6] Controller Function Select */
+ volatile uint16_t HSE : 1; // [7..7] High-Speed Operation Enable
+ volatile uint16_t CNEN : 1; /* [8..8] CNEN Single End Receiver Enable */
+ uint16_t : 1;
+ volatile uint16_t SCKE : 1; /* [10..10] USB Clock Enable */
+ uint16_t : 5;
+ } SYSCFG_b;
+ };
+
+ union {
+ volatile uint16_t BUSWAIT; /* (@ 0x00000002) CPU Bus Wait Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t BWAIT : 4; /* [3..0] CPU Bus Access Wait Specification BWAIT waits (BWAIT+2 access cycles) */
+ uint16_t : 12;
+ } BUSWAIT_b;
+ };
+
+ union {
+ volatile const uint16_t SYSSTS0; /* (@ 0x00000004) System Configuration Status Register 0 */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint16_t LNST : 2; /* [1..0] USB Data Line Status Monitor */
+ volatile const uint16_t IDMON : 1; /* [2..2] External ID0 Input Pin Monitor */
+ uint16_t : 2;
+ volatile const uint16_t SOFEA : 1; /* [5..5] SOF Active Monitor While Host Controller Function is Selected. */
+ volatile const uint16_t HTACT : 1; /* [6..6] USB Host Sequencer Status Monitor */
+ uint16_t : 7;
+ volatile const uint16_t OVCMON : 2; /* [15..14] External USB0_OVRCURA/ USB0_OVRCURB Input Pin Monitor */
+ } SYSSTS0_b;
+ };
+
+ union {
+ volatile const uint16_t PLLSTA; /* (@ 0x00000006) PLL Status Register */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint16_t PLLLOCK : 1; /* [0..0] PLL Lock Flag */
+ uint16_t : 15;
+ } PLLSTA_b;
+ };
+
+ union {
+ volatile uint16_t DVSTCTR0; /* (@ 0x00000008) Device State Control Register 0 */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint16_t RHST : 3; /* [2..0] USB Bus Reset Status */
+ uint16_t : 1;
+ volatile uint16_t UACT : 1; /* [4..4] USB Bus Enable */
+ volatile uint16_t RESUME : 1; /* [5..5] Resume Output */
+ volatile uint16_t USBRST : 1; /* [6..6] USB Bus Reset Output */
+ volatile uint16_t RWUPE : 1; /* [7..7] Wakeup Detection Enable */
+ volatile uint16_t WKUP : 1; /* [8..8] Wakeup Output */
+ volatile uint16_t VBUSEN : 1; /* [9..9] USB_VBUSEN Output Pin Control */
+ volatile uint16_t EXICEN : 1; /* [10..10] USB_EXICEN Output Pin Control */
+ volatile uint16_t HNPBTOA : 1; /* [11..11] Host Negotiation Protocol (HNP) */
+ uint16_t : 4;
+ } DVSTCTR0_b;
+ };
+ volatile const uint16_t RESERVED;
+
+ union {
+ volatile uint16_t TESTMODE; /* (@ 0x0000000C) USB Test Mode Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t UTST : 4; /* [3..0] Test Mode */
+ uint16_t : 12;
+ } TESTMODE_b;
+ };
+ volatile const uint16_t RESERVED1;
+ volatile const uint32_t RESERVED2;
+
+ union {
+ volatile uint32_t CFIFO; /* (@ 0x00000014) CFIFO Port Register */
+
+ struct TU_ATTR_PACKED {
+ union {
+ volatile uint16_t CFIFOL; /* (@ 0x00000014) CFIFO Port Register L */
+ volatile uint8_t CFIFOLL; /* (@ 0x00000014) CFIFO Port Register LL */
+ };
+
+ union {
+ volatile uint16_t CFIFOH; /* (@ 0x00000016) CFIFO Port Register H */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint8_t RESERVED3;
+ volatile uint8_t CFIFOHH; /* (@ 0x00000017) CFIFO Port Register HH */
+ };
+ };
+ };
+ };
+
+ union {
+ volatile uint32_t D0FIFO; /* (@ 0x00000018) D0FIFO Port Register */
+
+ struct TU_ATTR_PACKED {
+ union {
+ volatile uint16_t D0FIFOL; /* (@ 0x00000018) D0FIFO Port Register L */
+ volatile uint8_t D0FIFOLL; /* (@ 0x00000018) D0FIFO Port Register LL */
+ };
+
+ union {
+ volatile uint16_t D0FIFOH; /* (@ 0x0000001A) D0FIFO Port Register H */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint8_t RESERVED4;
+ volatile uint8_t D0FIFOHH; /* (@ 0x0000001B) D0FIFO Port Register HH */
+ };
+ };
+ };
+ };
+
+ union {
+ volatile uint32_t D1FIFO; /* (@ 0x0000001C) D1FIFO Port Register */
+
+ struct TU_ATTR_PACKED {
+ union {
+ volatile uint16_t D1FIFOL; /* (@ 0x0000001C) D1FIFO Port Register L */
+ volatile uint8_t D1FIFOLL; /* (@ 0x0000001C) D1FIFO Port Register LL */
+ };
+
+ union {
+ volatile uint16_t D1FIFOH; /* (@ 0x0000001E) D1FIFO Port Register H */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint8_t RESERVED5;
+ volatile uint8_t D1FIFOHH; /* (@ 0x0000001F) D1FIFO Port Register HH */
+ };
+ };
+ };
+ };
+
+ union {
+ volatile uint16_t CFIFOSEL; /* (@ 0x00000020) CFIFO Port Select Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t CURPIPE : 4; /* [3..0] CFIFO Port Access Pipe Specification */
+ uint16_t : 1;
+ volatile uint16_t ISEL : 1; /* [5..5] CFIFO Port Access Direction When DCP is Selected */
+ uint16_t : 2;
+ volatile uint16_t BIGEND : 1; /* [8..8] CFIFO Port Endian Control */
+ uint16_t : 1;
+ volatile uint16_t MBW : 2; /* [11..10] CFIFO Port Access Bit Width */
+ uint16_t : 2;
+ volatile uint16_t REW : 1; /* [14..14] Buffer Pointer Rewind */
+ volatile uint16_t RCNT : 1; /* [15..15] Read Count Mode */
+ } CFIFOSEL_b;
+ };
+
+ union {
+ volatile uint16_t CFIFOCTR; /* (@ 0x00000022) CFIFO Port Control Register */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint16_t DTLN : 12; /* [11..0] Receive Data LengthIndicates the length of the receive data. */
+ uint16_t : 1;
+ volatile const uint16_t FRDY : 1; /* [13..13] FIFO Port Ready */
+ volatile uint16_t BCLR : 1; /* [14..14] CPU Buffer ClearNote: Only 0 can be read. */
+ volatile uint16_t BVAL : 1; /* [15..15] Buffer Memory Valid Flag */
+ } CFIFOCTR_b;
+ };
+ volatile const uint32_t RESERVED6;
+
+ union {
+ volatile uint16_t D0FIFOSEL; /* (@ 0x00000028) D0FIFO Port Select Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t CURPIPE : 4; /* [3..0] FIFO Port Access Pipe Specification */
+ uint16_t : 4;
+ volatile uint16_t BIGEND : 1; /* [8..8] FIFO Port Endian Control */
+ uint16_t : 1;
+ volatile uint16_t MBW : 2; /* [11..10] FIFO Port Access Bit Width */
+ volatile uint16_t DREQE : 1; /* [12..12] DMA/DTC Transfer Request Enable */
+ volatile uint16_t DCLRM : 1; /* [13..13] Auto Buffer Memory Clear Mode Accessed after Specified Pipe Data is Read */
+ volatile uint16_t REW : 1; /* [14..14] Buffer Pointer RewindNote: Only 0 can be read. */
+ volatile uint16_t RCNT : 1; /* [15..15] Read Count Mode */
+ } D0FIFOSEL_b;
+ };
+
+ union {
+ volatile uint16_t D0FIFOCTR; /* (@ 0x0000002A) D0FIFO Port Control Register */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint16_t DTLN : 12; /* [11..0] Receive Data LengthIndicates the length of the receive data. */
+ uint16_t : 1;
+ volatile const uint16_t FRDY : 1; /* [13..13] FIFO Port Ready */
+ volatile uint16_t BCLR : 1; /* [14..14] CPU Buffer ClearNote: Only 0 can be read. */
+ volatile uint16_t BVAL : 1; /* [15..15] Buffer Memory Valid Flag */
+ } D0FIFOCTR_b;
+ };
+
+ union {
+ volatile uint16_t D1FIFOSEL; /* (@ 0x0000002C) D1FIFO Port Select Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t CURPIPE : 4; /* [3..0] FIFO Port Access Pipe Specification */
+ uint16_t : 4;
+ volatile uint16_t BIGEND : 1; /* [8..8] FIFO Port Endian Control */
+ uint16_t : 1;
+ volatile uint16_t MBW : 2; /* [11..10] FIFO Port Access Bit Width */
+ volatile uint16_t DREQE : 1; /* [12..12] DMA/DTC Transfer Request Enable */
+ volatile uint16_t DCLRM : 1; /* [13..13] Auto Buffer Memory Clear Mode Accessed after Specified Pipe Data is Read */
+ volatile uint16_t REW : 1; /* [14..14] Buffer Pointer Rewind */
+ volatile uint16_t RCNT : 1; /* [15..15] Read Count Mode */
+ } D1FIFOSEL_b;
+ };
+
+ union {
+ volatile uint16_t D1FIFOCTR; /* (@ 0x0000002E) D1FIFO Port Control Register */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint16_t DTLN : 12; /* [11..0] Receive Data LengthIndicates the length of the receive data. */
+ uint16_t : 1;
+ volatile const uint16_t FRDY : 1; /* [13..13] FIFO Port Ready */
+ volatile uint16_t BCLR : 1; /* [14..14] CPU Buffer ClearNote: Only 0 can be read. */
+ volatile uint16_t BVAL : 1; /* [15..15] Buffer Memory Valid Flag */
+ } D1FIFOCTR_b;
+ };
+
+ union {
+ volatile uint16_t INTENB0; /* (@ 0x00000030) Interrupt Enable Register 0 */
+
+ struct TU_ATTR_PACKED {
+ uint16_t : 8;
+ volatile uint16_t BRDYE : 1; /* [8..8] Buffer Ready Interrupt Enable */
+ volatile uint16_t NRDYE : 1; /* [9..9] Buffer Not Ready Response Interrupt Enable */
+ volatile uint16_t BEMPE : 1; /* [10..10] Buffer Empty Interrupt Enable */
+ volatile uint16_t CTRE : 1; /* [11..11] Control Transfer Stage Transition Interrupt Enable */
+ volatile uint16_t DVSE : 1; /* [12..12] Device State Transition Interrupt Enable */
+ volatile uint16_t SOFE : 1; /* [13..13] Frame Number Update Interrupt Enable */
+ volatile uint16_t RSME : 1; /* [14..14] Resume Interrupt Enable */
+ volatile uint16_t VBSE : 1; /* [15..15] VBUS Interrupt Enable */
+ } INTENB0_b;
+ };
+
+ union {
+ volatile uint16_t INTENB1; /* (@ 0x00000032) Interrupt Enable Register 1 */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t PDDETINTE0 : 1; /* [0..0] PDDETINT0 Detection Interrupt Enable */
+ uint16_t : 3;
+ volatile uint16_t SACKE : 1; /* [4..4] Setup Transaction Normal Response Interrupt Enable */
+ volatile uint16_t SIGNE : 1; /* [5..5] Setup Transaction Error Interrupt Enable */
+ volatile uint16_t EOFERRE : 1; /* [6..6] EOF Error Detection Interrupt Enable */
+ uint16_t : 1;
+ volatile uint16_t LPMENDE : 1; /*!< [8..8] LPM Transaction End Interrupt Enable */
+ volatile uint16_t L1RSMENDE : 1; /*!< [9..9] L1 Resume End Interrupt Enable */
+ uint16_t : 1;
+ volatile uint16_t ATTCHE : 1; /* [11..11] Connection Detection Interrupt Enable */
+ volatile uint16_t DTCHE : 1; /* [12..12] Disconnection Detection Interrupt Enable */
+ uint16_t : 1;
+ volatile uint16_t BCHGE : 1; /* [14..14] USB Bus Change Interrupt Enable */
+ volatile uint16_t OVRCRE : 1; /* [15..15] Overcurrent Input Change Interrupt Enable */
+ } INTENB1_b;
+ };
+ volatile const uint16_t RESERVED7;
+
+ union {
+ volatile uint16_t BRDYENB; /* (@ 0x00000036) BRDY Interrupt Enable Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t PIPE0BRDYE : 1; /* [0..0] BRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE1BRDYE : 1; /* [1..1] BRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE2BRDYE : 1; /* [2..2] BRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE3BRDYE : 1; /* [3..3] BRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE4BRDYE : 1; /* [4..4] BRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE5BRDYE : 1; /* [5..5] BRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE6BRDYE : 1; /* [6..6] BRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE7BRDYE : 1; /* [7..7] BRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE8BRDYE : 1; /* [8..8] BRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE9BRDYE : 1; /* [9..9] BRDY Interrupt Enable for PIPE */
+ uint16_t : 6;
+ } BRDYENB_b;
+ };
+
+ union {
+ volatile uint16_t NRDYENB; /* (@ 0x00000038) NRDY Interrupt Enable Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t PIPE0NRDYE : 1; /* [0..0] NRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE1NRDYE : 1; /* [1..1] NRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE2NRDYE : 1; /* [2..2] NRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE3NRDYE : 1; /* [3..3] NRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE4NRDYE : 1; /* [4..4] NRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE5NRDYE : 1; /* [5..5] NRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE6NRDYE : 1; /* [6..6] NRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE7NRDYE : 1; /* [7..7] NRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE8NRDYE : 1; /* [8..8] NRDY Interrupt Enable for PIPE */
+ volatile uint16_t PIPE9NRDYE : 1; /* [9..9] NRDY Interrupt Enable for PIPE */
+ uint16_t : 6;
+ } NRDYENB_b;
+ };
+
+ union {
+ volatile uint16_t BEMPENB; /* (@ 0x0000003A) BEMP Interrupt Enable Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t PIPE0BEMPE : 1; /* [0..0] BEMP Interrupt Enable for PIPE */
+ volatile uint16_t PIPE1BEMPE : 1; /* [1..1] BEMP Interrupt Enable for PIPE */
+ volatile uint16_t PIPE2BEMPE : 1; /* [2..2] BEMP Interrupt Enable for PIPE */
+ volatile uint16_t PIPE3BEMPE : 1; /* [3..3] BEMP Interrupt Enable for PIPE */
+ volatile uint16_t PIPE4BEMPE : 1; /* [4..4] BEMP Interrupt Enable for PIPE */
+ volatile uint16_t PIPE5BEMPE : 1; /* [5..5] BEMP Interrupt Enable for PIPE */
+ volatile uint16_t PIPE6BEMPE : 1; /* [6..6] BEMP Interrupt Enable for PIPE */
+ volatile uint16_t PIPE7BEMPE : 1; /* [7..7] BEMP Interrupt Enable for PIPE */
+ volatile uint16_t PIPE8BEMPE : 1; /* [8..8] BEMP Interrupt Enable for PIPE */
+ volatile uint16_t PIPE9BEMPE : 1; /* [9..9] BEMP Interrupt Enable for PIPE */
+ uint16_t : 6;
+ } BEMPENB_b;
+ };
+
+ union {
+ volatile uint16_t SOFCFG; /* (@ 0x0000003C) SOF Output Configuration Register */
+
+ struct TU_ATTR_PACKED {
+ uint16_t : 4;
+ volatile const uint16_t EDGESTS : 1; /* [4..4] Edge Interrupt Output Status Monitor */
+ volatile uint16_t INTL : 1; /* [5..5] Interrupt Output Sense Select */
+ volatile uint16_t BRDYM : 1; /* [6..6] BRDY Interrupt Status Clear Timing */
+ uint16_t : 1;
+ volatile uint16_t TRNENSEL : 1; /* [8..8] Transaction-Enabled Time Select */
+ uint16_t : 7;
+ } SOFCFG_b;
+ };
+
+ union {
+ volatile uint16_t PHYSET; /* (@ 0x0000003E) PHY Setting Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t DIRPD : 1; /* [0..0] Power-Down Control */
+ volatile uint16_t PLLRESET : 1; /* [1..1] PLL Reset Control */
+ uint16_t : 1;
+ volatile uint16_t CDPEN : 1; /* [3..3] Charging Downstream Port Enable */
+ volatile uint16_t CLKSEL : 2; /* [5..4] Input System Clock Frequency */
+ uint16_t : 2;
+ volatile uint16_t REPSEL : 2; /* [9..8] Terminating Resistance Adjustment Cycle */
+ uint16_t : 1;
+ volatile uint16_t REPSTART : 1; /* [11..11] Forcibly Start Terminating Resistance Adjustment */
+ uint16_t : 3;
+ volatile uint16_t HSEB : 1; /* [15..15] CL-Only Mode */
+ } PHYSET_b;
+ };
+
+ union {
+ volatile uint16_t INTSTS0; /* (@ 0x00000040) Interrupt Status Register 0 */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint16_t CTSQ : 3; /* [2..0] Control Transfer Stage */
+ volatile uint16_t VALID : 1; /* [3..3] USB Request Reception */
+ volatile const uint16_t DVSQ : 3; /* [6..4] Device State */
+ volatile const uint16_t VBSTS : 1; /* [7..7] VBUS Input Status */
+ volatile const uint16_t BRDY : 1; /* [8..8] Buffer Ready Interrupt Status */
+ volatile const uint16_t NRDY : 1; /* [9..9] Buffer Not Ready Interrupt Status */
+ volatile const uint16_t BEMP : 1; /* [10..10] Buffer Empty Interrupt Status */
+ volatile uint16_t CTRT : 1; /* [11..11] Control Transfer Stage Transition Interrupt Status */
+ volatile uint16_t DVST : 1; /* [12..12] Device State Transition Interrupt Status */
+ volatile uint16_t SOFR : 1; /* [13..13] Frame Number Refresh Interrupt Status */
+ volatile uint16_t RESM : 1; /* [14..14] Resume Interrupt Status */
+ volatile uint16_t VBINT : 1; /* [15..15] VBUS Interrupt Status */
+ } INTSTS0_b;
+ };
+
+ union {
+ volatile uint16_t INTSTS1; /* (@ 0x00000042) Interrupt Status Register 1 */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t PDDETINT0 : 1; /* [0..0] PDDET0 Detection Interrupt Status */
+ uint16_t : 3;
+ volatile uint16_t SACK : 1; /* [4..4] Setup Transaction Normal Response Interrupt Status */
+ volatile uint16_t SIGN : 1; /* [5..5] Setup Transaction Error Interrupt Status */
+ volatile uint16_t EOFERR : 1; /* [6..6] EOF Error Detection Interrupt Status */
+ uint16_t : 1;
+ volatile uint16_t LPMEND : 1; /* [8..8] LPM Transaction End Interrupt Status */
+ volatile uint16_t L1RSMEND : 1; /* [9..9] L1 Resume End Interrupt Status */
+ uint16_t : 1;
+ volatile uint16_t ATTCH : 1; /* [11..11] ATTCH Interrupt Status */
+ volatile uint16_t DTCH : 1; /* [12..12] USB Disconnection Detection Interrupt Status */
+ uint16_t : 1;
+ volatile uint16_t BCHG : 1; /* [14..14] USB Bus Change Interrupt Status */
+ volatile uint16_t OVRCR : 1; /* [15..15] Overcurrent Input Change Interrupt Status */
+ } INTSTS1_b;
+ };
+ volatile const uint16_t RESERVED8;
+
+ union {
+ volatile uint16_t BRDYSTS; /* (@ 0x00000046) BRDY Interrupt Status Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t PIPE0BRDY : 1; /* [0..0] BRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE1BRDY : 1; /* [1..1] BRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE2BRDY : 1; /* [2..2] BRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE3BRDY : 1; /* [3..3] BRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE4BRDY : 1; /* [4..4] BRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE5BRDY : 1; /* [5..5] BRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE6BRDY : 1; /* [6..6] BRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE7BRDY : 1; /* [7..7] BRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE8BRDY : 1; /* [8..8] BRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE9BRDY : 1; /* [9..9] BRDY Interrupt Status for PIPE */
+ uint16_t : 6;
+ } BRDYSTS_b;
+ };
+
+ union {
+ volatile uint16_t NRDYSTS; /* (@ 0x00000048) NRDY Interrupt Status Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t PIPE0NRDY : 1; /* [0..0] NRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE1NRDY : 1; /* [1..1] NRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE2NRDY : 1; /* [2..2] NRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE3NRDY : 1; /* [3..3] NRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE4NRDY : 1; /* [4..4] NRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE5NRDY : 1; /* [5..5] NRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE6NRDY : 1; /* [6..6] NRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE7NRDY : 1; /* [7..7] NRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE8NRDY : 1; /* [8..8] NRDY Interrupt Status for PIPE */
+ volatile uint16_t PIPE9NRDY : 1; /* [9..9] NRDY Interrupt Status for PIPE */
+ uint16_t : 6;
+ } NRDYSTS_b;
+ };
+
+ union {
+ volatile uint16_t BEMPSTS; /* (@ 0x0000004A) BEMP Interrupt Status Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t PIPE0BEMP : 1; /* [0..0] BEMP Interrupt Status for PIPE */
+ volatile uint16_t PIPE1BEMP : 1; /* [1..1] BEMP Interrupt Status for PIPE */
+ volatile uint16_t PIPE2BEMP : 1; /* [2..2] BEMP Interrupt Status for PIPE */
+ volatile uint16_t PIPE3BEMP : 1; /* [3..3] BEMP Interrupt Status for PIPE */
+ volatile uint16_t PIPE4BEMP : 1; /* [4..4] BEMP Interrupt Status for PIPE */
+ volatile uint16_t PIPE5BEMP : 1; /* [5..5] BEMP Interrupt Status for PIPE */
+ volatile uint16_t PIPE6BEMP : 1; /* [6..6] BEMP Interrupt Status for PIPE */
+ volatile uint16_t PIPE7BEMP : 1; /* [7..7] BEMP Interrupt Status for PIPE */
+ volatile uint16_t PIPE8BEMP : 1; /* [8..8] BEMP Interrupt Status for PIPE */
+ volatile uint16_t PIPE9BEMP : 1; /* [9..9] BEMP Interrupt Status for PIPE */
+ uint16_t : 6;
+ } BEMPSTS_b;
+ };
+
+ union {
+ volatile uint16_t FRMNUM; /* (@ 0x0000004C) Frame Number Register */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint16_t FRNM : 11; /* [10..0] Frame NumberLatest frame number */
+ uint16_t : 3;
+ volatile uint16_t CRCE : 1; /* [14..14] Receive Data Error */
+ volatile uint16_t OVRN : 1; /* [15..15] Overrun/Underrun Detection Status */
+ } FRMNUM_b;
+ };
+
+ union {
+ volatile uint16_t UFRMNUM; /* (@ 0x0000004E) uFrame Number Register */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint16_t UFRNM : 3; /* [2..0] MicroframeIndicate the microframe number. */
+ uint16_t : 12;
+ volatile uint16_t DVCHG : 1; /* [15..15] Device State Change */
+ } UFRMNUM_b;
+ };
+
+ union {
+ volatile uint16_t USBADDR; /* (@ 0x00000050) USB Address Register */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint16_t USBADDR : 7; /* [6..0] USB Address In device controller mode */
+ uint16_t : 1;
+ volatile uint16_t STSRECOV0 : 3; /* [10..8] Status Recovery */
+ uint16_t : 5;
+ } USBADDR_b;
+ };
+ volatile const uint16_t RESERVED9;
+
+ union {
+ volatile uint16_t USBREQ; /* (@ 0x00000054) USB Request Type Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t BMREQUESTTYPE : 8; /* [7..0] Request TypeThese bits store the USB request bmRequestType value. */
+ volatile uint16_t BREQUEST : 8; /* [15..8] RequestThese bits store the USB request bRequest value. */
+ } USBREQ_b;
+ };
+
+ union {
+ volatile uint16_t USBVAL; /* (@ 0x00000056) USB Request Value Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t WVALUE : 16; /* [15..0] ValueThese bits store the USB request Value value. */
+ } USBVAL_b;
+ };
+
+ union {
+ volatile uint16_t USBINDX; /* (@ 0x00000058) USB Request Index Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t WINDEX : 16; /* [15..0] IndexThese bits store the USB request wIndex value. */
+ } USBINDX_b;
+ };
+
+ union {
+ volatile uint16_t USBLENG; /* (@ 0x0000005A) USB Request Length Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t WLENGTH : 16; /* [15..0] LengthThese bits store the USB request wLength value. */
+ } USBLENG_b;
+ };
+
+ union {
+ volatile uint16_t DCPCFG; /* (@ 0x0000005C) DCP Configuration Register */
+
+ struct TU_ATTR_PACKED {
+ uint16_t : 4;
+ volatile uint16_t DIR : 1; /* [4..4] Transfer Direction */
+ uint16_t : 2;
+ volatile uint16_t SHTNAK : 1; /* [7..7] Pipe Disabled at End of Transfer */
+ volatile uint16_t CNTMD : 1; /* [8..8] Continuous Transfer Mode */
+ uint16_t : 7;
+ } DCPCFG_b;
+ };
+
+ union {
+ volatile uint16_t DCPMAXP; /* (@ 0x0000005E) DCP Maximum Packet Size Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t MXPS : 7; /* [6..0] Maximum Packet Size */
+ uint16_t : 5;
+ volatile uint16_t DEVSEL : 4; /* [15..12] Device Select */
+ } DCPMAXP_b;
+ };
+
+ union {
+ volatile uint16_t DCPCTR; /* (@ 0x00000060) DCP Control Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t PID : 2; /* [1..0] Response PID */
+ volatile uint16_t CCPL : 1; /* [2..2] Control Transfer End Enable */
+ uint16_t : 2;
+ volatile const uint16_t PBUSY : 1; /* [5..5] Pipe Busy */
+ volatile const uint16_t SQMON : 1; /* [6..6] Sequence Toggle Bit Monitor */
+ volatile uint16_t SQSET : 1; /* [7..7] Sequence Toggle Bit Set */
+ volatile uint16_t SQCLR : 1; /* [8..8] Sequence Toggle Bit Clear */
+ uint16_t : 2;
+ volatile uint16_t SUREQCLR : 1; /* [11..11] SUREQ Bit Clear */
+ volatile uint16_t CSSTS : 1; /* [12..12] Split Transaction COMPLETE SPLIT(CSPLIT) Status */
+ volatile uint16_t CSCLR : 1; /* [13..13] Split Transaction CSPLIT Status Clear */
+ volatile uint16_t SUREQ : 1; /* [14..14] Setup Token Transmission */
+ volatile const uint16_t BSTS : 1; /* [15..15] Buffer Status */
+ } DCPCTR_b;
+ };
+ volatile const uint16_t RESERVED10;
+
+ union {
+ volatile uint16_t PIPESEL; /* (@ 0x00000064) Pipe Window Select Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t PIPESEL : 4; /* [3..0] Pipe Window Select */
+ uint16_t : 12;
+ } PIPESEL_b;
+ };
+ volatile const uint16_t RESERVED11;
+
+ union {
+ volatile uint16_t PIPECFG; /* (@ 0x00000068) Pipe Configuration Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t EPNUM : 4; /* [3..0] Endpoint Number */
+ volatile uint16_t DIR : 1; /* [4..4] Transfer Direction */
+ uint16_t : 2;
+ volatile uint16_t SHTNAK : 1; /* [7..7] Pipe Disabled at End of Transfer */
+ volatile uint16_t CNTMD : 1; /* [8..8] Continuous Transfer Mode */
+ volatile uint16_t DBLB : 1; /* [9..9] Double Buffer Mode */
+ volatile uint16_t BFRE : 1; /* [10..10] BRDY Interrupt Operation Specification */
+ uint16_t : 3;
+ volatile uint16_t TYPE : 2; /* [15..14] Transfer Type */
+ } PIPECFG_b;
+ };
+
+ union {
+ volatile uint16_t PIPEBUF; /*!< (@ 0x0000006A) Pipe Buffer Register */
+
+ struct {
+ volatile uint16_t BUFNMB : 8; // [7..0] Buffer NumberThese bits specify the FIFO buffer number of the selected pipe (04h to 87h)
+ uint16_t : 2;
+ volatile uint16_t BUFSIZE : 5; /*!< [14..10] Buffer Size 00h: 64 bytes 01h: 128 bytes : 1Fh: 2 Kbytes */
+ uint16_t : 1;
+ } PIPEBUF_b;
+ };
+
+ union {
+ volatile uint16_t PIPEMAXP; /* (@ 0x0000006C) Pipe Maximum Packet Size Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t MXPS : 11; /* [10..0] Maximum Packet Size */
+ uint16_t : 1;
+ volatile uint16_t DEVSEL : 4; /* [15..12] Device Select */
+ } PIPEMAXP_b;
+ };
+
+ union {
+ volatile uint16_t PIPEPERI; /* (@ 0x0000006E) Pipe Cycle Control Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t IITV : 3; /* [2..0] Interval Error Detection Interval */
+ uint16_t : 9;
+ volatile uint16_t IFIS : 1; /* [12..12] Isochronous IN Buffer Flush */
+ uint16_t : 3;
+ } PIPEPERI_b;
+ };
+
+ union {
+ volatile uint16_t PIPE_CTR[9]; /* (@ 0x00000070) Pipe [0..8] Control Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t PID : 2; /* [1..0] Response PID */
+ uint16_t : 3;
+ volatile const uint16_t PBUSY : 1; /* [5..5] Pipe Busy */
+ volatile const uint16_t SQMON : 1; /* [6..6] Sequence Toggle Bit Confirmation */
+ volatile uint16_t SQSET : 1; /* [7..7] Sequence Toggle Bit Set */
+ volatile uint16_t SQCLR : 1; /* [8..8] Sequence Toggle Bit Clear */
+ volatile uint16_t ACLRM : 1; /* [9..9] Auto Buffer Clear Mode */
+ volatile uint16_t ATREPM : 1; /* [10..10] Auto Response Mode */
+ uint16_t : 1;
+ volatile const uint16_t CSSTS : 1; /* [12..12] CSSTS Status */
+ volatile uint16_t CSCLR : 1; /* [13..13] CSPLIT Status Clear */
+ volatile const uint16_t INBUFM : 1; /* [14..14] Transmit Buffer Monitor */
+ volatile const uint16_t BSTS : 1; /* [15..15] Buffer Status */
+ } PIPE_CTR_b[9];
+ };
+ volatile const uint16_t RESERVED13;
+ volatile const uint32_t RESERVED14[3];
+ volatile RUSB2_PIPE_TR_t PIPE_TR[5]; /* (@ 0x00000090) Pipe Transaction Counter Registers */
+ volatile const uint32_t RESERVED15[3];
+
+ union {
+ volatile uint16_t USBBCCTRL0; /* (@ 0x000000B0) BC Control Register 0 */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t RPDME0 : 1; /* [0..0] D- Pin Pull-Down Control */
+ volatile uint16_t IDPSRCE0 : 1; /* [1..1] D+ Pin IDPSRC Output Control */
+ volatile uint16_t IDMSINKE0 : 1; /* [2..2] D- Pin 0.6 V Input Detection (Comparator and Sink) Control */
+ volatile uint16_t VDPSRCE0 : 1; /* [3..3] D+ Pin VDPSRC (0.6 V) Output Control */
+ volatile uint16_t IDPSINKE0 : 1; /* [4..4] D+ Pin 0.6 V Input Detection (Comparator and Sink) Control */
+ volatile uint16_t VDMSRCE0 : 1; /* [5..5] D- Pin VDMSRC (0.6 V) Output Control */
+ uint16_t : 1;
+ volatile uint16_t BATCHGE0 : 1; /* [7..7] BC (Battery Charger) Function Ch0 General Enable Control */
+ volatile const uint16_t CHGDETSTS0 : 1; /* [8..8] D- Pin 0.6 V Input Detection Status */
+ volatile const uint16_t PDDETSTS0 : 1; /* [9..9] D+ Pin 0.6 V Input Detection Status */
+ uint16_t : 6;
+ } USBBCCTRL0_b;
+ };
+ volatile const uint16_t RESERVED16;
+ volatile const uint32_t RESERVED17[4];
+
+ union {
+ volatile uint16_t UCKSEL; /* (@ 0x000000C4) USB Clock Selection Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t UCKSELC : 1; /* [0..0] USB Clock Selection */
+ uint16_t : 15;
+ } UCKSEL_b;
+ };
+ volatile const uint16_t RESERVED18;
+ volatile const uint32_t RESERVED19;
+
+ union {
+ volatile uint16_t USBMC; /* (@ 0x000000CC) USB Module Control Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t VDDUSBE : 1; /* [0..0] USB Reference Power Supply Circuit On/Off Control */
+ uint16_t : 6;
+ volatile uint16_t VDCEN : 1; /* [7..7] USB Regulator On/Off Control */
+ uint16_t : 8;
+ } USBMC_b;
+ };
+ volatile const uint16_t RESERVED20;
+
+ union {
+ volatile uint16_t DEVADD[10]; /* (@ 0x000000D0) Device Address Configuration Register */
+
+ struct TU_ATTR_PACKED {
+ uint16_t : 6;
+ volatile uint16_t USBSPD : 2; /* [7..6] Transfer Speed of Communication Target Device */
+ volatile uint16_t HUBPORT : 3; /* [10..8] Communication Target Connecting Hub Port */
+ volatile uint16_t UPPHUB : 4; /* [14..11] Communication Target Connecting Hub Register */
+ uint16_t : 1;
+ } DEVADD_b[10];
+ };
+ volatile const uint32_t RESERVED21[3];
+
+ union {
+ volatile uint32_t PHYSLEW; /* (@ 0x000000F0) PHY Cross Point Adjustment Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint32_t SLEWR00 : 1; /* [0..0] Receiver Cross Point Adjustment 00 */
+ volatile uint32_t SLEWR01 : 1; /* [1..1] Receiver Cross Point Adjustment 01 */
+ volatile uint32_t SLEWF00 : 1; /* [2..2] Receiver Cross Point Adjustment 00 */
+ volatile uint32_t SLEWF01 : 1; /* [3..3] Receiver Cross Point Adjustment 01 */
+ uint32_t : 28;
+ } PHYSLEW_b;
+ };
+ volatile const uint32_t RESERVED22[3];
+
+ union {
+ volatile uint16_t LPCTRL; /* (@ 0x00000100) Low Power Control Register */
+
+ struct TU_ATTR_PACKED {
+ uint16_t : 7;
+ volatile uint16_t HWUPM : 1; /* [7..7] Resume Return Mode Setting */
+ uint16_t : 8;
+ } LPCTRL_b;
+ };
+
+ union {
+ volatile uint16_t LPSTS; /* (@ 0x00000102) Low Power Status Register */
+
+ struct TU_ATTR_PACKED {
+ uint16_t : 14;
+ volatile uint16_t SUSPENDM : 1; /* [14..14] UTMI SuspendM Control */
+ uint16_t : 1;
+ } LPSTS_b;
+ };
+ volatile const uint32_t RESERVED23[15];
+
+ union {
+ volatile uint16_t BCCTRL; /* (@ 0x00000140) Battery Charging Control Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t IDPSRCE : 1; /* [0..0] IDPSRC Control */
+ volatile uint16_t IDMSINKE : 1; /* [1..1] IDMSINK Control */
+ volatile uint16_t VDPSRCE : 1; /* [2..2] VDPSRC Control */
+ volatile uint16_t IDPSINKE : 1; /* [3..3] IDPSINK Control */
+ volatile uint16_t VDMSRCE : 1; /* [4..4] VDMSRC Control */
+ volatile uint16_t DCPMODE : 1; /* [5..5] DCP Mode Control */
+ uint16_t : 2;
+ volatile const uint16_t CHGDETSTS : 1; /* [8..8] CHGDET Status */
+ volatile const uint16_t PDDETSTS : 1; /* [9..9] PDDET Status */
+ uint16_t : 6;
+ } BCCTRL_b;
+ };
+ volatile const uint16_t RESERVED24;
+
+ union {
+ volatile uint16_t PL1CTRL1; /* (@ 0x00000144) Function L1 Control Register 1 */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t L1RESPEN : 1; /* [0..0] L1 Response Enable */
+ volatile uint16_t L1RESPMD : 2; /* [2..1] L1 Response Mode */
+ volatile uint16_t L1NEGOMD : 1; /* [3..3] L1 Response Negotiation Control. */
+ volatile const uint16_t DVSQ : 4; /* [7..4] DVSQ Extension.DVSQ[3] is Mirror of DVSQ[2:0] in INTSTS0. */
+ volatile uint16_t HIRDTHR : 4; /* [11..8] L1 Response Negotiation Threshold Value */
+ uint16_t : 2;
+ volatile uint16_t L1EXTMD : 1; /* [14..14] PHY Control Mode at L1 Return */
+ uint16_t : 1;
+ } PL1CTRL1_b;
+ };
+
+ union {
+ volatile uint16_t PL1CTRL2; /* (@ 0x00000146) Function L1 Control Register 2 */
+
+ struct TU_ATTR_PACKED {
+ uint16_t : 8;
+ volatile uint16_t HIRDMON : 4; /* [11..8] HIRD Value Monitor */
+ volatile uint16_t RWEMON : 1; /* [12..12] RWE Value Monitor */
+ uint16_t : 3;
+ } PL1CTRL2_b;
+ };
+
+ union {
+ volatile uint16_t HL1CTRL1; /* (@ 0x00000148) Host L1 Control Register 1 */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t L1REQ : 1; /* [0..0] L1 Transition Request */
+ volatile const uint16_t L1STATUS : 2; /* [2..1] L1 Request Completion Status */
+ uint16_t : 13;
+ } HL1CTRL1_b;
+ };
+
+ union {
+ volatile uint16_t HL1CTRL2; /* (@ 0x0000014A) Host L1 Control Register 2 */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t L1ADDR : 4; /* [3..0] LPM Token DeviceAddress */
+ uint16_t : 4;
+ volatile uint16_t HIRD : 4; /* [11..8] LPM Token HIRD */
+ volatile uint16_t L1RWE : 1; /* [12..12] LPM Token L1 Remote Wake Enable */
+ uint16_t : 2;
+ volatile uint16_t BESL : 1; /* [15..15] BESL & Alternate HIRD */
+ } HL1CTRL2_b;
+ };
+
+ volatile uint32_t RESERVED25_1;
+
+ union {
+ volatile uint16_t PHYTRIM1; /*!< (@ 0x00000150) PHY Timing Register 1 */
+
+ struct {
+ volatile uint16_t DRISE : 2; /*!< [1..0] FS/LS Rising-Edge Output Waveform Adjustment Function */
+ volatile uint16_t DFALL : 2; /*!< [3..2] FS/LS Falling-Edge Output Waveform Adjustment Function */
+ uint16_t : 3;
+ volatile uint16_t PCOMPENB : 1; /*!< [7..7] PVDD Start-up Detection */
+ volatile uint16_t HSIUP : 4; /*!< [11..8] HS Output Level Setting */
+ volatile uint16_t IMPOFFSET : 3; /*!< [14..12] terminating resistance offset value setting.Offset value for adjusting the terminating resistance. */
+ uint16_t : 1;
+ } PHYTRIM1_b;
+ };
+
+ union {
+ volatile uint16_t PHYTRIM2; /*!< (@ 0x00000152) PHY Timing Register 2 */
+
+ struct {
+ volatile uint16_t SQU : 4; /*!< [3..0] Squelch Detection Level */
+ uint16_t : 3;
+ volatile uint16_t HSRXENMO : 1; /*!< [7..7] HS Receive Enable Control Mode */
+ volatile uint16_t PDR : 2; /*!< [9..8] HS Output Adjustment Function */
+ uint16_t : 2;
+ volatile uint16_t DIS : 3; /*!< [14..12] Disconnect Detection Level */
+ uint16_t : 1;
+ } PHYTRIM2_b;
+ };
+ volatile uint32_t RESERVED25_2[3];
+
+ union {
+ volatile const uint32_t DPUSR0R; /* (@ 0x00000160) Deep Standby USB Transceiver Control/Pin Monitor Register */
+
+ struct TU_ATTR_PACKED {
+ uint32_t : 20;
+ volatile const uint32_t DOVCAHM : 1; /* [20..20] OVRCURA InputIndicates OVRCURA input signal on the HS side of USB port. */
+ volatile const uint32_t DOVCBHM : 1; /* [21..21] OVRCURB InputIndicates OVRCURB input signal on the HS side of USB port. */
+ uint32_t : 1;
+ volatile const uint32_t DVBSTSHM : 1; /* [23..23] VBUS InputIndicates VBUS input signal on the HS side of USB port. */
+ uint32_t : 8;
+ } DPUSR0R_b;
+ };
+
+ union {
+ volatile uint32_t DPUSR1R; /* (@ 0x00000164) Deep Standby USB Suspend/Resume Interrupt Register */
+
+ struct TU_ATTR_PACKED {
+ uint32_t : 4;
+ volatile uint32_t DOVCAHE : 1; /* [4..4] OVRCURA Interrupt Enable Clear */
+ volatile uint32_t DOVCBHE : 1; /* [5..5] OVRCURB Interrupt Enable Clear */
+ uint32_t : 1;
+ volatile uint32_t DVBSTSHE : 1; /* [7..7] VBUS Interrupt Enable/Clear */
+ uint32_t : 12;
+ volatile const uint32_t DOVCAH : 1; /* [20..20] Indication of Return from OVRCURA Interrupt Source */
+ volatile const uint32_t DOVCBH : 1; /* [21..21] Indication of Return from OVRCURB Interrupt Source */
+ uint32_t : 1;
+ volatile const uint32_t DVBSTSH : 1; /* [23..23] Indication of Return from VBUS Interrupt Source */
+ uint32_t : 8;
+ } DPUSR1R_b;
+ };
+
+ union {
+ volatile uint16_t DPUSR2R; /* (@ 0x00000168) Deep Standby USB Suspend/Resume Interrupt Register */
+
+ struct TU_ATTR_PACKED {
+ volatile const uint16_t DPINT : 1; /* [0..0] Indication of Return from DP Interrupt Source */
+ volatile const uint16_t DMINT : 1; /* [1..1] Indication of Return from DM Interrupt Source */
+ uint16_t : 2;
+ volatile const uint16_t DPVAL : 1; /* [4..4] DP InputIndicates DP input signal on the HS side of USB port. */
+ volatile const uint16_t DMVAL : 1; /* [5..5] DM InputIndicates DM input signal on the HS side of USB port. */
+ uint16_t : 2;
+ volatile uint16_t DPINTE : 1; /* [8..8] DP Interrupt Enable Clear */
+ volatile uint16_t DMINTE : 1; /* [9..9] DM Interrupt Enable Clear */
+ uint16_t : 6;
+ } DPUSR2R_b;
+ };
+
+ union {
+ volatile uint16_t DPUSRCR; /* (@ 0x0000016A) Deep Standby USB Suspend/Resume Command Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint16_t FIXPHY : 1; /* [0..0] USB Transceiver Control Fix */
+ volatile uint16_t FIXPHYPD : 1; /* [1..1] USB Transceiver Control Fix for PLL */
+ uint16_t : 14;
+ } DPUSRCR_b;
+ };
+ volatile const uint32_t RESERVED26[165];
+
+ union {
+ volatile uint32_t
+ DPUSR0R_FS; /* (@ 0x00000400) Deep Software Standby USB Transceiver Control/Pin Monitor Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint32_t SRPC0 : 1; /* [0..0] USB Single End Receiver Control */
+ volatile uint32_t RPUE0 : 1; /* [1..1] DP Pull-Up Resistor Control */
+ uint32_t : 1;
+ volatile uint32_t DRPD0 : 1; /* [3..3] D+/D- Pull-Down Resistor Control */
+ volatile uint32_t FIXPHY0 : 1; /* [4..4] USB Transceiver Output Fix */
+ uint32_t : 11;
+ volatile const uint32_t DP0 : 1; /* [16..16] USB0 D+ InputIndicates the D+ input signal of the USB. */
+ volatile const uint32_t DM0 : 1; /* [17..17] USB D-InputIndicates the D- input signal of the USB. */
+ uint32_t : 2;
+ volatile const uint32_t DOVCA0 : 1; /* [20..20] USB OVRCURA InputIndicates the OVRCURA input signal of the USB. */
+ volatile const uint32_t DOVCB0 : 1; /* [21..21] USB OVRCURB InputIndicates the OVRCURB input signal of the USB. */
+ uint32_t : 1;
+ volatile const uint32_t DVBSTS0 : 1; /* [23..23] USB VBUS InputIndicates the VBUS input signal of the USB. */
+ uint32_t : 8;
+ } DPUSR0R_FS_b;
+ };
+
+ union {
+ volatile uint32_t DPUSR1R_FS; /* (@ 0x00000404) Deep Software Standby USB Suspend/Resume Interrupt Register */
+
+ struct TU_ATTR_PACKED {
+ volatile uint32_t DPINTE0 : 1; /* [0..0] USB DP Interrupt Enable/Clear */
+ volatile uint32_t DMINTE0 : 1; /* [1..1] USB DM Interrupt Enable/Clear */
+ uint32_t : 2;
+ volatile uint32_t DOVRCRAE0 : 1; /* [4..4] USB OVRCURA Interrupt Enable/Clear */
+ volatile uint32_t DOVRCRBE0 : 1; /* [5..5] USB OVRCURB Interrupt Enable/Clear */
+ uint32_t : 1;
+ volatile uint32_t DVBSE0 : 1; /* [7..7] USB VBUS Interrupt Enable/Clear */
+ uint32_t : 8;
+ volatile const uint32_t DPINT0 : 1; /* [16..16] USB DP Interrupt Source Recovery */
+ volatile const uint32_t DMINT0 : 1; /* [17..17] USB DM Interrupt Source Recovery */
+ uint32_t : 2;
+ volatile const uint32_t DOVRCRA0 : 1; /* [20..20] USB OVRCURA Interrupt Source Recovery */
+ volatile const uint32_t DOVRCRB0 : 1; /* [21..21] USB OVRCURB Interrupt Source Recovery */
+ uint32_t : 1;
+ volatile const uint32_t DVBINT0 : 1; /* [23..23] USB VBUS Interrupt Source Recovery */
+ uint32_t : 8;
+ } DPUSR1R_FS_b;
+ };
+} rusb2_reg_t; /* Size = 1032 (0x408) */
+
+TU_ATTR_PACKED_END /* End of definition of packed structs (used by the CCRX toolchain) */
+TU_ATTR_BIT_FIELD_ORDER_END
+
+/*--------------------------------------------------------------------*/
+/* Register Bit Definitions */
+/*--------------------------------------------------------------------*/
+
+// PIPE_TR
+// E
+#define RUSB2_PIPE_TR_E_TRENB_Pos (9UL) /* TRENB (Bit 9) */
+#define RUSB2_PIPE_TR_E_TRENB_Msk (0x200UL) /* TRENB (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPE_TR_E_TRCLR_Pos (8UL) /* TRCLR (Bit 8) */
+#define RUSB2_PIPE_TR_E_TRCLR_Msk (0x100UL) /* TRCLR (Bitfield-Mask: 0x01) */
+
+// N
+#define RUSB2_PIPE_TR_N_TRNCNT_Pos (0UL) /* TRNCNT (Bit 0) */
+#define RUSB2_PIPE_TR_N_TRNCNT_Msk (0xffffUL) /* TRNCNT (Bitfield-Mask: 0xffff) */
+
+// Core Registers
+
+// SYSCFG
+#define RUSB2_SYSCFG_SCKE_Pos (10UL) /* SCKE (Bit 10) */
+#define RUSB2_SYSCFG_SCKE_Msk (0x400UL) /* SCKE (Bitfield-Mask: 0x01) */
+#define RUSB2_SYSCFG_CNEN_Pos (8UL) /* CNEN (Bit 8) */
+#define RUSB2_SYSCFG_CNEN_Msk (0x100UL) /* CNEN (Bitfield-Mask: 0x01) */
+#define RUSB2_SYSCFG_HSE_Pos (7UL) /*!< HSE (Bit 7) */
+#define RUSB2_SYSCFG_HSE_Msk (0x80UL) /*!< HSE (Bitfield-Mask: 0x01) */
+#define RUSB2_SYSCFG_DCFM_Pos (6UL) /* DCFM (Bit 6) */
+#define RUSB2_SYSCFG_DCFM_Msk (0x40UL) /* DCFM (Bitfield-Mask: 0x01) */
+#define RUSB2_SYSCFG_DRPD_Pos (5UL) /* DRPD (Bit 5) */
+#define RUSB2_SYSCFG_DRPD_Msk (0x20UL) /* DRPD (Bitfield-Mask: 0x01) */
+#define RUSB2_SYSCFG_DPRPU_Pos (4UL) /* DPRPU (Bit 4) */
+#define RUSB2_SYSCFG_DPRPU_Msk (0x10UL) /* DPRPU (Bitfield-Mask: 0x01) */
+#define RUSB2_SYSCFG_DMRPU_Pos (3UL) /* DMRPU (Bit 3) */
+#define RUSB2_SYSCFG_DMRPU_Msk (0x8UL) /* DMRPU (Bitfield-Mask: 0x01) */
+#define RUSB2_SYSCFG_USBE_Pos (0UL) /* USBE (Bit 0) */
+#define RUSB2_SYSCFG_USBE_Msk (0x1UL) /* USBE (Bitfield-Mask: 0x01) */
+
+// BUSWAIT
+#define RUSB2_BUSWAIT_BWAIT_Pos (0UL) /* BWAIT (Bit 0) */
+#define RUSB2_BUSWAIT_BWAIT_Msk (0xfUL) /* BWAIT (Bitfield-Mask: 0x0f) */
+
+// SYSSTS0
+#define RUSB2_SYSSTS0_OVCMON_Pos (14UL) /* OVCMON (Bit 14) */
+#define RUSB2_SYSSTS0_OVCMON_Msk (0xc000UL) /* OVCMON (Bitfield-Mask: 0x03) */
+#define RUSB2_SYSSTS0_HTACT_Pos (6UL) /* HTACT (Bit 6) */
+#define RUSB2_SYSSTS0_HTACT_Msk (0x40UL) /* HTACT (Bitfield-Mask: 0x01) */
+#define RUSB2_SYSSTS0_SOFEA_Pos (5UL) /* SOFEA (Bit 5) */
+#define RUSB2_SYSSTS0_SOFEA_Msk (0x20UL) /* SOFEA (Bitfield-Mask: 0x01) */
+#define RUSB2_SYSSTS0_IDMON_Pos (2UL) /* IDMON (Bit 2) */
+#define RUSB2_SYSSTS0_IDMON_Msk (0x4UL) /* IDMON (Bitfield-Mask: 0x01) */
+#define RUSB2_SYSSTS0_LNST_Pos (0UL) /* LNST (Bit 0) */
+#define RUSB2_SYSSTS0_LNST_Msk (0x3UL) /* LNST (Bitfield-Mask: 0x03) */
+
+// PLLSTA
+#define RUSB2_PLLSTA_PLLLOCK_Pos (0UL) /* PLLLOCK (Bit 0) */
+#define RUSB2_PLLSTA_PLLLOCK_Msk (0x1UL) /* PLLLOCK (Bitfield-Mask: 0x01) */
+
+// DVSTCTR0
+#define RUSB2_DVSTCTR0_HNPBTOA_Pos (11UL) /* HNPBTOA (Bit 11) */
+#define RUSB2_DVSTCTR0_HNPBTOA_Msk (0x800UL) /* HNPBTOA (Bitfield-Mask: 0x01) */
+#define RUSB2_DVSTCTR0_EXICEN_Pos (10UL) /* EXICEN (Bit 10) */
+#define RUSB2_DVSTCTR0_EXICEN_Msk (0x400UL) /* EXICEN (Bitfield-Mask: 0x01) */
+#define RUSB2_DVSTCTR0_VBUSEN_Pos (9UL) /* VBUSEN (Bit 9) */
+#define RUSB2_DVSTCTR0_VBUSEN_Msk (0x200UL) /* VBUSEN (Bitfield-Mask: 0x01) */
+#define RUSB2_DVSTCTR0_WKUP_Pos (8UL) /* WKUP (Bit 8) */
+#define RUSB2_DVSTCTR0_WKUP_Msk (0x100UL) /* WKUP (Bitfield-Mask: 0x01) */
+#define RUSB2_DVSTCTR0_RWUPE_Pos (7UL) /* RWUPE (Bit 7) */
+#define RUSB2_DVSTCTR0_RWUPE_Msk (0x80UL) /* RWUPE (Bitfield-Mask: 0x01) */
+#define RUSB2_DVSTCTR0_USBRST_Pos (6UL) /* USBRST (Bit 6) */
+#define RUSB2_DVSTCTR0_USBRST_Msk (0x40UL) /* USBRST (Bitfield-Mask: 0x01) */
+#define RUSB2_DVSTCTR0_RESUME_Pos (5UL) /* RESUME (Bit 5) */
+#define RUSB2_DVSTCTR0_RESUME_Msk (0x20UL) /* RESUME (Bitfield-Mask: 0x01) */
+#define RUSB2_DVSTCTR0_UACT_Pos (4UL) /* UACT (Bit 4) */
+#define RUSB2_DVSTCTR0_UACT_Msk (0x10UL) /* UACT (Bitfield-Mask: 0x01) */
+#define RUSB2_DVSTCTR0_RHST_Pos (0UL) /* RHST (Bit 0) */
+#define RUSB2_DVSTCTR0_RHST_Msk (0x7UL) /* RHST (Bitfield-Mask: 0x07) */
+
+// TESTMODE
+#define RUSB2_TESTMODE_UTST_Pos (0UL) /* UTST (Bit 0) */
+#define RUSB2_TESTMODE_UTST_Msk (0xfUL) /* UTST (Bitfield-Mask: 0x0f) */
+
+// CFIFOSEL
+#define RUSB2_CFIFOSEL_RCNT_Pos (15UL) /* RCNT (Bit 15) */
+#define RUSB2_CFIFOSEL_RCNT_Msk (0x8000UL) /* RCNT (Bitfield-Mask: 0x01) */
+#define RUSB2_CFIFOSEL_REW_Pos (14UL) /* REW (Bit 14) */
+#define RUSB2_CFIFOSEL_REW_Msk (0x4000UL) /* REW (Bitfield-Mask: 0x01) */
+#define RUSB2_CFIFOSEL_MBW_Pos (10UL) /* MBW (Bit 10) */
+#define RUSB2_CFIFOSEL_MBW_Msk (0xc00UL) /* MBW (Bitfield-Mask: 0x03) */
+#define RUSB2_CFIFOSEL_BIGEND_Pos (8UL) /* BIGEND (Bit 8) */
+#define RUSB2_CFIFOSEL_BIGEND_Msk (0x100UL) /* BIGEND (Bitfield-Mask: 0x01) */
+#define RUSB2_CFIFOSEL_ISEL_Pos (5UL) /* ISEL (Bit 5) */
+#define RUSB2_CFIFOSEL_ISEL_Msk (0x20UL) /* ISEL (Bitfield-Mask: 0x01) */
+#define RUSB2_CFIFOSEL_CURPIPE_Pos (0UL) /* CURPIPE (Bit 0) */
+#define RUSB2_CFIFOSEL_CURPIPE_Msk (0xfUL) /* CURPIPE (Bitfield-Mask: 0x0f) */
+
+// CFIFOCTR
+#define RUSB2_CFIFOCTR_BVAL_Pos (15UL) /* BVAL (Bit 15) */
+#define RUSB2_CFIFOCTR_BVAL_Msk (0x8000UL) /* BVAL (Bitfield-Mask: 0x01) */
+#define RUSB2_CFIFOCTR_BCLR_Pos (14UL) /* BCLR (Bit 14) */
+#define RUSB2_CFIFOCTR_BCLR_Msk (0x4000UL) /* BCLR (Bitfield-Mask: 0x01) */
+#define RUSB2_CFIFOCTR_FRDY_Pos (13UL) /* FRDY (Bit 13) */
+#define RUSB2_CFIFOCTR_FRDY_Msk (0x2000UL) /* FRDY (Bitfield-Mask: 0x01) */
+#define RUSB2_CFIFOCTR_DTLN_Pos (0UL) /* DTLN (Bit 0) */
+#define RUSB2_CFIFOCTR_DTLN_Msk (0xfffUL) /* DTLN (Bitfield-Mask: 0xfff) */
+
+// D0FIFOSEL
+#define RUSB2_D0FIFOSEL_RCNT_Pos (15UL) /* RCNT (Bit 15) */
+#define RUSB2_D0FIFOSEL_RCNT_Msk (0x8000UL) /* RCNT (Bitfield-Mask: 0x01) */
+#define RUSB2_D0FIFOSEL_REW_Pos (14UL) /* REW (Bit 14) */
+#define RUSB2_D0FIFOSEL_REW_Msk (0x4000UL) /* REW (Bitfield-Mask: 0x01) */
+#define RUSB2_D0FIFOSEL_DCLRM_Pos (13UL) /* DCLRM (Bit 13) */
+#define RUSB2_D0FIFOSEL_DCLRM_Msk (0x2000UL) /* DCLRM (Bitfield-Mask: 0x01) */
+#define RUSB2_D0FIFOSEL_DREQE_Pos (12UL) /* DREQE (Bit 12) */
+#define RUSB2_D0FIFOSEL_DREQE_Msk (0x1000UL) /* DREQE (Bitfield-Mask: 0x01) */
+#define RUSB2_D0FIFOSEL_MBW_Pos (10UL) /* MBW (Bit 10) */
+#define RUSB2_D0FIFOSEL_MBW_Msk (0xc00UL) /* MBW (Bitfield-Mask: 0x03) */
+#define RUSB2_D0FIFOSEL_BIGEND_Pos (8UL) /* BIGEND (Bit 8) */
+#define RUSB2_D0FIFOSEL_BIGEND_Msk (0x100UL) /* BIGEND (Bitfield-Mask: 0x01) */
+#define RUSB2_D0FIFOSEL_CURPIPE_Pos (0UL) /* CURPIPE (Bit 0) */
+#define RUSB2_D0FIFOSEL_CURPIPE_Msk (0xfUL) /* CURPIPE (Bitfield-Mask: 0x0f) */
+
+// D0FIFOCTR
+#define RUSB2_D0FIFOCTR_BVAL_Pos (15UL) /* BVAL (Bit 15) */
+#define RUSB2_D0FIFOCTR_BVAL_Msk (0x8000UL) /* BVAL (Bitfield-Mask: 0x01) */
+#define RUSB2_D0FIFOCTR_BCLR_Pos (14UL) /* BCLR (Bit 14) */
+#define RUSB2_D0FIFOCTR_BCLR_Msk (0x4000UL) /* BCLR (Bitfield-Mask: 0x01) */
+#define RUSB2_D0FIFOCTR_FRDY_Pos (13UL) /* FRDY (Bit 13) */
+#define RUSB2_D0FIFOCTR_FRDY_Msk (0x2000UL) /* FRDY (Bitfield-Mask: 0x01) */
+#define RUSB2_D0FIFOCTR_DTLN_Pos (0UL) /* DTLN (Bit 0) */
+#define RUSB2_D0FIFOCTR_DTLN_Msk (0xfffUL) /* DTLN (Bitfield-Mask: 0xfff) */
+
+// D1FIFOSEL
+#define RUSB2_D1FIFOSEL_RCNT_Pos (15UL) /* RCNT (Bit 15) */
+#define RUSB2_D1FIFOSEL_RCNT_Msk (0x8000UL) /* RCNT (Bitfield-Mask: 0x01) */
+#define RUSB2_D1FIFOSEL_REW_Pos (14UL) /* REW (Bit 14) */
+#define RUSB2_D1FIFOSEL_REW_Msk (0x4000UL) /* REW (Bitfield-Mask: 0x01) */
+#define RUSB2_D1FIFOSEL_DCLRM_Pos (13UL) /* DCLRM (Bit 13) */
+#define RUSB2_D1FIFOSEL_DCLRM_Msk (0x2000UL) /* DCLRM (Bitfield-Mask: 0x01) */
+#define RUSB2_D1FIFOSEL_DREQE_Pos (12UL) /* DREQE (Bit 12) */
+#define RUSB2_D1FIFOSEL_DREQE_Msk (0x1000UL) /* DREQE (Bitfield-Mask: 0x01) */
+#define RUSB2_D1FIFOSEL_MBW_Pos (10UL) /* MBW (Bit 10) */
+#define RUSB2_D1FIFOSEL_MBW_Msk (0xc00UL) /* MBW (Bitfield-Mask: 0x03) */
+#define RUSB2_D1FIFOSEL_BIGEND_Pos (8UL) /* BIGEND (Bit 8) */
+#define RUSB2_D1FIFOSEL_BIGEND_Msk (0x100UL) /* BIGEND (Bitfield-Mask: 0x01) */
+#define RUSB2_D1FIFOSEL_CURPIPE_Pos (0UL) /* CURPIPE (Bit 0) */
+#define RUSB2_D1FIFOSEL_CURPIPE_Msk (0xfUL) /* CURPIPE (Bitfield-Mask: 0x0f) */
+
+// D1FIFOCTR
+#define RUSB2_D1FIFOCTR_BVAL_Pos (15UL) /* BVAL (Bit 15) */
+#define RUSB2_D1FIFOCTR_BVAL_Msk (0x8000UL) /* BVAL (Bitfield-Mask: 0x01) */
+#define RUSB2_D1FIFOCTR_BCLR_Pos (14UL) /* BCLR (Bit 14) */
+#define RUSB2_D1FIFOCTR_BCLR_Msk (0x4000UL) /* BCLR (Bitfield-Mask: 0x01) */
+#define RUSB2_D1FIFOCTR_FRDY_Pos (13UL) /* FRDY (Bit 13) */
+#define RUSB2_D1FIFOCTR_FRDY_Msk (0x2000UL) /* FRDY (Bitfield-Mask: 0x01) */
+#define RUSB2_D1FIFOCTR_DTLN_Pos (0UL) /* DTLN (Bit 0) */
+#define RUSB2_D1FIFOCTR_DTLN_Msk (0xfffUL) /* DTLN (Bitfield-Mask: 0xfff) */
+
+// INTENB0
+#define RUSB2_INTENB0_VBSE_Pos (15UL) /* VBSE (Bit 15) */
+#define RUSB2_INTENB0_VBSE_Msk (0x8000UL) /* VBSE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB0_RSME_Pos (14UL) /* RSME (Bit 14) */
+#define RUSB2_INTENB0_RSME_Msk (0x4000UL) /* RSME (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB0_SOFE_Pos (13UL) /* SOFE (Bit 13) */
+#define RUSB2_INTENB0_SOFE_Msk (0x2000UL) /* SOFE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB0_DVSE_Pos (12UL) /* DVSE (Bit 12) */
+#define RUSB2_INTENB0_DVSE_Msk (0x1000UL) /* DVSE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB0_CTRE_Pos (11UL) /* CTRE (Bit 11) */
+#define RUSB2_INTENB0_CTRE_Msk (0x800UL) /* CTRE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB0_BEMPE_Pos (10UL) /* BEMPE (Bit 10) */
+#define RUSB2_INTENB0_BEMPE_Msk (0x400UL) /* BEMPE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB0_NRDYE_Pos (9UL) /* NRDYE (Bit 9) */
+#define RUSB2_INTENB0_NRDYE_Msk (0x200UL) /* NRDYE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB0_BRDYE_Pos (8UL) /* BRDYE (Bit 8) */
+#define RUSB2_INTENB0_BRDYE_Msk (0x100UL) /* BRDYE (Bitfield-Mask: 0x01) */
+
+// INTENB1
+#define RUSB2_INTENB1_OVRCRE_Pos (15UL) /* OVRCRE (Bit 15) */
+#define RUSB2_INTENB1_OVRCRE_Msk (0x8000UL) /* OVRCRE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB1_BCHGE_Pos (14UL) /* BCHGE (Bit 14) */
+#define RUSB2_INTENB1_BCHGE_Msk (0x4000UL) /* BCHGE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB1_DTCHE_Pos (12UL) /* DTCHE (Bit 12) */
+#define RUSB2_INTENB1_DTCHE_Msk (0x1000UL) /* DTCHE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB1_ATTCHE_Pos (11UL) /* ATTCHE (Bit 11) */
+#define RUSB2_INTENB1_ATTCHE_Msk (0x800UL) /* ATTCHE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB1_L1RSMENDE_Pos (9UL) /*!< L1RSMENDE (Bit 9) */
+#define RUSB2_INTENB1_L1RSMENDE_Msk (0x200UL) /*!< L1RSMENDE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB1_LPMENDE_Pos (8UL) /*!< LPMENDE (Bit 8) */
+#define RUSB2_INTENB1_LPMENDE_Msk (0x100UL) /*!< LPMENDE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB1_EOFERRE_Pos (6UL) /* EOFERRE (Bit 6) */
+#define RUSB2_INTENB1_EOFERRE_Msk (0x40UL) /* EOFERRE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB1_SIGNE_Pos (5UL) /* SIGNE (Bit 5) */
+#define RUSB2_INTENB1_SIGNE_Msk (0x20UL) /* SIGNE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB1_SACKE_Pos (4UL) /* SACKE (Bit 4) */
+#define RUSB2_INTENB1_SACKE_Msk (0x10UL) /* SACKE (Bitfield-Mask: 0x01) */
+#define RUSB2_INTENB1_PDDETINTE0_Pos (0UL) /* PDDETINTE0 (Bit 0) */
+#define RUSB2_INTENB1_PDDETINTE0_Msk (0x1UL) /* PDDETINTE0 (Bitfield-Mask: 0x01) */
+
+// BRDYENB
+#define RUSB2_BRDYENB_PIPEBRDYE_Pos (0UL) /* PIPEBRDYE (Bit 0) */
+#define RUSB2_BRDYENB_PIPEBRDYE_Msk (0x1UL) /* PIPEBRDYE (Bitfield-Mask: 0x01) */
+
+// NRDYENB
+#define RUSB2_NRDYENB_PIPENRDYE_Pos (0UL) /* PIPENRDYE (Bit 0) */
+#define RUSB2_NRDYENB_PIPENRDYE_Msk (0x1UL) /* PIPENRDYE (Bitfield-Mask: 0x01) */
+
+// BEMPENB
+#define RUSB2_BEMPENB_PIPEBEMPE_Pos (0UL) /* PIPEBEMPE (Bit 0) */
+#define RUSB2_BEMPENB_PIPEBEMPE_Msk (0x1UL) /* PIPEBEMPE (Bitfield-Mask: 0x01) */
+
+// SOFCFG
+#define RUSB2_SOFCFG_TRNENSEL_Pos (8UL) /* TRNENSEL (Bit 8) */
+#define RUSB2_SOFCFG_TRNENSEL_Msk (0x100UL) /* TRNENSEL (Bitfield-Mask: 0x01) */
+#define RUSB2_SOFCFG_BRDYM_Pos (6UL) /* BRDYM (Bit 6) */
+#define RUSB2_SOFCFG_BRDYM_Msk (0x40UL) /* BRDYM (Bitfield-Mask: 0x01) */
+#define RUSB2_SOFCFG_INTL_Pos (5UL) /* INTL (Bit 5) */
+#define RUSB2_SOFCFG_INTL_Msk (0x20UL) /* INTL (Bitfield-Mask: 0x01) */
+#define RUSB2_SOFCFG_EDGESTS_Pos (4UL) /* EDGESTS (Bit 4) */
+#define RUSB2_SOFCFG_EDGESTS_Msk (0x10UL) /* EDGESTS (Bitfield-Mask: 0x01) */
+
+// PHYSET
+#define RUSB2_PHYSET_HSEB_Pos (15UL) /* HSEB (Bit 15) */
+#define RUSB2_PHYSET_HSEB_Msk (0x8000UL) /* HSEB (Bitfield-Mask: 0x01) */
+#define RUSB2_PHYSET_REPSTART_Pos (11UL) /* REPSTART (Bit 11) */
+#define RUSB2_PHYSET_REPSTART_Msk (0x800UL) /* REPSTART (Bitfield-Mask: 0x01) */
+#define RUSB2_PHYSET_REPSEL_Pos (8UL) /* REPSEL (Bit 8) */
+#define RUSB2_PHYSET_REPSEL_Msk (0x300UL) /* REPSEL (Bitfield-Mask: 0x03) */
+#define RUSB2_PHYSET_CLKSEL_Pos (4UL) /* CLKSEL (Bit 4) */
+#define RUSB2_PHYSET_CLKSEL_Msk (0x30UL) /* CLKSEL (Bitfield-Mask: 0x03) */
+#define RUSB2_PHYSET_CDPEN_Pos (3UL) /* CDPEN (Bit 3) */
+#define RUSB2_PHYSET_CDPEN_Msk (0x8UL) /* CDPEN (Bitfield-Mask: 0x01) */
+#define RUSB2_PHYSET_PLLRESET_Pos (1UL) /* PLLRESET (Bit 1) */
+#define RUSB2_PHYSET_PLLRESET_Msk (0x2UL) /* PLLRESET (Bitfield-Mask: 0x01) */
+#define RUSB2_PHYSET_DIRPD_Pos (0UL) /* DIRPD (Bit 0) */
+#define RUSB2_PHYSET_DIRPD_Msk (0x1UL) /* DIRPD (Bitfield-Mask: 0x01) */
+
+// INTSTS0
+#define RUSB2_INTSTS0_VBINT_Pos (15UL) /* VBINT (Bit 15) */
+#define RUSB2_INTSTS0_VBINT_Msk (0x8000UL) /* VBINT (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS0_RESM_Pos (14UL) /* RESM (Bit 14) */
+#define RUSB2_INTSTS0_RESM_Msk (0x4000UL) /* RESM (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS0_SOFR_Pos (13UL) /* SOFR (Bit 13) */
+#define RUSB2_INTSTS0_SOFR_Msk (0x2000UL) /* SOFR (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS0_DVST_Pos (12UL) /* DVST (Bit 12) */
+#define RUSB2_INTSTS0_DVST_Msk (0x1000UL) /* DVST (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS0_CTRT_Pos (11UL) /* CTRT (Bit 11) */
+#define RUSB2_INTSTS0_CTRT_Msk (0x800UL) /* CTRT (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS0_BEMP_Pos (10UL) /* BEMP (Bit 10) */
+#define RUSB2_INTSTS0_BEMP_Msk (0x400UL) /* BEMP (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS0_NRDY_Pos (9UL) /* NRDY (Bit 9) */
+#define RUSB2_INTSTS0_NRDY_Msk (0x200UL) /* NRDY (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS0_BRDY_Pos (8UL) /* BRDY (Bit 8) */
+#define RUSB2_INTSTS0_BRDY_Msk (0x100UL) /* BRDY (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS0_VBSTS_Pos (7UL) /* VBSTS (Bit 7) */
+#define RUSB2_INTSTS0_VBSTS_Msk (0x80UL) /* VBSTS (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS0_DVSQ_Pos (4UL) /* DVSQ (Bit 4) */
+#define RUSB2_INTSTS0_DVSQ_Msk (0x70UL) /* DVSQ (Bitfield-Mask: 0x07) */
+#define RUSB2_INTSTS0_VALID_Pos (3UL) /* VALID (Bit 3) */
+#define RUSB2_INTSTS0_VALID_Msk (0x8UL) /* VALID (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS0_CTSQ_Pos (0UL) /* CTSQ (Bit 0) */
+#define RUSB2_INTSTS0_CTSQ_Msk (0x7UL) /* CTSQ (Bitfield-Mask: 0x07) */
+
+// INTSTS1
+#define RUSB2_INTSTS1_OVRCR_Pos (15UL) /* OVRCR (Bit 15) */
+#define RUSB2_INTSTS1_OVRCR_Msk (0x8000UL) /* OVRCR (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS1_BCHG_Pos (14UL) /* BCHG (Bit 14) */
+#define RUSB2_INTSTS1_BCHG_Msk (0x4000UL) /* BCHG (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS1_DTCH_Pos (12UL) /* DTCH (Bit 12) */
+#define RUSB2_INTSTS1_DTCH_Msk (0x1000UL) /* DTCH (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS1_ATTCH_Pos (11UL) /* ATTCH (Bit 11) */
+#define RUSB2_INTSTS1_ATTCH_Msk (0x800UL) /* ATTCH (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS1_L1RSMEND_Pos (9UL) /* L1RSMEND (Bit 9) */
+#define RUSB2_INTSTS1_L1RSMEND_Msk (0x200UL) /* L1RSMEND (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS1_LPMEND_Pos (8UL) /* LPMEND (Bit 8) */
+#define RUSB2_INTSTS1_LPMEND_Msk (0x100UL) /* LPMEND (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS1_EOFERR_Pos (6UL) /* EOFERR (Bit 6) */
+#define RUSB2_INTSTS1_EOFERR_Msk (0x40UL) /* EOFERR (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS1_SIGN_Pos (5UL) /* SIGN (Bit 5) */
+#define RUSB2_INTSTS1_SIGN_Msk (0x20UL) /* SIGN (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS1_SACK_Pos (4UL) /* SACK (Bit 4) */
+#define RUSB2_INTSTS1_SACK_Msk (0x10UL) /* SACK (Bitfield-Mask: 0x01) */
+#define RUSB2_INTSTS1_PDDETINT0_Pos (0UL) /* PDDETINT0 (Bit 0) */
+#define RUSB2_INTSTS1_PDDETINT0_Msk (0x1UL) /* PDDETINT0 (Bitfield-Mask: 0x01) */
+
+// BRDYSTS
+#define RUSB2_BRDYSTS_PIPEBRDY_Pos (0UL) /* PIPEBRDY (Bit 0) */
+#define RUSB2_BRDYSTS_PIPEBRDY_Msk (0x1UL) /* PIPEBRDY (Bitfield-Mask: 0x01) */
+
+// NRDYSTS
+#define RUSB2_NRDYSTS_PIPENRDY_Pos (0UL) /* PIPENRDY (Bit 0) */
+#define RUSB2_NRDYSTS_PIPENRDY_Msk (0x1UL) /* PIPENRDY (Bitfield-Mask: 0x01) */
+
+// BEMPSTS
+#define RUSB2_BEMPSTS_PIPEBEMP_Pos (0UL) /* PIPEBEMP (Bit 0) */
+#define RUSB2_BEMPSTS_PIPEBEMP_Msk (0x1UL) /* PIPEBEMP (Bitfield-Mask: 0x01) */
+
+// FRMNUM
+#define RUSB2_FRMNUM_OVRN_Pos (15UL) /* OVRN (Bit 15) */
+#define RUSB2_FRMNUM_OVRN_Msk (0x8000UL) /* OVRN (Bitfield-Mask: 0x01) */
+#define RUSB2_FRMNUM_CRCE_Pos (14UL) /* CRCE (Bit 14) */
+#define RUSB2_FRMNUM_CRCE_Msk (0x4000UL) /* CRCE (Bitfield-Mask: 0x01) */
+#define RUSB2_FRMNUM_FRNM_Pos (0UL) /* FRNM (Bit 0) */
+#define RUSB2_FRMNUM_FRNM_Msk (0x7ffUL) /* FRNM (Bitfield-Mask: 0x7ff) */
+
+// UFRMNUM
+#define RUSB2_UFRMNUM_DVCHG_Pos (15UL) /* DVCHG (Bit 15) */
+#define RUSB2_UFRMNUM_DVCHG_Msk (0x8000UL) /* DVCHG (Bitfield-Mask: 0x01) */
+#define RUSB2_UFRMNUM_UFRNM_Pos (0UL) /* UFRNM (Bit 0) */
+#define RUSB2_UFRMNUM_UFRNM_Msk (0x7UL) /* UFRNM (Bitfield-Mask: 0x07) */
+
+// USBADDR
+#define RUSB2_USBADDR_STSRECOV0_Pos (8UL) /* STSRECOV0 (Bit 8) */
+#define RUSB2_USBADDR_STSRECOV0_Msk (0x700UL) /* STSRECOV0 (Bitfield-Mask: 0x07) */
+#define RUSB2_USBADDR_USBADDR_Pos (0UL) /* USBADDR (Bit 0) */
+#define RUSB2_USBADDR_USBADDR_Msk (0x7fUL) /* USBADDR (Bitfield-Mask: 0x7f) */
+
+// USBREQ
+#define RUSB2_USBREQ_BREQUEST_Pos (8UL) /* BREQUEST (Bit 8) */
+#define RUSB2_USBREQ_BREQUEST_Msk (0xff00UL) /* BREQUEST (Bitfield-Mask: 0xff) */
+#define RUSB2_USBREQ_BMREQUESTTYPE_Pos (0UL) /* BMREQUESTTYPE (Bit 0) */
+#define RUSB2_USBREQ_BMREQUESTTYPE_Msk (0xffUL) /* BMREQUESTTYPE (Bitfield-Mask: 0xff) */
+
+// USBVAL
+#define RUSB2_USBVAL_WVALUE_Pos (0UL) /* WVALUE (Bit 0) */
+#define RUSB2_USBVAL_WVALUE_Msk (0xffffUL) /* WVALUE (Bitfield-Mask: 0xffff) */
+
+// USBINDX
+#define RUSB2_USBINDX_WINDEX_Pos (0UL) /* WINDEX (Bit 0) */
+#define RUSB2_USBINDX_WINDEX_Msk (0xffffUL) /* WINDEX (Bitfield-Mask: 0xffff) */
+
+// USBLENG
+#define RUSB2_USBLENG_WLENGTH_Pos (0UL) /* WLENGTH (Bit 0) */
+#define RUSB2_USBLENG_WLENGTH_Msk (0xffffUL) /* WLENGTH (Bitfield-Mask: 0xffff) */
+
+// DCPCFG
+#define RUSB2_DCPCFG_CNTMD_Pos (8UL) /* CNTMD (Bit 8) */
+#define RUSB2_DCPCFG_CNTMD_Msk (0x100UL) /* CNTMD (Bitfield-Mask: 0x01) */
+#define RUSB2_DCPCFG_SHTNAK_Pos (7UL) /* SHTNAK (Bit 7) */
+#define RUSB2_DCPCFG_SHTNAK_Msk (0x80UL) /* SHTNAK (Bitfield-Mask: 0x01) */
+#define RUSB2_DCPCFG_DIR_Pos (4UL) /* DIR (Bit 4) */
+#define RUSB2_DCPCFG_DIR_Msk (0x10UL) /* DIR (Bitfield-Mask: 0x01) */
+
+// DCPMAXP
+#define RUSB2_DCPMAXP_DEVSEL_Pos (12UL) /* DEVSEL (Bit 12) */
+#define RUSB2_DCPMAXP_DEVSEL_Msk (0xf000UL) /* DEVSEL (Bitfield-Mask: 0x0f) */
+#define RUSB2_DCPMAXP_MXPS_Pos (0UL) /* MXPS (Bit 0) */
+#define RUSB2_DCPMAXP_MXPS_Msk (0x7fUL) /* MXPS (Bitfield-Mask: 0x7f) */
+
+// DCPCTR
+#define RUSB2_DCPCTR_BSTS_Pos (15UL) /* BSTS (Bit 15) */
+#define RUSB2_DCPCTR_BSTS_Msk (0x8000UL) /* BSTS (Bitfield-Mask: 0x01) */
+#define RUSB2_DCPCTR_SUREQ_Pos (14UL) /* SUREQ (Bit 14) */
+#define RUSB2_DCPCTR_SUREQ_Msk (0x4000UL) /* SUREQ (Bitfield-Mask: 0x01) */
+#define R_USB_HS0_DCPCTR_CSCLR_Pos (13UL) /*!< CSCLR (Bit 13) */
+#define RUSB2_DCPCTR_CSCLR_Msk (0x2000UL) /*!< CSCLR (Bitfield-Mask: 0x01) */
+#define RUSB2_DCPCTR_CSSTS_Pos (12UL) /*!< CSSTS (Bit 12) */
+#define RUSB2_DCPCTR_CSSTS_Msk (0x1000UL) /*!< CSSTS (Bitfield-Mask: 0x01) */
+#define RUSB2_DCPCTR_SUREQCLR_Pos (11UL) /* SUREQCLR (Bit 11) */
+#define RUSB2_DCPCTR_SUREQCLR_Msk (0x800UL) /* SUREQCLR (Bitfield-Mask: 0x01) */
+#define RUSB2_DCPCTR_SQCLR_Pos (8UL) /* SQCLR (Bit 8) */
+#define RUSB2_DCPCTR_SQCLR_Msk (0x100UL) /* SQCLR (Bitfield-Mask: 0x01) */
+#define RUSB2_DCPCTR_SQSET_Pos (7UL) /* SQSET (Bit 7) */
+#define RUSB2_DCPCTR_SQSET_Msk (0x80UL) /* SQSET (Bitfield-Mask: 0x01) */
+#define RUSB2_DCPCTR_SQMON_Pos (6UL) /* SQMON (Bit 6) */
+#define RUSB2_DCPCTR_SQMON_Msk (0x40UL) /* SQMON (Bitfield-Mask: 0x01) */
+#define RUSB2_DCPCTR_PBUSY_Pos (5UL) /* PBUSY (Bit 5) */
+#define RUSB2_DCPCTR_PBUSY_Msk (0x20UL) /* PBUSY (Bitfield-Mask: 0x01) */
+#define RUSB2_DCPCTR_CCPL_Pos (2UL) /* CCPL (Bit 2) */
+#define RUSB2_DCPCTR_CCPL_Msk (0x4UL) /* CCPL (Bitfield-Mask: 0x01) */
+#define RUSB2_DCPCTR_PID_Pos (0UL) /* PID (Bit 0) */
+#define RUSB2_DCPCTR_PID_Msk (0x3UL) /* PID (Bitfield-Mask: 0x03) */
+
+// PIPESEL
+#define RUSB2_PIPESEL_PIPESEL_Pos (0UL) /* PIPESEL (Bit 0) */
+#define RUSB2_PIPESEL_PIPESEL_Msk (0xfUL) /* PIPESEL (Bitfield-Mask: 0x0f) */
+
+// PIPECFG
+#define RUSB2_PIPECFG_TYPE_Pos (14UL) /* TYPE (Bit 14) */
+#define RUSB2_PIPECFG_TYPE_Msk (0xc000UL) /* TYPE (Bitfield-Mask: 0x03) */
+#define RUSB2_PIPECFG_BFRE_Pos (10UL) /* BFRE (Bit 10) */
+#define RUSB2_PIPECFG_BFRE_Msk (0x400UL) /* BFRE (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPECFG_DBLB_Pos (9UL) /* DBLB (Bit 9) */
+#define RUSB2_PIPECFG_DBLB_Msk (0x200UL) /* DBLB (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPECFG_CNTMD_Pos (8UL) /*!< CNTMD (Bit 8) */
+#define RUSB2_PIPECFG_CNTMD_Msk (0x100UL) /*!< CNTMD (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPECFG_SHTNAK_Pos (7UL) /* SHTNAK (Bit 7) */
+#define RUSB2_PIPECFG_SHTNAK_Msk (0x80UL) /* SHTNAK (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPECFG_DIR_Pos (4UL) /* DIR (Bit 4) */
+#define RUSB2_PIPECFG_DIR_Msk (0x10UL) /* DIR (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPECFG_EPNUM_Pos (0UL) /* EPNUM (Bit 0) */
+#define RUSB2_PIPECFG_EPNUM_Msk (0xfUL) /* EPNUM (Bitfield-Mask: 0x0f) */
+
+// PIPEBUF
+#define RUSB2_PIPEBUF_BUFSIZE_Pos (10UL) /*!< BUFSIZE (Bit 10) */
+#define RUSB2_PIPEBUF_BUFSIZE_Msk (0x7c00UL) /*!< BUFSIZE (Bitfield-Mask: 0x1f) */
+#define RUSB2_PIPEBUF_BUFNMB_Pos (0UL) /*!< BUFNMB (Bit 0) */
+#define RUSB2_PIPEBUF_BUFNMB_Msk (0xffUL) /*!< BUFNMB (Bitfield-Mask: 0xff) */
+
+// PIPEMAXP
+#define RUSB2_PIPEMAXP_DEVSEL_Pos (12UL) /* DEVSEL (Bit 12) */
+#define RUSB2_PIPEMAXP_DEVSEL_Msk (0xf000UL) /* DEVSEL (Bitfield-Mask: 0x0f) */
+#define RUSB2_PIPEMAXP_MXPS_Pos (0UL) /* MXPS (Bit 0) */
+#define RUSB2_PIPEMAXP_MXPS_Msk (0x1ffUL) /* MXPS (Bitfield-Mask: 0x1ff) */
+
+// PIPEPERI
+#define RUSB2_PIPEPERI_IFIS_Pos (12UL) /* IFIS (Bit 12) */
+#define RUSB2_PIPEPERI_IFIS_Msk (0x1000UL) /* IFIS (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPEPERI_IITV_Pos (0UL) /* IITV (Bit 0) */
+#define RUSB2_PIPEPERI_IITV_Msk (0x7UL) /* IITV (Bitfield-Mask: 0x07) */
+
+// PIPE_CTR
+#define RUSB2_PIPE_CTR_BSTS_Pos (15UL) /* BSTS (Bit 15) */
+#define RUSB2_PIPE_CTR_BSTS_Msk (0x8000UL) /* BSTS (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPE_CTR_INBUFM_Pos (14UL) /* INBUFM (Bit 14) */
+#define RUSB2_PIPE_CTR_INBUFM_Msk (0x4000UL) /* INBUFM (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPE_CTR_CSCLR_Pos (13UL) /* CSCLR (Bit 13) */
+#define RUSB2_PIPE_CTR_CSCLR_Msk (0x2000UL) /* CSCLR (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPE_CTR_CSSTS_Pos (12UL) /* CSSTS (Bit 12) */
+#define RUSB2_PIPE_CTR_CSSTS_Msk (0x1000UL) /* CSSTS (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPE_CTR_ATREPM_Pos (10UL) /* ATREPM (Bit 10) */
+#define RUSB2_PIPE_CTR_ATREPM_Msk (0x400UL) /* ATREPM (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPE_CTR_ACLRM_Pos (9UL) /* ACLRM (Bit 9) */
+#define RUSB2_PIPE_CTR_ACLRM_Msk (0x200UL) /* ACLRM (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPE_CTR_SQCLR_Pos (8UL) /* SQCLR (Bit 8) */
+#define RUSB2_PIPE_CTR_SQCLR_Msk (0x100UL) /* SQCLR (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPE_CTR_SQSET_Pos (7UL) /* SQSET (Bit 7) */
+#define RUSB2_PIPE_CTR_SQSET_Msk (0x80UL) /* SQSET (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPE_CTR_SQMON_Pos (6UL) /* SQMON (Bit 6) */
+#define RUSB2_PIPE_CTR_SQMON_Msk (0x40UL) /* SQMON (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPE_CTR_PBUSY_Pos (5UL) /* PBUSY (Bit 5) */
+#define RUSB2_PIPE_CTR_PBUSY_Msk (0x20UL) /* PBUSY (Bitfield-Mask: 0x01) */
+#define RUSB2_PIPE_CTR_PID_Pos (0UL) /* PID (Bit 0) */
+#define RUSB2_PIPE_CTR_PID_Msk (0x3UL) /* PID (Bitfield-Mask: 0x03) */
+
+// DEVADD
+#define RUSB2_DEVADD_UPPHUB_Pos (11UL) /* UPPHUB (Bit 11) */
+#define RUSB2_DEVADD_UPPHUB_Msk (0x7800UL) /* UPPHUB (Bitfield-Mask: 0x0f) */
+#define RUSB2_DEVADD_HUBPORT_Pos (8UL) /* HUBPORT (Bit 8) */
+#define RUSB2_DEVADD_HUBPORT_Msk (0x700UL) /* HUBPORT (Bitfield-Mask: 0x07) */
+#define RUSB2_DEVADD_USBSPD_Pos (6UL) /* USBSPD (Bit 6) */
+#define RUSB2_DEVADD_USBSPD_Msk (0xc0UL) /* USBSPD (Bitfield-Mask: 0x03) */
+
+// USBBCCTRL0
+#define RUSB2_USBBCCTRL0_PDDETSTS0_Pos (9UL) /* PDDETSTS0 (Bit 9) */
+#define RUSB2_USBBCCTRL0_PDDETSTS0_Msk (0x200UL) /* PDDETSTS0 (Bitfield-Mask: 0x01) */
+#define RUSB2_USBBCCTRL0_CHGDETSTS0_Pos (8UL) /* CHGDETSTS0 (Bit 8) */
+#define RUSB2_USBBCCTRL0_CHGDETSTS0_Msk (0x100UL) /* CHGDETSTS0 (Bitfield-Mask: 0x01) */
+#define RUSB2_USBBCCTRL0_BATCHGE0_Pos (7UL) /* BATCHGE0 (Bit 7) */
+#define RUSB2_USBBCCTRL0_BATCHGE0_Msk (0x80UL) /* BATCHGE0 (Bitfield-Mask: 0x01) */
+#define RUSB2_USBBCCTRL0_VDMSRCE0_Pos (5UL) /* VDMSRCE0 (Bit 5) */
+#define RUSB2_USBBCCTRL0_VDMSRCE0_Msk (0x20UL) /* VDMSRCE0 (Bitfield-Mask: 0x01) */
+#define RUSB2_USBBCCTRL0_IDPSINKE0_Pos (4UL) /* IDPSINKE0 (Bit 4) */
+#define RUSB2_USBBCCTRL0_IDPSINKE0_Msk (0x10UL) /* IDPSINKE0 (Bitfield-Mask: 0x01) */
+#define RUSB2_USBBCCTRL0_VDPSRCE0_Pos (3UL) /* VDPSRCE0 (Bit 3) */
+#define RUSB2_USBBCCTRL0_VDPSRCE0_Msk (0x8UL) /* VDPSRCE0 (Bitfield-Mask: 0x01) */
+#define RUSB2_USBBCCTRL0_IDMSINKE0_Pos (2UL) /* IDMSINKE0 (Bit 2) */
+#define RUSB2_USBBCCTRL0_IDMSINKE0_Msk (0x4UL) /* IDMSINKE0 (Bitfield-Mask: 0x01) */
+#define RUSB2_USBBCCTRL0_IDPSRCE0_Pos (1UL) /* IDPSRCE0 (Bit 1) */
+#define RUSB2_USBBCCTRL0_IDPSRCE0_Msk (0x2UL) /* IDPSRCE0 (Bitfield-Mask: 0x01) */
+#define RUSB2_USBBCCTRL0_RPDME0_Pos (0UL) /* RPDME0 (Bit 0) */
+#define RUSB2_USBBCCTRL0_RPDME0_Msk (0x1UL) /* RPDME0 (Bitfield-Mask: 0x01) */
+
+// UCKSEL
+#define RUSB2_UCKSEL_UCKSELC_Pos (0UL) /* UCKSELC (Bit 0) */
+#define RUSB2_UCKSEL_UCKSELC_Msk (0x1UL) /* UCKSELC (Bitfield-Mask: 0x01) */
+
+// USBMC
+#define RUSB2_USBMC_VDCEN_Pos (7UL) /* VDCEN (Bit 7) */
+#define RUSB2_USBMC_VDCEN_Msk (0x80UL) /* VDCEN (Bitfield-Mask: 0x01) */
+#define RUSB2_USBMC_VDDUSBE_Pos (0UL) /* VDDUSBE (Bit 0) */
+#define RUSB2_USBMC_VDDUSBE_Msk (0x1UL) /* VDDUSBE (Bitfield-Mask: 0x01) */
+
+// PHYSLEW
+#define RUSB2_PHYSLEW_SLEWF01_Pos (3UL) /* SLEWF01 (Bit 3) */
+#define RUSB2_PHYSLEW_SLEWF01_Msk (0x8UL) /* SLEWF01 (Bitfield-Mask: 0x01) */
+#define RUSB2_PHYSLEW_SLEWF00_Pos (2UL) /* SLEWF00 (Bit 2) */
+#define RUSB2_PHYSLEW_SLEWF00_Msk (0x4UL) /* SLEWF00 (Bitfield-Mask: 0x01) */
+#define RUSB2_PHYSLEW_SLEWR01_Pos (1UL) /* SLEWR01 (Bit 1) */
+#define RUSB2_PHYSLEW_SLEWR01_Msk (0x2UL) /* SLEWR01 (Bitfield-Mask: 0x01) */
+#define RUSB2_PHYSLEW_SLEWR00_Pos (0UL) /* SLEWR00 (Bit 0) */
+#define RUSB2_PHYSLEW_SLEWR00_Msk (0x1UL) /* SLEWR00 (Bitfield-Mask: 0x01) */
+
+// LPCTRL
+#define RUSB2_LPCTRL_HWUPM_Pos (7UL) /* HWUPM (Bit 7) */
+#define RUSB2_LPCTRL_HWUPM_Msk (0x80UL) /* HWUPM (Bitfield-Mask: 0x01) */
+
+// LPSTS
+#define RUSB2_LPSTS_SUSPENDM_Pos (14UL) /* SUSPENDM (Bit 14) */
+#define RUSB2_LPSTS_SUSPENDM_Msk (0x4000UL) /* SUSPENDM (Bitfield-Mask: 0x01) */
+
+// BCCTRL
+#define RUSB2_BCCTRL_PDDETSTS_Pos (9UL) /* PDDETSTS (Bit 9) */
+#define RUSB2_BCCTRL_PDDETSTS_Msk (0x200UL) /* PDDETSTS (Bitfield-Mask: 0x01) */
+#define RUSB2_BCCTRL_CHGDETSTS_Pos (8UL) /* CHGDETSTS (Bit 8) */
+#define RUSB2_BCCTRL_CHGDETSTS_Msk (0x100UL) /* CHGDETSTS (Bitfield-Mask: 0x01) */
+#define RUSB2_BCCTRL_DCPMODE_Pos (5UL) /* DCPMODE (Bit 5) */
+#define RUSB2_BCCTRL_DCPMODE_Msk (0x20UL) /* DCPMODE (Bitfield-Mask: 0x01) */
+#define RUSB2_BCCTRL_VDMSRCE_Pos (4UL) /* VDMSRCE (Bit 4) */
+#define RUSB2_BCCTRL_VDMSRCE_Msk (0x10UL) /* VDMSRCE (Bitfield-Mask: 0x01) */
+#define RUSB2_BCCTRL_IDPSINKE_Pos (3UL) /* IDPSINKE (Bit 3) */
+#define RUSB2_BCCTRL_IDPSINKE_Msk (0x8UL) /* IDPSINKE (Bitfield-Mask: 0x01) */
+#define RUSB2_BCCTRL_VDPSRCE_Pos (2UL) /* VDPSRCE (Bit 2) */
+#define RUSB2_BCCTRL_VDPSRCE_Msk (0x4UL) /* VDPSRCE (Bitfield-Mask: 0x01) */
+#define RUSB2_BCCTRL_IDMSINKE_Pos (1UL) /* IDMSINKE (Bit 1) */
+#define RUSB2_BCCTRL_IDMSINKE_Msk (0x2UL) /* IDMSINKE (Bitfield-Mask: 0x01) */
+#define RUSB2_BCCTRL_IDPSRCE_Pos (0UL) /* IDPSRCE (Bit 0) */
+#define RUSB2_BCCTRL_IDPSRCE_Msk (0x1UL) /* IDPSRCE (Bitfield-Mask: 0x01) */
+
+// PL1CTRL1
+#define RUSB2_PL1CTRL1_L1EXTMD_Pos (14UL) /* L1EXTMD (Bit 14) */
+#define RUSB2_PL1CTRL1_L1EXTMD_Msk (0x4000UL) /* L1EXTMD (Bitfield-Mask: 0x01) */
+#define RUSB2_PL1CTRL1_HIRDTHR_Pos (8UL) /* HIRDTHR (Bit 8) */
+#define RUSB2_PL1CTRL1_HIRDTHR_Msk (0xf00UL) /* HIRDTHR (Bitfield-Mask: 0x0f) */
+#define RUSB2_PL1CTRL1_DVSQ_Pos (4UL) /* DVSQ (Bit 4) */
+#define RUSB2_PL1CTRL1_DVSQ_Msk (0xf0UL) /* DVSQ (Bitfield-Mask: 0x0f) */
+#define RUSB2_PL1CTRL1_L1NEGOMD_Pos (3UL) /* L1NEGOMD (Bit 3) */
+#define RUSB2_PL1CTRL1_L1NEGOMD_Msk (0x8UL) /* L1NEGOMD (Bitfield-Mask: 0x01) */
+#define RUSB2_PL1CTRL1_L1RESPMD_Pos (1UL) /* L1RESPMD (Bit 1) */
+#define RUSB2_PL1CTRL1_L1RESPMD_Msk (0x6UL) /* L1RESPMD (Bitfield-Mask: 0x03) */
+#define RUSB2_PL1CTRL1_L1RESPEN_Pos (0UL) /* L1RESPEN (Bit 0) */
+#define RUSB2_PL1CTRL1_L1RESPEN_Msk (0x1UL) /* L1RESPEN (Bitfield-Mask: 0x01) */
+
+// PL1CTRL2
+#define RUSB2_PL1CTRL2_RWEMON_Pos (12UL) /* RWEMON (Bit 12) */
+#define RUSB2_PL1CTRL2_RWEMON_Msk (0x1000UL) /* RWEMON (Bitfield-Mask: 0x01) */
+#define RUSB2_PL1CTRL2_HIRDMON_Pos (8UL) /* HIRDMON (Bit 8) */
+#define RUSB2_PL1CTRL2_HIRDMON_Msk (0xf00UL) /* HIRDMON (Bitfield-Mask: 0x0f) */
+
+// HL1CTRL1
+#define RUSB2_HL1CTRL1_L1STATUS_Pos (1UL) /* L1STATUS (Bit 1) */
+#define RUSB2_HL1CTRL1_L1STATUS_Msk (0x6UL) /* L1STATUS (Bitfield-Mask: 0x03) */
+#define RUSB2_HL1CTRL1_L1REQ_Pos (0UL) /* L1REQ (Bit 0) */
+#define RUSB2_HL1CTRL1_L1REQ_Msk (0x1UL) /* L1REQ (Bitfield-Mask: 0x01) */
+
+// HL1CTRL2
+#define RUSB2_HL1CTRL2_BESL_Pos (15UL) /* BESL (Bit 15) */
+#define RUSB2_HL1CTRL2_BESL_Msk (0x8000UL) /* BESL (Bitfield-Mask: 0x01) */
+#define RUSB2_HL1CTRL2_L1RWE_Pos (12UL) /* L1RWE (Bit 12) */
+#define RUSB2_HL1CTRL2_L1RWE_Msk (0x1000UL) /* L1RWE (Bitfield-Mask: 0x01) */
+#define RUSB2_HL1CTRL2_HIRD_Pos (8UL) /* HIRD (Bit 8) */
+#define RUSB2_HL1CTRL2_HIRD_Msk (0xf00UL) /* HIRD (Bitfield-Mask: 0x0f) */
+#define RUSB2_HL1CTRL2_L1ADDR_Pos (0UL) /* L1ADDR (Bit 0) */
+#define RUSB2_HL1CTRL2_L1ADDR_Msk (0xfUL) /* L1ADDR (Bitfield-Mask: 0x0f) */
+
+// PHYTRIM1
+#define RUSB2_PHYTRIM1_IMPOFFSET_Pos (12UL) /*!< IMPOFFSET (Bit 12) */
+#define RUSB2_PHYTRIM1_IMPOFFSET_Msk (0x7000UL) /*!< IMPOFFSET (Bitfield-Mask: 0x07) */
+#define RUSB2_PHYTRIM1_HSIUP_Pos (8UL) /*!< HSIUP (Bit 8) */
+#define RUSB2_PHYTRIM1_HSIUP_Msk (0xf00UL) /*!< HSIUP (Bitfield-Mask: 0x0f) */
+#define RUSB2_PHYTRIM1_PCOMPENB_Pos (7UL) /*!< PCOMPENB (Bit 7) */
+#define RUSB2_PHYTRIM1_PCOMPENB_Msk (0x80UL) /*!< PCOMPENB (Bitfield-Mask: 0x01) */
+#define RUSB2_PHYTRIM1_DFALL_Pos (2UL) /*!< DFALL (Bit 2) */
+#define RUSB2_PHYTRIM1_DFALL_Msk (0xcUL) /*!< DFALL (Bitfield-Mask: 0x03) */
+#define RUSB2_PHYTRIM1_DRISE_Pos (0UL) /*!< DRISE (Bit 0) */
+#define RUSB2_PHYTRIM1_DRISE_Msk (0x3UL) /*!< DRISE (Bitfield-Mask: 0x03) */
+
+// PHYTRIM2
+#define RUSB2_PHYTRIM2_DIS_Pos (12UL) /*!< DIS (Bit 12) */
+#define RUSB2_PHYTRIM2_DIS_Msk (0x7000UL) /*!< DIS (Bitfield-Mask: 0x07) */
+#define RUSB2_PHYTRIM2_PDR_Pos (8UL) /*!< PDR (Bit 8) */
+#define RUSB2_PHYTRIM2_PDR_Msk (0x300UL) /*!< PDR (Bitfield-Mask: 0x03) */
+#define RUSB2_PHYTRIM2_HSRXENMO_Pos (7UL) /*!< HSRXENMO (Bit 7) */
+#define RUSB2_PHYTRIM2_HSRXENMO_Msk (0x80UL) /*!< HSRXENMO (Bitfield-Mask: 0x01) */
+#define RUSB2_PHYTRIM2_SQU_Pos (0UL) /*!< SQU (Bit 0) */
+#define RUSB2_PHYTRIM2_SQU_Msk (0xfUL) /*!< SQU (Bitfield-Mask: 0x0f) */
+
+// DPUSR0R
+#define RUSB2_DPUSR0R_DVBSTSHM_Pos (23UL) /* DVBSTSHM (Bit 23) */
+#define RUSB2_DPUSR0R_DVBSTSHM_Msk (0x800000UL) /* DVBSTSHM (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR0R_DOVCBHM_Pos (21UL) /* DOVCBHM (Bit 21) */
+#define RUSB2_DPUSR0R_DOVCBHM_Msk (0x200000UL) /* DOVCBHM (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR0R_DOVCAHM_Pos (20UL) /* DOVCAHM (Bit 20) */
+#define RUSB2_DPUSR0R_DOVCAHM_Msk (0x100000UL) /* DOVCAHM (Bitfield-Mask: 0x01) */
+
+// DPUSR1R
+#define RUSB2_DPUSR1R_DVBSTSH_Pos (23UL) /* DVBSTSH (Bit 23) */
+#define RUSB2_DPUSR1R_DVBSTSH_Msk (0x800000UL) /* DVBSTSH (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_DOVCBH_Pos (21UL) /* DOVCBH (Bit 21) */
+#define RUSB2_DPUSR1R_DOVCBH_Msk (0x200000UL) /* DOVCBH (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_DOVCAH_Pos (20UL) /* DOVCAH (Bit 20) */
+#define RUSB2_DPUSR1R_DOVCAH_Msk (0x100000UL) /* DOVCAH (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_DVBSTSHE_Pos (7UL) /* DVBSTSHE (Bit 7) */
+#define RUSB2_DPUSR1R_DVBSTSHE_Msk (0x80UL) /* DVBSTSHE (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_DOVCBHE_Pos (5UL) /* DOVCBHE (Bit 5) */
+#define RUSB2_DPUSR1R_DOVCBHE_Msk (0x20UL) /* DOVCBHE (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_DOVCAHE_Pos (4UL) /* DOVCAHE (Bit 4) */
+#define RUSB2_DPUSR1R_DOVCAHE_Msk (0x10UL) /* DOVCAHE (Bitfield-Mask: 0x01) */
+
+// DPUSR2R
+#define RUSB2_DPUSR2R_DMINTE_Pos (9UL) /* DMINTE (Bit 9) */
+#define RUSB2_DPUSR2R_DMINTE_Msk (0x200UL) /* DMINTE (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR2R_DPINTE_Pos (8UL) /* DPINTE (Bit 8) */
+#define RUSB2_DPUSR2R_DPINTE_Msk (0x100UL) /* DPINTE (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR2R_DMVAL_Pos (5UL) /* DMVAL (Bit 5) */
+#define RUSB2_DPUSR2R_DMVAL_Msk (0x20UL) /* DMVAL (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR2R_DPVAL_Pos (4UL) /* DPVAL (Bit 4) */
+#define RUSB2_DPUSR2R_DPVAL_Msk (0x10UL) /* DPVAL (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR2R_DMINT_Pos (1UL) /* DMINT (Bit 1) */
+#define RUSB2_DPUSR2R_DMINT_Msk (0x2UL) /* DMINT (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR2R_DPINT_Pos (0UL) /* DPINT (Bit 0) */
+#define RUSB2_DPUSR2R_DPINT_Msk (0x1UL) /* DPINT (Bitfield-Mask: 0x01) */
+
+// DPUSRCR
+#define RUSB2_DPUSRCR_FIXPHYPD_Pos (1UL) /* FIXPHYPD (Bit 1) */
+#define RUSB2_DPUSRCR_FIXPHYPD_Msk (0x2UL) /* FIXPHYPD (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSRCR_FIXPHY_Pos (0UL) /* FIXPHY (Bit 0) */
+#define RUSB2_DPUSRCR_FIXPHY_Msk (0x1UL) /* FIXPHY (Bitfield-Mask: 0x01) */
+
+// DPUSR0R_FS
+#define RUSB2_DPUSR0R_FS_DVBSTS0_Pos (23UL) /* DVBSTS0 (Bit 23) */
+#define RUSB2_DPUSR0R_FS_DVBSTS0_Msk (0x800000UL) /* DVBSTS0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR0R_FS_DOVCB0_Pos (21UL) /* DOVCB0 (Bit 21) */
+#define RUSB2_DPUSR0R_FS_DOVCB0_Msk (0x200000UL) /* DOVCB0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR0R_FS_DOVCA0_Pos (20UL) /* DOVCA0 (Bit 20) */
+#define RUSB2_DPUSR0R_FS_DOVCA0_Msk (0x100000UL) /* DOVCA0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR0R_FS_DM0_Pos (17UL) /* DM0 (Bit 17) */
+#define RUSB2_DPUSR0R_FS_DM0_Msk (0x20000UL) /* DM0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR0R_FS_DP0_Pos (16UL) /* DP0 (Bit 16) */
+#define RUSB2_DPUSR0R_FS_DP0_Msk (0x10000UL) /* DP0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR0R_FS_FIXPHY0_Pos (4UL) /* FIXPHY0 (Bit 4) */
+#define RUSB2_DPUSR0R_FS_FIXPHY0_Msk (0x10UL) /* FIXPHY0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR0R_FS_DRPD0_Pos (3UL) /* DRPD0 (Bit 3) */
+#define RUSB2_DPUSR0R_FS_DRPD0_Msk (0x8UL) /* DRPD0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR0R_FS_RPUE0_Pos (1UL) /* RPUE0 (Bit 1) */
+#define RUSB2_DPUSR0R_FS_RPUE0_Msk (0x2UL) /* RPUE0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR0R_FS_SRPC0_Pos (0UL) /* SRPC0 (Bit 0) */
+#define RUSB2_DPUSR0R_FS_SRPC0_Msk (0x1UL) /* SRPC0 (Bitfield-Mask: 0x01) */
+
+// DPUSR1R_FS
+#define RUSB2_DPUSR1R_FS_DVBINT0_Pos (23UL) /* DVBINT0 (Bit 23) */
+#define RUSB2_DPUSR1R_FS_DVBINT0_Msk (0x800000UL) /* DVBINT0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_FS_DOVRCRB0_Pos (21UL) /* DOVRCRB0 (Bit 21) */
+#define RUSB2_DPUSR1R_FS_DOVRCRB0_Msk (0x200000UL) /* DOVRCRB0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_FS_DOVRCRA0_Pos (20UL) /* DOVRCRA0 (Bit 20) */
+#define RUSB2_DPUSR1R_FS_DOVRCRA0_Msk (0x100000UL) /* DOVRCRA0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_FS_DMINT0_Pos (17UL) /* DMINT0 (Bit 17) */
+#define RUSB2_DPUSR1R_FS_DMINT0_Msk (0x20000UL) /* DMINT0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_FS_DPINT0_Pos (16UL) /* DPINT0 (Bit 16) */
+#define RUSB2_DPUSR1R_FS_DPINT0_Msk (0x10000UL) /* DPINT0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_FS_DVBSE0_Pos (7UL) /* DVBSE0 (Bit 7) */
+#define RUSB2_DPUSR1R_FS_DVBSE0_Msk (0x80UL) /* DVBSE0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_FS_DOVRCRBE0_Pos (5UL) /* DOVRCRBE0 (Bit 5) */
+#define RUSB2_DPUSR1R_FS_DOVRCRBE0_Msk (0x20UL) /* DOVRCRBE0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_FS_DOVRCRAE0_Pos (4UL) /* DOVRCRAE0 (Bit 4) */
+#define RUSB2_DPUSR1R_FS_DOVRCRAE0_Msk (0x10UL) /* DOVRCRAE0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_FS_DMINTE0_Pos (1UL) /* DMINTE0 (Bit 1) */
+#define RUSB2_DPUSR1R_FS_DMINTE0_Msk (0x2UL) /* DMINTE0 (Bitfield-Mask: 0x01) */
+#define RUSB2_DPUSR1R_FS_DPINTE0_Pos (0UL) /* DPINTE0 (Bit 0) */
+#define RUSB2_DPUSR1R_FS_DPINTE0_Msk (0x1UL) /* DPINTE0 (Bitfield-Mask: 0x01) */
+
+/*--------------------------------------------------------------------*/
+/* Register Bit Utils */
+/*--------------------------------------------------------------------*/
+#define RUSB2_PIPE_CTR_PID_NAK (0U << RUSB2_PIPE_CTR_PID_Pos) /* NAK response */
+#define RUSB2_PIPE_CTR_PID_BUF (1U << RUSB2_PIPE_CTR_PID_Pos) /* BUF response (depends buffer state) */
+#define RUSB2_PIPE_CTR_PID_STALL (2U << RUSB2_PIPE_CTR_PID_Pos) /* STALL response */
+#define RUSB2_PIPE_CTR_PID_STALL2 (3U << RUSB2_PIPE_CTR_PID_Pos) /* Also STALL response */
+
+#define RUSB2_DVSTCTR0_RHST_LS (1U << RUSB2_DVSTCTR0_RHST_Pos) /* Low-speed connection */
+#define RUSB2_DVSTCTR0_RHST_FS (2U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */
+#define RUSB2_DVSTCTR0_RHST_HS (3U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */
+
+#define RUSB2_DEVADD_USBSPD_LS (1U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Low-speed */
+#define RUSB2_DEVADD_USBSPD_FS (2U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Full-speed */
+
+#define RUSB2_CFIFOSEL_ISEL_WRITE (1U << RUSB2_CFIFOSEL_ISEL_Pos) /* FIFO write AKA TX*/
+
+#define RUSB2_FIFOSEL_BIGEND (1U << RUSB2_CFIFOSEL_BIGEND_Pos) /* FIFO Big Endian */
+#define RUSB2_FIFOSEL_MBW_8BIT (0U << RUSB2_CFIFOSEL_MBW_Pos) /* 8-bit width */
+#define RUSB2_FIFOSEL_MBW_16BIT (1U << RUSB2_CFIFOSEL_MBW_Pos) /* 16-bit width */
+#define RUSB2_FIFOSEL_MBW_32BIT (2U << RUSB2_CFIFOSEL_MBW_Pos) /* 32-bit width */
+
+#define RUSB2_INTSTS0_CTSQ_CTRL_RDATA (1U << RUSB2_INTSTS0_CTSQ_Pos)
+
+#define RUSB2_INTSTS0_DVSQ_STATE_DEF (1U << RUSB2_INTSTS0_DVSQ_Pos) /* Default state */
+#define RUSB2_INTSTS0_DVSQ_STATE_ADDR (2U << RUSB2_INTSTS0_DVSQ_Pos) /* Address state */
+#define RUSB2_INTSTS0_DVSQ_STATE_SUSP0 (4U << RUSB2_INTSTS0_DVSQ_Pos) /* Suspend state */
+#define RUSB2_INTSTS0_DVSQ_STATE_SUSP1 (5U << RUSB2_INTSTS0_DVSQ_Pos) /* Suspend state */
+#define RUSB2_INTSTS0_DVSQ_STATE_SUSP2 (6U << RUSB2_INTSTS0_DVSQ_Pos) /* Suspend state */
+#define RUSB2_INTSTS0_DVSQ_STATE_SUSP3 (7U << RUSB2_INTSTS0_DVSQ_Pos) /* Suspend state */
+
+#define RUSB2_PIPECFG_TYPE_BULK (1U << RUSB2_PIPECFG_TYPE_Pos)
+#define RUSB2_PIPECFG_TYPE_INT (2U << RUSB2_PIPECFG_TYPE_Pos)
+#define RUSB2_PIPECFG_TYPE_ISO (3U << RUSB2_PIPECFG_TYPE_Pos)
+
+//--------------------------------------------------------------------+
+// Static Assert
+//--------------------------------------------------------------------+
+
+TU_VERIFY_STATIC(sizeof(RUSB2_PIPE_TR_t) == 4, "incorrect size");
+TU_VERIFY_STATIC(sizeof(rusb2_reg_t) == 1032, "incorrect size");
+
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, SYSCFG ) == 0x0000, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, BUSWAIT ) == 0x0002, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, SYSSTS0 ) == 0x0004, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PLLSTA ) == 0x0006, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DVSTCTR0 ) == 0x0008, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, TESTMODE ) == 0x000C, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, CFIFO ) == 0x0014, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, D0FIFO ) == 0x0018, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, D1FIFO ) == 0x001C, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, CFIFOSEL ) == 0x0020, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, CFIFOCTR ) == 0x0022, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, D0FIFOSEL ) == 0x0028, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, D0FIFOCTR ) == 0x002A, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, D1FIFOSEL ) == 0x002C, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, D1FIFOCTR ) == 0x002E, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, INTENB0 ) == 0x0030, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, INTENB1 ) == 0x0032, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, BRDYENB ) == 0x0036, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, NRDYENB ) == 0x0038, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, BEMPENB ) == 0x003A, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, SOFCFG ) == 0x003C, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PHYSET ) == 0x003E, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, INTSTS0 ) == 0x0040, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, INTSTS1 ) == 0x0042, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, BRDYSTS ) == 0x0046, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, NRDYSTS ) == 0x0048, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, BEMPSTS ) == 0x004A, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, FRMNUM ) == 0x004C, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, UFRMNUM ) == 0x004E, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBADDR ) == 0x0050, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBREQ ) == 0x0054, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBVAL ) == 0x0056, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBINDX ) == 0x0058, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBLENG ) == 0x005A, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DCPCFG ) == 0x005C, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DCPMAXP ) == 0x005E, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DCPCTR ) == 0x0060, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPESEL ) == 0x0064, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPECFG ) == 0x0068, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPEBUF ) == 0x006A, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPEMAXP ) == 0x006C, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPEPERI ) == 0x006E, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPE_CTR ) == 0x0070, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPE_TR ) == 0x0090, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBBCCTRL0 ) == 0x00B0, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, UCKSEL ) == 0x00C4, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBMC ) == 0x00CC, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DEVADD ) == 0x00D0, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PHYSLEW ) == 0x00F0, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, LPCTRL ) == 0x0100, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, LPSTS ) == 0x0102, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, BCCTRL ) == 0x0140, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PL1CTRL1 ) == 0x0144, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PL1CTRL2 ) == 0x0146, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, HL1CTRL1 ) == 0x0148, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, HL1CTRL2 ) == 0x014A, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PHYTRIM1 ) == 0x0150, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PHYTRIM2 ) == 0x0152, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DPUSR0R ) == 0x0160, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DPUSR1R ) == 0x0164, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DPUSR2R ) == 0x0168, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DPUSRCR ) == 0x016A, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DPUSR0R_FS ) == 0x0400, "incorrect offset");
+TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DPUSR1R_FS ) == 0x0404, "incorrect offset");
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TUSB_RUSB2_TYPE_H_ */
diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c
deleted file mode 100644
index 06ea1a3f9..000000000
--- a/src/portable/renesas/usba/dcd_usba.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2020 Koji Kitayama
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-#include "tusb_option.h"
-
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X )
-
-#include "device/dcd.h"
-#include "iodefine.h"
-
-//--------------------------------------------------------------------+
-// MACRO TYPEDEF CONSTANT ENUM DECLARATION
-//--------------------------------------------------------------------+
-#define SYSTEM_PRCR_PRC1 (1<<1)
-#define SYSTEM_PRCR_PRKEY (0xA5u<<8)
-
-#define USB_FIFOSEL_TX ((uint16_t)(1u<<5))
-#define USB_FIFOSEL_MBW_8 ((uint16_t)(0u<<10))
-#define USB_FIFOSEL_MBW_16 ((uint16_t)(1u<<10))
-#define USB_IS0_CTSQ ((uint16_t)(7u))
-#define USB_IS0_DVSQ ((uint16_t)(7u<<4))
-#define USB_IS0_VALID ((uint16_t)(1u<<3))
-#define USB_IS0_BRDY ((uint16_t)(1u<<8))
-#define USB_IS0_NRDY ((uint16_t)(1u<<9))
-#define USB_IS0_BEMP ((uint16_t)(1u<<10))
-#define USB_IS0_CTRT ((uint16_t)(1u<<11))
-#define USB_IS0_DVST ((uint16_t)(1u<<12))
-#define USB_IS0_SOFR ((uint16_t)(1u<<13))
-#define USB_IS0_RESM ((uint16_t)(1u<<14))
-#define USB_IS0_VBINT ((uint16_t)(1u<<15))
-#define USB_IS1_SACK ((uint16_t)(1u<<4))
-#define USB_IS1_SIGN ((uint16_t)(1u<<5))
-#define USB_IS1_EOFERR ((uint16_t)(1u<<6))
-#define USB_IS1_ATTCH ((uint16_t)(1u<<11))
-#define USB_IS1_DTCH ((uint16_t)(1u<<12))
-#define USB_IS1_BCHG ((uint16_t)(1u<<14))
-#define USB_IS1_OVRCR ((uint16_t)(1u<<15))
-
-#define USB_IS0_CTSQ_MSK (7u)
-#define USB_IS0_CTSQ_SETUP (1u)
-#define USB_IS0_DVSQ_DEF (1u<<4)
-#define USB_IS0_DVSQ_ADDR (2u<<4)
-#define USB_IS0_DVSQ_SUSP (4u<<4)
-
-#define USB_PIPECTR_PID_NAK (0u)
-#define USB_PIPECTR_PID_BUF (1u)
-#define USB_PIPECTR_PID_STALL (2u)
-#define USB_PIPECTR_CCPL (1u<<2)
-#define USB_PIPECTR_SQMON (1u<<6)
-#define USB_PIPECTR_SQCLR (1u<<8)
-#define USB_PIPECTR_ACLRM (1u<<9)
-#define USB_PIPECTR_INBUFM (1u<<14)
-#define USB_PIPECTR_BSTS (1u<<15)
-
-#define USB_FIFOCTR_DTLN (0x1FF)
-#define USB_FIFOCTR_FRDY (1u<<13)
-#define USB_FIFOCTR_BCLR (1u<<14)
-#define USB_FIFOCTR_BVAL (1u<<15)
-
-#define USB_PIPECFG_SHTNAK (1u<<7)
-#define USB_PIPECFG_DBLB (1u<<9)
-#define USB_PIPECFG_BULK (1u<<14)
-#define USB_PIPECFG_ISO (3u<<14)
-#define USB_PIPECFG_INT (2u<<14)
-
-#define FIFO_REQ_CLR (1u)
-#define FIFO_COMPLETE (1u<<1)
-
-typedef struct {
- union {
- struct {
- uint16_t : 8;
- uint16_t TRCLR: 1;
- uint16_t TRENB: 1;
- uint16_t : 0;
- };
- uint16_t TRE;
- };
- uint16_t TRN;
-} reg_pipetre_t;
-
-typedef union {
- struct {
- volatile uint16_t u8: 8;
- volatile uint16_t : 0;
- };
- volatile uint16_t u16;
-} hw_fifo_t;
-
-typedef struct TU_ATTR_PACKED
-{
- uintptr_t addr; /* the start address of a transfer data buffer */
- uint16_t length; /* the number of bytes in the buffer */
- uint16_t remaining; /* the number of bytes remaining in the buffer */
- struct {
- uint32_t ep : 8; /* an assigned endpoint address */
- uint32_t : 0;
- };
-} pipe_state_t;
-
-typedef struct
-{
- pipe_state_t pipe[9];
- uint8_t ep[2][16]; /* a lookup table for a pipe index from an endpoint address */
-} dcd_data_t;
-
-//--------------------------------------------------------------------+
-// INTERNAL OBJECT & FUNCTION DECLARATION
-//--------------------------------------------------------------------+
-CFG_TUSB_MEM_SECTION static dcd_data_t _dcd;
-
-static uint32_t disable_interrupt(void)
-{
- uint32_t pswi;
- pswi = __builtin_rx_mvfc(0) & 0x010000;
- __builtin_rx_clrpsw('I');
- return pswi;
-}
-
-static void enable_interrupt(uint32_t pswi)
-{
- __builtin_rx_mvtc(0, __builtin_rx_mvfc(0) | pswi);
-}
-
-static unsigned find_pipe(unsigned xfer)
-{
- switch (xfer) {
- case TUSB_XFER_ISOCHRONOUS:
- for (int i = 1; i <= 2; ++i) {
- if (0 == _dcd.pipe[i].ep) return i;
- }
- break;
- case TUSB_XFER_BULK:
- for (int i = 3; i <= 5; ++i) {
- if (0 == _dcd.pipe[i].ep) return i;
- }
- for (int i = 1; i <= 1; ++i) {
- if (0 == _dcd.pipe[i].ep) return i;
- }
- break;
- case TUSB_XFER_INTERRUPT:
- for (int i = 6; i <= 9; ++i) {
- if (0 == _dcd.pipe[i].ep) return i;
- }
- break;
- default:
- /* No support for control transfer */
- break;
- }
- return 0;
-}
-
-static volatile uint16_t* get_pipectr(unsigned num)
-{
- volatile uint16_t *ctr = NULL;
- if (num) {
- ctr = (volatile uint16_t*)&USB0.PIPE1CTR.WORD;
- ctr += num - 1;
- } else {
- ctr = (volatile uint16_t*)&USB0.DCPCTR.WORD;
- }
- return ctr;
-}
-
-static volatile reg_pipetre_t* get_pipetre(unsigned num)
-{
- volatile reg_pipetre_t* tre = NULL;
- if ((1 <= num) && (num <= 5)) {
- tre = (volatile reg_pipetre_t*)&USB0.PIPE1TRE.WORD;
- tre += num - 1;
- }
- return tre;
-}
-
-static volatile uint16_t* ep_addr_to_pipectr(uint8_t rhport, unsigned ep_addr)
-{
- (void)rhport;
- volatile uint16_t *ctr = NULL;
- const unsigned epn = tu_edpt_number(ep_addr);
- if (epn) {
- const unsigned dir = tu_edpt_dir(ep_addr);
- const unsigned num = _dcd.ep[dir][epn];
- if (num) {
- ctr = (volatile uint16_t*)&USB0.PIPE1CTR.WORD;
- ctr += num - 1;
- }
- } else {
- ctr = (volatile uint16_t*)&USB0.DCPCTR.WORD;
- }
- return ctr;
-}
-
-static unsigned wait_for_pipe_ready(void)
-{
- unsigned ctr;
- do {
- ctr = USB0.D0FIFOCTR.WORD;
- } while (!(ctr & USB_FIFOCTR_FRDY));
- return ctr;
-}
-
-static unsigned select_pipe(unsigned num, unsigned attr)
-{
- USB0.PIPESEL.WORD = num;
- USB0.D0FIFOSEL.WORD = num | attr;
- while (!(USB0.D0FIFOSEL.BIT.CURPIPE != num)) ;
- return wait_for_pipe_ready();
-}
-
-/* 1 less than mps bytes were written to FIFO
- * 2 no bytes were written to FIFO
- * 0 mps bytes were written to FIFO */
-static int fifo_write(volatile void *fifo, pipe_state_t* pipe, unsigned mps)
-{
- unsigned rem = pipe->remaining;
- if (!rem) return 2;
- unsigned len = TU_MIN(rem, mps);
-
- hw_fifo_t *reg = (hw_fifo_t*)fifo;
- uintptr_t addr = pipe->addr + pipe->length - rem;
- if (addr & 1u) {
- /* addr is not 2-byte aligned */
- reg->u8 = *(const uint8_t *)addr;
- ++addr;
- --len;
- }
- while (len >= 2) {
- reg->u16 = *(const uint16_t *)addr;
- addr += 2;
- len -= 2;
- }
- if (len) {
- reg->u8 = *(const uint8_t *)addr;
- ++addr;
- }
- if (rem < mps) return 1;
- return 0;
-}
-
-/* 1 less than mps bytes were read from FIFO
- * 2 the end of the buffer reached.
- * 0 mps bytes were read from FIFO */
-static int fifo_read(volatile void *fifo, pipe_state_t* pipe, unsigned mps, size_t len)
-{
- unsigned rem = pipe->remaining;
- if (!rem) return 2;
- if (rem < len) len = rem;
- pipe->remaining = rem - len;
-
- hw_fifo_t *reg = (hw_fifo_t*)fifo;
- uintptr_t addr = pipe->addr;
- unsigned loop = len;
- while (loop--) {
- *(uint8_t *)addr = reg->u8;
- ++addr;
- }
- pipe->addr = addr;
- if (rem < mps) return 1;
- if (rem == len) return 2;
- return 0;
-}
-
-static void process_setup_packet(uint8_t rhport)
-{
- uint16_t setup_packet[4];
- if (0 == (USB0.INTSTS0.WORD & USB_IS0_VALID)) return;
- USB0.CFIFOCTR.WORD = USB_FIFOCTR_BCLR;
- setup_packet[0] = USB0.USBREQ.WORD;
- setup_packet[1] = USB0.USBVAL;
- setup_packet[2] = USB0.USBINDX;
- setup_packet[3] = USB0.USBLENG;
- USB0.INTSTS0.WORD = ~USB_IS0_VALID;
- dcd_event_setup_received(rhport, (const uint8_t*)&setup_packet[0], true);
-}
-
-static void process_status_completion(uint8_t rhport)
-{
- uint8_t ep_addr;
- /* Check the data stage direction */
- if (USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX) {
- /* IN transfer. */
- ep_addr = tu_edpt_addr(0, TUSB_DIR_IN);
- } else {
- /* OUT transfer. */
- ep_addr = tu_edpt_addr(0, TUSB_DIR_OUT);
- }
- dcd_event_xfer_complete(rhport, ep_addr, 0, XFER_RESULT_SUCCESS, true);
-}
-
-static bool process_edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
-{
- (void)rhport;
-
- pipe_state_t *pipe = &_dcd.pipe[0];
- /* configure fifo direction and access unit settings */
- if (ep_addr) { /* IN, 2 bytes */
- USB0.CFIFOSEL.WORD = USB_FIFOSEL_TX | USB_FIFOSEL_MBW_16;
- while (!(USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX)) ;
- } else { /* OUT, a byte */
- USB0.CFIFOSEL.WORD = USB_FIFOSEL_MBW_8;
- while (USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX) ;
- }
- if (total_bytes) {
- pipe->addr = (uintptr_t)buffer;
- pipe->length = total_bytes;
- pipe->remaining = total_bytes;
- if (ep_addr) { /* IN */
- TU_ASSERT(USB0.DCPCTR.BIT.BSTS && (USB0.USBREQ.WORD & 0x80));
- if (fifo_write(&USB0.CFIFO.WORD, pipe, 64)) {
- USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL;
- }
- }
- USB0.DCPCTR.WORD = USB_PIPECTR_PID_BUF;
- } else {
- /* ZLP */
- pipe->addr = 0;
- pipe->length = 0;
- pipe->remaining = 0;
- USB0.DCPCTR.WORD = USB_PIPECTR_CCPL | USB_PIPECTR_PID_BUF;
- }
- return true;
-}
-
-static void process_edpt0_bemp(uint8_t rhport)
-{
- pipe_state_t *pipe = &_dcd.pipe[0];
- const unsigned rem = pipe->remaining;
- if (rem > 64) {
- pipe->remaining = rem - 64;
- int r = fifo_write(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64);
- if (r) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL;
- return;
- }
- pipe->addr = 0;
- pipe->remaining = 0;
- dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_IN),
- pipe->length, XFER_RESULT_SUCCESS, true);
-}
-
-static void process_edpt0_brdy(uint8_t rhport)
-{
- size_t len = USB0.CFIFOCTR.BIT.DTLN;
- int cplt = fifo_read(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64, len);
- if (cplt || (len < 64)) {
- if (2 != cplt) {
- USB0.CFIFOCTR.WORD = USB_FIFOCTR_BCLR;
- }
- dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_OUT),
- _dcd.pipe[0].length - _dcd.pipe[0].remaining,
- XFER_RESULT_SUCCESS, true);
- }
-}
-
-static bool process_pipe_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
-{
- (void)rhport;
-
- const unsigned epn = tu_edpt_number(ep_addr);
- const unsigned dir = tu_edpt_dir(ep_addr);
- const unsigned num = _dcd.ep[dir][epn];
-
- TU_ASSERT(num);
-
- pipe_state_t *pipe = &_dcd.pipe[num];
- pipe->addr = (uintptr_t)buffer;
- pipe->length = total_bytes;
- pipe->remaining = total_bytes;
-
- USB0.PIPESEL.WORD = num;
- const unsigned mps = USB0.PIPEMAXP.WORD;
- if (dir) { /* IN */
- USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_16;
- while (!(USB0.D0FIFOSEL.BIT.CURPIPE != num)) ;
- int r = fifo_write(&USB0.D0FIFO.WORD, pipe, mps);
- if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL;
- USB0.D0FIFOSEL.WORD = 0;
- } else {
- volatile reg_pipetre_t *pt = get_pipetre(num);
- if (pt) {
- volatile uint16_t *ctr = get_pipectr(num);
- if (*ctr & 0x3) *ctr = USB_PIPECTR_PID_NAK;
- pt->TRE = TU_BIT(8);
- pt->TRN = (total_bytes + mps - 1) / mps;
- pt->TRENB = 1;
- *ctr = USB_PIPECTR_PID_BUF;
- }
- }
- // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes);
- return true;
-}
-
-static void process_pipe_brdy(uint8_t rhport, unsigned num)
-{
- pipe_state_t *pipe = &_dcd.pipe[num];
- if (tu_edpt_dir(pipe->ep)) { /* IN */
- select_pipe(num, USB_FIFOSEL_MBW_16);
- const unsigned mps = USB0.PIPEMAXP.WORD;
- unsigned rem = pipe->remaining;
- rem -= TU_MIN(rem, mps);
- pipe->remaining = rem;
- if (rem) {
- int r = 0;
- r = fifo_write(&USB0.D0FIFO.WORD, pipe, mps);
- if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL;
- USB0.D0FIFOSEL.WORD = 0;
- return;
- }
- USB0.D0FIFOSEL.WORD = 0;
- pipe->addr = 0;
- pipe->remaining = 0;
- dcd_event_xfer_complete(rhport, pipe->ep, pipe->length,
- XFER_RESULT_SUCCESS, true);
- } else {
- const unsigned ctr = select_pipe(num, USB_FIFOSEL_MBW_8);
- const unsigned len = ctr & USB_FIFOCTR_DTLN;
- const unsigned mps = USB0.PIPEMAXP.WORD;
- int cplt = fifo_read(&USB0.D0FIFO.WORD, pipe, mps, len);
- if (cplt || (len < mps)) {
- if (2 != cplt) {
- USB0.D0FIFO.WORD = USB_FIFOCTR_BCLR;
- }
- USB0.D0FIFOSEL.WORD = 0;
- dcd_event_xfer_complete(rhport, pipe->ep,
- pipe->length - pipe->remaining,
- XFER_RESULT_SUCCESS, true);
- return;
- }
- USB0.D0FIFOSEL.WORD = 0;
- }
-}
-
-static void process_bus_reset(uint8_t rhport)
-{
- USB0.BEMPENB.WORD = 1;
- USB0.BRDYENB.WORD = 1;
- USB0.CFIFOCTR.WORD = USB_FIFOCTR_BCLR;
- USB0.D0FIFOSEL.WORD = 0;
- USB0.D1FIFOSEL.WORD = 0;
- volatile uint16_t *ctr = (volatile uint16_t*)((uintptr_t)(&USB0.PIPE1CTR.WORD));
- volatile uint16_t *tre = (volatile uint16_t*)((uintptr_t)(&USB0.PIPE1TRE.WORD));
- for (int i = 1; i <= 5; ++i) {
- USB0.PIPESEL.WORD = i;
- USB0.PIPECFG.WORD = 0;
- *ctr = USB_PIPECTR_ACLRM;
- *ctr = 0;
- ++ctr;
- *tre = TU_BIT(8);
- tre += 2;
- }
- for (int i = 6; i <= 9; ++i) {
- USB0.PIPESEL.WORD = i;
- USB0.PIPECFG.WORD = 0;
- *ctr = USB_PIPECTR_ACLRM;
- *ctr = 0;
- ++ctr;
- }
- tu_varclr(&_dcd);
- dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
-}
-
-static void process_set_address(uint8_t rhport)
-{
- const uint32_t addr = USB0.USBADDR.BIT.USBADDR;
- if (!addr) return;
- const tusb_control_request_t setup_packet = {
- .bmRequestType = 0,
- .bRequest = 5,
- .wValue = addr,
- .wIndex = 0,
- .wLength = 0,
- };
- dcd_event_setup_received(rhport, (const uint8_t*)&setup_packet, true);
-}
-
-/*------------------------------------------------------------------*/
-/* Device API
- *------------------------------------------------------------------*/
-void dcd_init(uint8_t rhport)
-{
- (void)rhport;
- /* Enable USB0 */
- uint32_t pswi = disable_interrupt();
- SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY | SYSTEM_PRCR_PRC1;
- MSTP(USB0) = 0;
- SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY;
- enable_interrupt(pswi);
- USB0.SYSCFG.BIT.SCKE = 1;
- while (!USB0.SYSCFG.BIT.SCKE) ;
- USB0.SYSCFG.BIT.DRPD = 0;
- USB0.SYSCFG.BIT.DCFM = 0;
- USB0.SYSCFG.BIT.USBE = 1;
-
- IR(USB0, USBI0) = 0;
-
- /* Setup default control pipe */
- USB0.DCPMAXP.BIT.MXPS = 64;
- USB0.INTENB0.WORD = USB_IS0_VBINT | USB_IS0_BRDY | USB_IS0_BEMP | USB_IS0_DVST | USB_IS0_CTRT;
- USB0.BEMPENB.WORD = 1;
- USB0.BRDYENB.WORD = 1;
-
- if (USB0.INTSTS0.BIT.VBSTS) {
- dcd_connect(rhport);
- }
-}
-
-void dcd_int_enable(uint8_t rhport)
-{
- (void)rhport;
- IEN(USB0, USBI0) = 1;
-}
-
-void dcd_int_disable(uint8_t rhport)
-{
- (void)rhport;
- IEN(USB0, USBI0) = 0;
-}
-
-void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
-{
- (void)rhport;
- (void)dev_addr;
-}
-
-void dcd_remote_wakeup(uint8_t rhport)
-{
- (void)rhport;
- /* TODO */
-}
-
-void dcd_connect(uint8_t rhport)
-{
- (void)rhport;
- USB0.SYSCFG.BIT.DPRPU = 1;
-}
-
-void dcd_disconnect(uint8_t rhport)
-{
- (void)rhport;
- USB0.SYSCFG.BIT.DPRPU = 0;
-}
-
-//--------------------------------------------------------------------+
-// Endpoint API
-//--------------------------------------------------------------------+
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
-{
- (void)rhport;
-
- const unsigned ep_addr = ep_desc->bEndpointAddress;
- const unsigned epn = tu_edpt_number(ep_addr);
- const unsigned dir = tu_edpt_dir(ep_addr);
- const unsigned xfer = ep_desc->bmAttributes.xfer;
-
- const unsigned mps = ep_desc->wMaxPacketSize.size;
- if (xfer == TUSB_XFER_ISOCHRONOUS && mps > 256) {
- /* USBa supports up to 256 bytes */
- return false;
- }
-
- const unsigned num = find_pipe(xfer);
- if (!num) return false;
- _dcd.pipe[num].ep = ep_addr;
- _dcd.ep[dir][epn] = num;
-
- /* setup pipe */
- dcd_int_disable(rhport);
- USB0.PIPESEL.WORD = num;
- USB0.PIPEMAXP.WORD = mps;
- volatile uint16_t *ctr = get_pipectr(num);
- *ctr = USB_PIPECTR_ACLRM;
- *ctr = 0;
- unsigned cfg = (dir << 4) | epn;
- if (xfer == TUSB_XFER_BULK) {
- cfg |= USB_PIPECFG_BULK | USB_PIPECFG_SHTNAK | USB_PIPECFG_DBLB;
- } else if (xfer == TUSB_XFER_INTERRUPT) {
- cfg |= USB_PIPECFG_INT;
- } else {
- cfg |= USB_PIPECFG_ISO | USB_PIPECFG_DBLB;
- }
- USB0.PIPECFG.WORD = cfg;
- USB0.BRDYSTS.WORD = 0x1FFu ^ TU_BIT(num);
- USB0.BRDYENB.WORD |= TU_BIT(num);
- if (dir || (xfer != TUSB_XFER_BULK)) {
- *ctr = USB_PIPECTR_PID_BUF;
- }
- // TU_LOG1("O %d %x %x\r\n", USB0.PIPESEL.WORD, USB0.PIPECFG.WORD, USB0.PIPEMAXP.WORD);
- dcd_int_enable(rhport);
-
- return true;
-}
-
-void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
-{
- (void)rhport;
- const unsigned epn = tu_edpt_number(ep_addr);
- const unsigned dir = tu_edpt_dir(ep_addr);
- const unsigned num = _dcd.ep[dir][epn];
-
- USB0.BRDYENB.WORD &= ~TU_BIT(num);
- volatile uint16_t *ctr = get_pipectr(num);
- *ctr = 0;
- USB0.PIPESEL.WORD = num;
- USB0.PIPECFG.WORD = 0;
- _dcd.pipe[num].ep = 0;
- _dcd.ep[dir][epn] = 0;
-}
-
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
-{
- bool r;
- const unsigned epn = tu_edpt_number(ep_addr);
- dcd_int_disable(rhport);
- if (0 == epn) {
- r = process_edpt0_xfer(rhport, ep_addr, buffer, total_bytes);
- } else {
- r = process_pipe_xfer(rhport, ep_addr, buffer, total_bytes);
- }
- dcd_int_enable(rhport);
- return r;
-}
-
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
-{
- volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr);
- if (!ctr) return;
- dcd_int_disable(rhport);
- const uint32_t pid = *ctr & 0x3;
- *ctr = pid | USB_PIPECTR_PID_STALL;
- *ctr = USB_PIPECTR_PID_STALL;
- dcd_int_enable(rhport);
-}
-
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
-{
- volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr);
- if (!ctr) return;
- dcd_int_disable(rhport);
- *ctr = USB_PIPECTR_SQCLR;
-
- if (tu_edpt_dir(ep_addr)) { /* IN */
- *ctr = USB_PIPECTR_PID_BUF;
- } else {
- const unsigned num = _dcd.ep[0][tu_edpt_number(ep_addr)];
- USB0.PIPESEL.WORD = num;
- if (USB0.PIPECFG.BIT.TYPE != 1) {
- *ctr = USB_PIPECTR_PID_BUF;
- }
- }
- dcd_int_enable(rhport);
-}
-
-//--------------------------------------------------------------------+
-// ISR
-//--------------------------------------------------------------------+
-void dcd_int_handler(uint8_t rhport)
-{
- (void)rhport;
-
- unsigned is0 = USB0.INTSTS0.WORD;
- /* clear bits except VALID */
- USB0.INTSTS0.WORD = USB_IS0_VALID;
- if (is0 & USB_IS0_VBINT) {
- if (USB0.INTSTS0.BIT.VBSTS) {
- dcd_connect(rhport);
- } else {
- dcd_disconnect(rhport);
- }
- }
- if (is0 & USB_IS0_DVST) {
- switch (is0 & USB_IS0_DVSQ) {
- case USB_IS0_DVSQ_DEF:
- process_bus_reset(rhport);
- break;
- case USB_IS0_DVSQ_ADDR:
- process_set_address(rhport);
- break;
- default:
- break;
- }
- }
- if (is0 & USB_IS0_CTRT) {
- if (is0 & USB_IS0_CTSQ_SETUP) {
- /* A setup packet has been received. */
- process_setup_packet(rhport);
- } else if (0 == (is0 & USB_IS0_CTSQ_MSK)) {
- /* A ZLP has been sent/received. */
- process_status_completion(rhport);
- }
- }
- if (is0 & USB_IS0_BEMP) {
- const unsigned s = USB0.BEMPSTS.WORD;
- USB0.BEMPSTS.WORD = 0;
- if (s & 1) {
- process_edpt0_bemp(rhport);
- }
- }
- if (is0 & USB_IS0_BRDY) {
- const unsigned m = USB0.BRDYENB.WORD;
- unsigned s = USB0.BRDYSTS.WORD & m;
- USB0.BRDYSTS.WORD = 0;
- if (s & 1) {
- process_edpt0_brdy(rhport);
- s &= ~1;
- }
- while (s) {
- const unsigned num = __builtin_ctz(s);
- process_pipe_brdy(rhport, num);
- s &= ~TU_BIT(num);
- }
- }
-}
-
-#endif
diff --git a/src/portable/silabs/efm32/dcd_efm32.c b/src/portable/silabs/efm32/dcd_efm32.c
deleted file mode 100644
index bd1f32e6b..000000000
--- a/src/portable/silabs/efm32/dcd_efm32.c
+++ /dev/null
@@ -1,931 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2021 Rafael Silva (@perigoso)
- * Copyright (c) 2021 Ha Thach (tinyusb.org)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-#include "tusb_option.h"
-
-#if TUSB_OPT_DEVICE_ENABLED && ( \
- (CFG_TUSB_MCU == OPT_MCU_EFM32GG) || \
- (CFG_TUSB_MCU == OPT_MCU_EFM32GG11) || \
- (CFG_TUSB_MCU == OPT_MCU_EFM32GG12) )
-
-/* Silabs */
-#include "em_device.h"
-
-#include "device/dcd.h"
-
-/*
- * Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
- * We disable SOF for now until needed later on
- */
-#define USE_SOF 0
-
-/*
- * Number of endpoints
- * 12 software-configurable endpoints (6 IN, 6 OUT) in addition to endpoint 0
- */
-#define EP_COUNT 7
-
-/* FIFO size in bytes */
-#define EP_FIFO_SIZE 2048
-
-/* Max number of IN EP FIFOs */
-#define EP_FIFO_NUM 7
-
-/* */
-typedef struct {
- uint8_t *buffer;
- uint16_t total_len;
- uint16_t queued_len;
- uint16_t max_size;
- bool short_packet;
-} xfer_ctl_t;
-
-static uint32_t _setup_packet[2];
-
-#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
-static xfer_ctl_t xfer_status[EP_COUNT][2];
-
-/* Keep count of how many FIFOs are in use */
-static uint8_t _allocated_fifos = 1; /* FIFO0 is always in use */
-
-static volatile uint32_t* tx_fifo[EP_FIFO_NUM] = {
- USB->FIFO0D,
- USB->FIFO1D,
- USB->FIFO2D,
- USB->FIFO3D,
- USB->FIFO4D,
- USB->FIFO5D,
- USB->FIFO6D,
-};
-
-/* Register Helpers */
-#define DCTL_WO_BITMASK (USB_DCTL_CGOUTNAK | USB_DCTL_SGOUTNAK | USB_DCTL_CGNPINNAK | USB_DCTL_SGNPINNAK)
-#define GUSBCFG_WO_BITMASK (USB_GUSBCFG_CORRUPTTXPKT)
-#define DEPCTL_WO_BITMASK (USB_DIEP_CTL_CNAK | USB_DIEP_CTL_SNAK | USB_DIEP_CTL_SETD0PIDEF | USB_DIEP_CTL_SETD1PIDOF)
-
-/* Will either return an unused FIFO number, or 0 if all are used. */
-static uint8_t get_free_fifo(void)
-{
- if(_allocated_fifos < EP_FIFO_NUM) return _allocated_fifos++;
- return 0;
-}
-
-/*
-static void flush_rx_fifo(void)
-{
- USB->GRSTCTL = USB_GRSTCTL_RXFFLSH;
- while(USB->GRSTCTL & USB_GRSTCTL_RXFFLSH);
-}
-*/
-
-static void flush_tx_fifo(uint8_t fifo_num)
-{
- USB->GRSTCTL = USB_GRSTCTL_TXFFLSH | (fifo_num << _USB_GRSTCTL_TXFNUM_SHIFT);
- while(USB->GRSTCTL & USB_GRSTCTL_TXFFLSH);
-}
-
-/* Setup the control endpoint 0. */
-static void bus_reset(void)
-{
- USB->DOEP0CTL |= USB_DIEP_CTL_SNAK;
- for(uint8_t i = 0; i < EP_COUNT - 1; i++)
- {
- USB->DOEP[i].CTL |= USB_DIEP_CTL_SNAK;
- }
-
- /* reset address */
- USB->DCFG &= ~_USB_DCFG_DEVADDR_MASK;
-
- USB->DAINTMSK |= USB_DAINTMSK_OUTEPMSK0 | USB_DAINTMSK_INEPMSK0;
- USB->DOEPMSK |= USB_DOEPMSK_SETUPMSK | USB_DOEPMSK_XFERCOMPLMSK;
- USB->DIEPMSK |= USB_DIEPMSK_TIMEOUTMSK | USB_DIEPMSK_XFERCOMPLMSK;
-
- /*
- * - All EP OUT shared a unique OUT FIFO which uses
- * * 10 locations in hardware for setup packets + setup control words (up to 3 setup packets).
- * * 2 locations for OUT endpoint control words.
- * * 16 for largest packet size of 64 bytes. ( TODO Highspeed is 512 bytes)
- * * 1 location for global NAK (not required/used here).
- * * It is recommended to allocate 2 times the largest packet size, therefore
- * Recommended value = 10 + 1 + 2 x (16+2) = 47 --> Let's make it 52
- */
- flush_tx_fifo(_USB_GRSTCTL_TXFNUM_FALL); // Flush All
- USB->GRXFSIZ = 52;
-
- /* Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) */
- USB->GNPTXFSIZ = (16 << _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_SHIFT) | (USB->GRXFSIZ & _USB_GNPTXFSIZ_NPTXFSTADDR_MASK);
-
- /* Ready to receive SETUP packet */
- USB->DOEP0TSIZ |= (1 << _USB_DOEP0TSIZ_SUPCNT_SHIFT);
-
- USB->GINTMSK |= USB_GINTMSK_IEPINTMSK | USB_GINTMSK_OEPINTMSK;
-}
-
-static void enum_done_processing(void)
-{
- /* Maximum packet size for EP 0 is set for both directions by writing DIEPCTL */
- if((USB->DSTS & _USB_DSTS_ENUMSPD_MASK) == USB_DSTS_ENUMSPD_FS)
- {
- /* Full Speed (PHY on 48 MHz) */
- USB->DOEP0CTL = (USB->DOEP0CTL & ~_USB_DOEP0CTL_MPS_MASK) | _USB_DOEP0CTL_MPS_64B; /* Maximum Packet Size 64 bytes */
- USB->DOEP0CTL &= ~_USB_DOEP0CTL_STALL_MASK; /* clear Stall */
- xfer_status[0][TUSB_DIR_OUT].max_size = 64;
- xfer_status[0][TUSB_DIR_IN].max_size = 64;
- }
- else
- {
- /* Low Speed (PHY on 6 MHz) */
- USB->DOEP0CTL = (USB->DOEP0CTL & ~_USB_DOEP0CTL_MPS_MASK) | _USB_DOEP0CTL_MPS_8B; /* Maximum Packet Size 64 bytes */
- USB->DOEP0CTL &= ~_USB_DOEP0CTL_STALL_MASK; /* clear Stall */
- xfer_status[0][TUSB_DIR_OUT].max_size = 8;
- xfer_status[0][TUSB_DIR_IN].max_size = 8;
- }
-}
-
-
-/*------------------------------------------------------------------*/
-/* Controller API */
-/*------------------------------------------------------------------*/
-void dcd_init(uint8_t rhport)
-{
- (void) rhport;
-
- /* Reset Core */
- USB->PCGCCTL &= ~USB_PCGCCTL_STOPPCLK;
- USB->PCGCCTL &= ~(USB_PCGCCTL_PWRCLMP | USB_PCGCCTL_RSTPDWNMODULE);
-
- /* Core Soft Reset */
- USB->GRSTCTL |= USB_GRSTCTL_CSFTRST;
- while(USB->GRSTCTL & USB_GRSTCTL_CSFTRST);
-
- while(!(USB->GRSTCTL & USB_GRSTCTL_AHBIDLE));
-
- /* Enable PHY pins */
- USB->ROUTE = USB_ROUTE_PHYPEN;
-
- dcd_disconnect(rhport);
-
- /*
- * Set device speed (Full speed PHY)
- * Stall on non-zero len status OUT packets (ctrl transfers)
- * periodic frame interval to 80%
- */
- USB->DCFG = (USB->DCFG & ~(_USB_DCFG_DEVSPD_MASK | _USB_DCFG_PERFRINT_MASK)) | USB_DCFG_DEVSPD_FS | USB_DCFG_NZSTSOUTHSHK;
-
- /* Enable Global Interrupts */
- USB->GAHBCFG = (USB->GAHBCFG & ~_USB_GAHBCFG_HBSTLEN_MASK) | USB_GAHBCFG_GLBLINTRMSK;
-
- /* Force Device Mode */
- USB->GUSBCFG = (USB->GUSBCFG & ~(GUSBCFG_WO_BITMASK | USB_GUSBCFG_FORCEHSTMODE)) | USB_GUSBCFG_FORCEDEVMODE;
-
- /* No Overrides */
- USB->GOTGCTL &= ~(USB_GOTGCTL_BVALIDOVVAL | USB_GOTGCTL_BVALIDOVEN | USB_GOTGCTL_VBVALIDOVVAL);
-
- /* Ignore frame numbers on ISO transfers. */
- USB->DCTL = (USB->DCTL & ~DCTL_WO_BITMASK) | USB_DCTL_IGNRFRMNUM;
-
- /* Setting SNAKs */
- USB->DOEP0CTL |= USB_DIEP_CTL_SNAK;
- for(uint8_t i = 0; i < EP_COUNT - 1; i++)
- {
- USB->DOEP[i].CTL |= USB_DIEP_CTL_SNAK;
- }
-
- /* D. Interruption masking */
- /* Disable all device interrupts */
- USB->DIEPMSK = 0;
- USB->DOEPMSK = 0;
- USB->DAINTMSK = 0;
- USB->DIEPEMPMSK = 0;
- USB->GINTMSK = 0;
- USB->GOTGINT = ~0U; /* clear OTG ints */
- USB->GINTSTS = ~0U; /* clear pending ints */
- USB->GINTMSK = USB_GINTMSK_MODEMISMSK |
- #if USE_SOF
- USB_GINTMSK_SOFMSK |
- #endif
- USB_GINTMSK_ERLYSUSPMSK |
- USB_GINTMSK_USBSUSPMSK |
- USB_GINTMSK_USBRSTMSK |
- USB_GINTMSK_ENUMDONEMSK |
- USB_GINTMSK_RESETDETMSK |
- USB_GINTMSK_DISCONNINTMSK;
-
- NVIC_ClearPendingIRQ(USB_IRQn);
-
- dcd_connect(rhport);
-}
-
-void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
-{
- (void) rhport;
-
- USB->DCFG = (USB->DCFG & ~_USB_DCFG_DEVADDR_MASK) | (dev_addr << _USB_DCFG_DEVADDR_SHIFT);
-
- /* Response with status after changing device address */
- dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
-}
-
-void dcd_remote_wakeup(uint8_t rhport)
-{
- (void) rhport;
-}
-
-void dcd_connect(uint8_t rhport)
-{
- (void) rhport;
-
- /* connect by enabling internal pull-up resistor on D+/D- */
- USB->DCTL &= ~(DCTL_WO_BITMASK | USB_DCTL_SFTDISCON);
-}
-
-void dcd_disconnect(uint8_t rhport)
-{
- (void) rhport;
-
- /* disconnect by disabling internal pull-up resistor on D+/D- */
- USB->DCTL = (USB->DCTL & ~(DCTL_WO_BITMASK)) | USB_DCTL_SFTDISCON;
-}
-
-/*------------------------------------------------------------------*/
-/* DCD Endpoint Port */
-/*------------------------------------------------------------------*/
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
-{
- (void) rhport;
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if(dir == TUSB_DIR_IN)
- {
- if(epnum == 0)
- {
- USB->DIEP0CTL = (USB->DIEP0CTL & ~DEPCTL_WO_BITMASK) | USB_DIEP0CTL_SNAK | USB_DIEP0CTL_STALL;
-
- flush_tx_fifo(_USB_GRSTCTL_TXFNUM_F0);
- }
- else
- {
- /* Only disable currently enabled non-control endpoint */
- if(USB->DIEP[epnum - 1].CTL & USB_DIEP_CTL_EPENA)
- {
- USB->DIEP[epnum - 1].CTL = (USB->DIEP[epnum - 1].CTL & ~DEPCTL_WO_BITMASK) | USB_DIEP_CTL_EPDIS | USB_DIEP_CTL_SNAK | USB_DIEP_CTL_STALL;
- while(!(USB->DIEP[epnum - 1].INT & USB_DIEP_INT_EPDISBLD));
- USB->DIEP[epnum - 1].INT |= USB_DIEP_INT_EPDISBLD;
- }
- else
- {
- USB->DIEP[epnum - 1].CTL = (USB->DIEP[epnum - 1].CTL & ~DEPCTL_WO_BITMASK) | USB_DIEP_CTL_SNAK | USB_DIEP_CTL_STALL;
- }
-
- /* Flush the FIFO */
- uint8_t const fifo_num = ((USB->DIEP[epnum - 1].CTL & _USB_DIEP_CTL_TXFNUM_MASK) >> _USB_DIEP_CTL_TXFNUM_SHIFT);
- flush_tx_fifo(fifo_num);
- }
- }
- else
- {
- if(epnum == 0)
- {
- USB->DOEP0CTL = (USB->DOEP0CTL & ~DEPCTL_WO_BITMASK) | USB_DIEP0CTL_STALL;
- }
- else
- {
- /* Only disable currently enabled non-control endpoint */
- if(USB->DOEP[epnum - 1].CTL & USB_DIEP_CTL_EPENA)
- {
- /* Asserting GONAK is required to STALL an OUT endpoint. */
- USB->DCTL |= USB_DCTL_SGOUTNAK;
- while(!(USB->GINTSTS & USB_GINTSTS_GOUTNAKEFF));
-
- /* Disable the endpoint. Note that only STALL and not SNAK is set here. */
- USB->DOEP[epnum - 1].CTL = (USB->DOEP[epnum - 1].CTL & ~DEPCTL_WO_BITMASK) | USB_DIEP_CTL_EPDIS | USB_DIEP_CTL_STALL;
- while(USB->DOEP[epnum - 1].INT & USB_DIEP_INT_EPDISBLD);
- USB->DOEP[epnum - 1].INT |= USB_DIEP_INT_EPDISBLD;
-
- /* Allow other OUT endpoints to keep receiving. */
- USB->DCTL |= USB_DCTL_CGOUTNAK;
- }
- else
- {
- USB->DIEP[epnum - 1].CTL = (USB->DIEP[epnum - 1].CTL & ~DEPCTL_WO_BITMASK) | USB_DIEP_CTL_STALL;
- }
- }
- }
-}
-
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
-{
- (void) rhport;
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if(dir == TUSB_DIR_IN)
- {
- if(epnum == 0)
- {
- USB->DIEP0CTL &= ~(DEPCTL_WO_BITMASK | USB_DIEP0CTL_STALL);
- }
- else
- {
- USB->DIEP[epnum - 1].CTL &= ~(DEPCTL_WO_BITMASK | USB_DIEP_CTL_STALL);
-
- /* Required by USB spec to reset DATA toggle bit to DATA0 on interrupt and bulk endpoints. */
- uint8_t eptype = (USB->DIEP[epnum - 1].CTL & _USB_DIEP_CTL_EPTYPE_MASK) >> _USB_DIEP_CTL_EPTYPE_SHIFT;
-
- if((eptype == _USB_DIEP_CTL_EPTYPE_BULK) || (eptype == _USB_DIEP_CTL_EPTYPE_INT))
- {
- USB->DIEP[epnum - 1].CTL |= USB_DIEP_CTL_SETD0PIDEF;
- }
- }
- }
- else
- {
- if(epnum == 0)
- {
- USB->DOEP0CTL &= ~(DEPCTL_WO_BITMASK | USB_DOEP0CTL_STALL);
- }
- else
- {
- USB->DOEP[epnum - 1].CTL &= ~(DEPCTL_WO_BITMASK | USB_DOEP_CTL_STALL);
-
- /* Required by USB spec to reset DATA toggle bit to DATA0 on interrupt and bulk endpoints. */
- uint8_t eptype = (USB->DOEP[epnum - 1].CTL & _USB_DOEP_CTL_EPTYPE_MASK) >> _USB_DOEP_CTL_EPTYPE_SHIFT;
-
- if((eptype == _USB_DOEP_CTL_EPTYPE_BULK) || (eptype == _USB_DOEP_CTL_EPTYPE_INT))
- {
- USB->DOEP[epnum - 1].CTL |= USB_DOEP_CTL_SETD0PIDEF;
- }
- }
- }
-}
-
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
-{
- (void)rhport;
-
- uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
-
- TU_ASSERT(p_endpoint_desc->wMaxPacketSize.size <= 64);
- TU_ASSERT(epnum < EP_COUNT);
- TU_ASSERT(epnum != 0);
-
- xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
- xfer->max_size = p_endpoint_desc->wMaxPacketSize.size;
-
- if(dir == TUSB_DIR_OUT)
- {
- USB->DOEP[epnum - 1].CTL |= USB_DOEP_CTL_USBACTEP |
- (p_endpoint_desc->bmAttributes.xfer << _USB_DOEP_CTL_EPTYPE_SHIFT) |
- (p_endpoint_desc->wMaxPacketSize.size << _USB_DOEP_CTL_MPS_SHIFT);
- USB->DAINTMSK |= (1 << (_USB_DAINTMSK_OUTEPMSK0_SHIFT + epnum));
- }
- else
- {
- uint8_t fifo_num = get_free_fifo();
- TU_ASSERT(fifo_num != 0);
-
- USB->DIEP[epnum - 1].CTL &= ~(_USB_DIEP_CTL_TXFNUM_MASK | _USB_DIEP_CTL_EPTYPE_MASK | USB_DIEP_CTL_SETD0PIDEF | _USB_DIEP_CTL_MPS_MASK);
- USB->DIEP[epnum - 1].CTL |= USB_DIEP_CTL_USBACTEP |
- (fifo_num << _USB_DIEP_CTL_TXFNUM_SHIFT) |
- (p_endpoint_desc->bmAttributes.xfer << _USB_DIEP_CTL_EPTYPE_SHIFT) |
- ((p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) ? USB_DIEP_CTL_SETD0PIDEF : 0) |
- (p_endpoint_desc->wMaxPacketSize.size << 0);
-
- USB->DAINTMSK |= (1 << epnum);
-
- /* Both TXFD and TXSA are in unit of 32-bit words. */
- /* IN FIFO 0 was configured during enumeration, hence the "+ 16". */
- uint16_t const allocated_size = (USB->GRXFSIZ & _USB_GRXFSIZ_RXFDEP_MASK) + 16;
- uint16_t const fifo_size = (EP_FIFO_SIZE/4 - allocated_size) / (EP_FIFO_NUM-1);
- uint32_t const fifo_offset = allocated_size + fifo_size*(fifo_num-1);
-
- /* DIEPTXF starts at FIFO #1. */
- volatile uint32_t* usb_dieptxf = &USB->DIEPTXF1;
- usb_dieptxf[epnum - 1] = (fifo_size << _USB_DIEPTXF1_INEPNTXFDEP_SHIFT) | fifo_offset;
- }
- return true;
-}
-
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
-{
- (void)rhport;
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = buffer;
- xfer->total_len = total_bytes;
- xfer->queued_len = 0;
- xfer->short_packet = false;
-
- uint16_t num_packets = (total_bytes / xfer->max_size);
- uint8_t short_packet_size = total_bytes % xfer->max_size;
-
- // Zero-size packet is special case.
- if(short_packet_size > 0 || (total_bytes == 0))
- {
- num_packets++;
- }
-
- // IN and OUT endpoint xfers are interrupt-driven, we just schedule them
- // here.
- if(dir == TUSB_DIR_IN)
- {
- if(epnum == 0)
- {
- // A full IN transfer (multiple packets, possibly) triggers XFRC.
- USB->DIEP0TSIZ = (num_packets << _USB_DIEP0TSIZ_PKTCNT_SHIFT) | total_bytes;
- USB->DIEP0CTL |= USB_DIEP0CTL_EPENA | USB_DIEP0CTL_CNAK; // Enable | CNAK
- }
- else
- {
- // A full IN transfer (multiple packets, possibly) triggers XFRC.
- USB->DIEP[epnum - 1].TSIZ = (num_packets << _USB_DIEP_TSIZ_PKTCNT_SHIFT) | total_bytes;
- USB->DIEP[epnum - 1].CTL |= USB_DIEP_CTL_EPENA | USB_DIEP_CTL_CNAK; // Enable | CNAK
- }
-
- // Enable fifo empty interrupt only if there are something to put in the fifo.
- if(total_bytes != 0)
- {
- USB->DIEPEMPMSK |= (1 << epnum);
- }
- }
- else
- {
- if(epnum == 0)
- {
- // A full IN transfer (multiple packets, possibly) triggers XFRC.
- USB->DOEP0TSIZ |= (1 << _USB_DOEP0TSIZ_PKTCNT_SHIFT) | ((xfer->max_size & _USB_DOEP0TSIZ_XFERSIZE_MASK) << _USB_DOEP0TSIZ_XFERSIZE_SHIFT);
- USB->DOEP0CTL |= USB_DOEP0CTL_EPENA | USB_DOEP0CTL_CNAK;
- }
- else
- {
- // A full IN transfer (multiple packets, possibly) triggers XFRC.
- USB->DOEP[epnum - 1].TSIZ |= (1 << _USB_DOEP_TSIZ_PKTCNT_SHIFT) | ((xfer->max_size & _USB_DOEP_TSIZ_XFERSIZE_MASK) << _USB_DOEP_TSIZ_XFERSIZE_SHIFT);
- USB->DOEP[epnum - 1].CTL |= USB_DOEP_CTL_EPENA | USB_DOEP_CTL_CNAK;
- }
- }
- return true;
-}
-
-/*------------------------------------------------------------------*/
-/* IRQ */
-/*------------------------------------------------------------------*/
-void dcd_int_enable(uint8_t rhport)
-{
- (void) rhport;
-
- NVIC_EnableIRQ(USB_IRQn);
-}
-
-void dcd_int_disable(uint8_t rhport)
-{
- (void) rhport;
-
- NVIC_DisableIRQ(USB_IRQn);
-}
-
-static void receive_packet(xfer_ctl_t *xfer, uint16_t xfer_size)
-{
- uint16_t remaining = xfer->total_len - xfer->queued_len;
- uint16_t to_recv_size;
-
- if(remaining <= xfer->max_size)
- {
- /* Avoid buffer overflow. */
- to_recv_size = (xfer_size > remaining) ? remaining : xfer_size;
- }
- else
- {
- /* Room for full packet, choose recv_size based on what the microcontroller claims. */
- to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
- }
-
- uint8_t to_recv_rem = to_recv_size % 4;
- uint16_t to_recv_size_aligned = to_recv_size - to_recv_rem;
-
- /* Do not assume xfer buffer is aligned. */
- uint8_t *base = (xfer->buffer + xfer->queued_len);
-
- /* This for loop always runs at least once- skip if less than 4 bytes to collect. */
- if(to_recv_size >= 4)
- {
- for(uint16_t i = 0; i < to_recv_size_aligned; i += 4)
- {
- uint32_t tmp = (*USB->FIFO0D);
- base[i] = tmp & 0x000000FF;
- base[i + 1] = (tmp & 0x0000FF00) >> 8;
- base[i + 2] = (tmp & 0x00FF0000) >> 16;
- base[i + 3] = (tmp & 0xFF000000) >> 24;
- }
- }
-
- /* Do not read invalid bytes from RX FIFO. */
- if(to_recv_rem != 0)
- {
- uint32_t tmp = (*USB->FIFO0D);
- uint8_t *last_32b_bound = base + to_recv_size_aligned;
-
- last_32b_bound[0] = tmp & 0x000000FF;
- if(to_recv_rem > 1)
- {
- last_32b_bound[1] = (tmp & 0x0000FF00) >> 8;
- }
- if(to_recv_rem > 2)
- {
- last_32b_bound[2] = (tmp & 0x00FF0000) >> 16;
- }
- }
-
- xfer->queued_len += xfer_size;
-
- /* Per USB spec, a short OUT packet (including length 0) is always */
- /* indicative of the end of a transfer (at least for ctl, bulk, int). */
- xfer->short_packet = (xfer_size < xfer->max_size);
-}
-
-static void transmit_packet(xfer_ctl_t *xfer, uint8_t fifo_num)
-{
- uint16_t remaining;
- if(fifo_num == 0)
- {
- remaining = (USB->DIEP0TSIZ & 0x7FFFFU) >> _USB_DIEP0TSIZ_XFERSIZE_SHIFT;
- }
- else
- {
- remaining = (USB->DIEP[fifo_num - 1].TSIZ & 0x7FFFFU) >> _USB_DIEP_TSIZ_XFERSIZE_SHIFT;
- }
- xfer->queued_len = xfer->total_len - remaining;
-
- uint16_t to_xfer_size = (remaining > xfer->max_size) ? xfer->max_size : remaining;
- uint8_t to_xfer_rem = to_xfer_size % 4;
- uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem;
-
- /* Buffer might not be aligned to 32b, so we need to force alignment by copying to a temp var. */
- uint8_t *base = (xfer->buffer + xfer->queued_len);
-
- /* This for loop always runs at least once- skip if less than 4 bytes to send off. */
- if(to_xfer_size >= 4)
- {
- for(uint16_t i = 0; i < to_xfer_size_aligned; i += 4)
- {
- uint32_t tmp = base[i] | (base[i + 1] << 8) | (base[i + 2] << 16) | (base[i + 3] << 24);
- *tx_fifo[fifo_num] = tmp;
- }
- }
-
- /* Do not read beyond end of buffer if not divisible by 4. */
- if(to_xfer_rem != 0)
- {
- uint32_t tmp = 0;
- uint8_t *last_32b_bound = base + to_xfer_size_aligned;
-
- tmp |= last_32b_bound[0];
- if(to_xfer_rem > 1)
- {
- tmp |= (last_32b_bound[1] << 8);
- }
- if(to_xfer_rem > 2)
- {
- tmp |= (last_32b_bound[2] << 16);
- }
-
- *tx_fifo[fifo_num] = tmp;
- }
-}
-
-static void read_rx_fifo(void)
-{
- /*
- * Pop control word off FIFO (completed xfers will have 2 control words,
- * we only pop one ctl word each interrupt).
- */
- uint32_t const ctl_word = USB->GRXSTSP;
- uint8_t const pktsts = (ctl_word & _USB_GRXSTSP_PKTSTS_MASK) >> _USB_GRXSTSP_PKTSTS_SHIFT;
- uint8_t const epnum = (ctl_word & _USB_GRXSTSP_CHNUM_MASK ) >> _USB_GRXSTSP_CHNUM_SHIFT;
- uint16_t const bcnt = (ctl_word & _USB_GRXSTSP_BCNT_MASK ) >> _USB_GRXSTSP_BCNT_SHIFT;
-
- switch(pktsts)
- {
- case 0x01: /* Global OUT NAK (Interrupt) */
- break;
-
- case 0x02:
- {
- /* Out packet recvd */
- xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
- receive_packet(xfer, bcnt);
- }
- break;
-
- case 0x03:
- /* Out packet done (Interrupt) */
- break;
-
- case 0x04:
- /* Step 2: Setup transaction completed (Interrupt) */
- /* After this event, OEPINT interrupt will occur with SETUP bit set */
- if(epnum == 0)
- {
- USB->DOEP0TSIZ |= (1 << _USB_DOEP0TSIZ_SUPCNT_SHIFT);
- }
-
- break;
-
- case 0x06:
- {
- /* Step1: Setup data packet received */
-
- /*
- * We can receive up to three setup packets in succession, but
- * only the last one is valid. Therefore we just overwrite it
- */
- _setup_packet[0] = (*USB->FIFO0D);
- _setup_packet[1] = (*USB->FIFO0D);
- }
- break;
-
- default:
- /* Invalid, breakpoint. */
- TU_BREAKPOINT();
- break;
- }
-}
-
-static void handle_epout_ints(void)
-{
- // GINTSTS will be cleared with DAINT == 0
- // DAINT for a given EP clears when DOEPINTx is cleared.
- // DOEPINT will be cleared when DAINT's out bits are cleared.
-
- for(uint8_t n = 0; n < EP_COUNT; n++)
- {
- xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
-
- if(n == 0)
- {
- if(USB->DAINT & (1 << (_USB_DAINT_OUTEPINT0_SHIFT + n)))
- {
- // SETUP packet Setup Phase done.
- if((USB->DOEP0INT & USB_DOEP0INT_SETUP))
- {
- USB->DOEP0INT = USB_DOEP0INT_STUPPKTRCVD | USB_DOEP0INT_SETUP; // clear
- dcd_event_setup_received(0, (uint8_t *)&_setup_packet[0], true);
- }
-
- // OUT XFER complete (single packet).q
- if(USB->DOEP0INT & USB_DOEP0INT_XFERCOMPL)
- {
- USB->DOEP0INT = USB_DOEP0INT_XFERCOMPL;
-
- // Transfer complete if short packet or total len is transferred
- if(xfer->short_packet || (xfer->queued_len == xfer->total_len))
- {
- xfer->short_packet = false;
- dcd_event_xfer_complete(0, n, xfer->queued_len, XFER_RESULT_SUCCESS, true);
- }
- else
- {
- // Schedule another packet to be received.
- USB->DOEP0TSIZ |= (1 << _USB_DOEP0TSIZ_PKTCNT_SHIFT) | ((xfer->max_size & _USB_DOEP0TSIZ_XFERSIZE_MASK) << _USB_DOEP0TSIZ_XFERSIZE_SHIFT);
- USB->DOEP0CTL |= USB_DOEP0CTL_EPENA | USB_DOEP0CTL_CNAK;
- }
- }
- }
- }
- else
- {
- if(USB->DAINT & (1 << (_USB_DAINT_OUTEPINT0_SHIFT + n)))
- {
- // SETUP packet Setup Phase done.
- if((USB->DOEP[n - 1].INT & USB_DOEP_INT_SETUP))
- {
- USB->DOEP[n - 1].INT = USB_DOEP_INT_STUPPKTRCVD | USB_DOEP_INT_SETUP; // clear
- dcd_event_setup_received(0, (uint8_t *)&_setup_packet[0], true);
- }
-
- // OUT XFER complete (single packet).q
- if(USB->DOEP[n - 1].INT & USB_DOEP_INT_XFERCOMPL)
- {
- USB->DOEP[n - 1].INT = USB_DOEP_INT_XFERCOMPL;
-
- // Transfer complete if short packet or total len is transferred
- if(xfer->short_packet || (xfer->queued_len == xfer->total_len))
- {
- xfer->short_packet = false;
- dcd_event_xfer_complete(0, n, xfer->queued_len, XFER_RESULT_SUCCESS, true);
- }
- else
- {
- // Schedule another packet to be received.
- USB->DOEP[n - 1].TSIZ |= (1 << _USB_DOEP_TSIZ_PKTCNT_SHIFT) | ((xfer->max_size & _USB_DOEP_TSIZ_XFERSIZE_MASK) << _USB_DOEP_TSIZ_XFERSIZE_SHIFT);
- USB->DOEP[n - 1].CTL |= USB_DOEP_CTL_EPENA | USB_DOEP_CTL_CNAK;
- }
- }
- }
- }
- }
-}
-
-static void handle_epin_ints(void)
-{
-
- for(uint32_t n = 0; n < EP_COUNT; n++)
- {
- xfer_ctl_t *xfer = &xfer_status[n][TUSB_DIR_IN];
-
- if(n == 0)
- {
- if(USB->DAINT & (1 << n))
- {
- /* IN XFER complete (entire xfer). */
- if(USB->DIEP0INT & USB_DIEP0INT_XFERCOMPL)
- {
- USB->DIEP0INT = USB_DIEP0INT_XFERCOMPL;
- dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
- }
-
- /* XFER FIFO empty */
- if(USB->DIEP0INT & USB_DIEP0INT_TXFEMP)
- {
- USB->DIEP0INT = USB_DIEP0INT_TXFEMP;
- transmit_packet(xfer, n);
-
- /* Turn off TXFE if all bytes are written. */
- if(xfer->queued_len == xfer->total_len)
- {
- USB->DIEPEMPMSK &= ~(1 << n);
- }
- }
-
- /* XFER Timeout */
- if(USB->DIEP0INT & USB_DIEP0INT_TIMEOUT)
- {
- /* Clear interrupt or enpoint will hang. */
- USB->DIEP0INT = USB_DIEP0INT_TIMEOUT;
- }
- }
- }
- else
- {
- if(USB->DAINT & (1 << n))
- {
- /* IN XFER complete (entire xfer). */
- if(USB->DIEP[n - 1].INT & USB_DIEP_INT_XFERCOMPL)
- {
- USB->DIEP[n - 1].INT = USB_DIEP_INT_XFERCOMPL;
- dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
- }
-
- /* XFER FIFO empty */
- if(USB->DIEP[n - 1].INT & USB_DIEP_INT_TXFEMP)
- {
- USB->DIEP[n - 1].INT = USB_DIEP_INT_TXFEMP;
- transmit_packet(xfer, n);
-
- /* Turn off TXFE if all bytes are written. */
- if(xfer->queued_len == xfer->total_len)
- {
- USB->DIEPEMPMSK &= ~(1 << n);
- }
- }
-
- /* XFER Timeout */
- if(USB->DIEP[n - 1].INT & USB_DIEP_INT_TIMEOUT)
- {
- /* Clear interrupt or enpoint will hang. */
- USB->DIEP[n - 1].INT = USB_DIEP_INT_TIMEOUT;
- }
- }
- }
- }
-}
-
-void dcd_int_handler(uint8_t rhport)
-{
- (void) rhport;
-
- const uint32_t int_status = USB->GINTSTS;
-
- /* USB Reset */
- if(int_status & USB_GINTSTS_USBRST)
- {
- /* start of reset */
- USB->GINTSTS = USB_GINTSTS_USBRST;
- /* FIFOs will be reassigned when the endpoints are reopen */
- _allocated_fifos = 1;
- bus_reset();
- }
-
- /* Reset detected Interrupt */
- if(int_status & USB_GINTSTS_RESETDET)
- {
- USB->GINTSTS = USB_GINTSTS_RESETDET;
- bus_reset();
- }
-
- /* Enumeration Done */
- if(int_status & USB_GINTSTS_ENUMDONE)
- {
- /* This interrupt is considered the end of reset. */
- USB->GINTSTS = USB_GINTSTS_ENUMDONE;
- enum_done_processing();
- dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
- }
-
- /* OTG Interrupt */
- if(int_status & USB_GINTSTS_OTGINT)
- {
- /* OTG INT bit is read-only */
-
- uint32_t const otg_int = USB->GOTGINT;
-
- if(otg_int & USB_GOTGINT_SESENDDET)
- {
- dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
- }
-
- USB->GOTGINT = otg_int;
- }
-
- #if USE_SOF
- if(int_status & USB_GINTSTS_SOF)
- {
- USB->GINTSTS = USB_GINTSTS_SOF;
- dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
- }
- #endif
-
- /* RxFIFO Non-Empty */
- if(int_status & USB_GINTSTS_RXFLVL)
- {
- /* RXFLVL bit is read-only */
-
- /* Mask out RXFLVL while reading data from FIFO */
- USB->GINTMSK &= ~USB_GINTMSK_RXFLVLMSK;
- read_rx_fifo();
- USB->GINTMSK |= USB_GINTMSK_RXFLVLMSK;
- }
-
- /* OUT Endpoints Interrupt */
- if(int_status & USB_GINTMSK_OEPINTMSK)
- {
- /* OEPINT is read-only */
- handle_epout_ints();
- }
-
- /* IN Endpoints Interrupt */
- if(int_status & USB_GINTMSK_IEPINTMSK)
- {
- /* IEPINT bit read-only */
- handle_epin_ints();
- }
-
- /* unhandled */
- USB->GINTSTS |= USB_GINTSTS_CURMOD |
- USB_GINTSTS_MODEMIS |
- USB_GINTSTS_OTGINT |
- USB_GINTSTS_NPTXFEMP |
- USB_GINTSTS_GINNAKEFF |
- USB_GINTSTS_GOUTNAKEFF |
- USB_GINTSTS_ERLYSUSP |
- USB_GINTSTS_USBSUSP |
- USB_GINTSTS_ISOOUTDROP |
- USB_GINTSTS_EOPF |
- USB_GINTSTS_EPMIS |
- USB_GINTSTS_INCOMPISOIN |
- USB_GINTSTS_INCOMPLP |
- USB_GINTSTS_FETSUSP |
- USB_GINTSTS_PTXFEMP;
-}
-
-#endif
diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c
index 834976468..41814370e 100644
--- a/src/portable/sony/cxd56/dcd_cxd56.c
+++ b/src/portable/sony/cxd56/dcd_cxd56.c
@@ -26,19 +26,20 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_CXD56
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_CXD56
#include <errno.h>
#include <nuttx/usb/usbdev.h>
#include <nuttx/arch.h>
#include "device/dcd.h"
+#include "device/usbd_pvt.h"
#define CXD56_EPNUM (7)
#define CXD56_SETUP_QUEUE_DEPTH (4)
#define CXD56_MAX_DATA_OUT_SIZE (64)
-OSAL_QUEUE_DEF(OPT_MODE_DEVICE, _setup_queue_def, CXD56_SETUP_QUEUE_DEPTH, struct usb_ctrlreq_s);
+OSAL_QUEUE_DEF(usbd_int_set, _setup_queue_def, CXD56_SETUP_QUEUE_DEPTH, struct usb_ctrlreq_s);
struct usbdcd_driver_s
{
@@ -101,17 +102,25 @@ static int _dcd_bind(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_
usbdev = dev;
usbdcd_driver.ep[0] = dev->ep0;
+ #ifdef EP_ALLOCREQ
+ // SDK v2
usbdcd_driver.req[0] = EP_ALLOCREQ(usbdcd_driver.ep[0]);
- if (usbdcd_driver.req[0] != NULL)
- {
+ if (usbdcd_driver.req[0] != NULL) {
usbdcd_driver.req[0]->len = 64;
usbdcd_driver.req[0]->buf = EP_ALLOCBUFFER(usbdcd_driver.ep[0], 64);
- if (!usbdcd_driver.req[0]->buf)
- {
+ if (!usbdcd_driver.req[0]->buf) {
EP_FREEREQ(usbdcd_driver.ep[0], usbdcd_driver.req[0]);
usbdcd_driver.req[0] = NULL;
+ return ENOMEM;
}
}
+ #else
+ // SDK v3
+ usbdcd_driver.req[0] = usbdev_allocreq(usbdcd_driver.ep[0], 64);
+ if (usbdcd_driver.req[0] == NULL) {
+ return ENOMEM;
+ }
+ #endif
usbdcd_driver.req[0]->callback = usbdcd_ep0incomplete;
@@ -134,7 +143,7 @@ static int _dcd_setup(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev
if (usbdcd_driver.setup_processed)
{
usbdcd_driver.setup_processed = false;
- dcd_event_setup_received(0, (uint8_t *) ctrl, true);
+ dcd_event_setup_received(0, (uint8_t const *) ctrl, true);
}
else
{
@@ -246,6 +255,14 @@ void dcd_disconnect(uint8_t rhport)
DEV_DISCONNECT(usbdev);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -257,6 +274,8 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
uint8_t epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
uint8_t xfrtype = 0;
+ uint16_t const ep_mps = tu_edpt_packet_size(p_endpoint_desc);
+
struct usb_epdesc_s epdesc;
if (epnum >= CXD56_EPNUM)
@@ -284,13 +303,19 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
}
usbdcd_driver.req[epnum] = NULL;
+
+ #ifdef EP_ALLOCREQ
+ // sdk v2
usbdcd_driver.req[epnum] = EP_ALLOCREQ(usbdcd_driver.ep[epnum]);
- if (usbdcd_driver.req[epnum] != NULL)
- {
- usbdcd_driver.req[epnum]->len = p_endpoint_desc->wMaxPacketSize.size;
+ if (usbdcd_driver.req[epnum] != NULL) {
+ usbdcd_driver.req[epnum]->len = ep_mps;
}
- else
- {
+ #else
+ // sdk v3
+ usbdcd_driver.req[epnum] = usbdev_allocreq(usbdcd_driver.ep[epnum], ep_mps);
+ #endif
+
+ if(usbdcd_driver.req[epnum] == NULL) {
return false;
}
@@ -300,8 +325,8 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
epdesc.type = p_endpoint_desc->bDescriptorType;
epdesc.addr = p_endpoint_desc->bEndpointAddress;
epdesc.attr = xfrtype;
- epdesc.mxpacketsize[0] = LSBYTE(p_endpoint_desc->wMaxPacketSize.size);
- epdesc.mxpacketsize[1] = MSBYTE(p_endpoint_desc->wMaxPacketSize.size);
+ epdesc.mxpacketsize[0] = LSBYTE(ep_mps);
+ epdesc.mxpacketsize[1] = MSBYTE(ep_mps);
epdesc.interval = p_endpoint_desc->bInterval;
if (EP_CONFIGURE(usbdcd_driver.ep[epnum], &epdesc, false) < 0)
@@ -312,6 +337,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
(void) rhport;
@@ -354,7 +385,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to
if (usbdcd_driver.setup_processed)
{
- if (osal_queue_receive(usbdcd_driver.setup_queue, &ctrl))
+ if (osal_queue_receive(usbdcd_driver.setup_queue, &ctrl, 100))
{
usbdcd_driver.setup_processed = false;
dcd_event_setup_received(0, (uint8_t *)&ctrl, false);
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index 74c144107..a26c66892 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Nathan Conrad
@@ -6,6 +6,8 @@
* Portions:
* Copyright (c) 2016 STMicroelectronics
* Copyright (c) 2019 Ha Thach (tinyusb.org)
+ * Copyright (c) 2022 Simon Küppers (skuep)
+ * Copyright (c) 2022 HiFiPhile
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -42,6 +44,7 @@
* L0x2, L0x3 1024 byte buffer
* L1 512 byte buffer
* L4x2, L4x3 1024 byte buffer
+ * G0 2048 byte buffer
*
* To use this driver, you must:
* - If you are using a device with crystal-less USB, set up the clock recovery system (CRS)
@@ -64,10 +67,6 @@
* - STALL handled, but not tested.
* - Does it work? No clue.
* - All EP BTABLE buffers are created based on max packet size of first EP opened with that address.
- * - No isochronous endpoints
- * - Endpoint index is the ID of the endpoint
- * - This means that priority is given to endpoints with lower ID numbers
- * - Code is mixing up EP IX with EP ID. Everywhere.
* - Packet buffer memory is copied in the interrupt.
* - This is better for performance, but means interrupts are disabled for longer
* - DMA may be the best choice, but it could also be pushed to the USBD task.
@@ -103,26 +102,15 @@
#include "tusb_option.h"
-#if defined(STM32F102x6) || defined(STM32F102xB) || \
- defined(STM32F103x6) || defined(STM32F103xB) || \
- defined(STM32F103xE) || defined(STM32F103xG)
-#define STM32F1_FSDEV
-#endif
-
-#if (TUSB_OPT_DEVICE_ENABLED) && ( \
- (CFG_TUSB_MCU == OPT_MCU_STM32F0 ) || \
- (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_FSDEV)) || \
- (CFG_TUSB_MCU == OPT_MCU_STM32F3 ) || \
- (CFG_TUSB_MCU == OPT_MCU_STM32L0 ) \
- )
-
-// In order to reduce the dependance on HAL, we undefine this.
-// Some definitions are copied to our private include file.
-#undef USE_HAL_DRIVER
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV)
#include "device/dcd.h"
-#include "portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h"
+#ifdef TUP_USBIP_FSDEV_STM32
+// Undefine to reduce the dependence on HAL
+#undef USE_HAL_DRIVER
+#include "portable/st/stm32_fsdev/dcd_stm32_fsdev.h"
+#endif
/*****************************************************
* Configuration
@@ -131,23 +119,17 @@
// HW supports max of 8 bidirectional endpoints, but this can be reduced to save RAM
// (8u here would mean 8 IN and 8 OUT)
#ifndef MAX_EP_COUNT
-# define MAX_EP_COUNT 8U
+#define MAX_EP_COUNT 8U
#endif
// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it
// Both of these MUST be a multiple of 2, and are in byte units.
#ifndef DCD_STM32_BTABLE_BASE
-# define DCD_STM32_BTABLE_BASE 0U
+#define DCD_STM32_BTABLE_BASE 0U
#endif
-#ifndef DCD_STM32_BTABLE_LENGTH
-# define DCD_STM32_BTABLE_LENGTH (PMA_LENGTH - DCD_STM32_BTABLE_BASE)
-#endif
-
-// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
-// We disable SOF for now until needed later on
-#ifndef USE_SOF
-# define USE_SOF 0
+#ifndef DCD_STM32_BTABLE_SIZE
+#define DCD_STM32_BTABLE_SIZE (FSDEV_PMA_SIZE - DCD_STM32_BTABLE_BASE)
#endif
/***************************************************
@@ -155,64 +137,78 @@
*/
TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware");
-
-TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_LENGTH))<=(PMA_LENGTH),
- "BTABLE does not fit in PMA RAM");
-
+TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_SIZE)) <= (FSDEV_PMA_SIZE), "BTABLE does not fit in PMA RAM");
TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes");
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
// One of these for every EP IN & OUT, uses a bit of RAM....
-typedef struct
-{
- uint8_t * buffer;
- // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
+typedef struct {
+ uint8_t *buffer;
+ tu_fifo_t *ff;
uint16_t total_len;
uint16_t queued_len;
- uint16_t pma_ptr;
- uint8_t max_packet_size;
- uint8_t pma_alloc_size;
+ uint16_t max_packet_size;
+ uint8_t ep_idx; // index for USB_EPnR register
+ bool iso_in_sending; // Workaround for ISO IN EP doesn't have interrupt mask
} xfer_ctl_t;
+// EP allocator
+typedef struct {
+ uint8_t ep_num;
+ uint8_t ep_type;
+ bool allocated[2];
+} ep_alloc_t;
+
static xfer_ctl_t xfer_status[MAX_EP_COUNT][2];
-static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t epnum, uint32_t dir)
-{
- return &xfer_status[epnum][dir];
-}
+static ep_alloc_t ep_alloc_status[STFSDEV_EP_COUNT];
static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6];
static uint8_t remoteWakeCountdown; // When wake is requested
+//--------------------------------------------------------------------+
+// Prototypes
+//--------------------------------------------------------------------+
+
// into the stack.
static void dcd_handle_bus_reset(void);
-static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix);
+static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix);
+static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr);
static void dcd_ep_ctr_handler(void);
-// PMA allocation/access
-static uint8_t open_ep_count;
+// PMA allocation/access
static uint16_t ep_buf_ptr; ///< Points to first free memory location
-static void dcd_pma_alloc_reset(void);
-static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length);
-static void dcd_pma_free(uint8_t ep_addr);
-static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes);
-static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes);
+static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf);
+static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type);
+static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes);
+static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes);
-//static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes);
-//static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes);
+static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes);
+static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes);
-// Using a function due to better type checks
-// This seems better than having to do type casts everywhere else
-static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) {
- *reg = (uint16_t)(*reg & ~mask);
-}
+//--------------------------------------------------------------------+
+// Inline helper
+//--------------------------------------------------------------------+
+
+TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint32_t ep_addr)
+{
+ uint8_t epnum = tu_edpt_number(ep_addr);
+ uint8_t dir = tu_edpt_dir(ep_addr);
+ // Fix -Werror=null-dereference
+ TU_ASSERT(epnum < MAX_EP_COUNT, &xfer_status[0][0]);
-// Bits in ISTR are cleared upon writing 0
-static inline void clear_istr_bits(uint16_t mask) {
- USB->ISTR = ~mask;
+ return &xfer_status[epnum][dir];
}
-void dcd_init (uint8_t rhport)
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+void dcd_init(uint8_t rhport)
{
/* Clocks should already be enabled */
/* Use __HAL_RCC_USB_CLK_ENABLE(); to enable the clocks before calling this function */
@@ -220,40 +216,41 @@ void dcd_init (uint8_t rhport)
/* The RM mentions to use a special ordering of PDWN and FRES, but this isn't done in HAL.
* Here, the RM is followed. */
- for(uint32_t i = 0; i<200; i++) // should be a few us
- {
+ for (uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
- // Perform USB peripheral reset
+ // Perform USB peripheral reset
USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN;
- for(uint32_t i = 0; i<200; i++) // should be a few us
- {
+ for (uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
- reg16_clear_bits(&USB->CNTR, USB_CNTR_PDWN);// Remove powerdown
+
+ USB->CNTR &= ~USB_CNTR_PDWN;
+
// Wait startup time, for F042 and F070, this is <= 1 us.
- for(uint32_t i = 0; i<200; i++) // should be a few us
- {
+ for (uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
USB->CNTR = 0; // Enable USB
-
- USB->BTABLE = DCD_STM32_BTABLE_BASE;
+#if !defined(STM32G0) && !defined(STM32H5) // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address
+ USB->BTABLE = DCD_STM32_BTABLE_BASE;
+#endif
USB->ISTR = 0; // Clear pending interrupts
// Reset endpoints to disabled
- for(uint32_t i=0; i<STFSDEV_EP_COUNT; i++)
- {
+ for (uint32_t i = 0; i < STFSDEV_EP_COUNT; i++) {
// This doesn't clear all bits since some bits are "toggle", but does set the type to DISABLED.
- pcd_set_endpoint(USB,i,0u);
+ pcd_set_endpoint(USB, i, 0u);
}
- USB->CNTR |= USB_CNTR_RESETM | (USE_SOF ? USB_CNTR_SOFM : 0) | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
+ USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
dcd_handle_bus_reset();
-
+
// Enable pull-up if supported
- if ( dcd_connect ) dcd_connect(rhport);
+ if (dcd_connect) {
+ dcd_connect(rhport);
+ }
}
// Define only on MCU with internal pull-up. BSP can define on MCU without internal PU.
@@ -262,41 +259,69 @@ void dcd_init (uint8_t rhport)
// Disable internal D+ PU
void dcd_disconnect(uint8_t rhport)
{
- (void) rhport;
+ (void)rhport;
USB->BCDR &= ~(USB_BCDR_DPPU);
}
// Enable internal D+ PU
void dcd_connect(uint8_t rhport)
{
- (void) rhport;
+ (void)rhport;
USB->BCDR |= USB_BCDR_DPPU;
}
+#elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151
+// Disable internal D+ PU
+void dcd_disconnect(uint8_t rhport)
+{
+ (void)rhport;
+ SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU);
+}
+
+// Enable internal D+ PU
+void dcd_connect(uint8_t rhport)
+{
+ (void)rhport;
+ SYSCFG->PMC |= SYSCFG_PMC_USB_PU;
+}
#endif
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void)rhport;
+ (void)en;
+
+ if (en) {
+ USB->CNTR |= USB_CNTR_SOFM;
+ } else {
+ USB->CNTR &= ~USB_CNTR_SOFM;
+ }
+}
+
// Enable device interrupt
-void dcd_int_enable (uint8_t rhport)
+void dcd_int_enable(uint8_t rhport)
{
(void)rhport;
// Member here forces write to RAM before allowing ISR to execute
__DSB();
__ISB();
-#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0
+#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4
NVIC_EnableIRQ(USB_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
+ NVIC_EnableIRQ(USB_LP_IRQn);
+
#elif CFG_TUSB_MCU == OPT_MCU_STM32F3
- // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
- // shared USB/CAN IRQs to separate CAN and USB IRQs.
- // This dynamically checks if this remap is active to enable the right IRQs.
- #ifdef SYSCFG_CFGR1_USB_IT_RMP
- if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP)
- {
+// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
+// shared USB/CAN IRQs to separate CAN and USB IRQs.
+// This dynamically checks if this remap is active to enable the right IRQs.
+#ifdef SYSCFG_CFGR1_USB_IT_RMP
+ if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) {
NVIC_EnableIRQ(USB_HP_IRQn);
NVIC_EnableIRQ(USB_LP_IRQn);
NVIC_EnableIRQ(USBWakeUp_RMP_IRQn);
- }
- else
- #endif
+ } else
+#endif
{
NVIC_EnableIRQ(USB_HP_CAN_TX_IRQn);
NVIC_EnableIRQ(USB_LP_CAN_RX0_IRQn);
@@ -306,8 +331,31 @@ void dcd_int_enable (uint8_t rhport)
NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
NVIC_EnableIRQ(USBWakeUp_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
+ NVIC_EnableIRQ(USB_HP_IRQn);
+ NVIC_EnableIRQ(USB_LP_IRQn);
+ NVIC_EnableIRQ(USBWakeUp_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
+#ifdef STM32G0B0xx
+ NVIC_EnableIRQ(USB_IRQn);
+#else
+ NVIC_EnableIRQ(USB_UCPD1_2_IRQn);
+#endif
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
+ NVIC_EnableIRQ(USB_DRD_FS_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ NVIC_EnableIRQ(USB_HP_IRQn);
+ NVIC_EnableIRQ(USB_LP_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
+ NVIC_EnableIRQ(USB_FS_IRQn);
+
#else
- #error Unknown arch in USB driver
+#error Unknown arch in USB driver
#endif
}
@@ -316,21 +364,21 @@ void dcd_int_disable(uint8_t rhport)
{
(void)rhport;
-#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0
+#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4
NVIC_DisableIRQ(USB_IRQn);
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
+ NVIC_DisableIRQ(USB_LP_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32F3
- // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
- // shared USB/CAN IRQs to separate CAN and USB IRQs.
- // This dynamically checks if this remap is active to disable the right IRQs.
- #ifdef SYSCFG_CFGR1_USB_IT_RMP
- if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP)
- {
+// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
+// shared USB/CAN IRQs to separate CAN and USB IRQs.
+// This dynamically checks if this remap is active to disable the right IRQs.
+#ifdef SYSCFG_CFGR1_USB_IT_RMP
+ if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) {
NVIC_DisableIRQ(USB_HP_IRQn);
NVIC_DisableIRQ(USB_LP_IRQn);
NVIC_DisableIRQ(USBWakeUp_RMP_IRQn);
- }
- else
- #endif
+ } else
+#endif
{
NVIC_DisableIRQ(USB_HP_CAN_TX_IRQn);
NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn);
@@ -340,8 +388,31 @@ void dcd_int_disable(uint8_t rhport)
NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
NVIC_DisableIRQ(USBWakeUp_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
+ NVIC_DisableIRQ(USB_HP_IRQn);
+ NVIC_DisableIRQ(USB_LP_IRQn);
+ NVIC_DisableIRQ(USBWakeUp_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
+#ifdef STM32G0B0xx
+ NVIC_DisableIRQ(USB_IRQn);
+#else
+ NVIC_DisableIRQ(USB_UCPD1_2_IRQn);
+#endif
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
+ NVIC_DisableIRQ(USB_DRD_FS_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ NVIC_DisableIRQ(USB_HP_IRQn);
+ NVIC_DisableIRQ(USB_LP_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
+ NVIC_DisableIRQ(USB_FS_IRQn);
+
#else
- #error Unknown arch in USB driver
+#error Unknown arch in USB driver
#endif
// CMSIS has a membar after disabling interrupts
@@ -350,11 +421,11 @@ void dcd_int_disable(uint8_t rhport)
// Receive Set Address request, mcu port must also include status IN response
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
{
- (void) rhport;
- (void) dev_addr;
+ (void)rhport;
+ (void)dev_addr;
// Respond with status
- dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+ dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK | 0x00, NULL, 0);
// DCD can only set address after status for this request is complete.
// do it at dcd_edpt0_status_complete()
@@ -362,48 +433,47 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
void dcd_remote_wakeup(uint8_t rhport)
{
- (void) rhport;
+ (void)rhport;
- USB->CNTR |= (uint16_t) USB_CNTR_RESUME;
+ USB->CNTR |= USB_CNTR_RESUME;
remoteWakeCountdown = 4u; // required to be 1 to 15 ms, ESOF should trigger every 1ms.
}
-static const tusb_desc_endpoint_t ep0OUT_desc =
-{
- .bLength = sizeof(tusb_desc_endpoint_t),
- .bDescriptorType = TUSB_DESC_ENDPOINT,
-
- .bEndpointAddress = 0x00,
- .bmAttributes = { .xfer = TUSB_XFER_CONTROL },
- .wMaxPacketSize = { .size = CFG_TUD_ENDPOINT0_SIZE },
- .bInterval = 0
+static const tusb_desc_endpoint_t ep0OUT_desc = {
+ .bLength = sizeof(tusb_desc_endpoint_t),
+ .bDescriptorType = TUSB_DESC_ENDPOINT,
+ .bEndpointAddress = 0x00,
+ .bmAttributes = {.xfer = TUSB_XFER_CONTROL},
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
+ .bInterval = 0
};
-static const tusb_desc_endpoint_t ep0IN_desc =
-{
- .bLength = sizeof(tusb_desc_endpoint_t),
- .bDescriptorType = TUSB_DESC_ENDPOINT,
-
- .bEndpointAddress = 0x80,
- .bmAttributes = { .xfer = TUSB_XFER_CONTROL },
- .wMaxPacketSize = { .size = CFG_TUD_ENDPOINT0_SIZE },
- .bInterval = 0
+static const tusb_desc_endpoint_t ep0IN_desc = {
+ .bLength = sizeof(tusb_desc_endpoint_t),
+ .bDescriptorType = TUSB_DESC_ENDPOINT,
+ .bEndpointAddress = 0x80,
+ .bmAttributes = {.xfer = TUSB_XFER_CONTROL},
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
+ .bInterval = 0
};
static void dcd_handle_bus_reset(void)
{
- //__IO uint16_t * const epreg = &(EPREG(0));
USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag
- // Clear all EPREG (or maybe this is automatic? I'm not sure)
- for(uint32_t i=0; i<STFSDEV_EP_COUNT; i++)
- {
- pcd_set_endpoint(USB,i,0u);
+ for (uint32_t i = 0; i < STFSDEV_EP_COUNT; i++) {
+ // Clear EP allocation status
+ ep_alloc_status[i].ep_num = 0xFF;
+ ep_alloc_status[i].ep_type = 0xFF;
+ ep_alloc_status[i].allocated[0] = false;
+ ep_alloc_status[i].allocated[1] = false;
}
- dcd_pma_alloc_reset();
- dcd_edpt_open (0, &ep0OUT_desc);
- dcd_edpt_open (0, &ep0IN_desc);
+ // Reset PMA allocation
+ ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * MAX_EP_COUNT;
+
+ dcd_edpt_open(0, &ep0OUT_desc);
+ dcd_edpt_open(0, &ep0IN_desc);
USB->DADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero.
}
@@ -415,99 +485,141 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr)
{
uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
+ uint8_t ep_addr = (wEPRegVal & USB_EPADDR_FIELD) | TUSB_DIR_IN_MASK;
// Verify the CTR_TX bit is set. This was in the ST Micro code,
// but I'm not sure it's actually necessary?
- if((wEPRegVal & USB_EP_CTR_TX) == 0U)
- {
+ if ((wEPRegVal & USB_EP_CTR_TX) == 0U) {
return;
}
/* clear int flag */
pcd_clear_tx_ep_ctr(USB, EPindex);
- xfer_ctl_t * xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_IN);
- if((xfer->total_len != xfer->queued_len)) /* TX not complete */
- {
- dcd_transmit_packet(xfer, EPindex);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
+
+ if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) {
+ // Ignore spurious interrupts that we don't schedule
+ // host can send IN token while there is no data to send, since ISO does not have NAK
+ // this will result to zero length packet --> trigger interrupt (which cannot be masked)
+ if (!xfer->iso_in_sending) {
+ return;
+ }
+ xfer->iso_in_sending = false;
+
+ if (wEPRegVal & USB_EP_DTOG_TX) {
+ pcd_set_ep_tx_dbuf0_cnt(USB, EPindex, 0);
+ } else {
+ pcd_set_ep_tx_dbuf1_cnt(USB, EPindex, 0);
+ }
}
- else /* TX Complete */
- {
- dcd_event_xfer_complete(0, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true);
+
+ if ((xfer->total_len != xfer->queued_len)) {
+ dcd_transmit_packet(xfer, EPindex);
+ } else {
+ dcd_event_xfer_complete(0, ep_addr, xfer->total_len, XFER_RESULT_SUCCESS, true);
}
}
// Handle CTR interrupt for the RX/OUT direction
-//
// Upon call, (wIstr & USB_ISTR_DIR) == 0U
static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
{
+#ifdef FSDEV_BUS_32BIT
+ /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf
+ * From STM32H503 errata 2.15.1: Buffer description table update completes after CTR interrupt triggers
+ * Description:
+ * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses
+ * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct.
+ * Workaround:
+ * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay
+ * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode
+ * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code
+ * also takes time, so we'll wait 60 cycles (count = 20).
+ * - Since Low Speed mode is not supported/popular, we will ignore it for now.
+ *
+ * Note: this errata also seems to apply to G0, U5, H5 etc.
+ */
+ volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver
+ while (cycle_count > 0U) {
+ cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
+ }
+#endif
+
uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
- uint32_t count = pcd_get_ep_rx_cnt(USB,EPindex);
+ uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD;
- xfer_ctl_t *xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_OUT);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
// Verify the CTR_RX bit is set. This was in the ST Micro code,
// but I'm not sure it's actually necessary?
- if((wEPRegVal & USB_EP_CTR_RX) == 0U)
- {
+ if ((wEPRegVal & USB_EP_CTR_RX) == 0U) {
return;
}
-
- if((EPindex == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) /* Setup packet */
- {
- // The setup_received function uses memcpy, so this must first copy the setup data into
- // user memory, to allow for the 32-bit access that memcpy performs.
- uint8_t userMemBuf[8];
- /* Get SETUP Packet*/
- if(count == 8) // Setup packet should always be 8 bytes. If not, ignore it, and try again.
- {
+
+ if ((ep_addr == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) {
+ /* Setup packet */
+ uint32_t count = pcd_get_ep_rx_cnt(USB, EPindex);
+ // Setup packet should always be 8 bytes. If not, ignore it, and try again.
+ if (count == 8) {
// Must reset EP to NAK (in case it had been stalling) (though, maybe too late here)
- pcd_set_ep_rx_status(USB,0u,USB_EP_RX_NAK);
- pcd_set_ep_tx_status(USB,0u,USB_EP_TX_NAK);
- dcd_read_packet_memory(userMemBuf, *pcd_ep_rx_address_ptr(USB,EPindex), 8);
- dcd_event_setup_received(0, (uint8_t*)userMemBuf, true);
+ pcd_set_ep_rx_status(USB, 0u, USB_EP_RX_NAK);
+ pcd_set_ep_tx_status(USB, 0u, USB_EP_TX_NAK);
+#ifdef FSDEV_BUS_32BIT
+ dcd_event_setup_received(0, (uint8_t *)(USB_PMAADDR + pcd_get_ep_rx_address(USB, EPindex)), true);
+#else
+ // The setup_received function uses memcpy, so this must first copy the setup data into
+ // user memory, to allow for the 32-bit access that memcpy performs.
+ uint8_t userMemBuf[8];
+ dcd_read_packet_memory(userMemBuf, pcd_get_ep_rx_address(USB, EPindex), 8);
+ dcd_event_setup_received(0, (uint8_t *)userMemBuf, true);
+#endif
}
- }
- else
- {
+ } else {
// Clear RX CTR interrupt flag
- if(EPindex != 0u)
- {
+ if (ep_addr != 0u) {
pcd_clear_rx_ep_ctr(USB, EPindex);
}
- if (count != 0U)
- {
-#if 0 // TODO support dcd_edpt_xfer_fifo API
- if (xfer->ff)
- {
- dcd_read_packet_memory_ff(xfer->ff, *pcd_ep_rx_address_ptr(USB,EPindex), count);
+ uint32_t count;
+ uint16_t addr;
+ /* Read from correct register when ISOCHRONOUS (double buffered) */
+ if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) {
+ if (wEPRegVal & USB_EP_DTOG_RX) {
+ count = pcd_get_ep_dbuf0_cnt(USB, EPindex);
+ addr = pcd_get_ep_dbuf0_address(USB, EPindex);
+ } else {
+ count = pcd_get_ep_dbuf1_cnt(USB, EPindex);
+ addr = pcd_get_ep_dbuf1_address(USB, EPindex);
}
- else
-#endif
- {
- dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), *pcd_ep_rx_address_ptr(USB,EPindex), count);
+ } else {
+ count = pcd_get_ep_rx_cnt(USB, EPindex);
+ addr = pcd_get_ep_rx_address(USB, EPindex);
+ }
+
+ TU_ASSERT(count <= xfer->max_packet_size, /**/);
+
+ if (count != 0U) {
+ if (xfer->ff) {
+ dcd_read_packet_memory_ff(xfer->ff, addr, count);
+ } else {
+ dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), addr, count);
}
xfer->queued_len = (uint16_t)(xfer->queued_len + count);
}
- if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len))
- {
- /* RX COMPLETE */
- dcd_event_xfer_complete(0, EPindex, xfer->queued_len, XFER_RESULT_SUCCESS, true);
- // Though the host could still send, we don't know.
- // Does the bulk pipe need to be reset to valid to allow for a ZLP?
- }
- else
- {
- uint32_t remaining = (uint32_t)xfer->total_len - (uint32_t)xfer->queued_len;
- if(remaining >= xfer->max_packet_size) {
- pcd_set_ep_rx_cnt(USB, EPindex,xfer->max_packet_size);
- } else {
- pcd_set_ep_rx_cnt(USB, EPindex,remaining);
+ if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) {
+ // all bytes received or short packet
+ dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+ } else {
+ /* Set endpoint active again for receiving more data.
+ * Note that isochronous endpoints stay active always */
+ if ((wEPRegVal & USB_EP_TYPE_MASK) != USB_EP_ISOCHRONOUS) {
+ uint16_t remaining = xfer->total_len - xfer->queued_len;
+ uint16_t cnt = tu_min16(remaining, xfer->max_packet_size);
+ pcd_set_ep_rx_cnt(USB, EPindex, cnt);
}
pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID);
}
@@ -516,9 +628,8 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
// For EP0, prepare to receive another SETUP packet.
// Clear CTR last so that a new packet does not overwrite the packing being read.
// (Based on the docs, it seems SETUP will always be accepted after CTR is cleared)
- if(EPindex == 0u)
- {
- // Always be prepared for a status packet...
+ if (ep_addr == 0u) {
+ // Always be prepared for a status packet...
pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE);
pcd_clear_rx_ep_ctr(USB, EPindex);
}
@@ -529,58 +640,60 @@ static void dcd_ep_ctr_handler(void)
uint32_t wIstr;
/* stay in loop while pending interrupts */
- while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U)
- {
-
- if ((wIstr & USB_ISTR_DIR) == 0U) /* TX/IN */
- {
+ while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) {
+ if ((wIstr & USB_ISTR_DIR) == 0U) {
+ /* TX/IN */
dcd_ep_ctr_tx_handler(wIstr);
- }
- else /* RX/OUT*/
- {
+ } else {
+ /* RX/OUT*/
dcd_ep_ctr_rx_handler(wIstr);
}
}
}
-void dcd_int_handler(uint8_t rhport) {
+void dcd_int_handler(uint8_t rhport)
+{
- (void) rhport;
+ (void)rhport;
uint32_t int_status = USB->ISTR;
- //const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP
- // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF;
- // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ )
+ // const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP
+ // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF;
+ // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ )
// The ST driver loops here on the CTR bit, but that loop has been moved into the
// dcd_ep_ctr_handler(), so less need to loop here. The other interrupts shouldn't
// be triggered repeatedly.
- if(int_status & USB_ISTR_RESET) {
+ /* Put SOF flag at the beginning of ISR in case to get least amount of jitter if it is used for timing purposes */
+ if (int_status & USB_ISTR_SOF) {
+ USB->ISTR = (fsdev_bus_t)~USB_ISTR_SOF;
+ dcd_event_sof(0, USB->FNR & USB_FNR_FN, true);
+ }
+
+ if (int_status & USB_ISTR_RESET) {
// USBRST is start of reset.
- clear_istr_bits(USB_ISTR_RESET);
+ USB->ISTR = (fsdev_bus_t)~USB_ISTR_RESET;
dcd_handle_bus_reset();
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
return; // Don't do the rest of the things here; perhaps they've been cleared?
}
- if (int_status & USB_ISTR_CTR)
- {
+ if (int_status & USB_ISTR_CTR) {
/* servicing of the endpoint correct transfer interrupt */
/* clear of the CTR flag into the sub */
dcd_ep_ctr_handler();
}
- if (int_status & USB_ISTR_WKUP)
- {
- reg16_clear_bits(&USB->CNTR, USB_CNTR_LPMODE);
- reg16_clear_bits(&USB->CNTR, USB_CNTR_FSUSP);
- clear_istr_bits(USB_ISTR_WKUP);
+ if (int_status & USB_ISTR_WKUP) {
+ USB->CNTR &= ~USB_CNTR_LPMODE;
+ USB->CNTR &= ~USB_CNTR_FSUSP;
+
+ USB->ISTR = (fsdev_bus_t)~USB_ISTR_WKUP;
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
}
- if (int_status & USB_ISTR_SUSP)
- {
+ if (int_status & USB_ISTR_SUSP) {
/* Suspend is asserted for both suspend and unplug events. without Vbus monitoring,
* these events cannot be differentiated, so we only trigger suspend. */
@@ -589,27 +702,18 @@ void dcd_int_handler(uint8_t rhport) {
USB->CNTR |= USB_CNTR_LPMODE;
/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
- clear_istr_bits(USB_ISTR_SUSP);
+ USB->ISTR = (fsdev_bus_t)~USB_ISTR_SUSP;
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
}
-#if USE_SOF
- if(int_status & USB_ISTR_SOF) {
- clear_istr_bits(USB_ISTR_SOF);
- dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
- }
-#endif
-
- if(int_status & USB_ISTR_ESOF) {
- if(remoteWakeCountdown == 1u)
- {
- USB->CNTR &= (uint16_t)(~USB_CNTR_RESUME);
+ if (int_status & USB_ISTR_ESOF) {
+ if (remoteWakeCountdown == 1u) {
+ USB->CNTR &= ~USB_CNTR_RESUME;
}
- if(remoteWakeCountdown > 0u)
- {
+ if (remoteWakeCountdown > 0u) {
remoteWakeCountdown--;
}
- clear_istr_bits(USB_ISTR_ESOF);
+ USB->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF;
}
}
@@ -619,492 +723,661 @@ void dcd_int_handler(uint8_t rhport) {
// Invoked when a control transfer's status stage is complete.
// May help DCD to prepare for next control transfer, this API is optional.
-void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request)
{
- (void) rhport;
+ (void)rhport;
if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
- request->bRequest == TUSB_REQ_SET_ADDRESS )
- {
- uint8_t const dev_addr = (uint8_t) request->wValue;
+ request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ uint8_t const dev_addr = (uint8_t)request->wValue;
// Setting new address after the whole request is complete
- reg16_clear_bits(&USB->DADDR, USB_DADDR_ADD);
- USB->DADDR = (uint16_t)(USB->DADDR | dev_addr); // leave the enable bit set
- }
-}
-
-static void dcd_pma_alloc_reset(void)
-{
- ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each)
- //TU_LOG2("dcd_pma_alloc_reset()\r\n");
- for(uint32_t i=0; i<MAX_EP_COUNT; i++)
- {
- xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_alloc_size = 0U;
- xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U;
- xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U;
- xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U;
+ USB->DADDR &= ~USB_DADDR_ADD;
+ USB->DADDR |= dev_addr; // leave the enable bit set
}
}
/***
* Allocate a section of PMA
- *
- * If the EP number has already been allocated, and the new allocation
- * is larger than the old allocation, then this will fail with a TU_ASSERT.
- * (This is done to simplify the code. More complicated algorithms could be used)
- *
+ * In case of double buffering, high 16bit is the address of 2nd buffer
* During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually.
*/
-static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length)
+static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf)
{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
- xfer_ctl_t* epXferCtl = xfer_ctl_ptr(epnum,dir);
+ // Ensure allocated buffer is aligned
+#ifdef FSDEV_BUS_32BIT
+ length = (length + 3) & ~0x03;
+#else
+ length = (length + 1) & ~0x01;
+#endif
- if(epXferCtl->pma_alloc_size != 0U)
- {
- //TU_LOG2("dcd_pma_alloc(%x,%x)=%x (cached)\r\n",ep_addr,length,epXferCtl->pma_ptr);
- // Previously allocated
- TU_ASSERT(length <= epXferCtl->pma_alloc_size, 0xFFFF); // Verify no larger than previous alloc
- return epXferCtl->pma_ptr;
- }
-
- uint16_t addr = ep_buf_ptr;
+ uint32_t addr = ep_buf_ptr;
ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer
-
- // Verify no overflow
- TU_ASSERT(ep_buf_ptr <= PMA_LENGTH, 0xFFFF);
-
- epXferCtl->pma_ptr = addr;
- epXferCtl->pma_alloc_size = length;
- //TU_LOG2("dcd_pma_alloc(%x,%x)=%x\r\n",ep_addr,length,addr);
+
+ if (dbuf) {
+ addr |= ((uint32_t)ep_buf_ptr) << 16;
+ ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer
+ }
+
+ // Verify packet buffer is not overflowed
+ TU_ASSERT(ep_buf_ptr <= FSDEV_PMA_SIZE, 0xFFFF);
return addr;
}
/***
- * Free a block of PMA space
+ * Allocate hardware endpoint
*/
-static void dcd_pma_free(uint8_t ep_addr)
+static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
{
uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- // Presently, this should never be called for EP0 IN/OUT
- TU_ASSERT(open_ep_count > 2, /**/);
- TU_ASSERT(xfer_ctl_ptr(epnum,dir)->max_packet_size != 0, /**/);
- open_ep_count--;
-
- // If count is 2, only EP0 should be open, so allocations can be mostly reset.
+ for (uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) {
+ // Check if already allocated
+ if (ep_alloc_status[i].allocated[dir] &&
+ ep_alloc_status[i].ep_type == ep_type &&
+ ep_alloc_status[i].ep_num == epnum) {
+ return i;
+ }
- if(open_ep_count == 2)
- {
- ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT + 2*CFG_TUD_ENDPOINT0_SIZE; // 8 bytes per endpoint (two TX and two RX words, each), and EP0
+ // If EP of current direction is not allocated
+ // Except for ISO endpoint, both direction should be free
+ if (!ep_alloc_status[i].allocated[dir] &&
+ (ep_type != TUSB_XFER_ISOCHRONOUS || !ep_alloc_status[i].allocated[dir ^ 1])) {
+ // Check if EP number is the same
+ if (ep_alloc_status[i].ep_num == 0xFF || ep_alloc_status[i].ep_num == epnum) {
+ // One EP pair has to be the same type
+ if (ep_alloc_status[i].ep_type == 0xFF || ep_alloc_status[i].ep_type == ep_type) {
+ ep_alloc_status[i].ep_num = epnum;
+ ep_alloc_status[i].ep_type = ep_type;
+ ep_alloc_status[i].allocated[dir] = true;
- // Skip EP0
- for(uint32_t i=1; i<MAX_EP_COUNT; i++)
- {
- xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_alloc_size = 0U;
- xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U;
- xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U;
- xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U;
+ return i;
+ }
+ }
}
}
+
+ // Allocation failed
+ TU_ASSERT(0);
}
// The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers,
// so I'm using the #define from HAL here, instead.
-bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
{
(void)rhport;
- uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
- const uint16_t epMaxPktSize = p_endpoint_desc->wMaxPacketSize.size;
+ uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress;
+ uint8_t const ep_idx = dcd_ep_alloc(ep_addr, p_endpoint_desc->bmAttributes.xfer);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc);
+ const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size);
uint16_t pma_addr;
uint32_t wType;
-
- // Isochronous not supported (yet), and some other driver assumptions.
- TU_ASSERT(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
- TU_ASSERT(epnum < MAX_EP_COUNT);
- // Set type
- switch(p_endpoint_desc->bmAttributes.xfer) {
- case TUSB_XFER_CONTROL:
- wType = USB_EP_CONTROL;
- break;
-#if (0)
- case TUSB_XFER_ISOCHRONOUS: // FIXME: Not yet supported
- wType = USB_EP_ISOCHRONOUS;
- break;
-#endif
+ TU_ASSERT(ep_idx < STFSDEV_EP_COUNT);
+ TU_ASSERT(buffer_size <= 64);
- case TUSB_XFER_BULK:
- wType = USB_EP_CONTROL;
- break;
+ // Set type
+ switch (p_endpoint_desc->bmAttributes.xfer) {
+ case TUSB_XFER_CONTROL:
+ wType = USB_EP_CONTROL;
+ break;
+ case TUSB_XFER_BULK:
+ wType = USB_EP_CONTROL;
+ break;
- case TUSB_XFER_INTERRUPT:
- wType = USB_EP_INTERRUPT;
- break;
+ case TUSB_XFER_INTERRUPT:
+ wType = USB_EP_INTERRUPT;
+ break;
- default:
- TU_ASSERT(false);
+ default:
+ // Note: ISO endpoint should use alloc / active functions
+ TU_ASSERT(false);
}
- pcd_set_eptype(USB, epnum, wType);
- pcd_set_ep_address(USB, epnum, epnum);
- // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint)
- // or being double-buffered (bulk endpoints)
- pcd_clear_ep_kind(USB,0);
+ pcd_set_eptype(USB, ep_idx, wType);
+ pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr));
- pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, p_endpoint_desc->wMaxPacketSize.size);
+ /* Create a packet memory buffer area. */
+ pma_addr = dcd_pma_alloc(buffer_size, false);
- if(dir == TUSB_DIR_IN)
- {
- *pcd_ep_tx_address_ptr(USB, epnum) = pma_addr;
- pcd_set_ep_tx_cnt(USB, epnum, p_endpoint_desc->wMaxPacketSize.size);
- pcd_clear_tx_dtog(USB, epnum);
- pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_NAK);
- }
- else
- {
- *pcd_ep_rx_address_ptr(USB, epnum) = pma_addr;
- pcd_set_ep_rx_cnt(USB, epnum, p_endpoint_desc->wMaxPacketSize.size);
- pcd_clear_rx_dtog(USB, epnum);
- pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_NAK);
+ if (dir == TUSB_DIR_IN) {
+ pcd_set_ep_tx_address(USB, ep_idx, pma_addr);
+ pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK);
+ pcd_clear_tx_dtog(USB, ep_idx);
+ } else {
+ pcd_set_ep_rx_address(USB, ep_idx, pma_addr);
+ pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK);
+ pcd_clear_rx_dtog(USB, ep_idx);
}
- xfer_ctl_ptr(epnum, dir)->max_packet_size = epMaxPktSize;
+ xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size;
+ xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx;
return true;
}
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ (void)rhport;
+
+ for (uint32_t i = 1; i < STFSDEV_EP_COUNT; i++) {
+ // Reset endpoint
+ pcd_set_endpoint(USB, i, 0);
+ // Clear EP allocation status
+ ep_alloc_status[i].ep_num = 0xFF;
+ ep_alloc_status[i].ep_type = 0xFF;
+ ep_alloc_status[i].allocated[0] = false;
+ ep_alloc_status[i].allocated[1] = false;
+ }
+
+ // Reset PMA allocation
+ ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * MAX_EP_COUNT + 2 * CFG_TUD_ENDPOINT0_SIZE;
+}
+
/**
* Close an endpoint.
- *
+ *
* This function may be called with interrupts enabled or disabled.
- *
+ *
* This also clears transfers in progress, should there be any.
*/
-void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
(void)rhport;
- uint32_t const epnum = tu_edpt_number(ep_addr);
- uint32_t const dir = tu_edpt_dir(ep_addr);
-
- if(dir == TUSB_DIR_IN)
- {
- pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_DIS);
+
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
+ uint8_t const ep_idx = xfer->ep_idx;
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ if (dir == TUSB_DIR_IN) {
+ pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS);
+ } else {
+ pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS);
}
- else
- {
- pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_DIS);
+}
+
+bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size)
+{
+ (void)rhport;
+
+ uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS);
+ const uint16_t buffer_size = pcd_aligned_buffer_size(largest_packet_size);
+
+ /* Create a packet memory buffer area. Enable double buffering for devices with 2048 bytes PMA,
+ for smaller devices double buffering occupy too much space. */
+#if FSDEV_PMA_SIZE > 1024u
+ uint32_t pma_addr = dcd_pma_alloc(buffer_size, true);
+ uint16_t pma_addr2 = pma_addr >> 16;
+#else
+ uint32_t pma_addr = dcd_pma_alloc(buffer_size, true);
+ uint16_t pma_addr2 = pma_addr;
+#endif
+ pcd_set_ep_tx_address(USB, ep_idx, pma_addr);
+ pcd_set_ep_rx_address(USB, ep_idx, pma_addr2);
+
+ pcd_set_eptype(USB, ep_idx, USB_EP_ISOCHRONOUS);
+
+ xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx;
+
+ return true;
+}
+
+bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
+{
+ (void)rhport;
+ uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress;
+ uint8_t const ep_idx = xfer_ctl_ptr(ep_addr)->ep_idx;
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc);
+
+ pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS);
+ pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS);
+
+ pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr));
+
+ pcd_clear_tx_dtog(USB, ep_idx);
+ pcd_clear_rx_dtog(USB, ep_idx);
+
+ if (dir == TUSB_DIR_IN) {
+ pcd_rx_dtog(USB, ep_idx);
+ } else {
+ pcd_tx_dtog(USB, ep_idx);
}
- dcd_pma_free(ep_addr);
+ xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size;
+
+ return true;
}
// Currently, single-buffered, and only 64 bytes at a time (max)
-static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix)
+static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix)
{
uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len);
-
- if(len > xfer->max_packet_size) // max packet size for FS transfer
- {
+ if (len > xfer->max_packet_size) {
len = xfer->max_packet_size;
}
- uint16_t oldAddr = *pcd_ep_tx_address_ptr(USB,ep_ix);
-#if 0 // TODO support dcd_edpt_xfer_fifo API
- if (xfer->ff)
- {
- dcd_write_packet_memory_ff(xfer->ff, oldAddr, len);
+ uint16_t ep_reg = pcd_get_endpoint(USB, ep_ix);
+ bool const is_iso = (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS;
+ uint16_t addr_ptr;
+
+ if (is_iso) {
+ if (ep_reg & USB_EP_DTOG_TX) {
+ addr_ptr = pcd_get_ep_dbuf1_address(USB, ep_ix);
+ pcd_set_ep_tx_dbuf1_cnt(USB, ep_ix, len);
+ } else {
+ addr_ptr = pcd_get_ep_dbuf0_address(USB, ep_ix);
+ pcd_set_ep_tx_dbuf0_cnt(USB, ep_ix, len);
+ }
+ } else {
+ addr_ptr = pcd_get_ep_tx_address(USB, ep_ix);
+ pcd_set_ep_tx_cnt(USB, ep_ix, len);
}
- else
-#endif
- {
- dcd_write_packet_memory(oldAddr, &(xfer->buffer[xfer->queued_len]), len);
+
+ if (xfer->ff) {
+ dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len);
+ } else {
+ dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len);
}
xfer->queued_len = (uint16_t)(xfer->queued_len + len);
- pcd_set_ep_tx_cnt(USB,ep_ix,len);
+ dcd_int_disable(0);
pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID);
+ if (is_iso) {
+ xfer->iso_in_sending = true;
+ }
+ dcd_int_enable(0);
}
-bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr)
{
- (void) rhport;
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir);
+ (void)rhport;
- xfer->buffer = buffer;
- // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
- xfer->total_len = total_bytes;
- xfer->queued_len = 0;
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
+ uint8_t const ep_idx = xfer->ep_idx;
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- if ( dir == TUSB_DIR_OUT )
- {
+ if (dir == TUSB_DIR_IN) {
+ dcd_transmit_packet(xfer, ep_idx);
+ } else {
// A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid
// buffer for the control endpoint.
- if (epnum == 0 && buffer == NULL)
- {
- xfer->buffer = (uint8_t*)_setup_packet;
+ if (ep_idx == 0 && xfer->buffer == NULL) {
+ xfer->buffer = (uint8_t *)_setup_packet;
}
- if(total_bytes > xfer->max_packet_size)
- {
- pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size);
+
+ uint32_t cnt = (uint32_t ) tu_min16(xfer->total_len, xfer->max_packet_size);
+ uint16_t ep_reg = pcd_get_endpoint(USB, ep_idx);
+
+ if ((ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) {
+ pcd_set_ep_rx_dbuf0_cnt(USB, ep_idx, cnt);
+ pcd_set_ep_rx_dbuf1_cnt(USB, ep_idx, cnt);
} else {
- pcd_set_ep_rx_cnt(USB,epnum,total_bytes);
+ pcd_set_ep_rx_cnt(USB, ep_idx, cnt);
}
- pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID);
- }
- else // IN
- {
- dcd_transmit_packet(xfer,epnum);
+
+ pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_VALID);
}
+
return true;
}
-#if 0 // TODO support dcd_edpt_xfer_fifo API
-bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
- (void) rhport;
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ xfer->buffer = buffer;
+ xfer->ff = NULL;
+ xfer->total_len = total_bytes;
+ xfer->queued_len = 0;
- xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir);
+ return edpt_xfer(rhport, ep_addr);
+}
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes)
+{
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
xfer->buffer = NULL;
- // xfer->ff = ff; // TODO support dcd_edpt_xfer_fifo API
+ xfer->ff = ff;
xfer->total_len = total_bytes;
xfer->queued_len = 0;
- if ( dir == TUSB_DIR_OUT )
- {
- if(total_bytes > xfer->max_packet_size)
- {
- pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size);
- } else {
- pcd_set_ep_rx_cnt(USB,epnum,total_bytes);
- }
- pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID);
- }
- else // IN
- {
- dcd_transmit_packet(xfer,epnum);
- }
- return true;
+ return edpt_xfer(rhport, ep_addr);
}
-#endif
-void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
(void)rhport;
- if (ep_addr & 0x80)
- { // IN
- pcd_set_ep_tx_status(USB, ep_addr & 0x7F, USB_EP_TX_STALL);
- }
- else
- { // OUT
- pcd_set_ep_rx_status(USB, ep_addr, USB_EP_RX_STALL);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
+ uint8_t const ep_idx = xfer->ep_idx;
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ if (dir == TUSB_DIR_IN) {
+ pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_STALL);
+ } else {
+ pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_STALL);
}
}
-void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{
(void)rhport;
- if (ep_addr & 0x80)
- { // IN
- ep_addr &= 0x7F;
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
+ uint8_t const ep_idx = xfer->ep_idx;
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- pcd_set_ep_tx_status(USB,ep_addr, USB_EP_TX_NAK);
+ if (dir == TUSB_DIR_IN) { // IN
+ if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) {
+ pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK);
+ }
/* Reset to DATA0 if clearing stall condition. */
- pcd_clear_tx_dtog(USB,ep_addr);
- }
- else
- { // OUT
+ pcd_clear_tx_dtog(USB, ep_idx);
+ } else { // OUT
+ if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) {
+ pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK);
+ }
/* Reset to DATA0 if clearing stall condition. */
- pcd_clear_rx_dtog(USB,ep_addr);
-
- pcd_set_ep_rx_status(USB,ep_addr, USB_EP_RX_NAK);
+ pcd_clear_rx_dtog(USB, ep_idx);
}
}
+#ifdef FSDEV_BUS_32BIT
+static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes)
+{
+ const uint8_t *srcVal = src;
+ volatile uint32_t *dst32 = (volatile uint32_t *)(USB_PMAADDR + dst);
+
+ for (uint32_t n = wNBytes / 4; n > 0; --n) {
+ *dst32++ = tu_unaligned_read32(srcVal);
+ srcVal += 4;
+ }
+
+ wNBytes = wNBytes & 0x03;
+ if (wNBytes) {
+ uint32_t wrVal = *srcVal;
+ wNBytes--;
+
+ if (wNBytes) {
+ wrVal |= *++srcVal << 8;
+ wNBytes--;
+
+ if (wNBytes) {
+ wrVal |= *++srcVal << 16;
+ }
+ }
+
+ *dst32 = wrVal;
+ }
+
+ return true;
+}
+#else
// Packet buffer access can only be 8- or 16-bit.
/**
- * @brief Copy a buffer from user memory area to packet memory area (PMA).
- * This uses byte-access for user memory (so support non-aligned buffers)
- * and 16-bit access for packet memory.
- * @param dst, byte address in PMA; must be 16-bit aligned
- * @param src pointer to user memory area.
- * @param wPMABufAddr address into PMA.
- * @param wNBytes no. of bytes to be copied.
- * @retval None
- */
-static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes)
+ * @brief Copy a buffer from user memory area to packet memory area (PMA).
+ * This uses byte-access for user memory (so support non-aligned buffers)
+ * and 16-bit access for packet memory.
+ * @param dst, byte address in PMA; must be 16-bit aligned
+ * @param src pointer to user memory area.
+ * @param wPMABufAddr address into PMA.
+ * @param wNBytes no. of bytes to be copied.
+ * @retval None
+ */
+static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes)
{
- uint32_t n = ((uint32_t)wNBytes + 1U) >> 1U;
- uint32_t i;
+ uint32_t n = (uint32_t)wNBytes >> 1U;
uint16_t temp1, temp2;
- const uint8_t * srcVal;
+ const uint8_t *srcVal;
// The GCC optimizer will combine access to 32-bit sizes if we let it. Force
// it volatile so that it won't do that.
__IO uint16_t *pdwVal;
srcVal = src;
- pdwVal = &pma[PMA_STRIDE*(dst>>1)];
+ pdwVal = &pma[FSDEV_PMA_STRIDE * (dst >> 1)];
- for (i = n; i != 0; i--)
- {
- temp1 = (uint16_t) *srcVal;
+ while (n--) {
+ temp1 = (uint16_t)*srcVal;
srcVal++;
- temp2 = temp1 | ((uint16_t)((uint16_t) ((*srcVal) << 8U))) ;
+ temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U));
*pdwVal = temp2;
- pdwVal += PMA_STRIDE;
+ pdwVal += FSDEV_PMA_STRIDE;
srcVal++;
}
+
+ if (wNBytes) {
+ temp1 = *srcVal;
+ *pdwVal = temp1;
+ }
+
return true;
}
+#endif
-#if 0 // TODO support dcd_edpt_xfer_fifo API
/**
- * @brief Copy from FIFO to packet memory area (PMA).
- * Uses byte-access of system memory and 16-bit access of packet memory
- * @param wNBytes no. of bytes to be copied.
- * @retval None
- */
-
-// THIS FUNCTION IS UNTESTED
-
-static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes)
+ * @brief Copy from FIFO to packet memory area (PMA).
+ * Uses byte-access of system memory and 16-bit access of packet memory
+ * @param wNBytes no. of bytes to be copied.
+ * @retval None
+ */
+static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes)
{
// Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
- // Check for first linear part
- void * src;
- uint16_t len = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes); // We want to read from the FIFO - THIS FUNCTION CHANGED!!!
- TU_VERIFY(len && dcd_write_packet_memory(dst, src, len)); // and write it into the PMA
- tu_fifo_advance_read_pointer(ff, len);
+ tu_fifo_buffer_info_t info;
+ tu_fifo_get_read_info(ff, &info);
- // Check for wrapped part
- if (len < wNBytes)
- {
- // Get remaining wrapped length
- uint16_t len2 = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes - len);
- TU_VERIFY(len2);
+ uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin);
+ uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap);
- // Update destination pointer
- dst += len;
+ // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part,
+ // last lin byte will be combined with wrapped part
+ // To ensure PMA is always access aligned (dst aligned to 16 or 32 bit)
+#ifdef FSDEV_BUS_32BIT
+ if ((cnt_lin & 0x03) && cnt_wrap) {
+ // Copy first linear part
+ dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x03);
+ dst += cnt_lin & ~0x03;
- // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split
- if (len % 2) // If len is uneven there is a byte left to copy
- {
- // Since PMA can accessed only 16 bit-wise we copy the last byte again
- tu_fifo_backward_read_pointer(ff, 1); // Move one byte back and copy two bytes for the PMA
- tu_fifo_read_n(ff, (void *) &pma[PMA_STRIDE*(dst>>1)], 2); // Since EP FIFOs must be of item size 1 this is safe to do
- dst++;
- len2--;
+ // Copy last linear bytes & first wrapped bytes to buffer
+ uint32_t i;
+ uint8_t tmp[4];
+ for (i = 0; i < (cnt_lin & 0x03); i++) {
+ tmp[i] = ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i];
+ }
+ uint32_t wCnt = cnt_wrap;
+ for (; i < 4 && wCnt > 0; i++, wCnt--) {
+ tmp[i] = *(uint8_t *)info.ptr_wrap;
+ info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1;
}
- TU_VERIFY(dcd_write_packet_memory(dst, src, len2));
- tu_fifo_advance_write_pointer(ff, len2);
+ // Write unaligned buffer
+ dcd_write_packet_memory(dst, &tmp, 4);
+ dst += 4;
+
+ // Copy rest of wrapped byte
+ if (wCnt)
+ dcd_write_packet_memory(dst, info.ptr_wrap, wCnt);
+ }
+#else
+ if ((cnt_lin & 0x01) && cnt_wrap) {
+ // Copy first linear part
+ dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x01);
+ dst += cnt_lin & ~0x01;
+
+ // Copy last linear byte & first wrapped byte
+ uint16_t tmp = ((uint8_t *)info.ptr_lin)[cnt_lin - 1] | ((uint16_t)(((uint8_t *)info.ptr_wrap)[0]) << 8U);
+ dcd_write_packet_memory(dst, &tmp, 2);
+ dst += 2;
+
+ // Copy rest of wrapped byte
+ dcd_write_packet_memory(dst, ((uint8_t *)info.ptr_wrap) + 1, cnt_wrap - 1);
+ }
+#endif
+ else {
+ // Copy linear part
+ dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin);
+ dst += info.len_lin;
+
+ if (info.len_wrap) {
+ // Copy wrapped byte
+ dcd_write_packet_memory(dst, info.ptr_wrap, cnt_wrap);
+ }
}
+ tu_fifo_advance_read_pointer(ff, cnt_lin + cnt_wrap);
+
return true;
}
-#endif
+#ifdef FSDEV_BUS_32BIT
+static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes)
+{
+ uint8_t *dstVal = dst;
+ volatile uint32_t *src32 = (volatile uint32_t *)(USB_PMAADDR + src);
+
+ for (uint32_t n = wNBytes / 4; n > 0; --n) {
+ tu_unaligned_write32(dstVal, *src32++);
+ dstVal += 4;
+ }
+
+ wNBytes = wNBytes & 0x03;
+ if (wNBytes) {
+ uint32_t rdVal = *src32;
+
+ *dstVal = tu_u32_byte0(rdVal);
+ wNBytes--;
+
+ if (wNBytes) {
+ *++dstVal = tu_u32_byte1(rdVal);
+ wNBytes--;
+
+ if (wNBytes) {
+ *++dstVal = tu_u32_byte2(rdVal);
+ }
+ }
+ }
+
+ return true;
+}
+#else
/**
- * @brief Copy a buffer from packet memory area (PMA) to user memory area.
- * Uses byte-access of system memory and 16-bit access of packet memory
- * @param wNBytes no. of bytes to be copied.
- * @retval None
- */
-static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes)
+ * @brief Copy a buffer from packet memory area (PMA) to user memory area.
+ * Uses byte-access of system memory and 16-bit access of packet memory
+ * @param wNBytes no. of bytes to be copied.
+ * @retval None
+ */
+static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes)
{
uint32_t n = (uint32_t)wNBytes >> 1U;
- uint32_t i;
// The GCC optimizer will combine access to 32-bit sizes if we let it. Force
// it volatile so that it won't do that.
__IO const uint16_t *pdwVal;
uint32_t temp;
- pdwVal = &pma[PMA_STRIDE*(src>>1)];
- uint8_t *dstVal = (uint8_t*)dst;
+ pdwVal = &pma[FSDEV_PMA_STRIDE * (src >> 1)];
+ uint8_t *dstVal = (uint8_t *)dst;
- for (i = n; i != 0U; i--)
- {
+ while (n--) {
temp = *pdwVal;
- pdwVal += PMA_STRIDE;
+ pdwVal += FSDEV_PMA_STRIDE;
*dstVal++ = ((temp >> 0) & 0xFF);
*dstVal++ = ((temp >> 8) & 0xFF);
}
- if (wNBytes % 2)
- {
+ if (wNBytes & 0x01) {
temp = *pdwVal;
- pdwVal += PMA_STRIDE;
+ pdwVal += FSDEV_PMA_STRIDE;
*dstVal++ = ((temp >> 0) & 0xFF);
}
return true;
}
+#endif
-#if 0 // TODO support dcd_edpt_xfer_fifo API
/**
- * @brief Copy a buffer from user packet memory area (PMA) to FIFO.
- * Uses byte-access of system memory and 16-bit access of packet memory
- * @param wNBytes no. of bytes to be copied.
- * @retval None
- */
-
-// THIS FUNCTION IS UNTESTED
-
-static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes)
+ * @brief Copy a buffer from user packet memory area (PMA) to FIFO.
+ * Uses byte-access of system memory and 16-bit access of packet memory
+ * @param wNBytes no. of bytes to be copied.
+ * @retval None
+ */
+static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes)
{
// Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
// Check for first linear part
- void * dst;
- uint16_t len = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes); // THIS FUNCTION CHANGED!!!!
- TU_VERIFY(len && dcd_read_packet_memory(dst, src, len));
- tu_fifo_advance_write_pointer(ff, len);
+ tu_fifo_buffer_info_t info;
+ tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO
- // Check for wrapped part
- if (len < wNBytes)
- {
- // Get remaining wrapped length
- uint16_t len2 = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes - len);
- TU_VERIFY(len2);
+ uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin);
+ uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap);
- // Update source pointer
- src += len;
+ // We want to read from PMA and write it into the FIFO, if LIN part is ODD and has WRAPPED part,
+ // last lin byte will be combined with wrapped part
+ // To ensure PMA is always access aligned (src aligned to 16 or 32 bit)
+#ifdef FSDEV_BUS_32BIT
+ if ((cnt_lin & 0x03) && cnt_wrap) {
+ // Copy first linear part
+ dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x03);
+ src += cnt_lin & ~0x03;
- // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split
- if (len % 2) // If len is uneven there is a byte left to copy
- {
- uint32_t temp = pma[PMA_STRIDE*(src>>1)];
- *((uint8_t *)dst++) = ((temp >> 8) & 0xFF);
- src++;
- len2--;
+ // Copy last linear bytes & first wrapped bytes
+ uint8_t tmp[4];
+ dcd_read_packet_memory(tmp, src, 4);
+ src += 4;
+
+ uint32_t i;
+ for (i = 0; i < (cnt_lin & 0x03); i++) {
+ ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i] = tmp[i];
+ }
+ uint32_t wCnt = cnt_wrap;
+ for (; i < 4 && wCnt > 0; i++, wCnt--) {
+ *(uint8_t *)info.ptr_wrap = tmp[i];
+ info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1;
}
- TU_VERIFY(dcd_read_packet_memory(dst, src, len2));
- tu_fifo_advance_write_pointer(ff, len2);
+ // Copy rest of wrapped byte
+ if (wCnt)
+ dcd_read_packet_memory(info.ptr_wrap, src, wCnt);
}
+#else
+ if ((cnt_lin & 0x01) && cnt_wrap) {
+ // Copy first linear part
+ dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x01);
+ src += cnt_lin & ~0x01;
- return true;
-}
+ // Copy last linear byte & first wrapped byte
+ uint8_t tmp[2];
+ dcd_read_packet_memory(tmp, src, 2);
+ src += 2;
-#endif
+ ((uint8_t *)info.ptr_lin)[cnt_lin - 1] = tmp[0];
+ ((uint8_t *)info.ptr_wrap)[0] = tmp[1];
+ // Copy rest of wrapped byte
+ dcd_read_packet_memory(((uint8_t *)info.ptr_wrap) + 1, src, cnt_wrap - 1);
+ }
#endif
+ else {
+ // Copy linear part
+ dcd_read_packet_memory(info.ptr_lin, src, cnt_lin);
+ src += cnt_lin;
+
+ if (info.len_wrap) {
+ // Copy wrapped byte
+ dcd_read_packet_memory(info.ptr_wrap, src, cnt_wrap);
+ }
+ }
+ tu_fifo_advance_write_pointer(ff, cnt_lin + cnt_wrap);
+
+ return true;
+}
+
+#endif
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h
new file mode 100644
index 000000000..7992f34a1
--- /dev/null
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h
@@ -0,0 +1,551 @@
+/*
+ * Copyright(c) 2016 STMicroelectronics
+ * Copyright(c) N Conrad
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+// This file contains source copied from ST's HAL, and thus should have their copyright statement.
+
+// FSDEV_PMA_SIZE is PMA buffer size in bytes.
+// On 512-byte devices, access with a stride of two words (use every other 16-bit address)
+// On 1024-byte devices, access with a stride of one word (use every 16-bit address)
+
+#ifndef PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_
+#define PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_
+
+#if CFG_TUSB_MCU == OPT_MCU_STM32F0
+ #include "stm32f0xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+ // F0x2 models are crystal-less
+ // All have internal D+ pull-up
+ // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support
+ // PMA dedicated to USB (no sharing with CAN)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
+ #include "stm32f1xx.h"
+ #define FSDEV_PMA_SIZE (512u)
+ // NO internal Pull-ups
+ // *B, and *C: 2 x 16 bits/word
+
+ // F1 names this differently from the rest
+ #define USB_CNTR_LPMODE USB_CNTR_LP_MODE
+
+#elif defined(STM32F302xB) || defined(STM32F302xC) || \
+ defined(STM32F303xB) || defined(STM32F303xC) || \
+ defined(STM32F373xC)
+ #include "stm32f3xx.h"
+ #define FSDEV_PMA_SIZE (512u)
+ // NO internal Pull-ups
+ // *B, and *C: 1 x 16 bits/word
+ // PMA dedicated to USB (no sharing with CAN)
+
+#elif defined(STM32F302x6) || defined(STM32F302x8) || \
+ defined(STM32F302xD) || defined(STM32F302xE) || \
+ defined(STM32F303xD) || defined(STM32F303xE)
+ #include "stm32f3xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+ // NO internal Pull-ups
+ // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support
+ // When CAN clock is enabled, USB can use first 768 bytes ONLY.
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L0
+ #include "stm32l0xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
+ #include "stm32l1xx.h"
+ #define FSDEV_PMA_SIZE (512u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
+ #include "stm32g4xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
+ #include "stm32g0xx.h"
+ #define FSDEV_BUS_32BIT
+ #define FSDEV_PMA_SIZE (2048u)
+ #undef USB_PMAADDR
+ #define USB_PMAADDR USB_DRD_PMAADDR
+ #define USB_TypeDef USB_DRD_TypeDef
+ #define EP0R CHEP0R
+ #define USB_EP_CTR_RX USB_EP_VTRX
+ #define USB_EP_CTR_TX USB_EP_VTTX
+ #define USB_EP_T_FIELD USB_CHEP_UTYPE
+ #define USB_EPREG_MASK USB_CHEP_REG_MASK
+ #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
+ #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
+ #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
+ #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
+ #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
+ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
+ #define USB_EPRX_STAT USB_CH_RX_VALID
+ #define USB_EPKIND_MASK USB_EP_KIND_MASK
+ #define USB USB_DRD_FS
+ #define USB_CNTR_FRES USB_CNTR_USBRST
+ #define USB_CNTR_RESUME USB_CNTR_L2RES
+ #define USB_ISTR_EP_ID USB_ISTR_IDN
+ #define USB_EPADDR_FIELD USB_CHEP_ADDR
+ #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
+ #include "stm32h5xx.h"
+ #define FSDEV_BUS_32BIT
+
+ #if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE)
+ #define USB_DRD_BASE USB_DRD_FS_BASE
+ #endif
+
+ #define FSDEV_PMA_SIZE (2048u)
+ #undef USB_PMAADDR
+ #define USB_PMAADDR USB_DRD_PMAADDR
+ #define USB_TypeDef USB_DRD_TypeDef
+ #define EP0R CHEP0R
+ #define USB_EP_CTR_RX USB_EP_VTRX
+ #define USB_EP_CTR_TX USB_EP_VTTX
+ #define USB_EP_T_FIELD USB_CHEP_UTYPE
+ #define USB_EPREG_MASK USB_CHEP_REG_MASK
+ #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
+ #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
+ #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
+ #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
+ #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
+ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
+ #define USB_EPRX_STAT USB_CH_RX_VALID
+ #define USB_EPKIND_MASK USB_EP_KIND_MASK
+ #define USB USB_DRD_FS
+ #define USB_CNTR_FRES USB_CNTR_USBRST
+ #define USB_CNTR_RESUME USB_CNTR_L2RES
+ #define USB_ISTR_EP_ID USB_ISTR_IDN
+ #define USB_EPADDR_FIELD USB_CHEP_ADDR
+ #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ #include "stm32wbxx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+ /* ST provided header has incorrect value */
+ #undef USB_PMAADDR
+ #define USB_PMAADDR USB1_PMAADDR
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
+ #include "stm32l4xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
+ #include "stm32l5xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+
+ #ifndef USB_PMAADDR
+ #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
+ #endif
+
+#else
+ #error You are using an untested or unimplemented STM32 variant. Please update the driver.
+ // This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4
+#endif
+
+// For purposes of accessing the packet
+#if ((FSDEV_PMA_SIZE) == 512u)
+ #define FSDEV_PMA_STRIDE (2u)
+#elif ((FSDEV_PMA_SIZE) == 1024u)
+ #define FSDEV_PMA_STRIDE (1u)
+#endif
+
+// The fsdev_bus_t type can be used for both register and PMA access necessities
+// For type-safety create a new macro for the volatile address of PMAADDR
+// The compiler should warn us if we cast it to a non-volatile type?
+#ifdef FSDEV_BUS_32BIT
+typedef uint32_t fsdev_bus_t;
+static __IO uint32_t * const pma32 = (__IO uint32_t*)USB_PMAADDR;
+
+#else
+typedef uint16_t fsdev_bus_t;
+// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden)
+static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR;
+
+TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) {
+ size_t total_word_offset = (((USBx)->BTABLE)>>1) + x;
+ total_word_offset *= FSDEV_PMA_STRIDE;
+ return &(pma[total_word_offset]);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
+ return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
+ return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u);
+}
+#endif
+
+/* Aligned buffer size according to hardware */
+TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) {
+ /* The STM32 full speed USB peripheral supports only a limited set of
+ * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */
+ uint16_t blocksize = (size > 62) ? 32 : 2;
+
+ // Round up while dividing requested size by blocksize
+ uint16_t numblocks = (size + blocksize - 1) / blocksize ;
+
+ return numblocks * blocksize;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) {
+#ifdef FSDEV_BUS_32BIT
+ (void) USBx;
+ __O uint32_t *reg = (__O uint32_t *)(USB_DRD_BASE + bEpIdx*4);
+ *reg = wRegValue;
+#else
+ __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpIdx*2u);
+ *reg = (uint16_t)wRegValue;
+#endif
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) {
+#ifdef FSDEV_BUS_32BIT
+ (void) USBx;
+ __I uint32_t *reg = (__I uint32_t *)(USB_DRD_BASE + bEpIdx*4);
+#else
+ __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpIdx*2u);
+#endif
+ return *reg;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ regVal &= (uint32_t)USB_EP_T_MASK;
+ regVal |= wType;
+ regVal |= USB_EP_CTR_RX | USB_EP_CTR_TX; // These clear on write0, so must set high
+ pcd_set_endpoint(USBx, bEpIdx, regVal);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ regVal &= USB_EP_T_FIELD;
+ return regVal;
+}
+
+/**
+ * @brief Clears bit CTR_RX / CTR_TX in the endpoint register.
+ * @param USBx USB peripheral instance register address.
+ * @param bEpIdx Endpoint Number.
+ * @retval None
+ */
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ regVal &= USB_EPREG_MASK;
+ regVal &= ~USB_EP_CTR_RX;
+ regVal |= USB_EP_CTR_TX; // preserve CTR_TX (clears on writing 0)
+ pcd_set_endpoint(USBx, bEpIdx, regVal);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ regVal &= USB_EPREG_MASK;
+ regVal &= ~USB_EP_CTR_TX;
+ regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0)
+ pcd_set_endpoint(USBx, bEpIdx,regVal);
+}
+
+/**
+ * @brief gets counter of the tx buffer.
+ * @param USBx USB peripheral instance register address.
+ * @param bEpIdx Endpoint Number.
+ * @retval Counter value
+ */
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) {
+#ifdef FSDEV_BUS_32BIT
+ (void) USBx;
+ return (pma32[2*bEpIdx] & 0x03FF0000) >> 16;
+#else
+ __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpIdx);
+ return *regPtr & 0x3ffU;
+#endif
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) {
+#ifdef FSDEV_BUS_32BIT
+ (void) USBx;
+ return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16;
+#else
+ __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx);
+ return *regPtr & 0x3ffU;
+#endif
+}
+
+#define pcd_get_ep_dbuf0_cnt pcd_get_ep_tx_cnt
+#define pcd_get_ep_dbuf1_cnt pcd_get_ep_rx_cnt
+
+/**
+ * @brief Sets address in an endpoint register.
+ * @param USBx USB peripheral instance register address.
+ * @param bEpIdx Endpoint Number.
+ * @param bAddr Address.
+ * @retval None
+ */
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ regVal &= USB_EPREG_MASK;
+ regVal |= bAddr;
+ regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
+ pcd_set_endpoint(USBx, bEpIdx,regVal);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx) {
+#ifdef FSDEV_BUS_32BIT
+ (void) USBx;
+ return pma32[2*bEpIdx] & 0x0000FFFFu ;
+#else
+ return *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u);
+#endif
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx) {
+#ifdef FSDEV_BUS_32BIT
+ (void) USBx;
+ return pma32[2*bEpIdx + 1] & 0x0000FFFFu;
+#else
+ return *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u);
+#endif
+}
+
+#define pcd_get_ep_dbuf0_address pcd_get_ep_tx_address
+#define pcd_get_ep_dbuf1_address pcd_get_ep_rx_address
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) {
+#ifdef FSDEV_BUS_32BIT
+ (void) USBx;
+ pma32[2*bEpIdx] = (pma32[2*bEpIdx] & 0xFFFF0000u) | (addr & 0x0000FFFCu);
+#else
+ *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u) = addr;
+#endif
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) {
+#ifdef FSDEV_BUS_32BIT
+ (void) USBx;
+ pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & 0xFFFF0000u) | (addr & 0x0000FFFCu);
+#else
+ *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u) = addr;
+#endif
+}
+
+#define pcd_set_ep_dbuf0_address pcd_set_ep_tx_address
+#define pcd_set_ep_dbuf1_address pcd_set_ep_rx_address
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
+#ifdef FSDEV_BUS_32BIT
+ (void) USBx;
+ pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16);
+#else
+ __IO uint16_t * reg = pcd_ep_tx_cnt_ptr(USBx, bEpIdx);
+ *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU);
+#endif
+}
+
+#define pcd_set_ep_tx_dbuf0_cnt pcd_set_ep_tx_cnt
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_dbuf1_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
+#ifdef FSDEV_BUS_32BIT
+ (void) USBx;
+ pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16);
+#else
+ __IO uint16_t * reg = pcd_ep_rx_cnt_ptr(USBx, bEpIdx);
+ *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU);
+#endif
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx,
+ uint32_t blocksize, uint32_t numblocks) {
+ /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */
+#ifdef FSDEV_BUS_32BIT
+ (void) USBx;
+ pma32[rxtx_idx] = (pma32[rxtx_idx] & 0x0000FFFFu) | (blocksize << 31) | ((numblocks - blocksize) << 26);
+#else
+ __IO uint16_t *pdwReg = pcd_btable_word_ptr(USBx, rxtx_idx*2u + 1u);
+ *pdwReg = (blocksize << 15) | ((numblocks - blocksize) << 10);
+#endif
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t wCount) {
+ wCount = pcd_aligned_buffer_size(wCount);
+
+ /* We assume that the buffer size is already aligned to hardware requirements. */
+ uint16_t blocksize = (wCount > 62) ? 1 : 0;
+ uint16_t numblocks = wCount / (blocksize ? 32 : 2);
+
+ /* There should be no remainder in the above calculation */
+ TU_ASSERT((wCount - (numblocks * (blocksize ? 32 : 2))) == 0, /**/);
+
+ /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */
+ pcd_set_ep_blsize_num_blocks(USBx, rxtx_idx, blocksize, numblocks);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_dbuf0_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
+ pcd_set_ep_bufsize(USBx, 2*bEpIdx, wCount);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
+ pcd_set_ep_bufsize(USBx, 2*bEpIdx + 1, wCount);
+}
+
+#define pcd_set_ep_rx_dbuf1_cnt pcd_set_ep_rx_cnt
+
+/**
+ * @brief sets the status for tx transfer (bits STAT_TX[1:0]).
+ * @param USBx USB peripheral instance register address.
+ * @param bEpIdx Endpoint Number.
+ * @param wState new state
+ * @retval None
+ */
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ regVal &= USB_EPTX_DTOGMASK;
+
+ /* toggle first bit ? */
+ if((USB_EPTX_DTOG1 & (wState))!= 0U)
+ {
+ regVal ^= USB_EPTX_DTOG1;
+ }
+ /* toggle second bit ? */
+ if((USB_EPTX_DTOG2 & ((uint32_t)(wState)))!= 0U)
+ {
+ regVal ^= USB_EPTX_DTOG2;
+ }
+
+ regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
+ pcd_set_endpoint(USBx, bEpIdx, regVal);
+}
+
+/**
+ * @brief sets the status for rx transfer (bits STAT_TX[1:0])
+ * @param USBx USB peripheral instance register address.
+ * @param bEpIdx Endpoint Number.
+ * @param wState new state
+ * @retval None
+ */
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ regVal &= USB_EPRX_DTOGMASK;
+
+ /* toggle first bit ? */
+ if((USB_EPRX_DTOG1 & wState)!= 0U) {
+ regVal ^= USB_EPRX_DTOG1;
+ }
+ /* toggle second bit ? */
+ if((USB_EPRX_DTOG2 & wState)!= 0U) {
+ regVal ^= USB_EPRX_DTOG2;
+ }
+
+ regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
+ pcd_set_endpoint(USBx, bEpIdx, regVal);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ return (regVal & USB_EPRX_STAT) >> (12u);
+}
+
+
+/**
+ * @brief Toggles DTOG_RX / DTOG_TX bit in the endpoint register.
+ * @param USBx USB peripheral instance register address.
+ * @param bEpIdx Endpoint Number.
+ * @retval None
+ */
+TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ regVal &= USB_EPREG_MASK;
+ regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX;
+ pcd_set_endpoint(USBx, bEpIdx, regVal);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ regVal &= USB_EPREG_MASK;
+ regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX;
+ pcd_set_endpoint(USBx, bEpIdx, regVal);
+}
+
+/**
+ * @brief Clears DTOG_RX / DTOG_TX bit in the endpoint register.
+ * @param USBx USB peripheral instance register address.
+ * @param bEpIdx Endpoint Number.
+ * @retval None
+ */
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ if((regVal & USB_EP_DTOG_RX) != 0) {
+ pcd_rx_dtog(USBx,bEpIdx);
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ if((regVal & USB_EP_DTOG_TX) != 0) {
+ pcd_tx_dtog(USBx,bEpIdx);
+ }
+}
+
+/**
+ * @brief set & clear EP_KIND bit.
+ * @param USBx USB peripheral instance register address.
+ * @param bEpIdx Endpoint Number.
+ * @retval None
+ */
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ regVal |= USB_EP_KIND;
+ regVal &= USB_EPREG_MASK;
+ regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
+ pcd_set_endpoint(USBx, bEpIdx, regVal);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) {
+ uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
+ regVal &= USB_EPKIND_MASK;
+ regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
+ pcd_set_endpoint(USBx, bEpIdx, regVal);
+}
+
+// This checks if the device has "LPM"
+#if defined(USB_ISTR_L1REQ)
+#define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ)
+#else
+#define USB_ISTR_L1REQ_FORCED ((uint16_t)0x0000U)
+#endif
+
+#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \
+ USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED )
+
+// Number of endpoints in hardware
+// TODO should use TUP_DCD_ENDPOINT_MAX
+#define STFSDEV_EP_COUNT (8u)
+
+#endif /* PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ */
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
deleted file mode 100644
index d26c700d2..000000000
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
+++ /dev/null
@@ -1,407 +0,0 @@
-/**
- ******************************************************************************
- * @file dcd_stm32f0_pvt_st.h
- * @brief DCD utilities from ST code
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
- * <h2><center>&copy; parts COPYRIGHT(c) N Conrad</center></h2>
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of STMicroelectronics nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- **********/
-
-// This file contains source copied from ST's HAL, and thus should have their copyright statement.
-
-// PMA_LENGTH is PMA buffer size in bytes.
-// On 512-byte devices, access with a stride of two words (use every other 16-bit address)
-// On 1024-byte devices, access with a stride of one word (use every 16-bit address)
-
-#ifndef PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_
-#define PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_
-
-#if defined(STM32F042x6) || \
- defined(STM32F070x6) || defined(STM32F070xB) || \
- defined(STM32F072xB) || \
- defined(STM32F078xx)
- #include "stm32f0xx.h"
- #define PMA_LENGTH (1024u)
- // F0x2 models are crystal-less
- // All have internal D+ pull-up
- // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support
- // PMA dedicated to USB (no sharing with CAN)
-
-#elif defined(STM32F1_FSDEV)
- #include "stm32f1xx.h"
- #define PMA_LENGTH (512u)
- // NO internal Pull-ups
- // *B, and *C: 2 x 16 bits/word
-
- // F1 names this differently from the rest
- #define USB_CNTR_LPMODE USB_CNTR_LP_MODE
-
-#elif defined(STM32F302xB) || defined(STM32F302xC) || \
- defined(STM32F303xB) || defined(STM32F303xC) || \
- defined(STM32F373xC)
- #include "stm32f3xx.h"
- #define PMA_LENGTH (512u)
- // NO internal Pull-ups
- // *B, and *C: 1 x 16 bits/word
- // PMA dedicated to USB (no sharing with CAN)
-
-#elif defined(STM32F302x6) || defined(STM32F302x8) || \
- defined(STM32F302xD) || defined(STM32F302xE) || \
- defined(STM32F303xD) || defined(STM32F303xE)
- #include "stm32f3xx.h"
- #define PMA_LENGTH (1024u)
- // NO internal Pull-ups
- // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support
- // When CAN clock is enabled, USB can use first 768 bytes ONLY.
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L0
- #include "stm32l0xx.h"
- #define PMA_LENGTH (1024u)
-
-#else
- #error You are using an untested or unimplemented STM32 variant. Please update the driver.
- // This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4
-#endif
-
-// For purposes of accessing the packet
-#if ((PMA_LENGTH) == 512u)
- #define PMA_STRIDE (2u)
-#elif ((PMA_LENGTH) == 1024u)
- #define PMA_STRIDE (1u)
-#endif
-
-// And for type-safety create a new macro for the volatile address of PMAADDR
-// The compiler should warn us if we cast it to a non-volatile type?
-// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden)
-static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR;
-
-// prototypes
-static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum);
-static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum);
-static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wRegValue);
-
-
-/* SetENDPOINT */
-static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wRegValue)
-{
- __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpNum*2u);
- *reg = (uint16_t)wRegValue;
-}
-
-/* GetENDPOINT */
-static inline uint16_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpNum) {
- __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpNum*2u);
- return *reg;
-}
-
-static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wType)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal &= (uint32_t)USB_EP_T_MASK;
- regVal |= wType;
- regVal |= USB_EP_CTR_RX | USB_EP_CTR_TX; // These clear on write0, so must set high
- pcd_set_endpoint(USBx, bEpNum, regVal);
-}
-
-static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal &= USB_EP_T_FIELD;
- return regVal;
-}
-/**
- * @brief Clears bit CTR_RX / CTR_TX in the endpoint register.
- * @param USBx USB peripheral instance register address.
- * @param bEpNum Endpoint Number.
- * @retval None
- */
-static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal &= USB_EPREG_MASK;
- regVal &= ~USB_EP_CTR_RX;
- regVal |= USB_EP_CTR_TX; // preserve CTR_TX (clears on writing 0)
- pcd_set_endpoint(USBx, bEpNum, regVal);
-}
-static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal &= USB_EPREG_MASK;
- regVal &= ~USB_EP_CTR_TX;
- regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0)
- pcd_set_endpoint(USBx, bEpNum,regVal);
-}
-/**
- * @brief gets counter of the tx buffer.
- * @param USBx USB peripheral instance register address.
- * @param bEpNum Endpoint Number.
- * @retval Counter value
- */
-static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpNum);
- return *regPtr & 0x3ffU;
-}
-
-static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpNum);
- return *regPtr & 0x3ffU;
-}
-
-/**
- * @brief Sets counter of rx buffer with no. of blocks.
- * @param dwReg Register
- * @param wCount Counter.
- * @param wNBlocks no. of Blocks.
- * @retval None
- */
-
-static inline void pcd_set_ep_cnt_rx_reg(__O uint16_t * pdwReg, size_t wCount) {
- uint32_t wNBlocks;
- if(wCount > 62u)
- {
- wNBlocks = wCount >> 5u;
- if((wCount & 0x1fU) == 0u)
- {
- wNBlocks--;
- }
- wNBlocks = wNBlocks << 10u;
- wNBlocks |= 0x8000u; // Mark block size as 32byte
- *pdwReg = (uint16_t)wNBlocks;
- }
- else
- {
- wNBlocks = wCount >> 1u;
- if((wCount & 0x1U) != 0u)
- {
- wNBlocks++;
- }
- *pdwReg = (uint16_t)((wNBlocks) << 10u);
- }
-}
-
-
-/**
- * @brief Sets address in an endpoint register.
- * @param USBx USB peripheral instance register address.
- * @param bEpNum Endpoint Number.
- * @param bAddr Address.
- * @retval None
- */
-static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t bAddr)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal &= USB_EPREG_MASK;
- regVal |= bAddr;
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
- pcd_set_endpoint(USBx, bEpNum,regVal);
-}
-
-static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x)
-{
- size_t total_word_offset = (((USBx)->BTABLE)>>1) + x;
- total_word_offset *= PMA_STRIDE;
- return &(pma[total_word_offset]);
-}
-
-// Pointers to the PMA table entries (using the ARM address space)
-static inline __IO uint16_t* pcd_ep_tx_address_ptr(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 0u);
-}
-static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 1u);
-}
-
-static inline __IO uint16_t* pcd_ep_rx_address_ptr(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 2u);
-}
-
-static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 3u);
-}
-
-static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wCount)
-{
- *pcd_ep_tx_cnt_ptr(USBx, bEpNum) = (uint16_t)wCount;
-}
-
-static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wCount)
-{
- __IO uint16_t *pdwReg = pcd_ep_rx_cnt_ptr((USBx),(bEpNum));
- pcd_set_ep_cnt_rx_reg(pdwReg, wCount);
-}
-
-/**
- * @brief sets the status for tx transfer (bits STAT_TX[1:0]).
- * @param USBx USB peripheral instance register address.
- * @param bEpNum Endpoint Number.
- * @param wState new state
- * @retval None
- */
-static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wState)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal &= USB_EPTX_DTOGMASK;
-
- /* toggle first bit ? */
- if((USB_EPTX_DTOG1 & (wState))!= 0U)
- {
- regVal ^= USB_EPTX_DTOG1;
- }
- /* toggle second bit ? */
- if((USB_EPTX_DTOG2 & ((uint32_t)(wState)))!= 0U)
- {
- regVal ^= USB_EPTX_DTOG2;
- }
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
- pcd_set_endpoint(USBx, bEpNum, regVal);
-} /* pcd_set_ep_tx_status */
-
-/**
- * @brief sets the status for rx transfer (bits STAT_TX[1:0])
- * @param USBx USB peripheral instance register address.
- * @param bEpNum Endpoint Number.
- * @param wState new state
- * @retval None
- */
-
-static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wState)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal &= USB_EPRX_DTOGMASK;
-
- /* toggle first bit ? */
- if((USB_EPRX_DTOG1 & wState)!= 0U)
- {
- regVal ^= USB_EPRX_DTOG1;
- }
- /* toggle second bit ? */
- if((USB_EPRX_DTOG2 & wState)!= 0U)
- {
- regVal ^= USB_EPRX_DTOG2;
- }
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
- pcd_set_endpoint(USBx, bEpNum, regVal);
-} /* pcd_set_ep_rx_status */
-
-static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- return (regVal & USB_EPRX_STAT) >> (12u);
-} /* pcd_get_ep_rx_status */
-
-
-/**
- * @brief Toggles DTOG_RX / DTOG_TX bit in the endpoint register.
- * @param USBx USB peripheral instance register address.
- * @param bEpNum Endpoint Number.
- * @retval None
- */
-static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal &= USB_EPREG_MASK;
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX;
- pcd_set_endpoint(USBx, bEpNum, regVal);
-}
-
-static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal &= USB_EPREG_MASK;
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX;
- pcd_set_endpoint(USBx, bEpNum, regVal);
-}
-
-/**
- * @brief Clears DTOG_RX / DTOG_TX bit in the endpoint register.
- * @param USBx USB peripheral instance register address.
- * @param bEpNum Endpoint Number.
- * @retval None
- */
-
-static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- if((regVal & USB_EP_DTOG_RX) != 0)
- {
- pcd_rx_dtog(USBx,bEpNum);
- }
-}
-
-static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- if((regVal & USB_EP_DTOG_TX) != 0)
- {
- pcd_tx_dtog(USBx,bEpNum);
- }
-}
-
-/**
- * @brief set & clear EP_KIND bit.
- * @param USBx USB peripheral instance register address.
- * @param bEpNum Endpoint Number.
- * @retval None
- */
-
-static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal |= USB_EP_KIND;
- regVal &= USB_EPREG_MASK;
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
- pcd_set_endpoint(USBx, bEpNum, regVal);
-}
-static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum)
-{
- uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal &= USB_EPKIND_MASK;
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
- pcd_set_endpoint(USBx, bEpNum, regVal);
-}
-
-// This checks if the device has "LPM"
-#if defined(USB_ISTR_L1REQ)
-#define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ)
-#else
-#define USB_ISTR_L1REQ_FORCED ((uint16_t)0x0000U)
-#endif
-
-#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \
- USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED )
-
-// Number of endpoints in hardware
-#define STFSDEV_EP_COUNT (8u)
-
-#endif /* PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ */
diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c
deleted file mode 100644
index 8a196e061..000000000
--- a/src/portable/st/synopsys/dcd_synopsys.c
+++ /dev/null
@@ -1,1153 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2018 Scott Shawcroft, 2019 William D. Jones for Adafruit Industries
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
- * Copyright (c) 2020 Jan Duempelmann
- * Copyright (c) 2020 Reinhard Panhuber
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-#include "tusb_option.h"
-
-// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
-// We disable SOF for now until needed later on
-#define USE_SOF 0
-
-#if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \
- defined (STM32F107xB) || defined (STM32F107xC)
-#define STM32F1_SYNOPSYS
-#endif
-
-#if defined (STM32L475xx) || defined (STM32L476xx) || \
- defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \
- defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \
- defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx)
-#define STM32L4_SYNOPSYS
-#endif
-
-#if TUSB_OPT_DEVICE_ENABLED && \
- ( (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_SYNOPSYS)) || \
- CFG_TUSB_MCU == OPT_MCU_STM32F2 || \
- CFG_TUSB_MCU == OPT_MCU_STM32F4 || \
- CFG_TUSB_MCU == OPT_MCU_STM32F7 || \
- CFG_TUSB_MCU == OPT_MCU_STM32H7 || \
- (CFG_TUSB_MCU == OPT_MCU_STM32L4 && defined(STM32L4_SYNOPSYS)) \
- )
-
-// EP_MAX : Max number of bi-directional endpoints including EP0
-// EP_FIFO_SIZE : Size of dedicated USB SRAM
-#if CFG_TUSB_MCU == OPT_MCU_STM32F1
-#include "stm32f1xx.h"
-#define EP_MAX_FS 4
-#define EP_FIFO_SIZE_FS 1280
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F2
-#include "stm32f2xx.h"
-#define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS
-#define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F4
-#include "stm32f4xx.h"
-#define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS
-#define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE
-#define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS
-#define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32H7
-#include "stm32h7xx.h"
-#define EP_MAX_FS 9
-#define EP_FIFO_SIZE_FS 4096
-#define EP_MAX_HS 9
-#define EP_FIFO_SIZE_HS 4096
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F7
-#include "stm32f7xx.h"
-#define EP_MAX_FS 6
-#define EP_FIFO_SIZE_FS 1280
-#define EP_MAX_HS 9
-#define EP_FIFO_SIZE_HS 4096
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
-#include "stm32l4xx.h"
-#define EP_MAX_FS 6
-#define EP_FIFO_SIZE_FS 1280
-
-#else
-#error "Unsupported MCUs"
-#endif
-
-#include "device/dcd.h"
-
-//--------------------------------------------------------------------+
-// MACRO TYPEDEF CONSTANT ENUM
-//--------------------------------------------------------------------+
-
-// On STM32 we associate Port0 to OTG_FS, and Port1 to OTG_HS
-#if TUD_OPT_RHPORT == 0
-#define EP_MAX EP_MAX_FS
-#define EP_FIFO_SIZE EP_FIFO_SIZE_FS
-#define RHPORT_REGS_BASE USB_OTG_FS_PERIPH_BASE
-#define RHPORT_IRQn OTG_FS_IRQn
-
-#else
-#define EP_MAX EP_MAX_HS
-#define EP_FIFO_SIZE EP_FIFO_SIZE_HS
-#define RHPORT_REGS_BASE USB_OTG_HS_PERIPH_BASE
-#define RHPORT_IRQn OTG_HS_IRQn
-
-#endif
-
-#define GLOBAL_BASE(_port) ((USB_OTG_GlobalTypeDef*) RHPORT_REGS_BASE)
-#define DEVICE_BASE(_port) (USB_OTG_DeviceTypeDef *) (RHPORT_REGS_BASE + USB_OTG_DEVICE_BASE)
-#define OUT_EP_BASE(_port) (USB_OTG_OUTEndpointTypeDef *) (RHPORT_REGS_BASE + USB_OTG_OUT_ENDPOINT_BASE)
-#define IN_EP_BASE(_port) (USB_OTG_INEndpointTypeDef *) (RHPORT_REGS_BASE + USB_OTG_IN_ENDPOINT_BASE)
-#define FIFO_BASE(_port, _x) ((volatile uint32_t *) (RHPORT_REGS_BASE + USB_OTG_FIFO_BASE + (_x) * USB_OTG_FIFO_SIZE))
-
-enum
-{
- DCD_HIGH_SPEED = 0, // Highspeed mode
- DCD_FULL_SPEED_USE_HS = 1, // Full speed in Highspeed port (probably with internal PHY)
- DCD_FULL_SPEED = 3, // Full speed with internal PHY
-};
-
-static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2];
-
-typedef struct {
- uint8_t * buffer;
- tu_fifo_t * ff;
- uint16_t total_len;
- uint16_t max_size;
- uint8_t interval;
-} xfer_ctl_t;
-
-typedef volatile uint32_t * usb_fifo_t;
-
-xfer_ctl_t xfer_status[EP_MAX][2];
-#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
-
-// EP0 transfers are limited to 1 packet - larger sizes has to be split
-static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type
-
-// TX FIFO RAM allocation so far in words - RX FIFO size is readily available from usb_otg->GRXFSIZ
-static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs)
-static bool _out_ep_closed; // Flag to check if RX FIFO size needs an update (reduce its size)
-
-// Calculate the RX FIFO size according to recommendations from reference manual
-static inline uint16_t calc_rx_ff_size(uint16_t ep_size)
-{
- return 15 + 2*(ep_size/4) + 2*EP_MAX;
-}
-
-static void update_grxfsiz(uint8_t rhport)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
-
- // Determine largest EP size for RX FIFO
- uint16_t max_epsize = 0;
- for (uint8_t epnum = 0; epnum < EP_MAX; epnum++)
- {
- max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size);
- }
-
- // Update size of RX FIFO
- usb_otg->GRXFSIZ = calc_rx_ff_size(max_epsize);
-}
-
-// Setup the control endpoint 0.
-static void bus_reset(uint8_t rhport)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- tu_memclr(xfer_status, sizeof(xfer_status));
- _out_ep_closed = false;
-
- for(uint8_t n = 0; n < EP_MAX; n++) {
- out_ep[n].DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
- }
-
- dev->DAINTMSK |= (1 << USB_OTG_DAINTMSK_OEPM_Pos) | (1 << USB_OTG_DAINTMSK_IEPM_Pos);
- dev->DOEPMSK |= USB_OTG_DOEPMSK_STUPM | USB_OTG_DOEPMSK_XFRCM;
- dev->DIEPMSK |= USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM;
-
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // The FIFO is split up in a lower part where the RX FIFO is located and an upper part where the TX FIFOs start.
- // We do this to allow the RX FIFO to grow dynamically which is possible since the free space is located
- // between the RX and TX FIFOs. This is required by ISO OUT EPs which need a bigger FIFO than the standard
- // configuration done below.
- //
- // Dynamically FIFO sizes are of interest only for ISO EPs since all others are usually not opened and closed.
- // All EPs other than ISO are opened as soon as the driver starts up i.e. when the host sends a
- // configure interface command. Hence, all IN EPs other the ISO will be located at the top. IN ISO EPs are usually
- // opened when the host sends an additional command: setInterface. At this point in time
- // the ISO EP will be located next to the free space and can change its size. In case more IN EPs change its size
- // an additional memory
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO 0 |
- // --------------- (320 or 1024) - 16
- // | IN FIFO 1 |
- // --------------- (320 or 1024) - 16 - x
- // | . . . . |
- // --------------- (320 or 1024) - 16 - x - y - ... - z
- // | IN FIFO MAX |
- // ---------------
- // | FREE |
- // --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
- // --------------- 0
- //
- // According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits):
- // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN
- //
- // - All EP OUT shared a unique OUT FIFO which uses
- // - 13 for setup packets + control words (up to 3 setup packets).
- // - 1 for global NAK (not required/used here).
- // - Largest-EPsize / 4 + 1. ( FS: 64 bytes, HS: 512 bytes). Recommended is "2 x (Largest-EPsize/4) + 1"
- // - 2 for each used OUT endpoint
- //
- // Therefore GRXFSIZ = 13 + 1 + 1 + 2 x (Largest-EPsize/4) + 2 x EPOUTnum
- // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x EP_MAX = 47 + 2 x EP_MAX
- // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x EP_MAX = 271 + 2 x EP_MAX
- //
- // NOTE: Largest-EPsize & EPOUTnum is actual used endpoints in configuration. Since DCD has no knowledge
- // of the overall picture yet. We will use the worst scenario: largest possible + EP_MAX
- //
- // For Isochronous, largest EP size can be 1023/1024 for FS/HS respectively. In addition if multiple ISO
- // are enabled at least "2 x (Largest-EPsize/4) + 1" are recommended. Maybe provide a macro for application to
- // overwrite this.
-
- usb_otg->GRXFSIZ = calc_rx_ff_size(TUD_OPT_HIGH_SPEED ? 512 : 64);
-
- _allocated_fifo_words_tx = 16;
-
- // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
- usb_otg->DIEPTXF0_HNPTXFSIZ = (16 << USB_OTG_TX0FD_Pos) | (EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
-
- // Fixed control EP0 size to 64 bytes
- in_ep[0].DIEPCTL &= ~(0x03 << USB_OTG_DIEPCTL_MPSIZ_Pos);
- xfer_status[0][TUSB_DIR_OUT].max_size = xfer_status[0][TUSB_DIR_IN].max_size = 64;
-
- out_ep[0].DOEPTSIZ |= (3 << USB_OTG_DOEPTSIZ_STUPCNT_Pos);
-
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_OEPINT | USB_OTG_GINTMSK_IEPINT;
-}
-
-// Set turn-around timeout according to link speed
-extern uint32_t SystemCoreClock;
-static void set_turnaround(USB_OTG_GlobalTypeDef * usb_otg, tusb_speed_t speed)
-{
- usb_otg->GUSBCFG &= ~USB_OTG_GUSBCFG_TRDT;
-
- if ( speed == TUSB_SPEED_HIGH )
- {
- // Use fixed 0x09 for Highspeed
- usb_otg->GUSBCFG |= (0x09 << USB_OTG_GUSBCFG_TRDT_Pos);
- }
- else
- {
- // Turnaround timeout depends on the MCU clock
- uint32_t turnaround;
-
- if ( SystemCoreClock >= 32000000U )
- turnaround = 0x6U;
- else if ( SystemCoreClock >= 27500000U )
- turnaround = 0x7U;
- else if ( SystemCoreClock >= 24000000U )
- turnaround = 0x8U;
- else if ( SystemCoreClock >= 21800000U )
- turnaround = 0x9U;
- else if ( SystemCoreClock >= 20000000U )
- turnaround = 0xAU;
- else if ( SystemCoreClock >= 18500000U )
- turnaround = 0xBU;
- else if ( SystemCoreClock >= 17200000U )
- turnaround = 0xCU;
- else if ( SystemCoreClock >= 16000000U )
- turnaround = 0xDU;
- else if ( SystemCoreClock >= 15000000U )
- turnaround = 0xEU;
- else
- turnaround = 0xFU;
-
- // Fullspeed depends on MCU clocks, but we will use 0x06 for 32+ Mhz
- usb_otg->GUSBCFG |= (turnaround << USB_OTG_GUSBCFG_TRDT_Pos);
- }
-}
-
-static tusb_speed_t get_speed(uint8_t rhport)
-{
- (void) rhport;
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- uint32_t const enum_spd = (dev->DSTS & USB_OTG_DSTS_ENUMSPD_Msk) >> USB_OTG_DSTS_ENUMSPD_Pos;
- return (enum_spd == DCD_HIGH_SPEED) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL;
-}
-
-static void set_speed(uint8_t rhport, tusb_speed_t speed)
-{
- uint32_t bitvalue;
-
- if ( rhport == 1 )
- {
- bitvalue = ((TUSB_SPEED_HIGH == speed) ? DCD_HIGH_SPEED : DCD_FULL_SPEED_USE_HS);
- }
- else
- {
- bitvalue = DCD_FULL_SPEED;
- }
-
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
-
- // Clear and set speed bits
- dev->DCFG &= ~(3 << USB_OTG_DCFG_DSPD_Pos);
- dev->DCFG |= (bitvalue << USB_OTG_DCFG_DSPD_Pos);
-}
-
-#if defined(USB_HS_PHYC)
-static bool USB_HS_PHYCInit(void)
-{
- USB_HS_PHYC_GlobalTypeDef *usb_hs_phyc = (USB_HS_PHYC_GlobalTypeDef*) USB_HS_PHYC_CONTROLLER_BASE;
-
- // Enable LDO
- usb_hs_phyc->USB_HS_PHYC_LDO |= USB_HS_PHYC_LDO_ENABLE;
-
- // Wait until LDO ready
- while ( 0 == (usb_hs_phyc->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_STATUS) ) {}
-
- uint32_t phyc_pll = 0;
-
- // TODO Try to get HSE_VALUE from registers instead of depending CFLAGS
- switch ( HSE_VALUE )
- {
- case 12000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12MHZ ; break;
- case 12500000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12_5MHZ ; break;
- case 16000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_16MHZ ; break;
- case 24000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_24MHZ ; break;
- case 25000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_25MHZ ; break;
- case 32000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_Msk ; break; // Value not defined in header
- default:
- TU_ASSERT(0);
- }
- usb_hs_phyc->USB_HS_PHYC_PLL = phyc_pll;
-
- // Control the tuning interface of the High Speed PHY
- // Use magic value (USB_HS_PHYC_TUNE_VALUE) from ST driver
- usb_hs_phyc->USB_HS_PHYC_TUNE |= 0x00000F13U;
-
- // Enable PLL internal PHY
- usb_hs_phyc->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN;
-
- // Original ST code has 2 ms delay for PLL stabilization.
- // Primitive test shows that more than 10 USB un/replug cycle showed no error with enumeration
-
- return true;
-}
-#endif
-
-static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, uint16_t total_bytes)
-{
- (void) rhport;
-
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- // EP0 is limited to one packet each xfer
- // We use multiple transaction of xfer->max_size length to get a whole transfer done
- if(epnum == 0) {
- xfer_ctl_t * const xfer = XFER_CTL_BASE(epnum, dir);
- total_bytes = tu_min16(ep0_pending[dir], xfer->max_size);
- ep0_pending[dir] -= total_bytes;
- }
-
- // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here.
- if(dir == TUSB_DIR_IN) {
- // A full IN transfer (multiple packets, possibly) triggers XFRC.
- in_ep[epnum].DIEPTSIZ = (num_packets << USB_OTG_DIEPTSIZ_PKTCNT_Pos) |
- ((total_bytes << USB_OTG_DIEPTSIZ_XFRSIZ_Pos) & USB_OTG_DIEPTSIZ_XFRSIZ_Msk);
-
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK;
- // For ISO endpoint set correct odd/even bit for next frame.
- if ((in_ep[epnum].DIEPCTL & USB_OTG_DIEPCTL_EPTYP) == USB_OTG_DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1)
- {
- // Take odd/even bit from frame counter.
- uint32_t const odd_frame_now = (dev->DSTS & (1u << USB_OTG_DSTS_FNSOF_Pos));
- in_ep[epnum].DIEPCTL |= (odd_frame_now ? USB_OTG_DIEPCTL_SD0PID_SEVNFRM_Msk : USB_OTG_DIEPCTL_SODDFRM_Msk);
- }
- // Enable fifo empty interrupt only if there are something to put in the fifo.
- if(total_bytes != 0) {
- dev->DIEPEMPMSK |= (1 << epnum);
- }
- } else {
- // A full OUT transfer (multiple packets, possibly) triggers XFRC.
- out_ep[epnum].DOEPTSIZ &= ~(USB_OTG_DOEPTSIZ_PKTCNT_Msk | USB_OTG_DOEPTSIZ_XFRSIZ);
- out_ep[epnum].DOEPTSIZ |= (num_packets << USB_OTG_DOEPTSIZ_PKTCNT_Pos) |
- ((total_bytes << USB_OTG_DOEPTSIZ_XFRSIZ_Pos) & USB_OTG_DOEPTSIZ_XFRSIZ_Msk);
-
- out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
- if ((out_ep[epnum].DOEPCTL & USB_OTG_DOEPCTL_EPTYP) == USB_OTG_DOEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1)
- {
- // Take odd/even bit from frame counter.
- uint32_t const odd_frame_now = (dev->DSTS & (1u << USB_OTG_DSTS_FNSOF_Pos));
- out_ep[epnum].DOEPCTL |= (odd_frame_now ? USB_OTG_DOEPCTL_SD0PID_SEVNFRM_Msk : USB_OTG_DOEPCTL_SODDFRM_Msk);
- }
- }
-}
-
-/*------------------------------------------------------------------*/
-/* Controller API
- *------------------------------------------------------------------*/
-void dcd_init (uint8_t rhport)
-{
- // Programming model begins in the last section of the chapter on the USB
- // peripheral in each Reference Manual.
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
-
- // No HNP/SRP (no OTG support), program timeout later.
- if ( rhport == 1 )
- {
- // On selected MCUs HS port1 can be used with external PHY via ULPI interface
-#if CFG_TUSB_RHPORT1_MODE & OPT_MODE_HIGH_SPEED
- // deactivate internal PHY
- usb_otg->GCCFG &= ~USB_OTG_GCCFG_PWRDWN;
-
- // Init The UTMI Interface
- usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_TSDPS | USB_OTG_GUSBCFG_ULPIFSLS | USB_OTG_GUSBCFG_PHYSEL);
-
- // Select default internal VBUS Indicator and Drive for ULPI
- usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_ULPIEVBUSD | USB_OTG_GUSBCFG_ULPIEVBUSI);
-#else
- usb_otg->GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL;
-#endif
-
-#if defined(USB_HS_PHYC)
- // Highspeed with embedded UTMI PHYC
-
- // Select UTMI Interface
- usb_otg->GUSBCFG &= ~USB_OTG_GUSBCFG_ULPI_UTMI_SEL;
- usb_otg->GCCFG |= USB_OTG_GCCFG_PHYHSEN;
-
- // Enables control of a High Speed USB PHY
- USB_HS_PHYCInit();
-#endif
- } else
- {
- // Enable internal PHY
- usb_otg->GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL;
- }
-
- // Reset core after selecting PHY
- // Wait AHB IDLE, reset then wait until it is cleared
- while ((usb_otg->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U) {}
- usb_otg->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
- while ((usb_otg->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST) {}
-
- // Restart PHY clock
- *((volatile uint32_t *)(RHPORT_REGS_BASE + USB_OTG_PCGCCTL_BASE)) = 0;
-
- // Clear all interrupts
- usb_otg->GINTSTS |= usb_otg->GINTSTS;
-
- // Required as part of core initialization.
- // TODO: How should mode mismatch be handled? It will cause
- // the core to stop working/require reset.
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_OTGINT | USB_OTG_GINTMSK_MMISM;
-
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
-
- // If USB host misbehaves during status portion of control xfer
- // (non zero-length packet), send STALL back and discard.
- dev->DCFG |= USB_OTG_DCFG_NZLSOHSK;
-
- set_speed(rhport, TUD_OPT_HIGH_SPEED ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL);
-
- // Enable internal USB transceiver, unless using HS core (port 1) with external PHY.
- if (!(rhport == 1 && (CFG_TUSB_RHPORT1_MODE & OPT_MODE_HIGH_SPEED))) usb_otg->GCCFG |= USB_OTG_GCCFG_PWRDWN;
-
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_USBRST | USB_OTG_GINTMSK_ENUMDNEM |
- USB_OTG_GINTMSK_USBSUSPM | USB_OTG_GINTMSK_WUIM |
- USB_OTG_GINTMSK_RXFLVLM | (USE_SOF ? USB_OTG_GINTMSK_SOFM : 0);
-
- // Enable global interrupt
- usb_otg->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
-
- dcd_connect(rhport);
-}
-
-void dcd_int_enable (uint8_t rhport)
-{
- (void) rhport;
- NVIC_EnableIRQ(RHPORT_IRQn);
-}
-
-void dcd_int_disable (uint8_t rhport)
-{
- (void) rhport;
- NVIC_DisableIRQ(RHPORT_IRQn);
-}
-
-void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
-{
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- dev->DCFG |= (dev_addr << USB_OTG_DCFG_DAD_Pos) & USB_OTG_DCFG_DAD_Msk;
-
- // Response with status after changing device address
- dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
-}
-
-void dcd_remote_wakeup(uint8_t rhport)
-{
- (void) rhport;
-
- // TODO must manually clear this bit after 1-15 ms
- // USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- // dev->DCTL |= USB_OTG_DCTL_RWUSIG;
-}
-
-void dcd_connect(uint8_t rhport)
-{
- (void) rhport;
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- dev->DCTL &= ~USB_OTG_DCTL_SDIS;
-}
-
-void dcd_disconnect(uint8_t rhport)
-{
- (void) rhport;
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- dev->DCTL |= USB_OTG_DCTL_SDIS;
-}
-
-
-/*------------------------------------------------------------------*/
-/* DCD Endpoint port
- *------------------------------------------------------------------*/
-
-bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
-
- TU_ASSERT(epnum < EP_MAX);
-
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->max_size = desc_edpt->wMaxPacketSize.size;
- xfer->interval = desc_edpt->bInterval;
-
- uint16_t const fifo_size = (desc_edpt->wMaxPacketSize.size + 3) / 4; // Round up to next full word
-
- if(dir == TUSB_DIR_OUT)
- {
- // Calculate required size of RX FIFO
- uint16_t const sz = calc_rx_ff_size(4*fifo_size);
-
- // If size_rx needs to be extended check if possible and if so enlarge it
- if (usb_otg->GRXFSIZ < sz)
- {
- TU_ASSERT(sz + _allocated_fifo_words_tx <= EP_FIFO_SIZE/4);
-
- // Enlarge RX FIFO
- usb_otg->GRXFSIZ = sz;
- }
-
- out_ep[epnum].DOEPCTL |= (1 << USB_OTG_DOEPCTL_USBAEP_Pos) |
- (desc_edpt->bmAttributes.xfer << USB_OTG_DOEPCTL_EPTYP_Pos) |
- (desc_edpt->wMaxPacketSize.size << USB_OTG_DOEPCTL_MPSIZ_Pos);
-
- dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_OEPM_Pos + epnum));
- }
- else
- {
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO 0 |
- // --------------- (320 or 1024) - 16
- // | IN FIFO 1 |
- // --------------- (320 or 1024) - 16 - x
- // | . . . . |
- // --------------- (320 or 1024) - 16 - x - y - ... - z
- // | IN FIFO MAX |
- // ---------------
- // | FREE |
- // --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
- // --------------- 0
- //
- // In FIFO is allocated by following rules:
- // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
-
- // Check if free space is available
- TU_ASSERT(_allocated_fifo_words_tx + fifo_size + usb_otg->GRXFSIZ <= EP_FIFO_SIZE/4);
-
- _allocated_fifo_words_tx += fifo_size;
-
- // DIEPTXF starts at FIFO #1.
- // Both TXFD and TXSA are in unit of 32-bit words.
- usb_otg->DIEPTXF[epnum - 1] = (fifo_size << USB_OTG_DIEPTXF_INEPTXFD_Pos) | (EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
-
- in_ep[epnum].DIEPCTL |= (1 << USB_OTG_DIEPCTL_USBAEP_Pos) |
- (epnum << USB_OTG_DIEPCTL_TXFNUM_Pos) |
- (desc_edpt->bmAttributes.xfer << USB_OTG_DIEPCTL_EPTYP_Pos) |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_OTG_DOEPCTL_SD0PID_SEVNFRM : 0) |
- (desc_edpt->wMaxPacketSize.size << USB_OTG_DIEPCTL_MPSIZ_Pos);
-
- dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_IEPM_Pos + epnum));
- }
-
- return true;
-}
-
-bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = buffer;
- xfer->ff = NULL;
- xfer->total_len = total_bytes;
-
- // EP0 can only handle one packet
- if(epnum == 0) {
- ep0_pending[dir] = total_bytes;
- // Schedule the first transaction for EP0 transfer
- edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]);
- return true;
- }
-
- uint16_t num_packets = (total_bytes / xfer->max_size);
- uint8_t const short_packet_size = total_bytes % xfer->max_size;
-
- // Zero-size packet is special case.
- if(short_packet_size > 0 || (total_bytes == 0)) {
- num_packets++;
- }
-
- // Schedule packets to be sent within interrupt
- edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes);
-
- return true;
-}
-
-// The number of bytes has to be given explicitly to allow more flexible control of how many
-// bytes should be written and second to keep the return value free to give back a boolean
-// success message. If total_bytes is too big, the FIFO will copy only what is available
-// into the USB buffer!
-bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
-{
- // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
- TU_ASSERT(ff->item_size == 1);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = NULL;
- xfer->ff = ff;
- xfer->total_len = total_bytes;
-
- uint16_t num_packets = (total_bytes / xfer->max_size);
- uint8_t const short_packet_size = total_bytes % xfer->max_size;
-
- // Zero-size packet is special case.
- if(short_packet_size > 0 || (total_bytes == 0)) num_packets++;
-
- // Schedule packets to be sent within interrupt
- edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes);
-
- return true;
-}
-
-static void dcd_edpt_disable (uint8_t rhport, uint8_t ep_addr, bool stall)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if(dir == TUSB_DIR_IN) {
- // Only disable currently enabled non-control endpoint
- if ( (epnum == 0) || !(in_ep[epnum].DIEPCTL & USB_OTG_DIEPCTL_EPENA) ){
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_SNAK | (stall ? USB_OTG_DIEPCTL_STALL : 0);
- } else {
- // Stop transmitting packets and NAK IN xfers.
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_SNAK;
- while((in_ep[epnum].DIEPINT & USB_OTG_DIEPINT_INEPNE) == 0);
-
- // Disable the endpoint.
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_EPDIS | (stall ? USB_OTG_DIEPCTL_STALL : 0);
- while((in_ep[epnum].DIEPINT & USB_OTG_DIEPINT_EPDISD_Msk) == 0);
- in_ep[epnum].DIEPINT = USB_OTG_DIEPINT_EPDISD;
- }
-
- // Flush the FIFO, and wait until we have confirmed it cleared.
- usb_otg->GRSTCTL |= (epnum << USB_OTG_GRSTCTL_TXFNUM_Pos);
- usb_otg->GRSTCTL |= USB_OTG_GRSTCTL_TXFFLSH;
- while((usb_otg->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH_Msk) != 0);
- } else {
- // Only disable currently enabled non-control endpoint
- if ( (epnum == 0) || !(out_ep[epnum].DOEPCTL & USB_OTG_DOEPCTL_EPENA) ){
- out_ep[epnum].DOEPCTL |= stall ? USB_OTG_DOEPCTL_STALL : 0;
- } else {
- // Asserting GONAK is required to STALL an OUT endpoint.
- // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt
- // anyway, and it can't be cleared by user code. If this while loop never
- // finishes, we have bigger problems than just the stack.
- dev->DCTL |= USB_OTG_DCTL_SGONAK;
- while((usb_otg->GINTSTS & USB_OTG_GINTSTS_BOUTNAKEFF_Msk) == 0);
-
- // Ditto here- disable the endpoint.
- out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_EPDIS | (stall ? USB_OTG_DOEPCTL_STALL : 0);
- while((out_ep[epnum].DOEPINT & USB_OTG_DOEPINT_EPDISD_Msk) == 0);
- out_ep[epnum].DOEPINT = USB_OTG_DOEPINT_EPDISD;
-
- // Allow other OUT endpoints to keep receiving.
- dev->DCTL |= USB_OTG_DCTL_CGONAK;
- }
- }
-}
-
-/**
- * Close an endpoint.
- */
-void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
-{
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- dcd_edpt_disable(rhport, ep_addr, false);
-
- // Update max_size
- xfer_status[epnum][dir].max_size = 0; // max_size = 0 marks a disabled EP - required for changing FIFO allocation
-
- if (dir == TUSB_DIR_IN)
- {
- uint16_t const fifo_size = (usb_otg->DIEPTXF[epnum - 1] & USB_OTG_DIEPTXF_INEPTXFD_Msk) >> USB_OTG_DIEPTXF_INEPTXFD_Pos;
- uint16_t const fifo_start = (usb_otg->DIEPTXF[epnum - 1] & USB_OTG_DIEPTXF_INEPTXSA_Msk) >> USB_OTG_DIEPTXF_INEPTXSA_Pos;
- // For now only the last opened endpoint can be closed without fuss.
- TU_ASSERT(fifo_start == EP_FIFO_SIZE/4 - _allocated_fifo_words_tx,);
- _allocated_fifo_words_tx -= fifo_size;
- }
- else
- {
- _out_ep_closed = true; // Set flag such that RX FIFO gets reduced in size once RX FIFO is empty
- }
-}
-
-void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
-{
- dcd_edpt_disable(rhport, ep_addr, true);
-}
-
-void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
-{
- (void) rhport;
-
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if(dir == TUSB_DIR_IN) {
- in_ep[epnum].DIEPCTL &= ~USB_OTG_DIEPCTL_STALL;
-
- uint8_t eptype = (in_ep[epnum].DIEPCTL & USB_OTG_DIEPCTL_EPTYP_Msk) >> USB_OTG_DIEPCTL_EPTYP_Pos;
- // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt and bulk endpoints.
- if(eptype == 2 || eptype == 3) {
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_SD0PID_SEVNFRM;
- }
- } else {
- out_ep[epnum].DOEPCTL &= ~USB_OTG_DOEPCTL_STALL;
-
- uint8_t eptype = (out_ep[epnum].DOEPCTL & USB_OTG_DOEPCTL_EPTYP_Msk) >> USB_OTG_DOEPCTL_EPTYP_Pos;
- // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt and bulk endpoints.
- if(eptype == 2 || eptype == 3) {
- out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_SD0PID_SEVNFRM;
- }
- }
-}
-
-/*------------------------------------------------------------------*/
-
-// Read a single data packet from receive FIFO
-static void read_fifo_packet(uint8_t rhport, uint8_t * dst, uint16_t len)
-{
- (void) rhport;
-
- usb_fifo_t rx_fifo = FIFO_BASE(rhport, 0);
-
- // Reading full available 32 bit words from fifo
- uint16_t full_words = len >> 2;
- for(uint16_t i = 0; i < full_words; i++) {
- uint32_t tmp = *rx_fifo;
- dst[0] = tmp & 0x000000FF;
- dst[1] = (tmp & 0x0000FF00) >> 8;
- dst[2] = (tmp & 0x00FF0000) >> 16;
- dst[3] = (tmp & 0xFF000000) >> 24;
- dst += 4;
- }
-
- // Read the remaining 1-3 bytes from fifo
- uint8_t bytes_rem = len & 0x03;
- if(bytes_rem != 0) {
- uint32_t tmp = *rx_fifo;
- dst[0] = tmp & 0x000000FF;
- if(bytes_rem > 1) {
- dst[1] = (tmp & 0x0000FF00) >> 8;
- }
- if(bytes_rem > 2) {
- dst[2] = (tmp & 0x00FF0000) >> 16;
- }
- }
-}
-
-// Write a single data packet to EPIN FIFO
-static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t * src, uint16_t len)
-{
- (void) rhport;
-
- usb_fifo_t tx_fifo = FIFO_BASE(rhport, fifo_num);
-
- // Pushing full available 32 bit words to fifo
- uint16_t full_words = len >> 2;
- for(uint16_t i = 0; i < full_words; i++){
- *tx_fifo = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
- src += 4;
- }
-
- // Write the remaining 1-3 bytes into fifo
- uint8_t bytes_rem = len & 0x03;
- if(bytes_rem){
- uint32_t tmp_word = 0;
- tmp_word |= src[0];
- if(bytes_rem > 1){
- tmp_word |= src[1] << 8;
- }
- if(bytes_rem > 2){
- tmp_word |= src[2] << 16;
- }
- *tx_fifo = tmp_word;
- }
-}
-
-static void handle_rxflvl_ints(uint8_t rhport, USB_OTG_OUTEndpointTypeDef * out_ep) {
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- usb_fifo_t rx_fifo = FIFO_BASE(rhport, 0);
-
- // Pop control word off FIFO
- uint32_t ctl_word = usb_otg->GRXSTSP;
- uint8_t pktsts = (ctl_word & USB_OTG_GRXSTSP_PKTSTS_Msk) >> USB_OTG_GRXSTSP_PKTSTS_Pos;
- uint8_t epnum = (ctl_word & USB_OTG_GRXSTSP_EPNUM_Msk) >> USB_OTG_GRXSTSP_EPNUM_Pos;
- uint16_t bcnt = (ctl_word & USB_OTG_GRXSTSP_BCNT_Msk) >> USB_OTG_GRXSTSP_BCNT_Pos;
-
- switch(pktsts) {
- case 0x01: // Global OUT NAK (Interrupt)
- break;
-
- case 0x02: // Out packet recvd
- {
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
-
- // Read packet off RxFIFO
- if (xfer->ff)
- {
- // Ring buffer
- tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) rx_fifo, bcnt);
- }
- else
- {
- // Linear buffer
- read_fifo_packet(rhport, xfer->buffer, bcnt);
-
- // Increment pointer to xfer data
- xfer->buffer += bcnt;
- }
-
- // Truncate transfer length in case of short packet
- if(bcnt < xfer->max_size) {
- xfer->total_len -= (out_ep[epnum].DOEPTSIZ & USB_OTG_DOEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DOEPTSIZ_XFRSIZ_Pos;
- if(epnum == 0) {
- xfer->total_len -= ep0_pending[TUSB_DIR_OUT];
- ep0_pending[TUSB_DIR_OUT] = 0;
- }
- }
- }
- break;
-
- case 0x03: // Out packet done (Interrupt)
- break;
-
- case 0x04: // Setup packet done (Interrupt)
- out_ep[epnum].DOEPTSIZ |= (3 << USB_OTG_DOEPTSIZ_STUPCNT_Pos);
- break;
-
- case 0x06: // Setup packet recvd
- // We can receive up to three setup packets in succession, but
- // only the last one is valid.
- _setup_packet[0] = (* rx_fifo);
- _setup_packet[1] = (* rx_fifo);
- break;
-
- default: // Invalid
- TU_BREAKPOINT();
- break;
- }
-}
-
-static void handle_epout_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OTG_OUTEndpointTypeDef * out_ep) {
- // DAINT for a given EP clears when DOEPINTx is cleared.
- // OEPINT will be cleared when DAINT's out bits are cleared.
- for(uint8_t n = 0; n < EP_MAX; n++) {
- xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
-
- if(dev->DAINT & (1 << (USB_OTG_DAINT_OEPINT_Pos + n))) {
- // SETUP packet Setup Phase done.
- if(out_ep[n].DOEPINT & USB_OTG_DOEPINT_STUP) {
- out_ep[n].DOEPINT = USB_OTG_DOEPINT_STUP;
- dcd_event_setup_received(rhport, (uint8_t*) &_setup_packet[0], true);
- }
-
- // OUT XFER complete
- if(out_ep[n].DOEPINT & USB_OTG_DOEPINT_XFRC) {
- out_ep[n].DOEPINT = USB_OTG_DOEPINT_XFRC;
-
- // EP0 can only handle one packet
- if((n == 0) && ep0_pending[TUSB_DIR_OUT]) {
- // Schedule another packet to be received.
- edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]);
- } else {
- dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true);
- }
- }
- }
- }
-}
-
-static void handle_epin_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointTypeDef * in_ep) {
- // DAINT for a given EP clears when DIEPINTx is cleared.
- // IEPINT will be cleared when DAINT's out bits are cleared.
- for ( uint8_t n = 0; n < EP_MAX; n++ )
- {
- xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
-
- if ( dev->DAINT & (1 << (USB_OTG_DAINT_IEPINT_Pos + n)) )
- {
- // IN XFER complete (entire xfer).
- if ( in_ep[n].DIEPINT & USB_OTG_DIEPINT_XFRC )
- {
- in_ep[n].DIEPINT = USB_OTG_DIEPINT_XFRC;
-
- // EP0 can only handle one packet
- if((n == 0) && ep0_pending[TUSB_DIR_IN]) {
- // Schedule another packet to be transmitted.
- edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]);
- } else {
- dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
- }
- }
-
- // XFER FIFO empty
- if ( (in_ep[n].DIEPINT & USB_OTG_DIEPINT_TXFE) && (dev->DIEPEMPMSK & (1 << n)) )
- {
- // DIEPINT's TXFE bit is read-only, software cannot clear it.
- // It will only be cleared by hardware when written bytes is more than
- // - 64 bytes or
- // - Half of TX FIFO size (configured by DIEPTXF)
-
- uint16_t remaining_packets = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_PKTCNT_Msk) >> USB_OTG_DIEPTSIZ_PKTCNT_Pos;
-
- // Process every single packet (only whole packets can be written to fifo)
- for(uint16_t i = 0; i < remaining_packets; i++)
- {
- uint16_t const remaining_bytes = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos;
-
- // Packet can not be larger than ep max size
- uint16_t const packet_size = tu_min16(remaining_bytes, xfer->max_size);
-
- // It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current
- // EP has to be checked if the buffer can take another WHOLE packet
- if(packet_size > ((in_ep[n].DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV_Msk) << 2)) break;
-
- // Push packet to Tx-FIFO
- if (xfer->ff)
- {
- usb_fifo_t tx_fifo = FIFO_BASE(rhport, n);
- tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) tx_fifo, packet_size);
- }
- else
- {
- write_fifo_packet(rhport, n, xfer->buffer, packet_size);
-
- // Increment pointer to xfer data
- xfer->buffer += packet_size;
- }
- }
-
- // Turn off TXFE if all bytes are written.
- if (((in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos) == 0)
- {
- dev->DIEPEMPMSK &= ~(1 << n);
- }
- }
- }
- }
-}
-
-void dcd_int_handler(uint8_t rhport)
-{
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- uint32_t int_status = usb_otg->GINTSTS;
-
- if(int_status & USB_OTG_GINTSTS_USBRST)
- {
- // USBRST is start of reset.
- usb_otg->GINTSTS = USB_OTG_GINTSTS_USBRST;
- bus_reset(rhport);
- }
-
- if(int_status & USB_OTG_GINTSTS_ENUMDNE)
- {
- // ENUMDNE is the end of reset where speed of the link is detected
-
- usb_otg->GINTSTS = USB_OTG_GINTSTS_ENUMDNE;
-
- tusb_speed_t const speed = get_speed(rhport);
-
- set_turnaround(usb_otg, speed);
- dcd_event_bus_reset(rhport, speed, true);
- }
-
- if(int_status & USB_OTG_GINTSTS_USBSUSP)
- {
- usb_otg->GINTSTS = USB_OTG_GINTSTS_USBSUSP;
- dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
- }
-
- if(int_status & USB_OTG_GINTSTS_WKUINT)
- {
- usb_otg->GINTSTS = USB_OTG_GINTSTS_WKUINT;
- dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
- }
-
- if(int_status & USB_OTG_GINTSTS_OTGINT)
- {
- // OTG INT bit is read-only
- uint32_t const otg_int = usb_otg->GOTGINT;
-
- if (otg_int & USB_OTG_GOTGINT_SEDET)
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
- }
-
- usb_otg->GOTGINT = otg_int;
- }
-
-#if USE_SOF
- if(int_status & USB_OTG_GINTSTS_SOF)
- {
- usb_otg->GINTSTS = USB_OTG_GINTSTS_SOF;
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
- }
-#endif
-
- // RxFIFO non-empty interrupt handling.
- if(int_status & USB_OTG_GINTSTS_RXFLVL)
- {
- // RXFLVL bit is read-only
-
- // Mask out RXFLVL while reading data from FIFO
- usb_otg->GINTMSK &= ~USB_OTG_GINTMSK_RXFLVLM;
-
- // Loop until all available packets were handled
- do
- {
- handle_rxflvl_ints(rhport, out_ep);
- int_status = usb_otg->GINTSTS;
- } while(int_status & USB_OTG_GINTSTS_RXFLVL);
-
- // Manage RX FIFO size
- if (_out_ep_closed)
- {
- update_grxfsiz(rhport);
-
- // Disable flag
- _out_ep_closed = false;
- }
-
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM;
- }
-
- // OUT endpoint interrupt handling.
- if(int_status & USB_OTG_GINTSTS_OEPINT)
- {
- // OEPINT is read-only
- handle_epout_ints(rhport, dev, out_ep);
- }
-
- // IN endpoint interrupt handling.
- if(int_status & USB_OTG_GINTSTS_IEPINT)
- {
- // IEPINT bit read-only
- handle_epin_ints(rhport, dev, in_ep);
- }
-
- // // Check for Incomplete isochronous IN transfer
- // if(int_status & USB_OTG_GINTSTS_IISOIXFR) {
- // printf(" IISOIXFR!\r\n");
- //// TU_LOG2(" IISOIXFR!\r\n");
- // }
-}
-
-#endif
diff --git a/src/portable/st/typec/typec_stm32.c b/src/portable/st/typec/typec_stm32.c
new file mode 100644
index 000000000..8da2e39ba
--- /dev/null
+++ b/src/portable/st/typec/typec_stm32.c
@@ -0,0 +1,372 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "tusb_option.h"
+#include "typec/tcd.h"
+
+#if CFG_TUC_ENABLED && defined(TUP_USBIP_TYPEC_STM32)
+
+#include "common/tusb_common.h"
+
+#if CFG_TUSB_MCU == OPT_MCU_STM32G4
+ #include "stm32g4xx.h"
+ #include "stm32g4xx_ll_dma.h" // for UCPD REQID
+#else
+ #error "Unsupported STM32 family"
+#endif
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+enum {
+ IMR_ATTACHED = UCPD_IMR_TXMSGDISCIE | UCPD_IMR_TXMSGSENTIE | UCPD_IMR_TXMSGABTIE | UCPD_IMR_TXUNDIE |
+ UCPD_IMR_RXHRSTDETIE | UCPD_IMR_RXOVRIE | UCPD_IMR_RXMSGENDIE | UCPD_IMR_RXORDDETIE |
+ UCPD_IMR_HRSTDISCIE | UCPD_IMR_HRSTSENTIE | UCPD_IMR_FRSEVTIE
+};
+
+#define PHY_SYNC1 0x18u
+#define PHY_SYNC2 0x11u
+#define PHY_SYNC3 0x06u
+#define PHY_RST1 0x07u
+#define PHY_RST2 0x19u
+#define PHY_EOP 0x0Du
+
+#define PHY_ORDERED_SET_SOP (PHY_SYNC1 | (PHY_SYNC1<<5u) | (PHY_SYNC1<<10u) | (PHY_SYNC2<<15u)) // SOP Ordered set coding
+#define PHY_ORDERED_SET_SOP_P (PHY_SYNC1 | (PHY_SYNC1<<5u) | (PHY_SYNC3<<10u) | (PHY_SYNC3<<15u)) // SOP' Ordered set coding
+#define PHY_ORDERED_SET_SOP_PP (PHY_SYNC1 | (PHY_SYNC3<<5u) | (PHY_SYNC1<<10u) | (PHY_SYNC3<<15u)) // SOP'' Ordered set coding
+#define PHY_ORDERED_SET_HARD_RESET (PHY_RST1 | (PHY_RST1<<5u) | (PHY_RST1<<10u) | (PHY_RST2<<15u )) // Hard Reset Ordered set coding
+#define PHY_ORDERED_SET_CABLE_RESET (PHY_RST1 | (PHY_SYNC1<<5u) | (PHY_RST1<<10u) | (PHY_SYNC3<<15u)) // Cable Reset Ordered set coding
+#define PHY_ORDERED_SET_SOP_P_DEBUG (PHY_SYNC1 | (PHY_RST2<<5u) | (PHY_RST2<<10u) | (PHY_SYNC3<<15u)) // SOP' Debug Ordered set coding
+#define PHY_ORDERED_SET_SOP_PP_DEBUG (PHY_SYNC1 | (PHY_RST2<<5u) | (PHY_SYNC3<<10u) | (PHY_SYNC2<<15u)) // SOP'' Debug Ordered set coding
+
+
+static uint8_t const* _rx_buf;
+static uint8_t const* _tx_pending_buf;
+static uint16_t _tx_pending_bytes;
+static uint16_t _tx_xferring_bytes;
+
+static pd_header_t _good_crc = {
+ .msg_type = PD_CTRL_GOOD_CRC,
+ .data_role = 0, // UFP
+ .specs_rev = PD_REV_20,
+ .power_role = 0, // Sink
+ .msg_id = 0,
+ .n_data_obj = 0,
+ .extended = 0
+};
+
+// address of DMA channel rx, tx for each port
+#define CFG_TUC_STM32_DMA { { DMA1_Channel1_BASE, DMA1_Channel2_BASE } }
+
+//--------------------------------------------------------------------+
+// DMA
+//--------------------------------------------------------------------+
+
+static const uint32_t _dma_addr_arr[TUP_TYPEC_RHPORTS_NUM][2] = CFG_TUC_STM32_DMA;
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t dma_get_addr(uint8_t rhport, bool is_rx) {
+ return _dma_addr_arr[rhport][is_rx ? 0 : 1];
+}
+
+static void dma_init(uint8_t rhport, bool is_rx) {
+ uint32_t dma_addr = dma_get_addr(rhport, is_rx);
+ DMA_Channel_TypeDef* dma_ch = (DMA_Channel_TypeDef*) dma_addr;
+ uint32_t req_id;
+
+ if (is_rx) {
+ // Peripheral -> Memory, Memory inc, 8-bit, High priority
+ dma_ch->CCR = DMA_CCR_MINC | DMA_CCR_PL_1;
+ dma_ch->CPAR = (uint32_t) &UCPD1->RXDR;
+
+ req_id = LL_DMAMUX_REQ_UCPD1_RX;
+ } else {
+ // Memory -> Peripheral, Memory inc, 8-bit, High priority
+ dma_ch->CCR = DMA_CCR_MINC | DMA_CCR_PL_1 | DMA_CCR_DIR;
+ dma_ch->CPAR = (uint32_t) &UCPD1->TXDR;
+
+ req_id = LL_DMAMUX_REQ_UCPD1_TX;
+ }
+
+ // find and set up mux channel TODO support mcu with multiple DMAMUXs
+ enum {
+ CH_DIFF = DMA1_Channel2_BASE - DMA1_Channel1_BASE
+ };
+ uint32_t mux_ch_num;
+
+ #ifdef DMA2_BASE
+ if (dma_addr > DMA2_BASE) {
+ mux_ch_num = 8 * ((dma_addr - DMA2_Channel1_BASE) / CH_DIFF);
+ } else
+ #endif
+ {
+ mux_ch_num = (dma_addr - DMA1_Channel1_BASE) / CH_DIFF;
+ }
+
+ DMAMUX_Channel_TypeDef* mux_ch = DMAMUX1_Channel0 + mux_ch_num;
+
+ uint32_t mux_ccr = mux_ch->CCR & ~(DMAMUX_CxCR_DMAREQ_ID);
+ mux_ccr |= req_id;
+ mux_ch->CCR = mux_ccr;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void dma_start(uint8_t rhport, bool is_rx, void const* buf, uint16_t len) {
+ DMA_Channel_TypeDef* dma_ch = (DMA_Channel_TypeDef*) dma_get_addr(rhport, is_rx);
+
+ dma_ch->CMAR = (uint32_t) buf;
+ dma_ch->CNDTR = len;
+ dma_ch->CCR |= DMA_CCR_EN;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void dma_stop(uint8_t rhport, bool is_rx) {
+ DMA_Channel_TypeDef* dma_ch = (DMA_Channel_TypeDef*) dma_get_addr(rhport, is_rx);
+ dma_ch->CCR &= ~DMA_CCR_EN;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool dma_enabled(uint8_t rhport, bool is_rx) {
+ DMA_Channel_TypeDef* dma_ch = (DMA_Channel_TypeDef*) dma_get_addr(rhport, is_rx);
+ return dma_ch->CCR & DMA_CCR_EN;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void dma_tx_start(uint8_t rhport, void const* buf, uint16_t len) {
+ UCPD1->TX_ORDSET = PHY_ORDERED_SET_SOP;
+ UCPD1->TX_PAYSZ = len;
+ dma_start(rhport, false, buf, len);
+ UCPD1->CR |= UCPD_CR_TXSEND;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void dma_tx_stop(uint8_t rhport) {
+ dma_stop(rhport, false);
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+bool tcd_init(uint8_t rhport, uint32_t port_type) {
+ (void) rhport;
+
+ // Init DMA for RX, TX
+ dma_init(rhport, true);
+ dma_init(rhport, false);
+
+ // Initialization phase: CFG1, detect all SOPs
+ UCPD1->CFG1 = (0x0d << UCPD_CFG1_HBITCLKDIV_Pos) | (0x10 << UCPD_CFG1_IFRGAP_Pos) | (0x07 << UCPD_CFG1_TRANSWIN_Pos) |
+ (0x01 << UCPD_CFG1_PSC_UCPDCLK_Pos) | (0x1f << UCPD_CFG1_RXORDSETEN_Pos);
+ UCPD1->CFG1 |= UCPD_CFG1_UCPDEN;
+
+ // General programming sequence (with UCPD configured then enabled)
+ if (port_type == TUSB_TYPEC_PORT_SNK) {
+ // Set analog mode enable both CC Phy
+ UCPD1->CR = (0x01 << UCPD_CR_ANAMODE_Pos) | (UCPD_CR_CCENABLE_0 | UCPD_CR_CCENABLE_1);
+
+ // Read Voltage State on CC1 & CC2 fore initial state
+ uint32_t v_cc[2];
+ (void) v_cc;
+ v_cc[0] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC1_Pos) & 0x03;
+ v_cc[1] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC2_Pos) & 0x03;
+ TU_LOG1("Initial VState CC1 = %lu, CC2 = %lu\r\n", v_cc[0], v_cc[1]);
+
+ // Enable CC1 & CC2 Interrupt
+ UCPD1->IMR = UCPD_IMR_TYPECEVT1IE | UCPD_IMR_TYPECEVT2IE;
+ }
+
+ // Disable dead battery in PWR's CR3
+ PWR->CR3 |= PWR_CR3_UCPD_DBDIS;
+
+ return true;
+}
+
+// Enable interrupt
+void tcd_int_enable (uint8_t rhport) {
+ (void) rhport;
+ NVIC_EnableIRQ(UCPD1_IRQn);
+}
+
+// Disable interrupt
+void tcd_int_disable(uint8_t rhport) {
+ (void) rhport;
+ NVIC_DisableIRQ(UCPD1_IRQn);
+}
+
+bool tcd_msg_receive(uint8_t rhport, uint8_t* buffer, uint16_t total_bytes) {
+ _rx_buf = buffer;
+ dma_start(rhport, true, buffer, total_bytes);
+ return true;
+}
+
+bool tcd_msg_send(uint8_t rhport, uint8_t const* buffer, uint16_t total_bytes) {
+ (void) rhport;
+
+ if (dma_enabled(rhport, false)) {
+ // DMA is busy, probably sending GoodCRC, save as pending TX
+ _tx_pending_buf = buffer;
+ _tx_pending_bytes = total_bytes;
+ }else {
+ // DMA is free, start sending
+ _tx_pending_buf = NULL;
+ _tx_pending_bytes = 0;
+
+ _tx_xferring_bytes = total_bytes;
+ dma_tx_start(rhport, buffer, total_bytes);
+ }
+
+ return true;
+}
+
+void tcd_int_handler(uint8_t rhport) {
+ (void) rhport;
+
+ uint32_t sr = UCPD1->SR;
+ sr &= UCPD1->IMR;
+
+ if (sr & (UCPD_SR_TYPECEVT1 | UCPD_SR_TYPECEVT2)) {
+ uint32_t v_cc[2];
+ v_cc[0] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC1_Pos) & 0x03;
+ v_cc[1] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC2_Pos) & 0x03;
+
+ TU_LOG3("VState CC1 = %lu, CC2 = %lu\r\n", v_cc[0], v_cc[1]);
+
+ uint32_t cr = UCPD1->CR;
+
+ // TODO only support SNK for now, required highest voltage for now
+ // Enable PHY on active CC and disable Rd on other CC
+ // FIXME somehow CC2 is vstate is not correct, always 1 even not attached.
+ // on DPOW1 board, it is connected to PA10 (USBPD_DBCC2), we probably miss something.
+ if ((sr & UCPD_SR_TYPECEVT1) && (v_cc[0] == 3)) {
+ TU_LOG3("Attach CC1\r\n");
+ cr &= ~(UCPD_CR_PHYCCSEL | UCPD_CR_CCENABLE);
+ cr |= UCPD_CR_PHYRXEN | UCPD_CR_CCENABLE_0;
+ } else if ((sr & UCPD_SR_TYPECEVT2) && (v_cc[1] == 3)) {
+ TU_LOG3("Attach CC2\r\n");
+ cr &= ~UCPD_CR_CCENABLE;
+ cr |= (UCPD_CR_PHYCCSEL | UCPD_CR_PHYRXEN | UCPD_CR_CCENABLE_1);
+ } else {
+ TU_LOG3("Detach\r\n");
+ cr &= ~UCPD_CR_PHYRXEN;
+ cr |= UCPD_CR_CCENABLE_0 | UCPD_CR_CCENABLE_1;
+ }
+
+ if (cr & UCPD_CR_PHYRXEN) {
+ // Attached
+ UCPD1->IMR |= IMR_ATTACHED;
+ UCPD1->CFG1 |= UCPD_CFG1_RXDMAEN | UCPD_CFG1_TXDMAEN;
+ }else {
+ // Detached
+ UCPD1->CFG1 &= ~(UCPD_CFG1_RXDMAEN | UCPD_CFG1_TXDMAEN);
+ UCPD1->IMR &= ~IMR_ATTACHED;
+ }
+
+ // notify stack
+ tcd_event_cc_changed(rhport, v_cc[0], v_cc[1], true);
+
+ UCPD1->CR = cr;
+
+ // ack
+ UCPD1->ICR = UCPD_ICR_TYPECEVT1CF | UCPD_ICR_TYPECEVT2CF;
+ }
+
+ //------------- RX -------------//
+ if (sr & UCPD_SR_RXORDDET) {
+ // SOP: Start of Packet.
+ TU_LOG3("SOP\r\n");
+ // UCPD1->RX_ORDSET & UCPD_RX_ORDSET_RXORDSET_Msk;
+
+ // ack
+ UCPD1->ICR = UCPD_ICR_RXORDDETCF;
+ }
+
+ // Received full message
+ if (sr & UCPD_SR_RXMSGEND) {
+ TU_LOG3("RX MSG END\r\n");
+
+ // stop TX
+ dma_stop(rhport, true);
+
+ uint8_t result;
+
+ if (!(sr & UCPD_SR_RXERR)) {
+ // response with good crc
+ // TODO move this to usbc stack
+ if (_rx_buf) {
+ _good_crc.msg_id = ((pd_header_t const *) _rx_buf)->msg_id;
+ dma_tx_start(rhport, &_good_crc, 2);
+ }
+
+ result = XFER_RESULT_SUCCESS;
+ }else {
+ // CRC failed
+ result = XFER_RESULT_FAILED;
+ }
+
+ // notify stack
+ tcd_event_rx_complete(rhport, UCPD1->RX_PAYSZ, result, true);
+
+ // ack
+ UCPD1->ICR = UCPD_ICR_RXMSGENDCF;
+ }
+
+ if (sr & UCPD_SR_RXOVR) {
+ TU_LOG3("RXOVR\r\n");
+ // ack
+ UCPD1->ICR = UCPD_ICR_RXOVRCF;
+ }
+
+ //------------- TX -------------//
+ // All tx events: complete and error
+ if (sr & (UCPD_SR_TXMSGSENT | (UCPD_SR_TXMSGDISC | UCPD_SR_TXMSGABT | UCPD_SR_TXUND))) {
+ // force TX stop
+ dma_tx_stop(rhport);
+
+ uint16_t const xferred_bytes = _tx_xferring_bytes - UCPD1->TX_PAYSZ;
+ uint8_t result;
+
+ if ( sr & UCPD_SR_TXMSGSENT ) {
+ TU_LOG3("TX MSG SENT\r\n");
+ result = XFER_RESULT_SUCCESS;
+ // ack
+ UCPD1->ICR = UCPD_ICR_TXMSGSENTCF;
+ }else {
+ TU_LOG3("TX Error\r\n");
+ result = XFER_RESULT_FAILED;
+ // ack
+ UCPD1->ICR = UCPD_SR_TXMSGDISC | UCPD_SR_TXMSGABT | UCPD_SR_TXUND;
+ }
+
+ // start pending TX if any
+ if (_tx_pending_buf && _tx_pending_bytes ) {
+ // Start the pending TX
+ dma_tx_start(rhport, _tx_pending_buf, _tx_pending_bytes);
+
+ // clear pending
+ _tx_pending_buf = NULL;
+ _tx_pending_bytes = 0;
+ }
+
+ // notify stack
+ tcd_event_tx_complete(rhport, xferred_bytes, result, true);
+ }
+}
+
+#endif
diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c
new file mode 100644
index 000000000..6f36ad441
--- /dev/null
+++ b/src/portable/sunxi/dcd_sunxi_musb.c
@@ -0,0 +1,1221 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ * Copyright (c) 2021 Tian Yunhao (t123yh)
+ * Copyright (c) 2021 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include <stdint.h>
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_F1C100S
+
+#include "osal/osal.h"
+#include <f1c100s-irq.h>
+#include <device/dcd.h>
+#include "musb_def.h"
+
+//#include "bsp/board_api.h"
+extern uint32_t board_millis(void); // TODO remove
+
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+
+
+#define REQUEST_TYPE_INVALID (0xFFu)
+
+typedef struct {
+ uint_fast16_t beg; /* offset of including first element */
+ uint_fast16_t end; /* offset of excluding the last element */
+} free_block_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ void *buf; /* the start address of a transfer data buffer */
+ uint16_t length; /* the number of bytes in the buffer */
+ uint16_t remaining; /* the number of bytes remaining in the buffer */
+} pipe_state_t;
+
+typedef struct
+{
+ CFG_TUD_MEM_ALIGN tusb_control_request_t setup_packet;
+ uint16_t remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */
+ int8_t status_out;
+ pipe_state_t pipe0;
+ pipe_state_t pipe[2][7]; /* pipe[direction][endpoint number - 1] */
+ uint16_t pipe_buf_is_fifo[2]; /* Bitmap. Each bit means whether 1:TU_FIFO or 0:POD. */
+} dcd_data_t;
+
+/*------------------------------------------------------------------
+ * SUNXI FUNCTION
+ *------------------------------------------------------------------*/
+
+static void usb_phy_write(int addr, int data, int len)
+{
+ int j = 0, usbc_bit = 0;
+ void *dest = (void *)USBC_REG_CSR(USBC0_BASE);
+
+ usbc_bit = 1 << (0 * 2);
+ for (j = 0; j < len; j++)
+ {
+ /* set the bit address to be written */
+ USBC_ClrBit_Mask_l(dest, 0xff << 8);
+ USBC_SetBit_Mask_l(dest, (addr + j) << 8);
+
+ USBC_ClrBit_Mask_l(dest, usbc_bit);
+ /* set data bit */
+ if (data & 0x1)
+ USBC_SetBit_Mask_l(dest, 1 << 7);
+ else
+ USBC_ClrBit_Mask_l(dest, 1 << 7);
+
+ USBC_SetBit_Mask_l(dest, usbc_bit);
+
+ USBC_ClrBit_Mask_l(dest, usbc_bit);
+
+ data >>= 1;
+ }
+}
+
+static void delay_ms(uint32_t ms)
+{
+#if CFG_TUSB_OS == OPT_OS_NONE
+ int now = board_millis();
+ while (board_millis() - now <= ms) asm("nop");
+#else
+ osal_task_delay(ms);
+#endif
+}
+
+static void USBC_HardwareReset(void)
+{
+ // Reset phy and controller
+ USBC_REG_set_bit_l(USBPHY_CLK_RST_BIT, USBPHY_CLK_REG);
+ USBC_REG_set_bit_l(BUS_RST_USB_BIT, BUS_CLK_RST_REG);
+ delay_ms(2);
+
+ USBC_REG_set_bit_l(USBPHY_CLK_GAT_BIT, USBPHY_CLK_REG);
+ USBC_REG_set_bit_l(USBPHY_CLK_RST_BIT, USBPHY_CLK_REG);
+
+ USBC_REG_set_bit_l(BUS_CLK_USB_BIT, BUS_CLK_GATE0_REG);
+ USBC_REG_set_bit_l(BUS_RST_USB_BIT, BUS_CLK_RST_REG);
+}
+
+static void USBC_PhyConfig(void)
+{
+ /* Regulation 45 ohms */
+ usb_phy_write(0x0c, 0x01, 1);
+
+ /* adjust PHY's magnitude and rate */
+ usb_phy_write(0x20, 0x14, 5);
+
+ /* threshold adjustment disconnect */
+ usb_phy_write(0x2a, 3, 2);
+
+ return;
+}
+
+static void USBC_ConfigFIFO_Base(void)
+{
+ u32 reg_value;
+
+ /* config usb fifo, 8kb mode */
+ reg_value = USBC_Readl(SUNXI_SRAMC_BASE + 0x04);
+ reg_value &= ~(0x03 << 0);
+ reg_value |= (1 << 0);
+ USBC_Writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
+}
+
+static unsigned int USBC_WakeUp_ClearChangeDetect(unsigned int reg_val)
+{
+ unsigned int temp = reg_val;
+ /* vbus, id, dpdm, these bit is set 1 to clear, so we clear these bit when operate other bits */
+ temp &= ~(1 << USBC_BP_ISCR_VBUS_CHANGE_DETECT);
+ temp &= ~(1 << USBC_BP_ISCR_ID_CHANGE_DETECT);
+ temp &= ~(1 << USBC_BP_ISCR_DPDM_CHANGE_DETECT);
+
+ return temp;
+}
+
+static void USBC_EnableDpDmPullUp(void)
+{
+ u32 reg_val = USBC_Readl(USBC_REG_ISCR(USBC0_BASE));
+ reg_val |= (1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
+ reg_val |= 3<<USBC_BP_ISCR_VBUS_VALID_SRC;
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ USBC_Writel(reg_val, USBC_REG_ISCR(USBC0_BASE));
+}
+
+static void USBC_ForceIdToHigh(void)
+{
+ /* first write 00, then write 10 */
+ u32 reg_val = USBC_Readl(USBC_REG_ISCR(USBC0_BASE));
+ reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ USBC_Writel(reg_val, USBC_REG_ISCR(USBC0_BASE));
+}
+
+static void USBC_ForceVbusValidToHigh(void)
+{
+ /* first write 00, then write 11 */
+ u32 reg_val = USBC_Readl(USBC_REG_ISCR(USBC0_BASE));
+ reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ USBC_Writel(reg_val, USBC_REG_ISCR(USBC0_BASE));
+}
+
+void USBC_SelectBus(u32 io_type, u32 ep_type, u32 ep_index)
+{
+ u32 reg_val = 0;
+
+ reg_val = USBC_Readb(USBC_REG_VEND0(USBC0_BASE));
+ if (io_type == USBC_IO_TYPE_DMA) {
+ if (ep_type == USBC_EP_TYPE_TX) {
+ reg_val |= ((ep_index - 0x01) << 1) << USBC_BP_VEND0_DRQ_SEL; //drq_sel
+ reg_val |= 0x1<<USBC_BP_VEND0_BUS_SEL; //io_dma
+ } else {
+ reg_val |= ((ep_index << 1) - 0x01) << USBC_BP_VEND0_DRQ_SEL;
+ reg_val |= 0x1<<USBC_BP_VEND0_BUS_SEL;
+ }
+ } else {
+ //reg_val &= ~(0x1 << USBC_BP_VEND0_DRQ_SEL); //clear drq_sel, select pio
+ reg_val &= 0x00; // clear drq_sel, select pio
+ }
+
+ /* in 1667 1673 and later ic, FIFO_BUS_SEL bit(bit24 of reg0x40 for host/device)
+ * is fixed to 1, the hw guarantee that it's ok for cpu/inner_dma/outer_dma transfer */
+
+// reg_val |= 0x1<<USBC_BP_VEND0_BUS_SEL; //for 1663 set 1: enable dma, set 0: enable fifo
+
+ USBC_Writeb(reg_val, USBC_REG_VEND0(USBC0_BASE));
+}
+
+static void USBC_SelectActiveEp(u8 ep_index)
+{
+ USBC_Writeb(ep_index, USBC_REG_EPIND(USBC0_BASE));
+}
+
+static u8 USBC_GetActiveEp(void)
+{
+ return USBC_Readb(USBC_REG_EPIND(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_SendStall(void)
+{
+ USBC_REG_set_bit_w(USBC_BP_CSR0_D_SEND_STALL, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_ClearStall(void)
+{
+ USBC_REG_clear_bit_w(USBC_BP_CSR0_D_SEND_STALL, USBC_REG_CSR0(USBC0_BASE));
+ USBC_REG_clear_bit_w(USBC_BP_CSR0_D_SENT_STALL, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void USBC_Dev_Ctrl_ClearSetupEnd(void)
+{
+ USBC_REG_set_bit_w(USBC_BP_CSR0_D_SERVICED_SETUP_END, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void USBC_Dev_SetAddress(u8 address)
+{
+ USBC_Writeb(address, USBC_REG_FADDR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Tx_SendStall(void)
+{
+ //send stall, and fifo is flushed automatically
+ USBC_REG_set_bit_w(USBC_BP_TXCSR_D_SEND_STALL, USBC_REG_TXCSR(USBC0_BASE));
+}
+static u32 __USBC_Dev_Tx_IsEpStall(void)
+{
+ return USBC_REG_test_bit_w(USBC_BP_TXCSR_D_SENT_STALL, USBC_REG_TXCSR(USBC0_BASE));
+}
+static void __USBC_Dev_Tx_ClearStall(void)
+{
+ u32 reg_val = USBC_Readw(USBC_REG_TXCSR(USBC0_BASE));
+ reg_val &= ~((1 << USBC_BP_TXCSR_D_SENT_STALL)|(1 << USBC_BP_TXCSR_D_SEND_STALL)|(1<<USBC_BP_TXCSR_D_UNDER_RUN));
+ reg_val |= (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE);
+ USBC_Writew(reg_val, USBC_REG_TXCSR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Rx_SendStall(void)
+{
+ USBC_REG_set_bit_w(USBC_BP_RXCSR_D_SEND_STALL, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static u32 __USBC_Dev_Rx_IsEpStall(void)
+{
+ return USBC_REG_test_bit_w(USBC_BP_RXCSR_D_SENT_STALL, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Rx_ClearStall(void)
+{
+ u32 reg_val = USBC_Readw(USBC_REG_RXCSR(USBC0_BASE));
+ reg_val &= ~((1 << USBC_BP_RXCSR_D_SENT_STALL)|(1 << USBC_BP_RXCSR_D_SEND_STALL)|(1<<USBC_BP_RXCSR_D_OVERRUN));
+ reg_val |= (1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE);
+ USBC_Writew(reg_val, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static tusb_speed_t USBC_Dev_QueryTransferMode(void)
+{
+ if (USBC_REG_test_bit_b(USBC_BP_POWER_D_HIGH_SPEED_FLAG, USBC_REG_PCTL(USBC0_BASE)))
+ return TUSB_SPEED_HIGH;
+ else
+ return TUSB_SPEED_FULL;
+}
+
+static void __USBC_Dev_ep0_ReadDataHalf(void)
+{
+ USBC_Writew(1<<USBC_BP_CSR0_D_SERVICED_RX_PKT_READY, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_ReadDataComplete(void)
+{
+ USBC_Writew((1<<USBC_BP_CSR0_D_SERVICED_RX_PKT_READY) | (1<<USBC_BP_CSR0_D_DATA_END),
+ USBC_REG_CSR0(USBC0_BASE));
+}
+
+
+static void __USBC_Dev_ep0_WriteDataHalf(void)
+{
+ USBC_Writew(1<<USBC_BP_CSR0_D_TX_PKT_READY, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_WriteDataComplete(void)
+{
+ USBC_Writew((1<<USBC_BP_CSR0_D_TX_PKT_READY) | (1<<USBC_BP_CSR0_D_DATA_END),
+ USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_Tx_WriteDataComplete(void)
+{
+ USBC_Writeb((1 << USBC_BP_TXCSR_D_TX_READY), USBC_REG_TXCSR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Rx_ReadDataComplete(void)
+{
+ USBC_Writeb(0, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static u32 __USBC_Dev_Rx_IsReadDataReady(void)
+{
+ return USBC_REG_test_bit_w(USBC_BP_RXCSR_D_RX_PKT_READY, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+/* open a tx ep's interrupt */
+static void USBC_INT_EnableTxEp(u8 ep_index)
+{
+ USBC_REG_set_bit_w(ep_index, USBC_REG_INTTxE(USBC0_BASE));
+}
+
+/* open a rx ep's interrupt */
+static void USBC_INT_EnableRxEp(u8 ep_index)
+{
+ USBC_REG_set_bit_w(ep_index, USBC_REG_INTRxE(USBC0_BASE));
+}
+
+/* close a tx ep's interrupt */
+static void USBC_INT_DisableTxEp(u8 ep_index)
+{
+ USBC_REG_clear_bit_w(ep_index, USBC_REG_INTTxE(USBC0_BASE));
+}
+
+/* close a rx ep's interrupt */
+static void USBC_INT_DisableRxEp(u8 ep_index)
+{
+ USBC_REG_clear_bit_w(ep_index, USBC_REG_INTRxE(USBC0_BASE));
+}
+
+/*------------------------------------------------------------------
+ * INTERNAL FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+
+CFG_TUD_MEM_ALIGN static dcd_data_t _dcd;
+
+static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
+{
+ free_block_t *cur = beg;
+ for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ;
+ return cur;
+}
+
+static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size)
+{
+ free_block_t *p = find_containing_block(blks, blks + num, addr);
+ TU_ASSERT(p != blks + num, -2);
+ if (p->beg == addr) {
+ /* Shrink block */
+ p->beg = addr + size;
+ if (p->beg != p->end) return 0;
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ } else {
+ /* Split into 2 blocks */
+ free_block_t tmp = {
+ .beg = addr + size,
+ .end = p->end
+ };
+ p->end = addr;
+ if (p->beg == p->end) {
+ if (tmp.beg != tmp.end) {
+ *p = tmp;
+ return 0;
+ }
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ }
+ if (tmp.beg == tmp.end) return 0;
+ blks[num] = tmp;
+ return 1;
+ }
+}
+
+static inline unsigned free_block_size(free_block_t const *blk)
+{
+ return blk->end - blk->beg;
+}
+
+#if 0
+static inline void print_block_list(free_block_t const *blk, unsigned num)
+{
+ TU_LOG1("*************\r\n");
+ for (unsigned i = 0; i < num; ++i) {
+ TU_LOG1(" Blk%u %u %u\r\n", i, blk->beg, blk->end);
+ ++blk;
+ }
+}
+#else
+#define print_block_list(a,b)
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_F1C100S
+#define USB_FIFO_SIZE_KB 4
+#else
+#error "Unsupported MCU"
+#endif
+
+static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
+{
+ free_block_t free_blocks[2 * (TUP_DCD_ENDPOINT_MAX - 1)];
+ unsigned num_blocks = 1;
+ /* Backup current EP to restore later */
+ u8 backup_ep = USBC_GetActiveEp();
+
+ /* Initialize free memory block list */
+ free_blocks[0].beg = 64 / 8;
+ free_blocks[0].end = (USB_FIFO_SIZE_KB << 10) / 8; /* 2KiB / 8 bytes */
+ for (int i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
+ uint_fast16_t addr;
+ int num;
+ USBC_SelectActiveEp(i);
+ addr = USBC_Readw(USBC_REG_TXFIFOAD(USBC0_BASE));
+ if (addr) {
+ unsigned sz = USBC_Readb(USBC_REG_TXFIFOSZ(USBC0_BASE));
+ unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ print_block_list(free_blocks, num_blocks);
+ }
+ addr = USBC_Readw(USBC_REG_RXFIFOAD(USBC0_BASE));
+ if (addr) {
+ unsigned sz = USBC_Readb(USBC_REG_RXFIFOSZ(USBC0_BASE));
+ unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ print_block_list(free_blocks, num_blocks);
+ }
+ }
+ print_block_list(free_blocks, num_blocks);
+
+ USBC_SelectActiveEp(backup_ep);
+
+ /* Find the best fit memory block */
+ uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3;
+ free_block_t const *min = NULL;
+ uint_fast16_t min_sz = 0xFFFFu;
+ free_block_t const *end = &free_blocks[num_blocks];
+ for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) {
+ uint_fast16_t sz = free_block_size(cur);
+ if (sz < size_in_8byte_unit) continue;
+ if (size_in_8byte_unit == sz) return cur->beg;
+ if (sz < min_sz) min = cur;
+ }
+ TU_ASSERT(min, 0);
+ return min->beg;
+}
+
+static void pipe_write_packet(void *buff, volatile void *fifo, unsigned cnt)
+{
+ u32 len = 0;
+ u32 i32 = 0;
+ u32 i8 = 0;
+ u8 *buf8 = 0;
+ u32 *buf32 = 0;
+
+ //--<1>-- adjust data
+ buf32 = buff;
+ len = cnt;
+
+ i32 = len >> 2;
+ i8 = len & 0x03;
+
+ //--<2>-- deal with 4byte part
+ while (i32--) {
+ USBC_Writel(*buf32++, fifo);
+ }
+
+ //--<3>-- deal with no 4byte part
+ buf8 = (u8 *)buf32;
+ while (i8--) {
+ USBC_Writeb(*buf8++, fifo);
+ }
+}
+
+static void pipe_read_packet(void *buff, volatile void *fifo, unsigned cnt)
+{
+ u32 len = 0;
+ u32 i32 = 0;
+ u32 i8 = 0;
+ u8 *buf8 = 0;
+ u32 *buf32 = 0;
+
+ //--<1>-- adjust data
+ buf32 = buff;
+ len = cnt;
+
+ i32 = len >> 2;
+ i8 = len & 0x03;
+
+ //--<2>-- deal with 4byte part
+ while (i32--) {
+ *buf32++ = USBC_Readl(fifo);
+ }
+
+ //--<3>-- deal with no 4byte part
+ buf8 = (u8 *)buf32;
+ while (i8--) {
+ *buf8++ = USBC_Readb(fifo);
+ }
+}
+
+static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigned len, unsigned dir)
+{
+ static const struct {
+ void (*tu_fifo_get_info)(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
+ void (*tu_fifo_advance)(tu_fifo_t *f, uint16_t n);
+ void (*pipe_read_write)(void *buf, volatile void *fifo, unsigned len);
+ } ops[] = {
+ /* OUT */ {tu_fifo_get_write_info,tu_fifo_advance_write_pointer,pipe_read_packet},
+ /* IN */ {tu_fifo_get_read_info, tu_fifo_advance_read_pointer, pipe_write_packet},
+ };
+ tu_fifo_buffer_info_t info;
+ ops[dir].tu_fifo_get_info(f, &info);
+ unsigned total_len = len;
+ len = TU_MIN(total_len, info.len_lin);
+ ops[dir].pipe_read_write(info.ptr_lin, fifo, len);
+ unsigned rem = total_len - len;
+ if (rem) {
+ len = TU_MIN(rem, info.len_wrap);
+ ops[dir].pipe_read_write(info.ptr_wrap, fifo, len);
+ rem -= len;
+ }
+ ops[dir].tu_fifo_advance(f, total_len - rem);
+}
+
+/*------------------------------------------------------------------
+ * TRANSFER FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+
+static void process_setup_packet(uint8_t rhport)
+{
+ uint32_t *p = (uint32_t*)(uintptr_t) &_dcd.setup_packet;
+ p[0] = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
+ p[1] = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
+
+ _dcd.pipe0.buf = NULL;
+ _dcd.pipe0.length = 0;
+ _dcd.pipe0.remaining = 0;
+ dcd_event_setup_received(rhport, (const uint8_t*)(uintptr_t)&_dcd.setup_packet, true);
+
+ const unsigned len = _dcd.setup_packet.wLength;
+ _dcd.remaining_ctrl = len;
+ const unsigned dir_in = tu_edpt_dir(_dcd.setup_packet.bmRequestType);
+ /* Clear RX FIFO and reverse the transaction direction */
+ if (len && dir_in) __USBC_Dev_ep0_ReadDataHalf();
+}
+
+static bool handle_xfer_in(uint_fast8_t ep_addr)
+{
+ unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
+ const unsigned rem = pipe->remaining;
+
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+
+ const unsigned mps = USBC_Readw(USBC_REG_TXMAXP(USBC0_BASE));
+ const unsigned len = TU_MIN(mps, rem);
+ uint8_t *buf = pipe->buf;
+ // TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem);
+ if (len) {
+ volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
+ if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
+ pipe_read_write_packet_ff((tu_fifo_t *)(uintptr_t) buf, addr, len, TUSB_DIR_IN);
+ } else {
+ pipe_write_packet(buf, addr, len);
+ pipe->buf = buf + len;
+ }
+ pipe->remaining = rem - len;
+ }
+ __USBC_Dev_Tx_WriteDataComplete();
+ // TU_LOG1(" TXCSRL%d = %x %d\r\n", epnum_minus1 + 1, regs->TXCSRL, rem - len);
+ return false;
+}
+
+static bool handle_xfer_out(uint_fast8_t ep_addr)
+{
+ unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
+ // TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, regs->RXCSRL);
+
+ TU_ASSERT(__USBC_Dev_Rx_IsReadDataReady());
+
+ const unsigned mps = USBC_Readw(USBC_REG_RXMAXP(USBC0_BASE));
+ const unsigned rem = pipe->remaining;
+ const unsigned vld = USBC_Readw(USBC_REG_RXCOUNT(USBC0_BASE));
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ uint8_t *buf = pipe->buf;
+ if (len) {
+ volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
+ if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
+ pipe_read_write_packet_ff((tu_fifo_t *)(uintptr_t )buf, addr, len, TUSB_DIR_OUT);
+ } else {
+ pipe_read_packet(buf, addr, len);
+ pipe->buf = buf + len;
+ }
+ pipe->remaining = rem - len;
+ }
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return NULL != buf;
+ }
+ __USBC_Dev_Rx_ReadDataComplete();
+ return false;
+}
+
+static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+
+ unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ unsigned dir_in = tu_edpt_dir(ep_addr);
+
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][epnum_minus1];
+ pipe->buf = buffer;
+ pipe->length = total_bytes;
+ pipe->remaining = total_bytes;
+
+ USBC_SelectActiveEp(tu_edpt_number(ep_addr));
+
+ if (dir_in) {
+ handle_xfer_in(ep_addr);
+ } else {
+ if (__USBC_Dev_Rx_IsReadDataReady())
+ __USBC_Dev_Rx_ReadDataComplete();
+ }
+ return true;
+}
+
+static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+ TU_ASSERT(total_bytes <= 64); /* Current implementation supports for only up to 64 bytes. */
+
+ const unsigned req = _dcd.setup_packet.bmRequestType;
+ TU_ASSERT(req != REQUEST_TYPE_INVALID || total_bytes == 0);
+
+ USBC_SelectActiveEp(0);
+
+ if (req == REQUEST_TYPE_INVALID || _dcd.status_out) {
+ /* STATUS OUT stage.
+ * MUSB controller automatically handles STATUS OUT packets without
+ * software helps. We do not have to do anything. And STATUS stage
+ * may have already finished and received the next setup packet
+ * without calling this function, so we have no choice but to
+ * invoke the callback function of status packet here. */
+ // TU_LOG1(" STATUS OUT CSRL0 = %x\r\n", CSRL0);
+ _dcd.status_out = 0;
+ if (req == REQUEST_TYPE_INVALID) {
+ dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false);
+ } else {
+ /* The next setup packet has already been received, it aborts
+ * invoking callback function to avoid confusing TUSB stack. */
+ TU_LOG1("Drop CONTROL_STAGE_ACK\r\n");
+ }
+ return true;
+ }
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ if (tu_edpt_dir(req) == dir_in) { /* DATA stage */
+ TU_ASSERT(total_bytes <= _dcd.remaining_ctrl);
+ const unsigned rem = _dcd.remaining_ctrl;
+ const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes);
+ if (dir_in) {
+ pipe_write_packet(buffer, (volatile void*) USBC_REG_EPFIFO0(USBC0_BASE), len);
+
+ _dcd.pipe0.buf = buffer + len;
+ _dcd.pipe0.length = len;
+ _dcd.pipe0.remaining = 0;
+
+ _dcd.remaining_ctrl = rem - len;
+ if ((len < 64) || (rem == len)) {
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; /* Change to STATUS/SETUP stage */
+ _dcd.status_out = 1;
+ /* Flush TX FIFO and reverse the transaction direction. */
+ __USBC_Dev_ep0_WriteDataComplete();
+ } else {
+ __USBC_Dev_ep0_WriteDataHalf();
+ }
+ // TU_LOG1(" IN CSRL0 = %x\r\n", CSRL0);
+ } else {
+ // TU_LOG1(" OUT CSRL0 = %x\r\n", CSRL0);
+ _dcd.pipe0.buf = buffer;
+ _dcd.pipe0.length = len;
+ _dcd.pipe0.remaining = len;
+ __USBC_Dev_ep0_ReadDataHalf();
+ }
+ } else if (dir_in) {
+ // TU_LOG1(" STATUS IN CSRL0 = %x\r\n", CSRL0);
+ _dcd.pipe0.buf = NULL;
+ _dcd.pipe0.length = 0;
+ _dcd.pipe0.remaining = 0;
+ /* Clear RX FIFO and reverse the transaction direction */
+ __USBC_Dev_ep0_ReadDataComplete();
+ }
+ return true;
+}
+
+static void process_ep0(uint8_t rhport)
+{
+ USBC_SelectActiveEp(0);
+ uint_fast8_t csrl = USBC_Readw(USBC_REG_CSR0(USBC0_BASE));
+
+ // TU_LOG1(" EP0 CSRL0 = %x\r\n", csrl);
+
+ if (csrl & USB_CSRL0_STALLED) {
+ /* Returned STALL packet to HOST. */
+ __USBC_Dev_ep0_ClearStall();
+ return;
+ }
+
+ unsigned req = _dcd.setup_packet.bmRequestType;
+ if (csrl & USB_CSRL0_SETEND) {
+ // TU_LOG1(" ABORT by the next packets\r\n");
+ USBC_Dev_Ctrl_ClearSetupEnd();
+ if (req != REQUEST_TYPE_INVALID && _dcd.pipe0.buf) {
+ /* DATA stage was aborted by receiving STATUS or SETUP packet. */
+ _dcd.pipe0.buf = NULL;
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ dcd_event_xfer_complete(rhport,
+ req & TUSB_DIR_IN_MASK,
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+ req = REQUEST_TYPE_INVALID;
+ if (!(csrl & USB_CSRL0_RXRDY)) return; /* Received SETUP packet */
+ }
+
+ if (csrl & USB_CSRL0_RXRDY) {
+ /* Received SETUP or DATA OUT packet */
+ if (req == REQUEST_TYPE_INVALID) {
+ /* SETUP */
+ TU_ASSERT(sizeof(tusb_control_request_t) == USBC_Readw(USBC_REG_COUNT0(USBC0_BASE)),);
+ process_setup_packet(rhport);
+ return;
+ }
+ if (_dcd.pipe0.buf) {
+ /* DATA OUT */
+ const unsigned vld = USBC_Readw(USBC_REG_COUNT0(USBC0_BASE));
+ const unsigned rem = _dcd.pipe0.remaining;
+ const unsigned len = TU_MIN(TU_MIN(rem, 64), vld);
+ pipe_read_packet(_dcd.pipe0.buf, (volatile void*)USBC_REG_EPFIFO0(USBC0_BASE), len);
+
+ _dcd.pipe0.remaining = rem - len;
+ _dcd.remaining_ctrl -= len;
+
+ _dcd.pipe0.buf = NULL;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(0, TUSB_DIR_OUT),
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+ return;
+ }
+
+ /* When CSRL0 is zero, it means that completion of sending a any length packet
+ * or receiving a zero length packet. */
+ if (req != REQUEST_TYPE_INVALID && !tu_edpt_dir(req)) {
+ /* STATUS IN */
+ if (*(const uint16_t*)(uintptr_t)&_dcd.setup_packet == 0x0500) {
+ /* The address must be changed on completion of the control transfer. */
+ USBC_Dev_SetAddress((uint8_t)_dcd.setup_packet.wValue);
+ }
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(0, TUSB_DIR_IN),
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ return;
+ }
+ if (_dcd.pipe0.buf) {
+ /* DATA IN */
+ _dcd.pipe0.buf = NULL;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(0, TUSB_DIR_IN),
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_edpt_n(uint8_t rhport, uint_fast8_t ep_addr)
+{
+ bool completed;
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned epn = tu_edpt_number(ep_addr);
+
+ USBC_SelectActiveEp(epn);
+
+ if (dir_in) {
+ // TU_LOG1(" TXCSRL%d = %x\r\n", epn_minus1 + 1, regs->TXCSRL);
+ if (__USBC_Dev_Tx_IsEpStall()) {
+ __USBC_Dev_Tx_ClearStall();
+ return;
+ }
+ completed = handle_xfer_in(ep_addr);
+ } else {
+ // TU_LOG1(" RXCSRL%d = %x\r\n", epn_minus1 + 1, regs->RXCSRL);
+ if (__USBC_Dev_Rx_IsEpStall()) {
+ __USBC_Dev_Rx_ClearStall();
+ return;
+ }
+ completed = handle_xfer_out(ep_addr);
+ }
+
+ if (completed) {
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][tu_edpt_number(ep_addr) - 1];
+ dcd_event_xfer_complete(rhport, ep_addr,
+ pipe->length - pipe->remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+ /* When bmRequestType is REQUEST_TYPE_INVALID(0xFF),
+ * a control transfer state is SETUP or STATUS stage. */
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ _dcd.status_out = 0;
+ /* When pipe0.buf has not NULL, DATA stage works in progress. */
+ _dcd.pipe0.buf = NULL;
+
+ USBC_Writew(1, USBC_REG_INTTxE(USBC0_BASE)); /* Enable only EP0 */
+ USBC_Writew(0, USBC_REG_INTRxE(USBC0_BASE));
+
+ dcd_event_bus_reset(rhport, USBC_Dev_QueryTransferMode(), true);
+}
+
+/*------------------------------------------------------------------
+ * Device API
+ *------------------------------------------------------------------*/
+
+static void usb_isr_handler(void) {
+ dcd_int_handler(0);
+}
+
+void dcd_init(uint8_t rhport)
+{
+ dcd_disconnect(rhport);
+ USBC_HardwareReset();
+ USBC_PhyConfig();
+ USBC_ConfigFIFO_Base();
+ USBC_EnableDpDmPullUp();
+ USBC_ForceIdToHigh(); // Force device mode
+ USBC_ForceVbusValidToHigh();
+ USBC_SelectBus(USBC_IO_TYPE_PIO, 0, 0);
+ dcd_edpt_close_all(rhport);
+
+ #if TUD_OPT_HIGH_SPEED
+ USBC_REG_set_bit_b(USBC_BP_POWER_D_HIGH_SPEED_EN, USBC_REG_PCTL(USBC0_BASE));
+ #else
+ USBC_REG_clear_bit_b(USBC_BP_POWER_D_HIGH_SPEED_EN, USBC_REG_PCTL(USBC0_BASE));
+ #endif
+
+ USBC_Writeb((1 << USBC_BP_INTUSBE_EN_SUSPEND)
+ | (1 << USBC_BP_INTUSBE_EN_RESUME)
+ | (1 << USBC_BP_INTUSBE_EN_RESET)
+ | (1 << USBC_BP_INTUSBE_EN_SOF)
+ | (1 << USBC_BP_INTUSBE_EN_DISCONNECT)
+ , USBC_REG_INTUSBE(USBC0_BASE));
+ f1c100s_intc_clear_pend(F1C100S_IRQ_USBOTG);
+ f1c100s_intc_set_isr(F1C100S_IRQ_USBOTG, usb_isr_handler);
+
+ dcd_connect(rhport);
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ (void)rhport;
+ USBC_REG_set_bit_b(USBC_BP_POWER_D_SOFT_CONNECT, USBC_REG_PCTL(USBC0_BASE));
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ (void)rhport;
+ USBC_REG_clear_bit_b(USBC_BP_POWER_D_SOFT_CONNECT, USBC_REG_PCTL(USBC0_BASE));
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ f1c100s_intc_enable_irq(F1C100S_IRQ_USBOTG);
+}
+
+static void musb_int_mask(void)
+{
+ f1c100s_intc_mask_irq(F1C100S_IRQ_USBOTG);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ f1c100s_intc_disable_irq(F1C100S_IRQ_USBOTG);
+}
+
+static void musb_int_unmask(void)
+{
+ f1c100s_intc_unmask_irq(F1C100S_IRQ_USBOTG);
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ (void)dev_addr;
+ _dcd.pipe0.buf = NULL;
+ _dcd.pipe0.length = 0;
+ _dcd.pipe0.remaining = 0;
+ /* Clear RX FIFO to return ACK. */
+ USBC_SelectActiveEp(0);
+ __USBC_Dev_ep0_ReadDataComplete();
+}
+
+// Wake up host
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void)rhport;
+ USBC_REG_set_bit_b(USBC_BP_POWER_D_RESUME, USBC_REG_PCTL(USBC0_BASE));
+ delay_ms(10);
+ USBC_REG_clear_bit_b(USBC_BP_POWER_D_RESUME, USBC_REG_PCTL(USBC0_BASE));
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+#ifndef __ARMCC_VERSION
+#define __clz __builtin_clz
+#endif
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void) rhport;
+
+ uint16_t reg_val;
+
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ const unsigned mps = tu_edpt_packet_size(ep_desc);
+
+ TU_ASSERT(epn < TUP_DCD_ENDPOINT_MAX);
+
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+
+ musb_int_mask();
+
+ // volatile hw_endpoint_t *regs = edpt_regs(epn - 1);
+ USBC_SelectActiveEp(epn);
+ if (dir_in) {
+ USBC_Writew(mps, USBC_REG_TXMAXP(USBC0_BASE));
+
+ reg_val = (1 << USBC_BP_TXCSR_D_MODE)
+ | (1 << USBC_BP_TXCSR_D_FLUSH_FIFO)
+ | (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE);
+ if (xfer == TUSB_XFER_ISOCHRONOUS)
+ reg_val |= (1 << USBC_BP_TXCSR_D_ISO);
+ USBC_Writew(reg_val, USBC_REG_TXCSR(USBC0_BASE));
+
+ USBC_INT_EnableTxEp(epn);
+ } else {
+ USBC_Writew(mps, USBC_REG_RXMAXP(USBC0_BASE));
+
+ reg_val = (1 << USBC_BP_RXCSR_D_FLUSH_FIFO)
+ | (1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE);
+ if (xfer == TUSB_XFER_ISOCHRONOUS)
+ reg_val |= (1 << USBC_BP_RXCSR_D_ISO);
+ USBC_Writew(reg_val, USBC_REG_RXCSR(USBC0_BASE));
+
+ USBC_INT_EnableRxEp(epn);
+ }
+
+ /* Setup FIFO */
+ int size_in_log2_minus3 = 28 - TU_MIN(28, __clz((uint32_t)mps));
+ if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3;
+ unsigned addr = find_free_memory(size_in_log2_minus3);
+ TU_ASSERT(addr);
+
+ if (dir_in) {
+ USBC_Writew(addr, USBC_REG_TXFIFOAD(USBC0_BASE));
+ USBC_Writeb(size_in_log2_minus3, USBC_REG_TXFIFOSZ(USBC0_BASE));
+ } else {
+ USBC_Writew(addr, USBC_REG_RXFIFOAD(USBC0_BASE));
+ USBC_Writeb(size_in_log2_minus3, USBC_REG_RXFIFOSZ(USBC0_BASE));
+ }
+
+ musb_int_unmask();
+
+ return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ (void) rhport;
+ musb_int_mask();
+ USBC_Writew(1, USBC_REG_INTTxE(USBC0_BASE)); /* Enable only EP0 */
+ USBC_Writew(0, USBC_REG_INTRxE(USBC0_BASE));
+ for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
+ USBC_SelectActiveEp(i);
+ USBC_Writew(0, USBC_REG_TXMAXP(USBC0_BASE));
+ USBC_Writew((1 << USBC_BP_TXCSR_D_MODE) | (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_TXCSR_D_FLUSH_FIFO),
+ USBC_REG_TXCSR(USBC0_BASE));
+
+ USBC_Writew(0, USBC_REG_RXMAXP(USBC0_BASE));
+ USBC_Writew((1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_RXCSR_D_FLUSH_FIFO),
+ USBC_REG_RXCSR(USBC0_BASE));
+
+ USBC_Writew(0, USBC_REG_TXFIFOAD(USBC0_BASE));
+ USBC_Writeb(0, USBC_REG_TXFIFOSZ(USBC0_BASE));
+ USBC_Writew(0, USBC_REG_RXFIFOAD(USBC0_BASE));
+ USBC_Writeb(0, USBC_REG_RXFIFOSZ(USBC0_BASE));
+ }
+ musb_int_unmask();
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ unsigned const dir_in = tu_edpt_dir(ep_addr);
+
+ musb_int_mask();
+ USBC_SelectActiveEp(epn);
+ if (dir_in) {
+ USBC_INT_DisableTxEp(epn);
+ USBC_Writew(0, USBC_REG_TXMAXP(USBC0_BASE));
+ USBC_Writew((1 << USBC_BP_TXCSR_D_MODE) | (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_TXCSR_D_FLUSH_FIFO),
+ USBC_REG_TXCSR(USBC0_BASE));
+
+ USBC_Writew(0, USBC_REG_TXFIFOAD(USBC0_BASE));
+ USBC_Writeb(0, USBC_REG_TXFIFOSZ(USBC0_BASE));
+ } else {
+ USBC_INT_DisableRxEp(epn);
+ USBC_Writew(0, USBC_REG_RXMAXP(USBC0_BASE));
+ USBC_Writew((1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_RXCSR_D_FLUSH_FIFO),
+ USBC_REG_RXCSR(USBC0_BASE));
+
+ USBC_Writew(0, USBC_REG_RXFIFOAD(USBC0_BASE));
+ USBC_Writeb(0, USBC_REG_RXFIFOSZ(USBC0_BASE));
+ }
+ musb_int_unmask();
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+ bool ret;
+ // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes);
+ unsigned const epnum = tu_edpt_number(ep_addr);
+ musb_int_mask();
+
+ if (epnum) {
+ _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] &= ~TU_BIT(epnum - 1);
+ ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes);
+ } else {
+ ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes);
+ }
+ musb_int_unmask();
+ return ret;
+}
+
+// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+ (void)rhport;
+ bool ret;
+ // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes);
+ unsigned const epnum = tu_edpt_number(ep_addr);
+ TU_ASSERT(epnum);
+
+ musb_int_mask();
+ _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] |= TU_BIT(epnum - 1);
+ ret = edpt_n_xfer(rhport, ep_addr, (uint8_t*)ff, total_bytes);
+ musb_int_unmask();
+
+ return ret;
+}
+
+// Stall endpoint
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ musb_int_mask();
+ USBC_SelectActiveEp(epn);
+ if (0 == epn) {
+ if (!ep_addr) { /* Ignore EP80 */
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ _dcd.pipe0.buf = NULL;
+ __USBC_Dev_ep0_SendStall();
+ }
+ } else {
+ if (tu_edpt_dir(ep_addr)) { /* IN */
+ __USBC_Dev_Tx_SendStall();
+ } else { /* OUT */
+ TU_ASSERT(!__USBC_Dev_Rx_IsReadDataReady(),);
+ __USBC_Dev_Rx_SendStall();
+ }
+ }
+ musb_int_unmask();
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ musb_int_mask();
+ USBC_SelectActiveEp(epn);
+ if (0 != epn) {
+ if (tu_edpt_dir(ep_addr)) { /* IN */
+ __USBC_Dev_Tx_ClearStall();
+ } else { /* OUT */
+ __USBC_Dev_Rx_ClearStall();
+ }
+ }
+ musb_int_unmask();
+}
+
+
+void dcd_int_handler(uint8_t rhport)
+{
+ uint8_t is;
+ uint16_t txis, rxis;
+
+ is = USBC_Readb(USBC_REG_INTUSB(USBC0_BASE)); /* read interrupt status */
+ txis = USBC_Readw(USBC_REG_INTTx(USBC0_BASE)); /* read interrupt status */
+ rxis = USBC_Readw(USBC_REG_INTRx(USBC0_BASE)); /* read interrupt status */
+
+ is &= USBC_Readb(USBC_REG_INTUSBE(USBC0_BASE)); /* ignore disabled interrupts */
+ USBC_Writeb(is, USBC_REG_INTUSB(USBC0_BASE)); /* sunxi musb requires a write to interrupt register to clear */
+ if (is & USBC_INTUSB_DISCONNECT) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+ }
+ if (is & USBC_INTUSB_SOF) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
+ if (is & USBC_INTUSB_RESET) {
+ /* ep0 FADDR must be 0 when (re)entering peripheral mode */
+ USBC_SelectActiveEp(0);
+ USBC_Dev_SetAddress(0);
+ process_bus_reset(rhport);
+ }
+ if (is & USBC_INTUSB_RESUME) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+ }
+ if (is & USBC_INTUSB_SUSPEND) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+ }
+
+ txis &= USBC_Readw(USBC_REG_INTTxE(USBC0_BASE));
+ USBC_Writew(txis, USBC_REG_INTTx(USBC0_BASE));
+ if (txis & USBC_INTTx_FLAG_EP0) {
+ process_ep0(rhport);
+ txis &= ~TU_BIT(0);
+ }
+ while (txis) {
+ unsigned const num = __builtin_ctz(txis);
+ process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_IN));
+ txis &= ~TU_BIT(num);
+ }
+
+ rxis &= USBC_Readw(USBC_REG_INTRxE(USBC0_BASE));
+ USBC_Writew(rxis, USBC_REG_INTRx(USBC0_BASE));
+ while (rxis) {
+ unsigned const num = __builtin_ctz(rxis);
+ process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_OUT));
+ rxis &= ~TU_BIT(num);
+ }
+}
+
+#endif
diff --git a/src/portable/sunxi/musb_def.h b/src/portable/sunxi/musb_def.h
new file mode 100644
index 000000000..53da5ded2
--- /dev/null
+++ b/src/portable/sunxi/musb_def.h
@@ -0,0 +1,643 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ * Copyright (c) 2021 Tian Yunhao (t123yh)
+ * Copyright (c) 2021 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_MUSB_DEF
+#define _TUSB_MUSB_DEF
+
+
+#define USBC_Readb(reg) (*(volatile unsigned char *)(reg))
+#define USBC_Readw(reg) (*(volatile unsigned short *)(reg))
+#define USBC_Readl(reg) (*(volatile unsigned long *)(reg))
+
+#define USBC_Writeb(value, reg) (*(volatile unsigned char *)(reg) = (value))
+#define USBC_Writew(value, reg) (*(volatile unsigned short *)(reg) = (value))
+#define USBC_Writel(value, reg) (*(volatile unsigned long *)(reg) = (value))
+
+
+#define USBC_SetBit_Mask_b(reg,mask) do { \
+ unsigned char _r = USBC_Readb(reg); \
+ _r |= (unsigned char)(mask); \
+ USBC_Writeb(_r,reg); \
+ }while(0)
+#define USBC_SetBit_Mask_w(reg,mask) do { \
+ unsigned short _r = USBC_Readw(reg); \
+ _r |= (unsigned short)(mask); \
+ USBC_Writew(_r,reg); \
+ }while(0)
+#define USBC_SetBit_Mask_l(reg,mask) do { \
+ unsigned int _r = USBC_Readl(reg); \
+ _r |= (unsigned int)(mask); \
+ USBC_Writel(_r,reg); \
+ }while(0)
+
+
+#define USBC_ClrBit_Mask_b(reg,mask) do { \
+ unsigned char _r = USBC_Readb(reg); \
+ _r &= (~(unsigned char)(mask)); \
+ USBC_Writeb(_r,reg); \
+ }while(0);
+#define USBC_ClrBit_Mask_w(reg,mask) do { \
+ unsigned short _r = USBC_Readw(reg); \
+ _r &= (~(unsigned short)(mask)); \
+ USBC_Writew(_r,reg); \
+ }while(0)
+#define USBC_ClrBit_Mask_l(reg,mask) do { \
+ unsigned int _r = USBC_Readl(reg); \
+ _r &= (~(unsigned int)(mask)); \
+ USBC_Writel(_r,reg); \
+ }while(0)
+#define USBC_REG_test_bit_b(bp, reg) (USBC_Readb(reg) & (1 << (bp)))
+#define USBC_REG_test_bit_w(bp, reg) (USBC_Readw(reg) & (1 << (bp)))
+#define USBC_REG_test_bit_l(bp, reg) (USBC_Readl(reg) & (1 << (bp)))
+
+#define USBC_REG_set_bit_b(bp, reg) (USBC_Writeb((USBC_Readb(reg) | (1 << (bp))) , (reg)))
+#define USBC_REG_set_bit_w(bp, reg) (USBC_Writew((USBC_Readw(reg) | (1 << (bp))) , (reg)))
+#define USBC_REG_set_bit_l(bp, reg) (USBC_Writel((USBC_Readl(reg) | (1 << (bp))) , (reg)))
+
+#define USBC_REG_clear_bit_b(bp, reg) (USBC_Writeb((USBC_Readb(reg) & (~ (1 << (bp)))) , (reg)))
+#define USBC_REG_clear_bit_w(bp, reg) (USBC_Writew((USBC_Readw(reg) & (~ (1 << (bp)))) , (reg)))
+#define USBC_REG_clear_bit_l(bp, reg) (USBC_Writel((USBC_Readl(reg) & (~ (1 << (bp)))) , (reg)))
+
+#define SW_UDC_EPNUMS 3
+
+#define SUNXI_SRAMC_BASE 0x01c00000
+//---------------------------------------------------------------
+// reg base
+//---------------------------------------------------------------
+#define USBC0_BASE 0x01c13000
+#define USBC1_BASE 0x01c14000
+#define USBC2_BASE 0x01c1E000
+
+//Some reg within musb
+#define USBPHY_CLK_REG 0x01c200CC
+#define USBPHY_CLK_RST_BIT 0
+#define USBPHY_CLK_GAT_BIT 1
+
+#define BUS_CLK_RST_REG 0x01c202c0 //Bus Clock Reset Register Bit24 : USB CLK RST
+#define BUS_RST_USB_BIT 24
+
+#define BUS_CLK_GATE0_REG 0x01c20060 //Bus Clock Gating Register Bit24 : USB CLK GATE 0: Mask 1 : Pass
+#define BUS_CLK_USB_BIT 24
+
+//#define USB_INTR
+
+#define NDMA_CFG_REG
+//-----------------------------------------------------------------------
+// musb reg offset
+//-----------------------------------------------------------------------
+
+#define USBC_REG_o_FADDR 0x0098
+#define USBC_REG_o_PCTL 0x0040
+#define USBC_REG_o_INTTx 0x0044
+#define USBC_REG_o_INTRx 0x0046
+#define USBC_REG_o_INTTxE 0x0048
+#define USBC_REG_o_INTRxE 0x004A
+#define USBC_REG_o_INTUSB 0x004C
+#define USBC_REG_o_INTUSBE 0x0050
+#define USBC_REG_o_FRNUM 0x0054
+#define USBC_REG_o_EPIND 0x0042
+#define USBC_REG_o_TMCTL 0x007C
+
+#define USBC_REG_o_TXMAXP 0x0080
+#define USBC_REG_o_CSR0 0x0082
+#define USBC_REG_o_TXCSR 0x0082
+#define USBC_REG_o_RXMAXP 0x0084
+#define USBC_REG_o_RXCSR 0x0086
+#define USBC_REG_o_COUNT0 0x0088
+#define USBC_REG_o_RXCOUNT 0x0088
+#define USBC_REG_o_EP0TYPE 0x008C
+#define USBC_REG_o_TXTYPE 0x008C
+#define USBC_REG_o_NAKLIMIT0 0x008D
+#define USBC_REG_o_TXINTERVAL 0x008D
+#define USBC_REG_o_RXTYPE 0x008E
+#define USBC_REG_o_RXINTERVAL 0x008F
+
+//#define USBC_REG_o_CONFIGDATA 0x001F //
+
+#define USBC_REG_o_EPFIFO0 0x0000
+#define USBC_REG_o_EPFIFO1 0x0004
+#define USBC_REG_o_EPFIFO2 0x0008
+#define USBC_REG_o_EPFIFO3 0x000C
+#define USBC_REG_o_EPFIFO4 0x0010
+#define USBC_REG_o_EPFIFO5 0x0014
+#define USBC_REG_o_EPFIFOx(n) (0x0000 + (n<<2))
+
+#define USBC_REG_o_DEVCTL 0x0041
+
+#define USBC_REG_o_TXFIFOSZ 0x0090
+#define USBC_REG_o_RXFIFOSZ 0x0094
+#define USBC_REG_o_TXFIFOAD 0x0092
+#define USBC_REG_o_RXFIFOAD 0x0096
+
+#define USBC_REG_o_VEND0 0x0043
+#define USBC_REG_o_VEND1 0x007D
+#define USBC_REG_o_VEND3 0x007E
+
+//#define USBC_REG_o_PHYCTL 0x006C
+#define USBC_REG_o_EPINFO 0x0078
+#define USBC_REG_o_RAMINFO 0x0079
+#define USBC_REG_o_LINKINFO 0x007A
+#define USBC_REG_o_VPLEN 0x007B
+#define USBC_REG_o_HSEOF 0x007C
+#define USBC_REG_o_FSEOF 0x007D
+#define USBC_REG_o_LSEOF 0x007E
+
+//new
+#define USBC_REG_o_FADDR0 0x0098
+#define USBC_REG_o_HADDR0 0x009A
+#define USBC_REG_o_HPORT0 0x009B
+#define USBC_REG_o_TXFADDRx 0x0098
+#define USBC_REG_o_TXHADDRx 0x009A
+#define USBC_REG_o_TXHPORTx 0x009B
+#define USBC_REG_o_RXFADDRx 0x009C
+#define USBC_REG_o_RXHADDRx 0x009E
+#define USBC_REG_o_RXHPORTx 0x009F
+
+
+#define USBC_REG_o_RPCOUNT 0x008A
+
+//new
+#define USBC_REG_o_ISCR 0x0400
+#define USBC_REG_o_PHYCTL 0x0404
+#define USBC_REG_o_PHYBIST 0x0408
+#define USBC_REG_o_PHYTUNE 0x040c
+
+#define USBC_REG_o_CSR 0x0410
+
+#define USBC_REG_o_PMU_IRQ 0x0800
+
+//-----------------------------------------------------------------------
+// registers
+//-----------------------------------------------------------------------
+
+#define USBC_REG_FADDR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_FADDR )
+#define USBC_REG_PCTL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PCTL )
+#define USBC_REG_INTTx(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTTx )
+#define USBC_REG_INTRx(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTRx )
+#define USBC_REG_INTTxE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTTxE )
+#define USBC_REG_INTRxE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTRxE )
+#define USBC_REG_INTUSB(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTUSB )
+#define USBC_REG_INTUSBE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTUSBE )
+#define USBC_REG_FRNUM(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_FRNUM )
+#define USBC_REG_EPIND(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPIND )
+#define USBC_REG_TMCTL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TMCTL )
+#define USBC_REG_TXMAXP(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXMAXP )
+
+#define USBC_REG_CSR0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_CSR0 )
+#define USBC_REG_TXCSR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXCSR )
+
+#define USBC_REG_RXMAXP(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXMAXP )
+#define USBC_REG_RXCSR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXCSR )
+
+#define USBC_REG_COUNT0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_COUNT0 )
+#define USBC_REG_RXCOUNT(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXCOUNT )
+
+#define USBC_REG_EP0TYPE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EP0TYPE )
+#define USBC_REG_TXTYPE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXTYPE )
+
+#define USBC_REG_NAKLIMIT0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_NAKLIMIT0 )
+#define USBC_REG_TXINTERVAL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXINTERVAL )
+
+#define USBC_REG_RXTYPE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXTYPE )
+#define USBC_REG_RXINTERVAL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXINTERVAL )
+//#define USBC_REG_CONFIGDATA(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_CONFIGDATA )
+#define USBC_REG_EPFIFO0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO0 )
+#define USBC_REG_EPFIFO1(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO1 )
+#define USBC_REG_EPFIFO2(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO2 )
+#define USBC_REG_EPFIFO3(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO3 )
+#define USBC_REG_EPFIFO4(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO4 )
+#define USBC_REG_EPFIFO5(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO5 )
+#define USBC_REG_EPFIFOx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_EPFIFOx(n) )
+#define USBC_REG_DEVCTL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_DEVCTL )
+#define USBC_REG_TXFIFOSZ(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXFIFOSZ )
+#define USBC_REG_RXFIFOSZ(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXFIFOSZ )
+#define USBC_REG_TXFIFOAD(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXFIFOAD )
+#define USBC_REG_RXFIFOAD(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXFIFOAD )
+#define USBC_REG_VEND0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_VEND0 )
+#define USBC_REG_VEND1(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_VEND1 )
+#define USBC_REG_EPINFO(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPINFO )
+#define USBC_REG_RAMINFO(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RAMINFO )
+#define USBC_REG_LINKINFO(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_LINKINFO )
+#define USBC_REG_VPLEN(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_VPLEN )
+#define USBC_REG_HSEOF(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_HSEOF )
+#define USBC_REG_FSEOF(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_FSEOF )
+#define USBC_REG_LSEOF(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_LSEOF )
+
+#define USBC_REG_FADDR0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_FADDR0 )
+#define USBC_REG_HADDR0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_HADDR0 )
+#define USBC_REG_HPORT0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_HPORT0 )
+
+#define USBC_REG_TXFADDRx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_TXFADDRx )
+#define USBC_REG_TXHADDRx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_TXHADDRx )
+#define USBC_REG_TXHPORTx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_TXHPORTx )
+#define USBC_REG_RXFADDRx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_RXFADDRx )
+#define USBC_REG_RXHADDRx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_RXHADDRx )
+#define USBC_REG_RXHPORTx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_RXHPORTx )
+
+#define USBC_REG_RPCOUNTx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_RPCOUNT )
+
+#define USBC_REG_ISCR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_ISCR )
+#define USBC_REG_PHYCTL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PHYCTL )
+#define USBC_REG_PHYBIST(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PHYBIST )
+#define USBC_REG_PHYTUNE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PHYTUNE )
+#define USBC_REG_PMU_IRQ(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PMU_IRQ )
+#define USBC_REG_CSR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_CSR)
+//-----------------------------------------------------------------------
+// bit position
+//-----------------------------------------------------------------------
+
+/* USB Power Control for Host only */
+#define USBC_BP_POWER_H_HIGH_SPEED_EN 5
+#define USBC_BP_POWER_H_HIGH_SPEED_FLAG 4
+#define USBC_BP_POWER_H_RESET 3
+#define USBC_BP_POWER_H_RESUME 2
+#define USBC_BP_POWER_H_SUSPEND 1
+#define USBC_BP_POWER_H_SUEPEND_EN 0
+
+/* USB Power Control for device only */
+#define USBC_BP_POWER_D_ISO_UPDATE_EN 7
+#define USBC_BP_POWER_D_SOFT_CONNECT 6
+#define USBC_BP_POWER_D_HIGH_SPEED_EN 5
+#define USBC_BP_POWER_D_HIGH_SPEED_FLAG 4
+#define USBC_BP_POWER_D_RESET_FLAG 3
+#define USBC_BP_POWER_D_RESUME 2
+#define USBC_BP_POWER_D_SUSPEND 1
+#define USBC_BP_POWER_D_ENABLE_SUSPENDM 0
+
+/* interrupt flags for ep0 and the Tx ep1~4 */
+#define USBC_BP_INTTx_FLAG_EP5 5
+#define USBC_BP_INTTx_FLAG_EP4 4
+#define USBC_BP_INTTx_FLAG_EP3 3
+#define USBC_BP_INTTx_FLAG_EP2 2
+#define USBC_BP_INTTx_FLAG_EP1 1
+#define USBC_BP_INTTx_FLAG_EP0 0
+
+/* interrupt flags for Rx ep1~4 */
+#define USBC_BP_INTRx_FLAG_EP5 5
+#define USBC_BP_INTRx_FLAG_EP4 4
+#define USBC_BP_INTRx_FLAG_EP3 3
+#define USBC_BP_INTRx_FLAG_EP2 2
+#define USBC_BP_INTRx_FLAG_EP1 1
+
+/* interrupt enable for Tx ep0~4 */
+#define USBC_BP_INTTxE_EN_EP5 5
+#define USBC_BP_INTTxE_EN_EP4 4
+#define USBC_BP_INTTxE_EN_EP3 3
+#define USBC_BP_INTTxE_EN_EP2 2
+#define USBC_BP_INTTxE_EN_EP1 1
+#define USBC_BP_INTTxE_EN_EP0 0
+
+/* interrupt enable for Rx ep1~4 */
+#define USBC_BP_INTRxE_EN_EP5 5
+#define USBC_BP_INTRxE_EN_EP4 4
+#define USBC_BP_INTRxE_EN_EP3 3
+#define USBC_BP_INTRxE_EN_EP2 2
+#define USBC_BP_INTRxE_EN_EP1 1
+
+/* USB interrupt */
+#define USBC_BP_INTUSB_VBUS_ERROR 7
+#define USBC_BP_INTUSB_SESSION_REQ 6
+#define USBC_BP_INTUSB_DISCONNECT 5
+#define USBC_BP_INTUSB_CONNECT 4
+#define USBC_BP_INTUSB_SOF 3
+#define USBC_BP_INTUSB_RESET 2
+#define USBC_BP_INTUSB_RESUME 1
+#define USBC_BP_INTUSB_SUSPEND 0
+
+/* USB interrupt enable */
+#define USBC_BP_INTUSBE_EN_VBUS_ERROR 7
+#define USBC_BP_INTUSBE_EN_SESSION_REQ 6
+#define USBC_BP_INTUSBE_EN_DISCONNECT 5
+#define USBC_BP_INTUSBE_EN_CONNECT 4
+#define USBC_BP_INTUSBE_EN_SOF 3
+#define USBC_BP_INTUSBE_EN_RESET 2
+#define USBC_BP_INTUSBE_EN_RESUME 1
+#define USBC_BP_INTUSBE_EN_SUSPEND 0
+
+/* Test Mode Control */
+#define USBC_BP_TMCTL_FORCE_HOST 7
+#define USBC_BP_TMCTL_FIFO_ACCESS 6
+#define USBC_BP_TMCTL_FORCE_FS 5
+#define USBC_BP_TMCTL_FORCE_HS 4
+#define USBC_BP_TMCTL_TEST_PACKET 3
+#define USBC_BP_TMCTL_TEST_K 2
+#define USBC_BP_TMCTL_TEST_J 1
+#define USBC_BP_TMCTL_TEST_SE0_NAK 0
+
+/* Tx Max packet */
+#define USBC_BP_TXMAXP_PACKET_COUNT 11
+#define USBC_BP_TXMAXP_MAXIMUM_PAYLOAD 0
+
+/* Control and Status Register for ep0 for Host only */
+#define USBC_BP_CSR0_H_DisPing 11
+#define USBC_BP_CSR0_H_FlushFIFO 8
+#define USBC_BP_CSR0_H_NAK_Timeout 7
+#define USBC_BP_CSR0_H_StatusPkt 6
+#define USBC_BP_CSR0_H_ReqPkt 5
+#define USBC_BP_CSR0_H_Error 4
+#define USBC_BP_CSR0_H_SetupPkt 3
+#define USBC_BP_CSR0_H_RxStall 2
+#define USBC_BP_CSR0_H_TxPkRdy 1
+#define USBC_BP_CSR0_H_RxPkRdy 0
+
+/* Control and Status Register for ep0 for device only */
+#define USBC_BP_CSR0_D_FLUSH_FIFO 8
+#define USBC_BP_CSR0_D_SERVICED_SETUP_END 7
+#define USBC_BP_CSR0_D_SERVICED_RX_PKT_READY 6
+#define USBC_BP_CSR0_D_SEND_STALL 5
+#define USBC_BP_CSR0_D_SETUP_END 4
+#define USBC_BP_CSR0_D_DATA_END 3
+#define USBC_BP_CSR0_D_SENT_STALL 2
+#define USBC_BP_CSR0_D_TX_PKT_READY 1
+#define USBC_BP_CSR0_D_RX_PKT_READY 0
+
+/* Tx ep Control and Status Register for Host only */
+#define USBC_BP_TXCSR_H_AUTOSET 15
+#define USBC_BP_TXCSR_H_RESERVED 14
+#define USBC_BP_TXCSR_H_MODE 13
+#define USBC_BP_TXCSR_H_DMA_REQ_EN 12
+#define USBC_BP_TXCSR_H_FORCE_DATA_TOGGLE 11
+#define USBC_BP_TXCSR_H_DMA_REQ_MODE 10
+#define USBC_BP_TXCSR_H_NAK_TIMEOUT 7
+#define USBC_BP_TXCSR_H_CLEAR_DATA_TOGGLE 6
+#define USBC_BP_TXCSR_H_TX_STALL 5
+#define USBC_BP_TXCSR_H_FLUSH_FIFO 3
+#define USBC_BP_TXCSR_H_ERROR 2
+#define USBC_BP_TXCSR_H_FIFO_NOT_EMPTY 1
+#define USBC_BP_TXCSR_H_TX_READY 0
+
+/* Tx ep Control and Status Register for Device only */
+#define USBC_BP_TXCSR_D_AUTOSET 15
+#define USBC_BP_TXCSR_D_ISO 14
+#define USBC_BP_TXCSR_D_MODE 13
+#define USBC_BP_TXCSR_D_DMA_REQ_EN 12
+#define USBC_BP_TXCSR_D_FORCE_DATA_TOGGLE 11
+#define USBC_BP_TXCSR_D_DMA_REQ_MODE 10
+#define USBC_BP_TXCSR_D_INCOMPLETE 7
+#define USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE 6
+#define USBC_BP_TXCSR_D_SENT_STALL 5
+#define USBC_BP_TXCSR_D_SEND_STALL 4
+#define USBC_BP_TXCSR_D_FLUSH_FIFO 3
+#define USBC_BP_TXCSR_D_UNDER_RUN 2
+#define USBC_BP_TXCSR_D_FIFO_NOT_EMPTY 1
+#define USBC_BP_TXCSR_D_TX_READY 0
+
+/* Rx Max Packet */
+#define USBC_BP_RXMAXP_PACKET_COUNT 11
+#define USBC_BP_RXMAXP_MAXIMUM_PAYLOAD 0
+
+/* Rx ep Control and Status Register for Host only */
+#define USBC_BP_RXCSR_H_AUTO_CLEAR 15
+#define USBC_BP_RXCSR_H_AUTO_REQ 14
+#define USBC_BP_RXCSR_H_DMA_REQ_EN 13
+#define USBC_BP_RXCSR_H_PID_ERROR 12
+#define USBC_BP_RXCSR_H_DMA_REQ_MODE 11
+
+#define USBC_BP_RXCSR_H_INCOMPLETE 8
+#define USBC_BP_RXCSR_H_CLEAR_DATA_TOGGLE 7
+#define USBC_BP_RXCSR_H_RX_STALL 6
+#define USBC_BP_RXCSR_H_REQ_PACKET 5
+#define USBC_BP_RXCSR_H_FLUSH_FIFO 4
+#define USBC_BP_RXCSR_H_NAK_TIMEOUT 3
+#define USBC_BP_RXCSR_H_ERROR 2
+#define USBC_BP_RXCSR_H_FIFO_FULL 1
+#define USBC_BP_RXCSR_H_RX_PKT_READY 0
+
+/* Rx ep Control and Status Register for Device only */
+#define USBC_BP_RXCSR_D_AUTO_CLEAR 15
+#define USBC_BP_RXCSR_D_ISO 14
+#define USBC_BP_RXCSR_D_DMA_REQ_EN 13
+#define USBC_BP_RXCSR_D_DISABLE_NYET 12
+#define USBC_BP_RXCSR_D_DMA_REQ_MODE 11
+
+#define USBC_BP_RXCSR_D_INCOMPLETE 8
+#define USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE 7
+#define USBC_BP_RXCSR_D_SENT_STALL 6
+#define USBC_BP_RXCSR_D_SEND_STALL 5
+#define USBC_BP_RXCSR_D_FLUSH_FIFO 4
+#define USBC_BP_RXCSR_D_DATA_ERROR 3
+#define USBC_BP_RXCSR_D_OVERRUN 2
+#define USBC_BP_RXCSR_D_FIFO_FULL 1
+#define USBC_BP_RXCSR_D_RX_PKT_READY 0
+
+/* Tx Type Register for host only */
+#define USBC_BP_TXTYPE_SPEED 6 //new
+#define USBC_BP_TXTYPE_PROROCOL 4
+#define USBC_BP_TXTYPE_TARGET_EP_NUM 0
+
+/* Rx Type Register for host only */
+#define USBC_BP_RXTYPE_SPEED 6 //new
+#define USBC_BP_RXTYPE_PROROCOL 4
+#define USBC_BP_RXTYPE_TARGET_EP_NUM 0
+
+/* Core Configueation */
+#define USBC_BP_CONFIGDATA_MPRXE 7
+#define USBC_BP_CONFIGDATA_MPTXE 6
+#define USBC_BP_CONFIGDATA_BIGENDIAN 5
+#define USBC_BP_CONFIGDATA_HBRXE 4
+#define USBC_BP_CONFIGDATA_HBTXE 3
+#define USBC_BP_CONFIGDATA_DYNFIFO_SIZING 2
+#define USBC_BP_CONFIGDATA_SOFTCONE 1
+#define USBC_BP_CONFIGDATA_UTMI_DATAWIDTH 0
+
+/* OTG Device Control */
+#define USBC_BP_DEVCTL_B_DEVICE 7
+#define USBC_BP_DEVCTL_FS_DEV 6
+#define USBC_BP_DEVCTL_LS_DEV 5
+
+#define USBC_BP_DEVCTL_VBUS 3
+#define USBC_BP_DEVCTL_HOST_MODE 2
+#define USBC_BP_DEVCTL_HOST_REQ 1
+#define USBC_BP_DEVCTL_SESSION 0
+
+/* Tx EP FIFO size control */
+#define USBC_BP_TXFIFOSZ_DPB 4
+#define USBC_BP_TXFIFOSZ_SZ 0
+
+/* Rx EP FIFO size control */
+#define USBC_BP_RXFIFOSZ_DPB 4
+#define USBC_BP_RXFIFOSZ_SZ 0
+
+/* vendor0 */
+#define USBC_BP_VEND0_DRQ_SEL 1
+#define USBC_BP_VEND0_BUS_SEL 0
+
+/* hub address */
+#define USBC_BP_HADDR_MULTI_TT 7
+
+/* Interface Status and Control */
+#define USBC_BP_ISCR_VBUS_VALID_FROM_DATA 30
+#define USBC_BP_ISCR_VBUS_VALID_FROM_VBUS 29
+#define USBC_BP_ISCR_EXT_ID_STATUS 28
+#define USBC_BP_ISCR_EXT_DM_STATUS 27
+#define USBC_BP_ISCR_EXT_DP_STATUS 26
+#define USBC_BP_ISCR_MERGED_VBUS_STATUS 25
+#define USBC_BP_ISCR_MERGED_ID_STATUS 24
+
+#define USBC_BP_ISCR_ID_PULLUP_EN 17
+#define USBC_BP_ISCR_DPDM_PULLUP_EN 16
+#define USBC_BP_ISCR_FORCE_ID 14
+#define USBC_BP_ISCR_FORCE_VBUS_VALID 12
+#define USBC_BP_ISCR_VBUS_VALID_SRC 10
+
+#define USBC_BP_ISCR_HOSC_EN 7
+#define USBC_BP_ISCR_VBUS_CHANGE_DETECT 6
+#define USBC_BP_ISCR_ID_CHANGE_DETECT 5
+#define USBC_BP_ISCR_DPDM_CHANGE_DETECT 4
+#define USBC_BP_ISCR_IRQ_ENABLE 3
+#define USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN 2
+#define USBC_BP_ISCR_ID_CHANGE_DETECT_EN 1
+#define USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN 0
+
+
+#define SUNXI_EHCI_AHB_ICHR8_EN (1 << 10)
+#define SUNXI_EHCI_AHB_INCR4_BURST_EN (1 << 9)
+#define SUNXI_EHCI_AHB_INCRX_ALIGN_EN (1 << 8)
+#define SUNXI_EHCI_ULPI_BYPASS_EN (1 << 0)
+//-----------------------------------------------------------------------
+// �Զ���
+//-----------------------------------------------------------------------
+
+/* usb��Դ���� */
+#define USBC_MAX_CTL_NUM 1
+#define USBC_MAX_EP_NUM 3 //ep0~2, ep�ĸ���
+#define USBC_MAX_FIFO_SIZE (2 * 1024)
+
+/* usb OTG mode */
+#define USBC_OTG_HOST 0
+#define USBC_OTG_DEVICE 1
+
+/* usb device type */
+#define USBC_DEVICE_HSDEV 0
+#define USBC_DEVICE_FSDEV 1
+#define USBC_DEVICE_LSDEV 2
+
+/* usb transfer type */
+#define USBC_TS_TYPE_IDLE 0
+#define USBC_TS_TYPE_CTRL 1
+#define USBC_TS_TYPE_ISO 2
+#define USBC_TS_TYPE_INT 3
+#define USBC_TS_TYPE_BULK 4
+
+/* usb transfer mode */
+#define USBC_TS_MODE_UNKOWN 0
+#define USBC_TS_MODE_LS 1
+#define USBC_TS_MODE_FS 2
+#define USBC_TS_MODE_HS 3
+
+/* usb Vbus status */
+#define USBC_VBUS_STATUS_BELOW_SESSIONEND 0
+#define USBC_VBUS_STATUS_ABOVE_SESSIONEND_BELOW_AVALID 1
+#define USBC_VBUS_STATUS_ABOVE_AVALID_BELOW_VBUSVALID 2
+#define USBC_VBUS_STATUS_ABOVE_VBUSVALID 3
+
+/* usb io type */
+#define USBC_IO_TYPE_PIO 0
+#define USBC_IO_TYPE_DMA 1
+
+/* usb ep type */
+#define USBC_EP_TYPE_IDLE 0
+#define USBC_EP_TYPE_EP0 1
+#define USBC_EP_TYPE_TX 2
+#define USBC_EP_TYPE_RX 3
+
+/* usb id type */
+#define USBC_ID_TYPE_DISABLE 0
+#define USBC_ID_TYPE_HOST 1
+#define USBC_ID_TYPE_DEVICE 2
+
+/* usb vbus valid type */
+#define USBC_VBUS_TYPE_DISABLE 0
+#define USBC_VBUS_TYPE_LOW 1
+#define USBC_VBUS_TYPE_HIGH 2
+
+/* usb a valid source */
+#define USBC_A_VALID_SOURCE_UTMI_AVALID 0
+#define USBC_A_VALID_SOURCE_UTMI_VBUS 1
+
+/* usb device switch */
+#define USBC_DEVICE_SWITCH_OFF 0
+#define USBC_DEVICE_SWITCH_ON 1
+
+/* usb fifo config mode */
+#define USBC_FIFO_MODE_4K 0
+#define USBC_FIFO_MODE_8K 1
+
+/*
+ **************************************************
+ * usb interrupt mask
+ *
+ **************************************************
+ */
+
+/* interrupt flags for ep0 and the Tx ep1~4 */
+#define USBC_INTTx_FLAG_EP5 (1 << USBC_BP_INTTx_FLAG_EP5)
+#define USBC_INTTx_FLAG_EP4 (1 << USBC_BP_INTTx_FLAG_EP4)
+#define USBC_INTTx_FLAG_EP3 (1 << USBC_BP_INTTx_FLAG_EP3)
+#define USBC_INTTx_FLAG_EP2 (1 << USBC_BP_INTTx_FLAG_EP2)
+#define USBC_INTTx_FLAG_EP1 (1 << USBC_BP_INTTx_FLAG_EP1)
+#define USBC_INTTx_FLAG_EP0 (1 << USBC_BP_INTTx_FLAG_EP0)
+
+/* interrupt flags for Rx ep1~4 */
+#define USBC_INTRx_FLAG_EP5 (1 << USBC_BP_INTRx_FLAG_EP5)
+#define USBC_INTRx_FLAG_EP4 (1 << USBC_BP_INTRx_FLAG_EP4)
+#define USBC_INTRx_FLAG_EP3 (1 << USBC_BP_INTRx_FLAG_EP3)
+#define USBC_INTRx_FLAG_EP2 (1 << USBC_BP_INTRx_FLAG_EP2)
+#define USBC_INTRx_FLAG_EP1 (1 << USBC_BP_INTRx_FLAG_EP1)
+
+/* USB interrupt */
+#define USBC_INTUSB_VBUS_ERROR (1 << USBC_BP_INTUSB_VBUS_ERROR)
+#define USBC_INTUSB_SESSION_REQ (1 << USBC_BP_INTUSB_SESSION_REQ)
+#define USBC_INTUSB_DISCONNECT (1 << USBC_BP_INTUSB_DISCONNECT)
+#define USBC_INTUSB_CONNECT (1 << USBC_BP_INTUSB_CONNECT)
+#define USBC_INTUSB_SOF (1 << USBC_BP_INTUSB_SOF)
+#define USBC_INTUSB_RESET (1 << USBC_BP_INTUSB_RESET)
+#define USBC_INTUSB_RESUME (1 << USBC_BP_INTUSB_RESUME)
+#define USBC_INTUSB_SUSPEND (1 << USBC_BP_INTUSB_SUSPEND)
+
+#define USB_CSRL0_NAKTO 0x00000080 // NAK Timeout
+#define USB_CSRL0_SETENDC 0x00000080 // Setup End Clear
+#define USB_CSRL0_STATUS 0x00000040 // STATUS Packet
+#define USB_CSRL0_RXRDYC 0x00000040 // RXRDY Clear
+#define USB_CSRL0_REQPKT 0x00000020 // Request Packet
+#define USB_CSRL0_STALL 0x00000020 // Send Stall
+#define USB_CSRL0_SETEND 0x00000010 // Setup End
+#define USB_CSRL0_ERROR 0x00000010 // Error
+#define USB_CSRL0_DATAEND 0x00000008 // Data End
+#define USB_CSRL0_SETUP 0x00000008 // Setup Packet
+#define USB_CSRL0_STALLED 0x00000004 // Endpoint Stalled
+#define USB_CSRL0_TXRDY 0x00000002 // Transmit Packet Ready
+#define USB_CSRL0_RXRDY 0x00000001 // Receive Packet Ready
+
+#define USB_RXFIFOSZ_DPB 0x00000010 // Double Packet Buffer Support
+#define USB_RXFIFOSZ_SIZE_M 0x0000000F // Max Packet Size
+
+#define USB_TXFIFOSZ_DPB 0x00000010 // Double Packet Buffer Support
+#define USB_TXFIFOSZ_SIZE_M 0x0000000F // Max Packet Size
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
new file mode 100644
index 000000000..692096fc8
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -0,0 +1,1198 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 William D. Jones
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ * Copyright (c) 2020 Jan Duempelmann
+ * Copyright (c) 2020 Reinhard Panhuber
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_DWC2)
+
+#include "device/dcd.h"
+#include "dwc2_type.h"
+
+// Following symbols must be defined by port header
+// - _dwc2_controller[]: array of controllers
+// - DWC2_EP_MAX: largest EP counts of all controllers
+// - dwc2_phy_init/dwc2_phy_update: phy init called before and after core reset
+// - dwc2_dcd_int_enable/dwc2_dcd_int_disable
+// - dwc2_remote_wakeup_delay
+
+#if defined(TUP_USBIP_DWC2_STM32)
+ #include "dwc2_stm32.h"
+#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+ #include "dwc2_esp32.h"
+#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
+ #include "dwc2_gd32.h"
+#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837)
+ #include "dwc2_bcm.h"
+#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
+ #include "dwc2_efm32.h"
+#elif TU_CHECK_MCU(OPT_MCU_XMC4000)
+ #include "dwc2_xmc.h"
+#else
+ #error "Unsupported MCUs"
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
+
+// DWC2 registers
+#define DWC2_REG(_port) ((dwc2_regs_t*) _dwc2_controller[_port].reg_base)
+
+// Debug level for DWC2
+#define DWC2_DEBUG 2
+
+#ifndef dcache_clean
+#define dcache_clean(_addr, _size)
+#endif
+
+#ifndef dcache_invalidate
+#define dcache_invalidate(_addr, _size)
+#endif
+
+#ifndef dcache_clean_invalidate
+#define dcache_clean_invalidate(_addr, _size)
+#endif
+
+static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2];
+
+typedef struct {
+ uint8_t* buffer;
+ tu_fifo_t* ff;
+ uint16_t total_len;
+ uint16_t max_size;
+ uint8_t interval;
+} xfer_ctl_t;
+
+static xfer_ctl_t xfer_status[DWC2_EP_MAX][2];
+#define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir])
+
+// EP0 transfers are limited to 1 packet - larger sizes has to be split
+static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type
+
+// TX FIFO RAM allocation so far in words - RX FIFO size is readily available from dwc2->grxfsiz
+static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs)
+
+// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by
+static bool _sof_en;
+
+// Calculate the RX FIFO size according to minimum recommendations from reference manual
+// RxFIFO = (5 * number of control endpoints + 8) +
+// ((largest USB packet used / 4) + 1 for status information) +
+// (2 * number of OUT endpoints) + 1 for Global NAK
+// with number of control endpoints = 1 we have
+// RxFIFO = 15 + (largest USB packet used / 4) + 2 * number of OUT endpoints
+// we double the largest USB packet size to be able to hold up to 2 packets
+static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) {
+ return 15 + 2 * (max_ep_size / 4) + 2 * ep_count;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void fifo_flush_tx(dwc2_regs_t* dwc2, uint8_t epnum) {
+ // flush TX fifo and wait for it cleared
+ dwc2->grstctl = GRSTCTL_TXFFLSH | (epnum << GRSTCTL_TXFNUM_Pos);
+ while (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) {}
+}
+TU_ATTR_ALWAYS_INLINE static inline void fifo_flush_rx(dwc2_regs_t* dwc2) {
+ // flush RX fifo and wait for it cleared
+ dwc2->grstctl = GRSTCTL_RXFFLSH;
+ while (dwc2->grstctl & GRSTCTL_RXFFLSH_Msk) {}
+}
+
+static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ TU_ASSERT(epnum < ep_count);
+
+ uint16_t fifo_size = tu_div_ceil(packet_size, 4);
+
+ // "USB Data FIFOs" section in reference manual
+ // Peripheral FIFO architecture
+ //
+ // --------------- 320 or 1024 ( 1280 or 4096 bytes )
+ // | IN FIFO 0 |
+ // --------------- (320 or 1024) - 16
+ // | IN FIFO 1 |
+ // --------------- (320 or 1024) - 16 - x
+ // | . . . . |
+ // --------------- (320 or 1024) - 16 - x - y - ... - z
+ // | IN FIFO MAX |
+ // ---------------
+ // | FREE |
+ // --------------- GRXFSIZ
+ // | OUT FIFO |
+ // | ( Shared ) |
+ // --------------- 0
+ //
+ // In FIFO is allocated by following rules:
+ // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
+ if (dir == TUSB_DIR_OUT) {
+ // Calculate required size of RX FIFO
+ uint16_t const sz = calc_grxfsiz(4 * fifo_size, ep_count);
+
+ // If size_rx needs to be extended check if possible and if so enlarge it
+ if (dwc2->grxfsiz < sz) {
+ TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size / 4);
+
+ // Enlarge RX FIFO
+ dwc2->grxfsiz = sz;
+ }
+ } else {
+ // Note if The TXFELVL is configured as half empty. In order
+ // to be able to write a packet at that point, the fifo must be twice the max_size.
+ if ((dwc2->gahbcfg & GAHBCFG_TXFELVL) == 0) {
+ fifo_size *= 2;
+ }
+
+ // Check if free space is available
+ TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size / 4);
+ _allocated_fifo_words_tx += fifo_size;
+ TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %" PRIu32, fifo_size * 4,
+ _dwc2_controller[rhport].ep_fifo_size - _allocated_fifo_words_tx * 4);
+
+ // DIEPTXF starts at FIFO #1.
+ // Both TXFD and TXSA are in unit of 32-bit words.
+ dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) |
+ (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx);
+ }
+
+ return true;
+}
+
+static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+ uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+
+ xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
+ xfer->max_size = tu_edpt_packet_size(p_endpoint_desc);
+ xfer->interval = p_endpoint_desc->bInterval;
+
+ // USBAEP, EPTYP, SD0PID_SEVNFRM, MPSIZ are the same for IN and OUT endpoints.
+ uint32_t const dxepctl = (1 << DOEPCTL_USBAEP_Pos) |
+ (p_endpoint_desc->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) |
+ (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) |
+ (xfer->max_size << DOEPCTL_MPSIZ_Pos);
+
+ if (dir == TUSB_DIR_OUT) {
+ dwc2->epout[epnum].doepctl = dxepctl;
+ dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum);
+ } else {
+ dwc2->epin[epnum].diepctl = dxepctl | (epnum << DIEPCTL_TXFNUM_Pos);
+ dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum));
+ }
+}
+
+static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
+ (void) rhport;
+
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ if (dir == TUSB_DIR_IN) {
+ dwc2_epin_t* epin = dwc2->epin;
+
+ // Only disable currently enabled non-control endpoint
+ if ((epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA)) {
+ epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0);
+ } else {
+ // Stop transmitting packets and NAK IN xfers.
+ epin[epnum].diepctl |= DIEPCTL_SNAK;
+ while ((epin[epnum].diepint & DIEPINT_INEPNE) == 0) {}
+
+ // Disable the endpoint.
+ epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0);
+ while ((epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0) {}
+
+ epin[epnum].diepint = DIEPINT_EPDISD;
+ }
+
+ // Flush the FIFO, and wait until we have confirmed it cleared.
+ fifo_flush_tx(dwc2, epnum);
+ } else {
+ dwc2_epout_t* epout = dwc2->epout;
+
+ // Only disable currently enabled non-control endpoint
+ if ((epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA)) {
+ epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0;
+ } else {
+ // Asserting GONAK is required to STALL an OUT endpoint.
+ // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt
+ // anyway, and it can't be cleared by user code. If this while loop never
+ // finishes, we have bigger problems than just the stack.
+ dwc2->dctl |= DCTL_SGONAK;
+ while ((dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0) {}
+
+ // Ditto here- disable the endpoint.
+ epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0);
+ while ((epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0) {}
+
+ epout[epnum].doepint = DOEPINT_EPDISD;
+
+ // Allow other OUT endpoints to keep receiving.
+ dwc2->dctl |= DCTL_CGONAK;
+ }
+ }
+}
+
+// Start of Bus Reset
+static void bus_reset(uint8_t rhport) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
+
+ tu_memclr(xfer_status, sizeof(xfer_status));
+
+ _sof_en = false;
+
+ // clear device address
+ dwc2->dcfg &= ~DCFG_DAD_Msk;
+
+ // 1. NAK for all OUT endpoints
+ for (uint8_t n = 0; n < ep_count; n++) {
+ dwc2->epout[n].doepctl |= DOEPCTL_SNAK;
+ }
+
+ // 2. Disable all IN endpoints
+ for (uint8_t n = 0; n < ep_count; n++) {
+ if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) {
+ dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS;
+ }
+ }
+
+ fifo_flush_tx(dwc2, 0x10); // all tx fifo
+ fifo_flush_rx(dwc2);
+
+ // 3. Set up interrupt mask
+ dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos);
+ dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM;
+ dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM;
+
+ // "USB Data FIFOs" section in reference manual
+ // Peripheral FIFO architecture
+ //
+ // The FIFO is split up in a lower part where the RX FIFO is located and an upper part where the TX FIFOs start.
+ // We do this to allow the RX FIFO to grow dynamically which is possible since the free space is located
+ // between the RX and TX FIFOs. This is required by ISO OUT EPs which need a bigger FIFO than the standard
+ // configuration done below.
+ //
+ // Dynamically FIFO sizes are of interest only for ISO EPs since all others are usually not opened and closed.
+ // All EPs other than ISO are opened as soon as the driver starts up i.e. when the host sends a
+ // configure interface command. Hence, all IN EPs other the ISO will be located at the top. IN ISO EPs are usually
+ // opened when the host sends an additional command: setInterface. At this point in time
+ // the ISO EP will be located next to the free space and can change its size. In case more IN EPs change its size
+ // an additional memory
+ //
+ // --------------- 320 or 1024 ( 1280 or 4096 bytes )
+ // | IN FIFO 0 |
+ // --------------- (320 or 1024) - 16
+ // | IN FIFO 1 |
+ // --------------- (320 or 1024) - 16 - x
+ // | . . . . |
+ // --------------- (320 or 1024) - 16 - x - y - ... - z
+ // | IN FIFO MAX |
+ // ---------------
+ // | FREE |
+ // --------------- GRXFSIZ
+ // | OUT FIFO |
+ // | ( Shared ) |
+ // --------------- 0
+ //
+ // According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits):
+ // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN
+ //
+ // - All EP OUT shared a unique OUT FIFO which uses
+ // - 13 for setup packets + control words (up to 3 setup packets).
+ // - 1 for global NAK (not required/used here).
+ // - Largest-EPsize / 4 + 1. ( FS: 64 bytes, HS: 512 bytes). Recommended is "2 x (Largest-EPsize/4) + 1"
+ // - 2 for each used OUT endpoint
+ //
+ // Therefore GRXFSIZ = 13 + 1 + 1 + 2 x (Largest-EPsize/4) + 2 x EPOUTnum
+ // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x ep_count = 47 + 2 x ep_count
+ // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x ep_count = 271 + 2 x ep_count
+ //
+ // NOTE: Largest-EPsize & EPOUTnum is actual used endpoints in configuration. Since DCD has no knowledge
+ // of the overall picture yet. We will use the worst scenario: largest possible + ep_count
+ //
+ // For Isochronous, largest EP size can be 1023/1024 for FS/HS respectively. In addition if multiple ISO
+ // are enabled at least "2 x (Largest-EPsize/4) + 1" are recommended. Maybe provide a macro for application to
+ // overwrite this.
+
+ // EP0 out max is 64
+ dwc2->grxfsiz = calc_grxfsiz(64, ep_count);
+
+ // Setup the control endpoint 0
+ _allocated_fifo_words_tx = 16;
+
+ // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
+ dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx);
+
+ // Fixed control EP0 size to 64 bytes
+ dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos);
+ xfer_status[0][TUSB_DIR_OUT].max_size = 64;
+ xfer_status[0][TUSB_DIR_IN].max_size = 64;
+
+ dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
+
+ dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT;
+}
+
+static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets,
+ uint16_t total_bytes) {
+ (void) rhport;
+
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ // EP0 is limited to one packet each xfer
+ // We use multiple transaction of xfer->max_size length to get a whole transfer done
+ if (epnum == 0) {
+ xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir);
+ total_bytes = tu_min16(ep0_pending[dir], xfer->max_size);
+ ep0_pending[dir] -= total_bytes;
+ }
+
+ // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here.
+ if (dir == TUSB_DIR_IN) {
+ dwc2_epin_t* epin = dwc2->epin;
+
+ // A full IN transfer (multiple packets, possibly) triggers XFRC.
+ epin[epnum].dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) |
+ ((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk);
+
+ epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK;
+
+ // For ISO endpoint set correct odd/even bit for next frame.
+ if ((epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) {
+ // Take odd/even bit from frame counter.
+ uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos));
+ epin[epnum].diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk);
+ }
+ // Enable fifo empty interrupt only if there are something to put in the fifo.
+ if (total_bytes != 0) {
+ dwc2->diepempmsk |= (1 << epnum);
+ }
+ } else {
+ dwc2_epout_t* epout = dwc2->epout;
+
+ // A full OUT transfer (multiple packets, possibly) triggers XFRC.
+ epout[epnum].doeptsiz &= ~(DOEPTSIZ_PKTCNT_Msk | DOEPTSIZ_XFRSIZ);
+ epout[epnum].doeptsiz |= (num_packets << DOEPTSIZ_PKTCNT_Pos) |
+ ((total_bytes << DOEPTSIZ_XFRSIZ_Pos) & DOEPTSIZ_XFRSIZ_Msk);
+
+ epout[epnum].doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK;
+ if ((epout[epnum].doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 &&
+ XFER_CTL_BASE(epnum, dir)->interval == 1) {
+ // Take odd/even bit from frame counter.
+ uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos));
+ epout[epnum].doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk);
+ }
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* Controller API
+ *------------------------------------------------------------------*/
+#if CFG_TUSB_DEBUG >= DWC2_DEBUG
+void print_dwc2_info(dwc2_regs_t* dwc2) {
+ // print guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4
+ // use dwc2_info.py/md for bit-field value and comparison with other ports
+ volatile uint32_t const* p = (volatile uint32_t const*) &dwc2->guid;
+ TU_LOG(DWC2_DEBUG, "guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4\r\n");
+ for (size_t i = 0; i < 5; i++) {
+ TU_LOG(DWC2_DEBUG, "0x%08" PRIX32 ", ", p[i]);
+ }
+ TU_LOG(DWC2_DEBUG, "0x%08" PRIX32 "\r\n", p[5]);
+}
+#endif
+
+static void reset_core(dwc2_regs_t* dwc2) {
+ // reset core
+ dwc2->grstctl |= GRSTCTL_CSRST;
+
+ // wait for reset bit is cleared
+ // TODO version 4.20a should wait for RESET DONE mask
+ while (dwc2->grstctl & GRSTCTL_CSRST) {}
+
+ // wait for AHB master IDLE
+ while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {}
+
+ // wait for device mode ?
+}
+
+static bool phy_hs_supported(dwc2_regs_t* dwc2) {
+ (void) dwc2;
+
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+ // note: esp32 incorrect report its hs_phy_type as utmi
+ return false;
+#elif !TUD_OPT_HIGH_SPEED
+ return false;
+#else
+ return dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE;
+#endif
+}
+
+static void phy_fs_init(dwc2_regs_t* dwc2) {
+ TU_LOG(DWC2_DEBUG, "Fullspeed PHY init\r\n");
+
+ // Select FS PHY
+ dwc2->gusbcfg |= GUSBCFG_PHYSEL;
+
+ // MCU specific PHY init before reset
+ dwc2_phy_init(dwc2, HS_PHY_TYPE_NONE);
+
+ // Reset core after selecting PHY
+ reset_core(dwc2);
+
+ // USB turnaround time is critical for certification where long cables and 5-Hubs are used.
+ // So if you need the AHB to run at less than 30 MHz, and if USB turnaround time is not critical,
+ // these bits can be programmed to a larger value. Default is 5
+ dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos);
+
+ // MCU specific PHY update post reset
+ dwc2_phy_update(dwc2, HS_PHY_TYPE_NONE);
+
+ // set max speed
+ dwc2->dcfg = (dwc2->dcfg & ~DCFG_DSPD_Msk) | (DCFG_DSPD_FS << DCFG_DSPD_Pos);
+}
+
+static void phy_hs_init(dwc2_regs_t* dwc2) {
+ uint32_t gusbcfg = dwc2->gusbcfg;
+
+ // De-select FS PHY
+ gusbcfg &= ~GUSBCFG_PHYSEL;
+
+ if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) {
+ TU_LOG(DWC2_DEBUG, "Highspeed ULPI PHY init\r\n");
+
+ // Select ULPI
+ gusbcfg |= GUSBCFG_ULPI_UTMI_SEL;
+
+ // ULPI 8-bit interface, single data rate
+ gusbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
+
+ // default internal VBUS Indicator and Drive
+ gusbcfg &= ~(GUSBCFG_ULPIEVBUSD | GUSBCFG_ULPIEVBUSI);
+
+ // Disable FS/LS ULPI
+ gusbcfg &= ~(GUSBCFG_ULPIFSLS | GUSBCFG_ULPICSM);
+ } else {
+ TU_LOG(DWC2_DEBUG, "Highspeed UTMI+ PHY init\r\n");
+
+ // Select UTMI+ with 8-bit interface
+ gusbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
+
+ // Set 16-bit interface if supported
+ if (dwc2->ghwcfg4_bm.utmi_phy_data_width) gusbcfg |= GUSBCFG_PHYIF16;
+ }
+
+ // Apply config
+ dwc2->gusbcfg = gusbcfg;
+
+ // mcu specific phy init
+ dwc2_phy_init(dwc2, dwc2->ghwcfg2_bm.hs_phy_type);
+
+ // Reset core after selecting PHY
+ reset_core(dwc2);
+
+ // Set turn-around, must after core reset otherwise it will be clear
+ // - 9 if using 8-bit PHY interface
+ // - 5 if using 16-bit PHY interface
+ gusbcfg &= ~GUSBCFG_TRDT_Msk;
+ gusbcfg |= (dwc2->ghwcfg4_bm.utmi_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);
+
+ // Set max speed
+ uint32_t dcfg = dwc2->dcfg;
+ dcfg &= ~DCFG_DSPD_Msk;
+ dcfg |= DCFG_DSPD_HS << DCFG_DSPD_Pos;
+
+ // 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 == HS_PHY_TYPE_ULPI) dcfg |= DCFG_XCVRDLY;
+
+ dwc2->dcfg = dcfg;
+}
+
+static bool check_dwc2(dwc2_regs_t* dwc2) {
+#if CFG_TUSB_DEBUG >= DWC2_DEBUG
+ print_dwc2_info(dwc2);
+#endif
+
+ // For some reasons: GD32VF103 snpsid and all hwcfg register are always zero (skip it)
+ (void) dwc2;
+#if !TU_CHECK_MCU(OPT_MCU_GD32VF103)
+ uint32_t const gsnpsid = dwc2->gsnpsid & GSNPSID_ID_MASK;
+ TU_ASSERT(gsnpsid == DWC2_OTG_ID || gsnpsid == DWC2_FS_IOT_ID || gsnpsid == DWC2_HS_IOT_ID);
+#endif
+
+ return true;
+}
+
+void dcd_init(uint8_t rhport) {
+ // Programming model begins in the last section of the chapter on the USB
+ // peripheral in each Reference Manual.
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ // Check Synopsys ID register, failed if controller clock/power is not enabled
+ if (!check_dwc2(dwc2)) return;
+ dcd_disconnect(rhport);
+
+ // max number of endpoints & total_fifo_size are:
+ // hw_cfg2->num_dev_ep, hw_cfg2->total_fifo_size
+
+ if (phy_hs_supported(dwc2)) {
+ phy_hs_init(dwc2); // Highspeed
+ } else {
+ phy_fs_init(dwc2); // core does not support highspeed or hs phy is not present
+ }
+
+ // Restart PHY clock
+ dwc2->pcgctl &= ~(PCGCTL_STOPPCLK | PCGCTL_GATEHCLK | PCGCTL_PWRCLMP | PCGCTL_RSTPDWNMODULE);
+
+ /* Set HS/FS Timeout Calibration to 7 (max available value).
+ * The number of PHY clocks that the application programs in
+ * this field is added to the high/full speed interpacket timeout
+ * duration in the core to account for any additional delays
+ * introduced by the PHY. This can be required, because the delay
+ * introduced by the PHY in generating the linestate condition
+ * can vary from one PHY to another.
+ */
+ dwc2->gusbcfg |= (7ul << GUSBCFG_TOCAL_Pos);
+
+ // Force device mode
+ dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD;
+
+ // Clear A override, force B Valid
+ dwc2->gotgctl = (dwc2->gotgctl & ~GOTGCTL_AVALOEN) | GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL;
+
+ // If USB host misbehaves during status portion of control xfer
+ // (non zero-length packet), send STALL back and discard.
+ dwc2->dcfg |= DCFG_NZLSOHSK;
+
+ fifo_flush_tx(dwc2, 0x10); // all tx fifo
+ fifo_flush_rx(dwc2);
+
+ // Clear all interrupts
+ uint32_t int_mask = dwc2->gintsts;
+ dwc2->gintsts |= int_mask;
+ int_mask = dwc2->gotgint;
+ dwc2->gotgint |= int_mask;
+
+ // Required as part of core initialization.
+ dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_RXFLVLM |
+ GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM;
+
+ // Configure TX FIFO empty level for interrupt. Default is complete empty
+ dwc2->gahbcfg |= GAHBCFG_TXFELVL;
+
+ // Enable global interrupt
+ dwc2->gahbcfg |= GAHBCFG_GINT;
+
+ // make sure we are in device mode
+// TU_ASSERT(!(dwc2->gintsts & GINTSTS_CMOD), );
+
+// TU_LOG_HEX(DWC2_DEBUG, dwc2->gotgctl);
+// TU_LOG_HEX(DWC2_DEBUG, dwc2->gusbcfg);
+// TU_LOG_HEX(DWC2_DEBUG, dwc2->dcfg);
+// TU_LOG_HEX(DWC2_DEBUG, dwc2->gahbcfg);
+
+ dcd_connect(rhport);
+}
+
+void dcd_int_enable(uint8_t rhport) {
+ dwc2_dcd_int_enable(rhport);
+}
+
+void dcd_int_disable(uint8_t rhport) {
+ dwc2_dcd_int_disable(rhport);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ dwc2->dcfg = (dwc2->dcfg & ~DCFG_DAD_Msk) | (dev_addr << DCFG_DAD_Pos);
+
+ // Response with status after changing device address
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+void dcd_remote_wakeup(uint8_t rhport) {
+ (void) rhport;
+
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ // set remote wakeup
+ dwc2->dctl |= DCTL_RWUSIG;
+
+ // enable SOF to detect bus resume
+ dwc2->gintsts = GINTSTS_SOF;
+ dwc2->gintmsk |= GINTMSK_SOFM;
+
+ // Per specs: remote wakeup signal bit must be clear within 1-15ms
+ dwc2_remote_wakeup_delay();
+
+ dwc2->dctl &= ~DCTL_RWUSIG;
+}
+
+void dcd_connect(uint8_t rhport) {
+ (void) rhport;
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ dwc2->dctl &= ~DCTL_SDIS;
+}
+
+void dcd_disconnect(uint8_t rhport) {
+ (void) rhport;
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ dwc2->dctl |= DCTL_SDIS;
+}
+
+// Be advised: audio, video and possibly other iso-ep classes use dcd_sof_enable() to enable/disable its corresponding ISR on purpose!
+void dcd_sof_enable(uint8_t rhport, bool en) {
+ (void) rhport;
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ _sof_en = en;
+
+ if (en) {
+ dwc2->gintsts = GINTSTS_SOF;
+ dwc2->gintmsk |= GINTMSK_SOFM;
+ } else {
+ dwc2->gintmsk &= ~GINTMSK_SOFM;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* DCD Endpoint port
+ *------------------------------------------------------------------*/
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
+ TU_ASSERT(fifo_alloc(rhport, desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt)));
+ edpt_activate(rhport, desc_edpt);
+ return true;
+}
+
+// Close all non-control endpoints, cancel all pending transfers if any.
+void dcd_edpt_close_all(uint8_t rhport) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
+
+ // Disable non-control interrupt
+ dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos);
+
+ for (uint8_t n = 1; n < ep_count; n++) {
+ // disable OUT endpoint
+ if (dwc2->epout[n].doepctl & DOEPCTL_EPENA) {
+ dwc2->epout[n].doepctl |= DOEPCTL_SNAK | DOEPCTL_EPDIS;
+ }
+ xfer_status[n][TUSB_DIR_OUT].max_size = 0;
+
+ // disable IN endpoint
+ if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) {
+ dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS;
+ }
+ xfer_status[n][TUSB_DIR_IN].max_size = 0;
+ }
+
+ // reset allocated fifo OUT
+ dwc2->grxfsiz = calc_grxfsiz(64, ep_count);
+ // reset allocated fifo IN
+ _allocated_fifo_words_tx = 16;
+
+ fifo_flush_tx(dwc2, 0x10); // all tx fifo
+ fifo_flush_rx(dwc2);
+}
+
+bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
+ TU_ASSERT(fifo_alloc(rhport, ep_addr, largest_packet_size));
+ return true;
+}
+
+bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) {
+ // Disable EP to clear potential incomplete transfers
+ edpt_disable(rhport, p_endpoint_desc->bEndpointAddress, false);
+
+ edpt_activate(rhport, p_endpoint_desc);
+
+ return true;
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
+ xfer->buffer = buffer;
+ xfer->ff = NULL;
+ xfer->total_len = total_bytes;
+
+ // EP0 can only handle one packet
+ if (epnum == 0) {
+ ep0_pending[dir] = total_bytes;
+
+ // Schedule the first transaction for EP0 transfer
+ edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]);
+ } else {
+ uint16_t num_packets = (total_bytes / xfer->max_size);
+ uint16_t const short_packet_size = total_bytes % xfer->max_size;
+
+ // Zero-size packet is special case.
+ if ((short_packet_size > 0) || (total_bytes == 0)) num_packets++;
+
+ // Schedule packets to be sent within interrupt
+ edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes);
+ }
+
+ return true;
+}
+
+// The number of bytes has to be given explicitly to allow more flexible control of how many
+// bytes should be written and second to keep the return value free to give back a boolean
+// success message. If total_bytes is too big, the FIFO will copy only what is available
+// into the USB buffer!
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes) {
+ // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
+ TU_ASSERT(ff->item_size == 1);
+
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
+ xfer->buffer = NULL;
+ xfer->ff = ff;
+ xfer->total_len = total_bytes;
+
+ uint16_t num_packets = (total_bytes / xfer->max_size);
+ uint16_t const short_packet_size = total_bytes % xfer->max_size;
+
+ // Zero-size packet is special case.
+ if (short_packet_size > 0 || (total_bytes == 0)) num_packets++;
+
+ // Schedule packets to be sent within interrupt
+ edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes);
+
+ return true;
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
+ edpt_disable(rhport, ep_addr, false);
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
+ edpt_disable(rhport, ep_addr, true);
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
+
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ // Clear stall and reset data toggle
+ if (dir == TUSB_DIR_IN) {
+ dwc2->epin[epnum].diepctl &= ~DIEPCTL_STALL;
+ dwc2->epin[epnum].diepctl |= DIEPCTL_SD0PID_SEVNFRM;
+ } else {
+ dwc2->epout[epnum].doepctl &= ~DOEPCTL_STALL;
+ dwc2->epout[epnum].doepctl |= DOEPCTL_SD0PID_SEVNFRM;
+ }
+}
+
+/*------------------------------------------------------------------*/
+
+// Read a single data packet from receive FIFO
+static void read_fifo_packet(uint8_t rhport, uint8_t* dst, uint16_t len) {
+ (void) rhport;
+
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ volatile const uint32_t* rx_fifo = dwc2->fifo[0];
+
+ // Reading full available 32 bit words from fifo
+ uint16_t full_words = len >> 2;
+ while (full_words--) {
+ tu_unaligned_write32(dst, *rx_fifo);
+ dst += 4;
+ }
+
+ // Read the remaining 1-3 bytes from fifo
+ uint8_t const bytes_rem = len & 0x03;
+ if (bytes_rem != 0) {
+ uint32_t const tmp = *rx_fifo;
+ dst[0] = tu_u32_byte0(tmp);
+ if (bytes_rem > 1) dst[1] = tu_u32_byte1(tmp);
+ if (bytes_rem > 2) dst[2] = tu_u32_byte2(tmp);
+ }
+}
+
+// Write a single data packet to EPIN FIFO
+static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const* src, uint16_t len) {
+ (void) rhport;
+
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num];
+
+ // Pushing full available 32 bit words to fifo
+ uint16_t full_words = len >> 2;
+ while (full_words--) {
+ *tx_fifo = tu_unaligned_read32(src);
+ src += 4;
+ }
+
+ // Write the remaining 1-3 bytes into fifo
+ uint8_t const bytes_rem = len & 0x03;
+ if (bytes_rem) {
+ uint32_t tmp_word = src[0];
+ if (bytes_rem > 1) tmp_word |= (src[1] << 8);
+ if (bytes_rem > 2) tmp_word |= (src[2] << 16);
+
+ *tx_fifo = tmp_word;
+ }
+}
+
+static void handle_rxflvl_irq(uint8_t rhport) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ volatile uint32_t const* rx_fifo = dwc2->fifo[0];
+
+ // Pop control word off FIFO
+ uint32_t const ctl_word = dwc2->grxstsp;
+ uint8_t const pktsts = (ctl_word & GRXSTSP_PKTSTS_Msk) >> GRXSTSP_PKTSTS_Pos;
+ uint8_t const epnum = (ctl_word & GRXSTSP_EPNUM_Msk) >> GRXSTSP_EPNUM_Pos;
+ uint16_t const bcnt = (ctl_word & GRXSTSP_BCNT_Msk) >> GRXSTSP_BCNT_Pos;
+
+ dwc2_epout_t* epout = &dwc2->epout[epnum];
+
+//#if CFG_TUSB_DEBUG >= DWC2_DEBUG
+// const char * pktsts_str[] =
+// {
+// "ASSERT", "Global NAK (ISR)", "Out Data Received", "Out Transfer Complete (ISR)",
+// "Setup Complete (ISR)", "ASSERT", "Setup Data Received"
+// };
+// TU_LOG_LOCATION();
+// TU_LOG(DWC2_DEBUG, " EP %02X, Byte Count %u, %s\r\n", epnum, bcnt, pktsts_str[pktsts]);
+// TU_LOG(DWC2_DEBUG, " daint = %08lX, doepint = %04X\r\n", (unsigned long) dwc2->daint, (unsigned int) epout->doepint);
+//#endif
+
+ switch (pktsts) {
+ // Global OUT NAK: do nothing
+ case GRXSTS_PKTSTS_GLOBALOUTNAK:
+ break;
+
+ case GRXSTS_PKTSTS_SETUPRX:
+ // Setup packet received
+
+ // We can receive up to three setup packets in succession, but
+ // only the last one is valid.
+ _setup_packet[0] = (*rx_fifo);
+ _setup_packet[1] = (*rx_fifo);
+ break;
+
+ case GRXSTS_PKTSTS_SETUPDONE:
+ // Setup packet done (Interrupt)
+ epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
+ break;
+
+ case GRXSTS_PKTSTS_OUTRX: {
+ // Out packet received
+ xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
+
+ // Read packet off RxFIFO
+ if (xfer->ff) {
+ // Ring buffer
+ tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void*) (uintptr_t) rx_fifo, bcnt);
+ } else {
+ // Linear buffer
+ read_fifo_packet(rhport, xfer->buffer, bcnt);
+
+ // Increment pointer to xfer data
+ xfer->buffer += bcnt;
+ }
+
+ // Truncate transfer length in case of short packet
+ if (bcnt < xfer->max_size) {
+ xfer->total_len -= (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos;
+ if (epnum == 0) {
+ xfer->total_len -= ep0_pending[TUSB_DIR_OUT];
+ ep0_pending[TUSB_DIR_OUT] = 0;
+ }
+ }
+ }
+ break;
+
+ // Out packet done (Interrupt)
+ case GRXSTS_PKTSTS_OUTDONE:
+ // Occurred on STM32L47 with dwc2 version 3.10a but not found on other version like 2.80a or 3.30a
+ // May (or not) be 3.10a specific feature/bug or depending on MCU configuration
+ // XFRC complete is additionally generated when
+ // - setup packet is received
+ // - complete the data stage of control write is complete
+ if ((epnum == 0) && (bcnt == 0) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) {
+ uint32_t doepint = epout->doepint;
+
+ if (doepint & (DOEPINT_STPKTRX | DOEPINT_OTEPSPR)) {
+ // skip this "no-data" transfer complete event
+ // Note: STPKTRX will be clear later by setup received handler
+ uint32_t clear_flags = DOEPINT_XFRC;
+
+ if (doepint & DOEPINT_OTEPSPR) clear_flags |= DOEPINT_OTEPSPR;
+
+ epout->doepint = clear_flags;
+
+ // TU_LOG(DWC2_DEBUG, " FIX extra transfer complete on setup/data compete\r\n");
+ }
+ }
+ break;
+
+ default: // Invalid
+ TU_BREAKPOINT();
+ break;
+ }
+}
+
+static void handle_epout_irq(uint8_t rhport) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
+
+ // DAINT for a given EP clears when DOEPINTx is cleared.
+ // OEPINT will be cleared when DAINT's out bits are cleared.
+ for (uint8_t n = 0; n < ep_count; n++) {
+ if (dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n)) {
+ dwc2_epout_t* epout = &dwc2->epout[n];
+
+ uint32_t const doepint = epout->doepint;
+
+ // SETUP packet Setup Phase done.
+ if (doepint & DOEPINT_STUP) {
+ uint32_t clear_flag = DOEPINT_STUP;
+
+ // STPKTRX is only available for version from 3_00a
+ if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) {
+ clear_flag |= DOEPINT_STPKTRX;
+ }
+
+ epout->doepint = clear_flag;
+ dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true);
+ }
+
+ // OUT XFER complete
+ if (epout->doepint & DOEPINT_XFRC) {
+ epout->doepint = DOEPINT_XFRC;
+
+ xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
+
+ // EP0 can only handle one packet
+ if ((n == 0) && ep0_pending[TUSB_DIR_OUT]) {
+ // Schedule another packet to be received.
+ edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]);
+ } else {
+ dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true);
+ }
+ }
+ }
+ }
+}
+
+static void handle_epin_irq(uint8_t rhport) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
+ dwc2_epin_t* epin = dwc2->epin;
+
+ // DAINT for a given EP clears when DIEPINTx is cleared.
+ // IEPINT will be cleared when DAINT's out bits are cleared.
+ for (uint8_t n = 0; n < ep_count; n++) {
+ if (dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n)) {
+ // IN XFER complete (entire xfer).
+ xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
+
+ if (epin[n].diepint & DIEPINT_XFRC) {
+ epin[n].diepint = DIEPINT_XFRC;
+
+ // EP0 can only handle one packet
+ if ((n == 0) && ep0_pending[TUSB_DIR_IN]) {
+ // Schedule another packet to be transmitted.
+ edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]);
+ } else {
+ dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
+ }
+ }
+
+ // XFER FIFO empty
+ if ((epin[n].diepint & DIEPINT_TXFE) && (dwc2->diepempmsk & (1 << n))) {
+ // diepint's TXFE bit is read-only, software cannot clear it.
+ // It will only be cleared by hardware when written bytes is more than
+ // - 64 bytes or
+ // - Half of TX FIFO size (configured by DIEPTXF)
+
+ uint16_t remaining_packets = (epin[n].dieptsiz & DIEPTSIZ_PKTCNT_Msk) >> DIEPTSIZ_PKTCNT_Pos;
+
+ // Process every single packet (only whole packets can be written to fifo)
+ for (uint16_t i = 0; i < remaining_packets; i++) {
+ uint16_t const remaining_bytes = (epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos;
+
+ // Packet can not be larger than ep max size
+ uint16_t const packet_size = tu_min16(remaining_bytes, xfer->max_size);
+
+ // It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current
+ // EP has to be checked if the buffer can take another WHOLE packet
+ if (packet_size > ((epin[n].dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) break;
+
+ // Push packet to Tx-FIFO
+ if (xfer->ff) {
+ volatile uint32_t* tx_fifo = dwc2->fifo[n];
+ tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*) (uintptr_t) tx_fifo, packet_size);
+ } else {
+ write_fifo_packet(rhport, n, xfer->buffer, packet_size);
+
+ // Increment pointer to xfer data
+ xfer->buffer += packet_size;
+ }
+ }
+
+ // Turn off TXFE if all bytes are written.
+ if (((epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos) == 0) {
+ dwc2->diepempmsk &= ~(1 << n);
+ }
+ }
+ }
+ }
+}
+
+void dcd_int_handler(uint8_t rhport) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ uint32_t const int_mask = dwc2->gintmsk;
+ uint32_t const int_status = dwc2->gintsts & int_mask;
+
+ if (int_status & GINTSTS_USBRST) {
+ // USBRST is start of reset.
+ dwc2->gintsts = GINTSTS_USBRST;
+ bus_reset(rhport);
+ }
+
+ if (int_status & GINTSTS_ENUMDNE) {
+ // ENUMDNE is the end of reset where speed of the link is detected
+ dwc2->gintsts = GINTSTS_ENUMDNE;
+
+ tusb_speed_t speed;
+ switch ((dwc2->dsts & DSTS_ENUMSPD_Msk) >> DSTS_ENUMSPD_Pos) {
+ case DSTS_ENUMSPD_HS:
+ speed = TUSB_SPEED_HIGH;
+ break;
+
+ case DSTS_ENUMSPD_LS:
+ speed = TUSB_SPEED_LOW;
+ break;
+
+ case DSTS_ENUMSPD_FS_HSPHY:
+ case DSTS_ENUMSPD_FS:
+ default:
+ speed = TUSB_SPEED_FULL;
+ break;
+ }
+
+ // TODO must update GUSBCFG_TRDT according to link speed
+
+ dcd_event_bus_reset(rhport, speed, true);
+ }
+
+ if (int_status & GINTSTS_USBSUSP) {
+ dwc2->gintsts = GINTSTS_USBSUSP;
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+ }
+
+ if (int_status & GINTSTS_WKUINT) {
+ dwc2->gintsts = GINTSTS_WKUINT;
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+ }
+
+ // TODO check GINTSTS_DISCINT for disconnect detection
+ // if(int_status & GINTSTS_DISCINT)
+
+ if (int_status & GINTSTS_OTGINT) {
+ // OTG INT bit is read-only
+ uint32_t const otg_int = dwc2->gotgint;
+
+ if (otg_int & GOTGINT_SEDET) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+ }
+
+ dwc2->gotgint = otg_int;
+ }
+
+ if(int_status & GINTSTS_SOF) {
+ dwc2->gintsts = GINTSTS_SOF;
+ const uint32_t frame = (dwc2->dsts & DSTS_FNSOF) >> DSTS_FNSOF_Pos;
+
+ // Disable SOF interrupt if SOF was not explicitly enabled since SOF was used for remote wakeup detection
+ if (!_sof_en) {
+ dwc2->gintmsk &= ~GINTMSK_SOFM;
+ }
+
+ dcd_event_sof(rhport, frame, true);
+ }
+
+ // RxFIFO non-empty interrupt handling.
+ if (int_status & GINTSTS_RXFLVL) {
+ // RXFLVL bit is read-only
+
+ // Mask out RXFLVL while reading data from FIFO
+ dwc2->gintmsk &= ~GINTMSK_RXFLVLM;
+
+ // Loop until all available packets were handled
+ do {
+ handle_rxflvl_irq(rhport);
+ } while(dwc2->gintsts & GINTSTS_RXFLVL);
+
+ dwc2->gintmsk |= GINTMSK_RXFLVLM;
+ }
+
+ // OUT endpoint interrupt handling.
+ if (int_status & GINTSTS_OEPINT) {
+ // OEPINT is read-only, clear using DOEPINTn
+ handle_epout_irq(rhport);
+ }
+
+ // IN endpoint interrupt handling.
+ if (int_status & GINTSTS_IEPINT) {
+ // IEPINT bit read-only, clear using DIEPINTn
+ handle_epin_irq(rhport);
+ }
+
+ // // Check for Incomplete isochronous IN transfer
+ // if(int_status & GINTSTS_IISOIXFR) {
+ // printf(" IISOIXFR!\r\n");
+ //// TU_LOG(DWC2_DEBUG, " IISOIXFR!\r\n");
+ // }
+}
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_bcm.h b/src/portable/synopsys/dwc2/dwc2_bcm.h
new file mode 100644
index 000000000..732d96ae0
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_bcm.h
@@ -0,0 +1,89 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_DWC2_BCM_H_
+#define _TUSB_DWC2_BCM_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "broadcom/defines.h"
+#include "broadcom/interrupts.h"
+#include "broadcom/caches.h"
+
+#define DWC2_EP_MAX 8
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ { .reg_base = USB_OTG_GLOBAL_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 4096 }
+};
+
+#define dcache_clean(_addr, _size) data_clean(_addr, _size)
+#define dcache_invalidate(_addr, _size) data_invalidate(_addr, _size)
+#define dcache_clean_invalidate(_addr, _size) data_clean_and_invalidate(_addr, _size)
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_enable(uint8_t rhport)
+{
+ BP_EnableIRQ(_dwc2_controller[rhport].irqnum);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_disable (uint8_t rhport)
+{
+ BP_DisableIRQ(_dwc2_controller[rhport].irqnum);
+}
+
+static inline void dwc2_remote_wakeup_delay(void)
+{
+ // try to delay for 1 ms
+ // TODO implement later
+}
+
+// MCU specific PHY init, called BEFORE core reset
+static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+ (void) dwc2;
+ (void) hs_phy_type;
+
+ // nothing to do
+}
+
+// MCU specific PHY update, it is called AFTER init() and core reset
+static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+ (void) dwc2;
+ (void) hs_phy_type;
+
+ // nothing to do
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_efm32.h b/src/portable/synopsys/dwc2/dwc2_efm32.h
new file mode 100644
index 000000000..0e3570cbb
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_efm32.h
@@ -0,0 +1,89 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Rafael Silva (@perigoso)
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _DWC2_EFM32_H_
+#define _DWC2_EFM32_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "em_device.h"
+
+// EFM32 has custom control register before DWC registers
+#define DWC2_REG_BASE (USB_BASE + offsetof(USB_TypeDef, GOTGCTL))
+#define DWC2_EP_MAX 7
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ { .reg_base = DWC2_REG_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 2048 }
+};
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_enable(uint8_t rhport)
+{
+ NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_disable (uint8_t rhport)
+{
+ NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum);
+}
+
+static inline void dwc2_remote_wakeup_delay(void)
+{
+ // try to delay for 1 ms
+// uint32_t count = SystemCoreClock / 1000;
+// while ( count-- ) __NOP();
+}
+
+// MCU specific PHY init, called BEFORE core reset
+static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+ (void) dwc2;
+ (void) hs_phy_type;
+
+ // Enable PHY
+ USB->ROUTE = USB_ROUTE_PHYPEN;
+}
+
+// MCU specific PHY update, it is called AFTER init() and core reset
+static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+ (void) dwc2;
+ (void) hs_phy_type;
+
+ // EFM32 Manual: turn around must be 5 (reset & default value)
+ // dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h
new file mode 100644
index 000000000..c50dd66b8
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_esp32.h
@@ -0,0 +1,96 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+
+#ifndef _DWC2_ESP32_H_
+#define _DWC2_ESP32_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "esp_intr_alloc.h"
+#include "soc/periph_defs.h"
+//#include "soc/usb_periph.h"
+
+#define DWC2_REG_BASE 0x60080000UL
+#define DWC2_EP_MAX 6 // USB_OUT_EP_NUM. TODO ESP32Sx only has 5 tx fifo (5 endpoint IN)
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ { .reg_base = DWC2_REG_BASE, .irqnum = 0, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1024 }
+};
+
+static intr_handle_t usb_ih;
+
+static void dcd_int_handler_wrap(void* arg)
+{
+ (void) arg;
+ dcd_int_handler(0);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_enable (uint8_t rhport)
+{
+ (void) rhport;
+ esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, dcd_int_handler_wrap, NULL, &usb_ih);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_disable (uint8_t rhport)
+{
+ (void) rhport;
+ esp_intr_free(usb_ih);
+}
+
+static inline void dwc2_remote_wakeup_delay(void)
+{
+ vTaskDelay(pdMS_TO_TICKS(1));
+}
+
+// MCU specific PHY init, called BEFORE core reset
+static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+ (void) dwc2;
+ (void) hs_phy_type;
+
+ // nothing to do
+}
+
+// MCU specific PHY update, it is called AFTER init() and core reset
+static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+ (void) dwc2;
+ (void) hs_phy_type;
+
+ // nothing to do
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DWC2_ESP32_H_ */
diff --git a/src/portable/synopsys/dwc2/dwc2_gd32.h b/src/portable/synopsys/dwc2/dwc2_gd32.h
new file mode 100644
index 000000000..0375fffe4
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_gd32.h
@@ -0,0 +1,101 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+
+#ifndef DWC2_GD32_H_
+#define DWC2_GD32_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define DWC2_REG_BASE 0x50000000UL
+#define DWC2_EP_MAX 4
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ { .reg_base = DWC2_REG_BASE, .irqnum = 86, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1280 }
+};
+
+extern uint32_t SystemCoreClock;
+
+// The GD32VF103 is a RISC-V MCU, which implements the ECLIC Core-Local
+// Interrupt Controller by Nuclei. It is nearly API compatible to the
+// NVIC used by ARM MCUs.
+#define ECLIC_INTERRUPT_ENABLE_BASE 0xD2001001UL
+
+TU_ATTR_ALWAYS_INLINE
+static inline void __eclic_enable_interrupt (uint32_t irq) {
+ *(volatile uint8_t*)(ECLIC_INTERRUPT_ENABLE_BASE + (irq * 4)) = 1;
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void __eclic_disable_interrupt (uint32_t irq){
+ *(volatile uint8_t*)(ECLIC_INTERRUPT_ENABLE_BASE + (irq * 4)) = 0;
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_enable(uint8_t rhport)
+{
+ __eclic_enable_interrupt(_dwc2_controller[rhport].irqnum);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_disable (uint8_t rhport)
+{
+ __eclic_disable_interrupt(_dwc2_controller[rhport].irqnum);
+}
+
+static inline void dwc2_remote_wakeup_delay(void)
+{
+ // try to delay for 1 ms
+ uint32_t count = SystemCoreClock / 1000;
+ while ( count-- ) __asm volatile ("nop");
+}
+
+// MCU specific PHY init, called BEFORE core reset
+static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+ (void) dwc2;
+ (void) hs_phy_type;
+
+ // nothing to do
+}
+
+// MCU specific PHY update, it is called AFTER init() and core reset
+static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+ (void) dwc2;
+ (void) hs_phy_type;
+
+ // nothing to do
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DWC2_GD32_H_ */
diff --git a/src/portable/synopsys/dwc2/dwc2_info.md b/src/portable/synopsys/dwc2/dwc2_info.md
new file mode 100644
index 000000000..8690a0755
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_info.md
@@ -0,0 +1,55 @@
+| | BCM2711 (Pi4) | EFM32GG FullSpeed | ESP32-S2 | STM32F407 Fullspeed | STM32F407 Highspeed | STM32F411 Fullspeed | STM32F412 Fullspeed | STM32F429 Fullspeed | STM32F429 Highspeed | STM32F723 Fullspeed | STM32F723 HighSpeed | STM32F767 Fullspeed | STM32H743 Highspeed | STM32L476 Fullspeed | STM32U5A5 Highspeed | GD32VF103 Fullspeed | XMC4500 |
+|:----------------------------|:----------------|:--------------------|:-----------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:----------------------|:-----------|
+| guid | 0x2708A000 | 0x00000000 | 0x00000000 | 0x00001200 | 0x00001100 | 0x00001200 | 0x00002000 | 0x00001200 | 0x00001100 | 0x00003000 | 0x00003100 | 0x00002000 | 0x00002300 | 0x00002000 | 0x00005000 | 0x00001000 | 0x00AEC000 |
+| gsnpsid | 0x4F54280A | 0x4F54330A | 0x4F54400A | 0x4F54281A | 0x4F54281A | 0x4F54281A | 0x4F54320A | 0x4F54281A | 0x4F54281A | 0x4F54330A | 0x4F54330A | 0x4F54320A | 0x4F54330A | 0x4F54310A | 0x4F54411A | 0x00000000 | 0x4F54292A |
+| - specs version | 2.80a | 3.30a | 4.00a | 2.81a | 2.81a | 2.81a | 3.20a | 2.81a | 2.81a | 3.30a | 3.30a | 3.20a | 3.30a | 3.10a | 4.11a | 0.00W | 2.92a |
+| ghwcfg1 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 |
+| ghwcfg2 | 0x228DDD50 | 0x228F5910 | 0x224DD930 | 0x229DCD20 | 0x229ED590 | 0x229DCD20 | 0x229ED520 | 0x229DCD20 | 0x229ED590 | 0x229ED520 | 0x229FE1D0 | 0x229ED520 | 0x229FE190 | 0x229ED520 | 0x228FE052 | 0x00000000 | 0x228F5930 |
+| - op_mode | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 |
+| - arch | 2 | 2 | 2 | 0 | 2 | 0 | 0 | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 2 |
+| - point2point | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 |
+| - hs_phy_type | 1 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 2 | 0 | 3 | 0 | 2 | 0 | 1 | 0 | 0 |
+| - fs_phy_type | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
+| - num_dev_ep | 7 | 6 | 6 | 3 | 5 | 3 | 5 | 3 | 5 | 5 | 8 | 5 | 8 | 5 | 8 | 0 | 6 |
+| - num_host_ch | 7 | 13 | 7 | 7 | 11 | 7 | 11 | 7 | 11 | 11 | 15 | 11 | 15 | 11 | 15 | 0 | 13 |
+| - period_channel_support | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
+| - enable_dynamic_fifo | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
+| - mul_cpu_int | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - reserved21 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - nperiod_tx_q_depth | 2 | 2 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 0 | 2 |
+| - host_period_tx_q_depth | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 0 | 2 |
+| - dev_token_q_depth | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 | 8 |
+| - otg_enable_ic_usb | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| ghwcfg3 | 0x0FF000E8 | 0x01F204E8 | 0x00C804B5 | 0x020001E8 | 0x03F403E8 | 0x020001E8 | 0x0200D1E8 | 0x020001E8 | 0x03F403E8 | 0x0200D1E8 | 0x03EED2E8 | 0x0200D1E8 | 0x03B8D2E8 | 0x0200D1E8 | 0x03B882E8 | 0x00000000 | 0x027A01E5 |
+| - xfer_size_width | 8 | 8 | 5 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 | 5 |
+| - packet_size_width | 6 | 6 | 3 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 0 | 6 |
+| - otg_enable | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
+| - i2c_enable | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 |
+| - vendor_ctrl_itf | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 |
+| - optional_feature_removed | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - synch_reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - otg_adp_support | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - otg_enable_hsic | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - battery_charger_support | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - lpm_mode | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
+| - total_fifo_size | 4080 | 498 | 200 | 512 | 1012 | 512 | 512 | 512 | 1012 | 512 | 1006 | 512 | 952 | 512 | 952 | 0 | 634 |
+| ghwcfg4 | 0x1FF00020 | 0x1BF08030 | 0xD3F0A030 | 0x0FF08030 | 0x17F00030 | 0x0FF08030 | 0x17F08030 | 0x0FF08030 | 0x17F00030 | 0x17F08030 | 0x23F00030 | 0x17F08030 | 0xE3F00030 | 0x17F08030 | 0xE2103E30 | 0x00000000 | 0xDBF08030 |
+| - num_dev_period_in_ep | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - power_optimized | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
+| - ahb_freq_min | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
+| - hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - reserved7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 |
+| - service_interval_mode | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - ipg_isoc_en | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - acg_enable | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - reserved13 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - utmi_phy_data_width | 0 | 2 | 2 | 2 | 0 | 2 | 2 | 2 | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 0 | 2 |
+| - dev_ctrl_ep_num | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - iddg_filter_enabled | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
+| - vbus_valid_filter_enabled | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
+| - a_valid_filter_enabled | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
+| - b_valid_filter_enabled | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
+| - dedicated_fifos | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
+| - num_dev_in_eps | 15 | 13 | 9 | 7 | 11 | 7 | 11 | 7 | 11 | 11 | 1 | 11 | 1 | 11 | 1 | 0 | 13 |
+| - dma_desc_enable | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 |
+| - dma_dynamic | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
diff --git a/src/portable/synopsys/dwc2/dwc2_info.py b/src/portable/synopsys/dwc2/dwc2_info.py
new file mode 100644
index 000000000..55bec3d23
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_info.py
@@ -0,0 +1,169 @@
+import click
+import ctypes
+import pandas as pd
+
+# hex value for register: guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4
+dwc2_reg_list = ['guid', 'gsnpsid', 'ghwcfg1', 'ghwcfg2', 'ghwcfg3', 'ghwcfg4']
+dwc2_reg_value = {
+ 'BCM2711 (Pi4)': [0x2708A000, 0x4F54280A, 0, 0x228DDD50, 0xFF000E8, 0x1FF00020],
+ 'EFM32GG FullSpeed': [0, 0x4F54330A, 0, 0x228F5910, 0x1F204E8, 0x1BF08030],
+ 'ESP32-S2': [0, 0x4F54400A, 0, 0x224DD930, 0xC804B5, 0xD3F0A030],
+ 'STM32F407 Fullspeed': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x20001E8, 0xFF08030],
+ 'STM32F407 Highspeed': [0x1100, 0x4F54281A, 0, 0x229ED590, 0x3F403E8, 0x17F00030],
+ 'STM32F411 Fullspeed': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x20001E8, 0xFF08030],
+ 'STM32F412 Fullspeed': [0x2000, 0x4F54320A, 0, 0x229ED520, 0x200D1E8, 0x17F08030],
+ 'STM32F429 Fullspeed': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x20001E8, 0xFF08030],
+ 'STM32F429 Highspeed': [0x1100, 0x4F54281A, 0, 0x229ED590, 0x3F403E8, 0x17F00030],
+ 'STM32F723 Fullspeed': [0x3000, 0x4F54330A, 0, 0x229ED520, 0x200D1E8, 0x17F08030],
+ 'STM32F723 HighSpeed': [0x3100, 0x4F54330A, 0, 0x229FE1D0, 0x3EED2E8, 0x23F00030],
+ 'STM32F767 Fullspeed': [0x2000, 0x4F54320A, 0, 0x229ED520, 0x200D1E8, 0x17F08030],
+ 'STM32H743 Highspeed': [0x2300, 0x4F54330A, 0, 0x229FE190, 0x3B8D2E8, 0xE3F00030], # both HS cores
+ 'STM32L476 Fullspeed': [0x2000, 0x4F54310A, 0, 0x229ED520, 0x200D1E8, 0x17F08030],
+ 'STM32U5A5 Highspeed': [0x00005000, 0x4F54411A, 0x00000000, 0x228FE052, 0x03B882E8, 0xE2103E30],
+ 'GD32VF103 Fullspeed': [0x1000, 0, 0, 0, 0, 0],
+ 'XMC4500': [0xAEC000, 0x4F54292A, 0, 0x228F5930, 0x27A01E5, 0xDBF08030]
+}
+
+# Combine dwc2_info with dwc2_reg_list
+# dwc2_info = {
+# 'BCM2711 (Pi4)': {
+# 'guid': 0x2708A000,
+# 'gsnpsid': 0x4F54280A,
+# 'ghwcfg1': 0,
+# 'ghwcfg2': 0x228DDD50,
+# 'ghwcfg3': 0xFF000E8,
+# 'ghwcfg4': 0x1FF00020
+# },
+dwc2_info = {key: {field: value for field, value in zip(dwc2_reg_list, values)} for key, values in dwc2_reg_value.items()}
+
+
+class GHWCFG2(ctypes.LittleEndianStructure):
+ _fields_ = [
+ ("op_mode", ctypes.c_uint32, 3),
+ ("arch", ctypes.c_uint32, 2),
+ ("point2point", 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),
+ ("num_host_ch", ctypes.c_uint32, 4),
+ ("period_channel_support", ctypes.c_uint32, 1),
+ ("enable_dynamic_fifo", ctypes.c_uint32, 1),
+ ("mul_cpu_int", ctypes.c_uint32, 1),
+ ("reserved21", ctypes.c_uint32, 1),
+ ("nperiod_tx_q_depth", ctypes.c_uint32, 2),
+ ("host_period_tx_q_depth", ctypes.c_uint32, 2),
+ ("dev_token_q_depth", ctypes.c_uint32, 5),
+ ("otg_enable_ic_usb", ctypes.c_uint32, 1)
+ ]
+
+
+class GHWCFG3(ctypes.LittleEndianStructure):
+ _fields_ = [
+ ("xfer_size_width", ctypes.c_uint32, 4),
+ ("packet_size_width", ctypes.c_uint32, 3),
+ ("otg_enable", ctypes.c_uint32, 1),
+ ("i2c_enable", ctypes.c_uint32, 1),
+ ("vendor_ctrl_itf", ctypes.c_uint32, 1),
+ ("optional_feature_removed", ctypes.c_uint32, 1),
+ ("synch_reset", ctypes.c_uint32, 1),
+ ("otg_adp_support", ctypes.c_uint32, 1),
+ ("otg_enable_hsic", ctypes.c_uint32, 1),
+ ("battery_charger_support", ctypes.c_uint32, 1),
+ ("lpm_mode", ctypes.c_uint32, 1),
+ ("total_fifo_size", ctypes.c_uint32, 16)
+ ]
+
+
+class GHWCFG4(ctypes.LittleEndianStructure):
+ _fields_ = [
+ ("num_dev_period_in_ep", ctypes.c_uint32, 4),
+ ("power_optimized", ctypes.c_uint32, 1),
+ ("ahb_freq_min", ctypes.c_uint32, 1),
+ ("hibernation", ctypes.c_uint32, 1),
+ ("reserved7", ctypes.c_uint32, 3),
+ ("service_interval_mode", ctypes.c_uint32, 1),
+ ("ipg_isoc_en", ctypes.c_uint32, 1),
+ ("acg_enable", ctypes.c_uint32, 1),
+ ("reserved13", ctypes.c_uint32, 1),
+ ("utmi_phy_data_width", ctypes.c_uint32, 2),
+ ("dev_ctrl_ep_num", ctypes.c_uint32, 4),
+ ("iddg_filter_enabled", ctypes.c_uint32, 1),
+ ("vbus_valid_filter_enabled", ctypes.c_uint32, 1),
+ ("a_valid_filter_enabled", ctypes.c_uint32, 1),
+ ("b_valid_filter_enabled", ctypes.c_uint32, 1),
+ ("dedicated_fifos", ctypes.c_uint32, 1),
+ ("num_dev_in_eps", ctypes.c_uint32, 4),
+ ("dma_desc_enable", ctypes.c_uint32, 1),
+ ("dma_dynamic", ctypes.c_uint32, 1)
+ ]
+
+
+def cli():
+ pass
+
+
[email protected]('mcus', nargs=-1)
[email protected]('-a', '--all', is_flag=True, help='Print all bit-field values')
+def info(mcus, all):
+ """Print DWC2 register values for given MCU(s)"""
+ if len(mcus) == 0:
+ mcus = dwc2_info
+
+ for mcu in mcus:
+ for entry in dwc2_info:
+ if mcu.lower() in entry.lower():
+ print(f"## {entry}")
+ for r_name, r_value in dwc2_info[entry].items():
+ print(f"{r_name} = 0x{r_value:08X}")
+ # Print bit-field values
+ if all and r_name.upper() in globals():
+ class_name = globals()[r_name.upper()]
+ ghwcfg = class_name.from_buffer_copy(r_value.to_bytes(4, byteorder='little'))
+ for field_name, field_type, _ in class_name._fields_:
+ print(f" {field_name} = {getattr(ghwcfg, field_name)}")
+
+
+def render_md():
+ """Render dwc2_info to Markdown table"""
+ # Create an empty list to hold the dictionaries
+ dwc2_info_list = []
+
+ # Iterate over the dwc2_info dictionary and extract fields
+ for device, reg_values in dwc2_info.items():
+ entry_dict = {"Device": device}
+ for r_name, r_value in reg_values.items():
+ entry_dict[r_name] = f"0x{r_value:08X}"
+
+ if r_name == 'gsnpsid':
+ # Get dwc2 specs version
+ major = ((r_value >> 8) >> 4) & 0x0F
+ minor = (r_value >> 4) & 0xFF
+ patch = chr((r_value & 0x0F) + ord('a') - 0xA)
+ entry_dict[f' - specs version'] = f"{major:X}.{minor:02X}{patch}"
+ elif r_name.upper() in globals():
+ # Get bit-field values which exist as ctypes structures
+ class_name = globals()[r_name.upper()]
+ ghwcfg = class_name.from_buffer_copy(r_value.to_bytes(4, byteorder='little'))
+ for field_name, field_type, _ in class_name._fields_:
+ entry_dict[f' - {field_name}'] = getattr(ghwcfg, field_name)
+
+ dwc2_info_list.append(entry_dict)
+
+ # Create a Pandas DataFrame from the list of dictionaries
+ df = pd.DataFrame(dwc2_info_list).set_index('Device')
+
+ # Transpose the DataFrame to switch rows and columns
+ df = df.T
+ #print(df)
+
+ # Write the Markdown table to a file
+ with open('dwc2_info.md', 'w') as md_file:
+ md_file.write(df.to_markdown())
+ md_file.write('\n')
+
+
+if __name__ == '__main__':
+ cli()
diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h
new file mode 100644
index 000000000..3237a50f6
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_stm32.h
@@ -0,0 +1,261 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef DWC2_STM32_H_
+#define DWC2_STM32_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// EP_MAX : Max number of bi-directional endpoints including EP0
+// EP_FIFO_SIZE : Size of dedicated USB SRAM
+#if CFG_TUSB_MCU == OPT_MCU_STM32F1
+ #include "stm32f1xx.h"
+ #define EP_MAX_FS 4
+ #define EP_FIFO_SIZE_FS 1280
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F2
+ #include "stm32f2xx.h"
+ #define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS
+ #define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE
+
+ #define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS
+ #define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F4
+ #include "stm32f4xx.h"
+ #define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS
+ #define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE
+
+ #define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS
+ #define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32H7
+ #include "stm32h7xx.h"
+ #define EP_MAX_FS 9
+ #define EP_FIFO_SIZE_FS 4096
+
+ #define EP_MAX_HS 9
+ #define EP_FIFO_SIZE_HS 4096
+
+ // NOTE: H7 with only 1 USB port: H72x / H73x / H7Ax / H7Bx
+ // USB_OTG_FS_PERIPH_BASE and OTG_FS_IRQn not defined
+ #if (! defined USB2_OTG_FS)
+ #define USB_OTG_FS_PERIPH_BASE USB1_OTG_HS_PERIPH_BASE
+ #define OTG_FS_IRQn OTG_HS_IRQn
+ #endif
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F7
+ #include "stm32f7xx.h"
+ #define EP_MAX_FS 6
+ #define EP_FIFO_SIZE_FS 1280
+
+ #define EP_MAX_HS 9
+ #define EP_FIFO_SIZE_HS 4096
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
+ #include "stm32l4xx.h"
+ #define EP_MAX_FS 6
+ #define EP_FIFO_SIZE_FS 1280
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
+ #include "stm32u5xx.h"
+ // U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY
+ #ifdef USB_OTG_FS
+ #define USB_OTG_FS_PERIPH_BASE USB_OTG_FS_BASE
+ #define EP_MAX_FS 6
+ #define EP_FIFO_SIZE_FS 1280
+ #else
+ #define USB_OTG_HS_PERIPH_BASE USB_OTG_HS_BASE
+ #define EP_MAX_HS 9
+ #define EP_FIFO_SIZE_HS 4096
+ #endif
+#else
+ #error "Unsupported MCUs"
+#endif
+
+// OTG HS always has higher number of endpoints than FS
+#ifdef USB_OTG_HS_PERIPH_BASE
+ #define DWC2_EP_MAX EP_MAX_HS
+#else
+ #define DWC2_EP_MAX EP_MAX_FS
+#endif
+
+// On STM32 for consistency we associate
+// - Port0 to OTG_FS, and Port1 to OTG_HS
+static const dwc2_controller_t _dwc2_controller[] = {
+ #ifdef USB_OTG_FS_PERIPH_BASE
+ { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .ep_fifo_size = EP_FIFO_SIZE_FS },
+ #endif
+
+ #ifdef USB_OTG_HS_PERIPH_BASE
+ { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .ep_fifo_size = EP_FIFO_SIZE_HS },
+ #endif
+};
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+// SystemCoreClock is already included by family header
+// extern uint32_t SystemCoreClock;
+
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_enable(uint8_t rhport) {
+ NVIC_EnableIRQ((IRQn_Type) _dwc2_controller[rhport].irqnum);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_disable(uint8_t rhport) {
+ NVIC_DisableIRQ((IRQn_Type) _dwc2_controller[rhport].irqnum);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) {
+ // try to delay for 1 ms
+ uint32_t count = SystemCoreClock / 1000;
+ while (count--) __NOP();
+}
+
+// MCU specific PHY init, called BEFORE core reset
+// - dwc2 3.30a (H5) use USB_HS_PHYC
+// - dwc2 4.11a (U5) use femtoPHY
+static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
+ if (hs_phy_type == HS_PHY_TYPE_NONE) {
+ // Enable on-chip FS PHY
+ dwc2->stm32_gccfg |= STM32_GCCFG_PWRDWN;
+
+ // https://community.st.com/t5/stm32cubemx-mcus/why-stm32h743-usb-fs-doesn-t-work-if-freertos-tickless-idle/m-p/349480#M18867
+ // H7 running on full-speed phy need to disable ULPI clock in sleep mode.
+ // Otherwise, USB won't work when mcu executing WFI/WFE instruction i.e tick-less RTOS.
+ // Note: there may be other family that is affected by this, but only H7 and F7 is tested so far
+ #if defined(USB_OTG_FS_PERIPH_BASE) && defined(RCC_AHB1LPENR_USB2OTGFSULPILPEN)
+ if ( USB_OTG_FS_PERIPH_BASE == (uint32_t) dwc2 ) {
+ RCC->AHB1LPENR &= ~RCC_AHB1LPENR_USB2OTGFSULPILPEN;
+ }
+ #endif
+
+ #if defined(USB_OTG_HS_PERIPH_BASE) && defined(RCC_AHB1LPENR_USB1OTGHSULPILPEN)
+ if ( USB_OTG_HS_PERIPH_BASE == (uint32_t) dwc2 ) {
+ RCC->AHB1LPENR &= ~RCC_AHB1LPENR_USB1OTGHSULPILPEN;
+ }
+ #endif
+
+ #if defined(USB_OTG_HS_PERIPH_BASE) && defined(RCC_AHB1LPENR_OTGHSULPILPEN)
+ if ( USB_OTG_HS_PERIPH_BASE == (uint32_t) dwc2 ) {
+ RCC->AHB1LPENR &= ~RCC_AHB1LPENR_OTGHSULPILPEN;
+ }
+ #endif
+
+ } else {
+#if CFG_TUSB_MCU != OPT_MCU_STM32U5
+ // Disable FS PHY, TODO on U5A5 (dwc2 4.11a) 16th bit is 'Host CDP behavior enable'
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_PWRDWN;
+#endif
+
+ // Enable on-chip HS PHY
+ if (hs_phy_type == HS_PHY_TYPE_UTMI || hs_phy_type == HS_PHY_TYPE_UTMI_ULPI) {
+ #ifdef USB_HS_PHYC
+ // Enable UTMI HS PHY
+ dwc2->stm32_gccfg |= STM32_GCCFG_PHYHSEN;
+
+ // Enable LDO
+ USB_HS_PHYC->USB_HS_PHYC_LDO |= USB_HS_PHYC_LDO_ENABLE;
+
+ // Wait until LDO ready
+ while ( 0 == (USB_HS_PHYC->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_STATUS) ) {}
+
+ uint32_t phyc_pll = 0;
+
+ // TODO Try to get HSE_VALUE from registers instead of depending CFLAGS
+ switch ( HSE_VALUE )
+ {
+ case 12000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12MHZ ; break;
+ case 12500000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12_5MHZ ; break;
+ case 16000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_16MHZ ; break;
+ case 24000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_24MHZ ; break;
+ case 25000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_25MHZ ; break;
+ case 32000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_Msk ; break; // Value not defined in header
+ default:
+ TU_ASSERT(false, );
+ }
+ USB_HS_PHYC->USB_HS_PHYC_PLL = phyc_pll;
+
+ // Control the tuning interface of the High Speed PHY
+ // Use magic value (USB_HS_PHYC_TUNE_VALUE) from ST driver for F7
+ USB_HS_PHYC->USB_HS_PHYC_TUNE |= 0x00000F13U;
+
+ // Enable PLL internal PHY
+ USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN;
+ #else
+
+ #endif
+ }
+ }
+}
+
+// MCU specific PHY update, it is called AFTER init() and core reset
+static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
+ // used to set turnaround time for fullspeed, nothing to do in highspeed mode
+ if (hs_phy_type == HS_PHY_TYPE_NONE) {
+ // Turnaround timeout depends on the AHB clock dictated by STM32 Reference Manual
+ uint32_t turnaround;
+
+ if (SystemCoreClock >= 32000000u) {
+ turnaround = 0x6u;
+ } else if (SystemCoreClock >= 27500000u) {
+ turnaround = 0x7u;
+ } else if (SystemCoreClock >= 24000000u) {
+ turnaround = 0x8u;
+ } else if (SystemCoreClock >= 21800000u) {
+ turnaround = 0x9u;
+ }
+ else if (SystemCoreClock >= 20000000u) {
+ turnaround = 0xAu;
+ }
+ else if (SystemCoreClock >= 18500000u) {
+ turnaround = 0xBu;
+ }
+ else if (SystemCoreClock >= 17200000u) {
+ turnaround = 0xCu;
+ }
+ else if (SystemCoreClock >= 16000000u) {
+ turnaround = 0xDu;
+ }
+ else if (SystemCoreClock >= 15000000u) {
+ turnaround = 0xEu;
+ }
+ else {
+ turnaround = 0xFu;
+ }
+
+ dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (turnaround << GUSBCFG_TRDT_Pos);
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h
new file mode 100644
index 000000000..c15771237
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -0,0 +1,1770 @@
+/**
+ * @author MCD Application Team
+ * Ha Thach (tinyusb.org)
+ *
+ * @attention
+ *
+ * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
+ * All rights reserved.</center></h2>
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ */
+
+#ifndef _TUSB_DWC2_TYPES_H_
+#define _TUSB_DWC2_TYPES_H_
+
+#include "stdint.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// Controller
+typedef struct
+{
+ uintptr_t reg_base;
+ uint32_t irqnum;
+ uint8_t ep_count;
+ uint32_t ep_fifo_size;
+}dwc2_controller_t;
+
+// DWC OTG HW Release versions
+#define DWC2_CORE_REV_2_71a 0x4f54271a
+#define DWC2_CORE_REV_2_72a 0x4f54272a
+#define DWC2_CORE_REV_2_80a 0x4f54280a
+#define DWC2_CORE_REV_2_90a 0x4f54290a
+#define DWC2_CORE_REV_2_91a 0x4f54291a
+#define DWC2_CORE_REV_2_92a 0x4f54292a
+#define DWC2_CORE_REV_2_94a 0x4f54294a
+#define DWC2_CORE_REV_3_00a 0x4f54300a
+#define DWC2_CORE_REV_3_10a 0x4f54310a
+#define DWC2_CORE_REV_4_00a 0x4f54400a
+#define DWC2_CORE_REV_4_11a 0x4f54411a
+#define DWC2_CORE_REV_4_20a 0x4f54420a
+#define DWC2_FS_IOT_REV_1_00a 0x5531100a
+#define DWC2_HS_IOT_REV_1_00a 0x5532100a
+#define DWC2_CORE_REV_MASK 0x0000ffff
+
+// DWC OTG HW Core ID
+#define DWC2_OTG_ID 0x4f540000
+#define DWC2_FS_IOT_ID 0x55310000
+#define DWC2_HS_IOT_ID 0x55320000
+
+#if 0
+// HS PHY
+typedef struct
+{
+ volatile uint32_t HS_PHYC_PLL; // 000h This register is used to control the PLL of the HS PHY.
+ volatile uint32_t Reserved04; // 004h Reserved
+ volatile uint32_t Reserved08; // 008h Reserved
+ volatile uint32_t HS_PHYC_TUNE; // 00Ch This register is used to control the tuning interface of the High Speed PHY.
+ volatile uint32_t Reserved10; // 010h Reserved
+ volatile uint32_t Reserved14; // 014h Reserved
+ volatile uint32_t HS_PHYC_LDO; // 018h This register is used to control the regulator (LDO).
+} HS_PHYC_GlobalTypeDef;
+#endif
+
+enum {
+ HS_PHY_TYPE_NONE = 0 , // not supported
+ HS_PHY_TYPE_UTMI , // internal PHY (mostly)
+ HS_PHY_TYPE_ULPI , // external PHY
+ HS_PHY_TYPE_UTMI_ULPI ,
+};
+
+enum {
+ FS_PHY_TYPE_NONE = 0, // not supported
+ FS_PHY_TYPE_DEDICATED,
+ FS_PHY_TYPE_UTMI,
+ FS_PHY_TYPE_ULPI,
+};
+
+typedef struct TU_ATTR_PACKED
+{
+ uint32_t op_mode : 3; // 0: HNP and SRP | 1: SRP | 2: non-HNP, non-SRP
+ uint32_t arch : 2; // 0: slave-only | 1: External DMA | 2: Internal DMA | 3: others
+ uint32_t point2point : 1; // 0: support hub and split | 1: no hub, no split
+ uint32_t hs_phy_type : 2; // 0: not supported | 1: UTMI+ | 2: ULPI | 3: UTMI+ and ULPI
+ uint32_t fs_phy_type : 2; // 0: not supported | 1: dedicated | 2: UTMI+ | 3: ULPI
+ uint32_t num_dev_ep : 4; // Number of device endpoints (not including EP0)
+ uint32_t num_host_ch : 4; // Number of host channel
+ uint32_t period_channel_support : 1; // Support Periodic OUT Host Channel
+ uint32_t enable_dynamic_fifo : 1; // Dynamic FIFO Sizing Enabled
+ uint32_t mul_cpu_int : 1; // Multi-Processor Interrupt Enabled
+ uint32_t reserved21 : 1;
+ uint32_t nperiod_tx_q_depth : 2; // Non-periodic request queue depth: 0 = 2. 1 = 4, 2 = 8
+ uint32_t host_period_tx_q_depth : 2; // Host periodic request queue depth: 0 = 2. 1 = 4, 2 = 8
+ uint32_t dev_token_q_depth : 5; // Device IN token sequence learning queue depth: 0-30
+ uint32_t otg_enable_ic_usb : 1; // 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; // Transfer size counter in bits = 11 + n (max 19 bits)
+ uint32_t packet_size_width : 3; // Packet size counter in bits = 4 + n (max 10 bits)
+ uint32_t otg_enable : 1; // 1 is OTG capable
+ uint32_t i2c_enable : 1; // I2C interface is available
+ uint32_t vendor_ctrl_itf : 1; // Vendor control interface is available
+ uint32_t optional_feature_removed : 1; // remove User ID, GPIO, SOF toggle & counter
+ uint32_t synch_reset : 1; // 0: async reset | 1: synch reset
+ uint32_t otg_adp_support : 1; // ADP logic is present along with HSOTG controller
+ uint32_t otg_enable_hsic : 1; // 1: HSIC-capable with shared UTMI PHY interface | 0: non-HSIC
+ uint32_t battery_charger_support : 1; // support battery charger
+ uint32_t lpm_mode : 1; // LPC mode
+ uint32_t total_fifo_size : 16; // DFIFO depth value 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; // Number of Device Periodic IN Endpoints
+ uint32_t power_optimized : 1; // Partial Power Down Enabled
+ uint32_t ahb_freq_min : 1; // 1: minimum of AHB frequency is less than 60 MHz
+ uint32_t hibernation : 1; // Hibernation feature is enabled
+ uint32_t reserved7 : 3;
+ uint32_t service_interval_mode : 1; // Service Interval supported
+ uint32_t ipg_isoc_en : 1; // IPG ISOC supported
+ uint32_t acg_enable : 1; // ACG enabled
+ uint32_t reserved13 : 1;
+ uint32_t utmi_phy_data_width : 2; // 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable
+ uint32_t dev_ctrl_ep_num : 4; // Number of Device control endpoints in addition to EP0
+ uint32_t iddg_filter_enabled : 1;
+ uint32_t vbus_valid_filter_enabled : 1;
+ uint32_t a_valid_filter_enabled : 1;
+ uint32_t b_valid_filter_enabled : 1;
+ uint32_t dedicated_fifos : 1; // Dedicated tx fifo for device IN Endpoint is enabled
+ uint32_t num_dev_in_eps : 4; // Number of Device IN Endpoints including EP0
+ uint32_t dma_desc_enable : 1; // scatter/gather DMA configuration
+ uint32_t dma_dynamic : 1; // Dynamic scatter/gather DMA
+}dwc2_ghwcfg4_t;
+
+TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg4_t) == 4, "incorrect size");
+
+// Host Channel
+typedef struct
+{
+ 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;
+
+// Endpoint IN
+typedef struct
+{
+ volatile uint32_t diepctl; // 900 + 20*ep Device IN Endpoint Control
+ uint32_t reserved04; // 904
+ volatile uint32_t diepint; // 908 + 20*ep Device IN Endpoint Interrupt
+ uint32_t reserved0c; // 90C
+ volatile uint32_t dieptsiz; // 910 + 20*ep Device IN Endpoint Transfer Size
+ volatile uint32_t diepdma; // 914 + 20*ep Device IN Endpoint DMA Address
+ volatile uint32_t dtxfsts; // 918 + 20*ep Device IN Endpoint Tx FIFO Status
+ uint32_t reserved1c; // 91C
+} dwc2_epin_t;
+
+// Endpoint OUT
+typedef struct
+{
+ volatile uint32_t doepctl; // B00 + 20*ep Device OUT Endpoint Control
+ uint32_t reserved04; // B04
+ volatile uint32_t doepint; // B08 + 20*ep Device OUT Endpoint Interrupt
+ uint32_t reserved0c; // B0C
+ volatile uint32_t doeptsiz; // B10 + 20*ep Device OUT Endpoint Transfer Size
+ volatile uint32_t doepdma; // B14 + 20*ep Device OUT Endpoint DMA Address
+ uint32_t reserved18[2]; // B18..B1C
+} dwc2_epout_t;
+
+typedef struct
+{
+ //------------- Core Global -------------//
+ 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
+};
+ volatile uint32_t gnptxsts; // 02c Non-periodic Transmit FIFO/Queue Status
+ 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
+ dwc2_ghwcfg2_t ghwcfg2_bm;
+};
+union {
+ volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3
+ dwc2_ghwcfg3_t ghwcfg3_bm;
+};
+union {
+ volatile uint32_t ghwcfg4; // 050 User Hardware Configuration4
+ 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
+
+ //------------- 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
+
+ //------------- 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
+ volatile uint32_t deachint; // 838 Device Each Endpoint Interrupt
+ volatile uint32_t deachmsk; // 83C Device Each Endpoint Interrupt msk
+ 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 -------------//
+ dwc2_epin_t epin[16]; // 900..AFF IN Endpoints
+ dwc2_epout_t epout[16]; // B00..CFF OUT Endpoints
+ uint32_t reservedd00[64]; // D00..DFF
+
+ //------------- Power Clock -------------//
+ volatile uint32_t pcgctl; // E00 Power and Clock Gating Control
+ volatile uint32_t pcgctl1; // E04
+ 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
+} dwc2_regs_t;
+
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, hcfg ) == 0x0400, "incorrect size");
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, channel) == 0x0500, "incorrect size");
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, dcfg ) == 0x0800, "incorrect size");
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, epin ) == 0x0900, "incorrect size");
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, epout ) == 0x0B00, "incorrect size");
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, pcgctl ) == 0x0E00, "incorrect size");
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
+
+//--------------------------------------------------------------------+
+// Register Bit Definitions
+//--------------------------------------------------------------------+
+
+/******************** Bit definition for GOTGCTL register ********************/
+#define GOTGCTL_SRQSCS_Pos (0U)
+#define GOTGCTL_SRQSCS_Msk (0x1UL << GOTGCTL_SRQSCS_Pos) // 0x00000001
+#define GOTGCTL_SRQSCS GOTGCTL_SRQSCS_Msk // Session request success
+#define GOTGCTL_SRQ_Pos (1U)
+#define GOTGCTL_SRQ_Msk (0x1UL << GOTGCTL_SRQ_Pos) // 0x00000002
+#define GOTGCTL_SRQ GOTGCTL_SRQ_Msk // Session request
+#define GOTGCTL_VBVALOEN_Pos (2U)
+#define GOTGCTL_VBVALOEN_Msk (0x1UL << GOTGCTL_VBVALOEN_Pos) // 0x00000004
+#define GOTGCTL_VBVALOEN GOTGCTL_VBVALOEN_Msk // VBUS valid override enable
+#define GOTGCTL_VBVALOVAL_Pos (3U)
+#define GOTGCTL_VBVALOVAL_Msk (0x1UL << GOTGCTL_VBVALOVAL_Pos) // 0x00000008
+#define GOTGCTL_VBVALOVAL GOTGCTL_VBVALOVAL_Msk // VBUS valid override value
+#define GOTGCTL_AVALOEN_Pos (4U)
+#define GOTGCTL_AVALOEN_Msk (0x1UL << GOTGCTL_AVALOEN_Pos) // 0x00000010
+#define GOTGCTL_AVALOEN GOTGCTL_AVALOEN_Msk // A-peripheral session valid override enable
+#define GOTGCTL_AVALOVAL_Pos (5U)
+#define GOTGCTL_AVALOVAL_Msk (0x1UL << GOTGCTL_AVALOVAL_Pos) // 0x00000020
+#define GOTGCTL_AVALOVAL GOTGCTL_AVALOVAL_Msk // A-peripheral session valid override value
+#define GOTGCTL_BVALOEN_Pos (6U)
+#define GOTGCTL_BVALOEN_Msk (0x1UL << GOTGCTL_BVALOEN_Pos) // 0x00000040
+#define GOTGCTL_BVALOEN GOTGCTL_BVALOEN_Msk // B-peripheral session valid override enable
+#define GOTGCTL_BVALOVAL_Pos (7U)
+#define GOTGCTL_BVALOVAL_Msk (0x1UL << GOTGCTL_BVALOVAL_Pos) // 0x00000080
+#define GOTGCTL_BVALOVAL GOTGCTL_BVALOVAL_Msk // B-peripheral session valid override value
+#define GOTGCTL_HNGSCS_Pos (8U)
+#define GOTGCTL_HNGSCS_Msk (0x1UL << GOTGCTL_HNGSCS_Pos) // 0x00000100
+#define GOTGCTL_HNGSCS GOTGCTL_HNGSCS_Msk // Host set HNP enable
+#define GOTGCTL_HNPRQ_Pos (9U)
+#define GOTGCTL_HNPRQ_Msk (0x1UL << GOTGCTL_HNPRQ_Pos) // 0x00000200
+#define GOTGCTL_HNPRQ GOTGCTL_HNPRQ_Msk // HNP request
+#define GOTGCTL_HSHNPEN_Pos (10U)
+#define GOTGCTL_HSHNPEN_Msk (0x1UL << GOTGCTL_HSHNPEN_Pos) // 0x00000400
+#define GOTGCTL_HSHNPEN GOTGCTL_HSHNPEN_Msk // Host set HNP enable
+#define GOTGCTL_DHNPEN_Pos (11U)
+#define GOTGCTL_DHNPEN_Msk (0x1UL << GOTGCTL_DHNPEN_Pos) // 0x00000800
+#define GOTGCTL_DHNPEN GOTGCTL_DHNPEN_Msk // Device HNP enabled
+#define GOTGCTL_EHEN_Pos (12U)
+#define GOTGCTL_EHEN_Msk (0x1UL << GOTGCTL_EHEN_Pos) // 0x00001000
+#define GOTGCTL_EHEN GOTGCTL_EHEN_Msk // Embedded host enable
+#define GOTGCTL_CIDSTS_Pos (16U)
+#define GOTGCTL_CIDSTS_Msk (0x1UL << GOTGCTL_CIDSTS_Pos) // 0x00010000
+#define GOTGCTL_CIDSTS GOTGCTL_CIDSTS_Msk // Connector ID status
+#define GOTGCTL_DBCT_Pos (17U)
+#define GOTGCTL_DBCT_Msk (0x1UL << GOTGCTL_DBCT_Pos) // 0x00020000
+#define GOTGCTL_DBCT GOTGCTL_DBCT_Msk // Long/short debounce time
+#define GOTGCTL_ASVLD_Pos (18U)
+#define GOTGCTL_ASVLD_Msk (0x1UL << GOTGCTL_ASVLD_Pos) // 0x00040000
+#define GOTGCTL_ASVLD GOTGCTL_ASVLD_Msk // A-session valid
+#define GOTGCTL_BSESVLD_Pos (19U)
+#define GOTGCTL_BSESVLD_Msk (0x1UL << GOTGCTL_BSESVLD_Pos) // 0x00080000
+#define GOTGCTL_BSESVLD GOTGCTL_BSESVLD_Msk // B-session valid
+#define GOTGCTL_OTGVER_Pos (20U)
+#define GOTGCTL_OTGVER_Msk (0x1UL << GOTGCTL_OTGVER_Pos) // 0x00100000
+#define GOTGCTL_OTGVER GOTGCTL_OTGVER_Msk // OTG version
+
+/******************** Bit definition for HCFG register ********************/
+#define HCFG_FSLSPCS_Pos (0U)
+#define HCFG_FSLSPCS_Msk (0x3UL << HCFG_FSLSPCS_Pos) // 0x00000003
+#define HCFG_FSLSPCS HCFG_FSLSPCS_Msk // FS/LS PHY clock select
+#define HCFG_FSLSPCS_0 (0x1UL << HCFG_FSLSPCS_Pos) // 0x00000001
+#define HCFG_FSLSPCS_1 (0x2UL << HCFG_FSLSPCS_Pos) // 0x00000002
+#define HCFG_FSLSS_Pos (2U)
+#define HCFG_FSLSS_Msk (0x1UL << HCFG_FSLSS_Pos) // 0x00000004
+#define HCFG_FSLSS HCFG_FSLSS_Msk // FS- and LS-only support
+
+/******************** Bit definition for PCGCR register ********************/
+#define PCGCR_STPPCLK_Pos (0U)
+#define PCGCR_STPPCLK_Msk (0x1UL << PCGCR_STPPCLK_Pos) // 0x00000001
+#define PCGCR_STPPCLK PCGCR_STPPCLK_Msk // Stop PHY clock
+#define PCGCR_GATEHCLK_Pos (1U)
+#define PCGCR_GATEHCLK_Msk (0x1UL << PCGCR_GATEHCLK_Pos) // 0x00000002
+#define PCGCR_GATEHCLK PCGCR_GATEHCLK_Msk // Gate HCLK
+#define PCGCR_PHYSUSP_Pos (4U)
+#define PCGCR_PHYSUSP_Msk (0x1UL << PCGCR_PHYSUSP_Pos) // 0x00000010
+#define PCGCR_PHYSUSP PCGCR_PHYSUSP_Msk // PHY suspended
+
+/******************** Bit definition for GOTGINT register ********************/
+#define GOTGINT_SEDET_Pos (2U)
+#define GOTGINT_SEDET_Msk (0x1UL << GOTGINT_SEDET_Pos) // 0x00000004
+#define GOTGINT_SEDET GOTGINT_SEDET_Msk // Session end detected
+#define GOTGINT_SRSSCHG_Pos (8U)
+#define GOTGINT_SRSSCHG_Msk (0x1UL << GOTGINT_SRSSCHG_Pos) // 0x00000100
+#define GOTGINT_SRSSCHG GOTGINT_SRSSCHG_Msk // Session request success status change
+#define GOTGINT_HNSSCHG_Pos (9U)
+#define GOTGINT_HNSSCHG_Msk (0x1UL << GOTGINT_HNSSCHG_Pos) // 0x00000200
+#define GOTGINT_HNSSCHG GOTGINT_HNSSCHG_Msk // Host negotiation success status change
+#define GOTGINT_HNGDET_Pos (17U)
+#define GOTGINT_HNGDET_Msk (0x1UL << GOTGINT_HNGDET_Pos) // 0x00020000
+#define GOTGINT_HNGDET GOTGINT_HNGDET_Msk // Host negotiation detected
+#define GOTGINT_ADTOCHG_Pos (18U)
+#define GOTGINT_ADTOCHG_Msk (0x1UL << GOTGINT_ADTOCHG_Pos) // 0x00040000
+#define GOTGINT_ADTOCHG GOTGINT_ADTOCHG_Msk // A-device timeout change
+#define GOTGINT_DBCDNE_Pos (19U)
+#define GOTGINT_DBCDNE_Msk (0x1UL << GOTGINT_DBCDNE_Pos) // 0x00080000
+#define GOTGINT_DBCDNE GOTGINT_DBCDNE_Msk // Debounce done
+#define GOTGINT_IDCHNG_Pos (20U)
+#define GOTGINT_IDCHNG_Msk (0x1UL << GOTGINT_IDCHNG_Pos) // 0x00100000
+#define GOTGINT_IDCHNG GOTGINT_IDCHNG_Msk // Change in ID pin input value
+
+/******************** Bit definition for DCFG register ********************/
+#define DCFG_DSPD_Pos (0U)
+#define DCFG_DSPD_Msk (0x3UL << DCFG_DSPD_Pos) // 0x00000003
+#define DCFG_DSPD_HS 0 // Highspeed
+#define DCFG_DSPD_FS_HSPHY 1 // Fullspeed on HS PHY
+#define DCFG_DSPD_LS 2 // Lowspeed
+#define DCFG_DSPD_FS 3 // Fullspeed on FS PHY
+
+#define DCFG_NZLSOHSK_Pos (2U)
+#define DCFG_NZLSOHSK_Msk (0x1UL << DCFG_NZLSOHSK_Pos) // 0x00000004
+#define DCFG_NZLSOHSK DCFG_NZLSOHSK_Msk // Nonzero-length status OUT handshake
+
+#define DCFG_DAD_Pos (4U)
+#define DCFG_DAD_Msk (0x7FUL << DCFG_DAD_Pos) // 0x000007F0
+#define DCFG_DAD DCFG_DAD_Msk // Device address
+#define DCFG_DAD_0 (0x01UL << DCFG_DAD_Pos) // 0x00000010
+#define DCFG_DAD_1 (0x02UL << DCFG_DAD_Pos) // 0x00000020
+#define DCFG_DAD_2 (0x04UL << DCFG_DAD_Pos) // 0x00000040
+#define DCFG_DAD_3 (0x08UL << DCFG_DAD_Pos) // 0x00000080
+#define DCFG_DAD_4 (0x10UL << DCFG_DAD_Pos) // 0x00000100
+#define DCFG_DAD_5 (0x20UL << DCFG_DAD_Pos) // 0x00000200
+#define DCFG_DAD_6 (0x40UL << DCFG_DAD_Pos) // 0x00000400
+
+#define DCFG_PFIVL_Pos (11U)
+#define DCFG_PFIVL_Msk (0x3UL << DCFG_PFIVL_Pos) // 0x00001800
+#define DCFG_PFIVL DCFG_PFIVL_Msk // Periodic (micro)frame interval
+#define DCFG_PFIVL_0 (0x1UL << DCFG_PFIVL_Pos) // 0x00000800
+#define DCFG_PFIVL_1 (0x2UL << DCFG_PFIVL_Pos) // 0x00001000
+
+#define DCFG_XCVRDLY_Pos (14U)
+#define DCFG_XCVRDLY_Msk (0x1UL << DCFG_XCVRDLY_Pos) // 0x00004000
+#define DCFG_XCVRDLY DCFG_XCVRDLY_Msk // Enables delay between xcvr_sel and txvalid during device chirp
+
+#define DCFG_PERSCHIVL_Pos (24U)
+#define DCFG_PERSCHIVL_Msk (0x3UL << DCFG_PERSCHIVL_Pos) // 0x03000000
+#define DCFG_PERSCHIVL DCFG_PERSCHIVL_Msk // Periodic scheduling interval
+#define DCFG_PERSCHIVL_0 (0x1UL << DCFG_PERSCHIVL_Pos) // 0x01000000
+#define DCFG_PERSCHIVL_1 (0x2UL << DCFG_PERSCHIVL_Pos) // 0x02000000
+
+/******************** Bit definition for DCTL register ********************/
+#define DCTL_RWUSIG_Pos (0U)
+#define DCTL_RWUSIG_Msk (0x1UL << DCTL_RWUSIG_Pos) // 0x00000001
+#define DCTL_RWUSIG DCTL_RWUSIG_Msk // Remote wakeup signaling
+#define DCTL_SDIS_Pos (1U)
+#define DCTL_SDIS_Msk (0x1UL << DCTL_SDIS_Pos) // 0x00000002
+#define DCTL_SDIS DCTL_SDIS_Msk // Soft disconnect
+#define DCTL_GINSTS_Pos (2U)
+#define DCTL_GINSTS_Msk (0x1UL << DCTL_GINSTS_Pos) // 0x00000004
+#define DCTL_GINSTS DCTL_GINSTS_Msk // Global IN NAK status
+#define DCTL_GONSTS_Pos (3U)
+#define DCTL_GONSTS_Msk (0x1UL << DCTL_GONSTS_Pos) // 0x00000008
+#define DCTL_GONSTS DCTL_GONSTS_Msk // Global OUT NAK status
+
+#define DCTL_TCTL_Pos (4U)
+#define DCTL_TCTL_Msk (0x7UL << DCTL_TCTL_Pos) // 0x00000070
+#define DCTL_TCTL DCTL_TCTL_Msk // Test control
+#define DCTL_TCTL_0 (0x1UL << DCTL_TCTL_Pos) // 0x00000010
+#define DCTL_TCTL_1 (0x2UL << DCTL_TCTL_Pos) // 0x00000020
+#define DCTL_TCTL_2 (0x4UL << DCTL_TCTL_Pos) // 0x00000040
+#define DCTL_SGINAK_Pos (7U)
+#define DCTL_SGINAK_Msk (0x1UL << DCTL_SGINAK_Pos) // 0x00000080
+#define DCTL_SGINAK DCTL_SGINAK_Msk // Set global IN NAK
+#define DCTL_CGINAK_Pos (8U)
+#define DCTL_CGINAK_Msk (0x1UL << DCTL_CGINAK_Pos) // 0x00000100
+#define DCTL_CGINAK DCTL_CGINAK_Msk // Clear global IN NAK
+#define DCTL_SGONAK_Pos (9U)
+#define DCTL_SGONAK_Msk (0x1UL << DCTL_SGONAK_Pos) // 0x00000200
+#define DCTL_SGONAK DCTL_SGONAK_Msk // Set global OUT NAK
+#define DCTL_CGONAK_Pos (10U)
+#define DCTL_CGONAK_Msk (0x1UL << DCTL_CGONAK_Pos) // 0x00000400
+#define DCTL_CGONAK DCTL_CGONAK_Msk // Clear global OUT NAK
+#define DCTL_POPRGDNE_Pos (11U)
+#define DCTL_POPRGDNE_Msk (0x1UL << DCTL_POPRGDNE_Pos) // 0x00000800
+#define DCTL_POPRGDNE DCTL_POPRGDNE_Msk // Power-on programming done
+
+/******************** Bit definition for HFIR register ********************/
+#define HFIR_FRIVL_Pos (0U)
+#define HFIR_FRIVL_Msk (0xFFFFUL << HFIR_FRIVL_Pos) // 0x0000FFFF
+#define HFIR_FRIVL HFIR_FRIVL_Msk // Frame interval
+
+/******************** Bit definition for HFNUM register ********************/
+#define HFNUM_FRNUM_Pos (0U)
+#define HFNUM_FRNUM_Msk (0xFFFFUL << HFNUM_FRNUM_Pos) // 0x0000FFFF
+#define HFNUM_FRNUM HFNUM_FRNUM_Msk // Frame number
+#define HFNUM_FTREM_Pos (16U)
+#define HFNUM_FTREM_Msk (0xFFFFUL << HFNUM_FTREM_Pos) // 0xFFFF0000
+#define HFNUM_FTREM HFNUM_FTREM_Msk // Frame time remaining
+
+/******************** Bit definition for DSTS register ********************/
+#define DSTS_SUSPSTS_Pos (0U)
+#define DSTS_SUSPSTS_Msk (0x1UL << DSTS_SUSPSTS_Pos) // 0x00000001
+#define DSTS_SUSPSTS DSTS_SUSPSTS_Msk // Suspend status
+#define DSTS_ENUMSPD_Pos (1U)
+#define DSTS_ENUMSPD_Msk (0x3UL << DSTS_ENUMSPD_Pos) // 0x00000006
+#define DSTS_ENUMSPD DSTS_ENUMSPD_Msk // Enumerated speed
+#define DSTS_ENUMSPD_HS 0 // Highspeed
+#define DSTS_ENUMSPD_FS_HSPHY 1 // Fullspeed on HS PHY
+#define DSTS_ENUMSPD_LS 2 // Lowspeed
+#define DSTS_ENUMSPD_FS 3 // Fullspeed on FS PHY
+
+
+#define DSTS_EERR_Pos (3U)
+#define DSTS_EERR_Msk (0x1UL << DSTS_EERR_Pos) // 0x00000008
+#define DSTS_EERR DSTS_EERR_Msk // Erratic error
+#define DSTS_FNSOF_Pos (8U)
+#define DSTS_FNSOF_Msk (0x3FFFUL << DSTS_FNSOF_Pos) // 0x003FFF00
+#define DSTS_FNSOF DSTS_FNSOF_Msk // Frame number of the received SOF
+
+/******************** Bit definition for GAHBCFG register ********************/
+#define GAHBCFG_GINT_Pos (0U)
+#define GAHBCFG_GINT_Msk (0x1UL << GAHBCFG_GINT_Pos) // 0x00000001
+#define GAHBCFG_GINT GAHBCFG_GINT_Msk // Global interrupt mask
+#define GAHBCFG_HBSTLEN_Pos (1U)
+#define GAHBCFG_HBSTLEN_Msk (0xFUL << GAHBCFG_HBSTLEN_Pos) // 0x0000001E
+#define GAHBCFG_HBSTLEN GAHBCFG_HBSTLEN_Msk // Burst length/type
+#define GAHBCFG_HBSTLEN_0 (0x0UL << GAHBCFG_HBSTLEN_Pos) // Single
+#define GAHBCFG_HBSTLEN_1 (0x1UL << GAHBCFG_HBSTLEN_Pos) // INCR
+#define GAHBCFG_HBSTLEN_2 (0x3UL << GAHBCFG_HBSTLEN_Pos) // INCR4
+#define GAHBCFG_HBSTLEN_3 (0x5UL << GAHBCFG_HBSTLEN_Pos) // INCR8
+#define GAHBCFG_HBSTLEN_4 (0x7UL << GAHBCFG_HBSTLEN_Pos) // INCR16
+#define GAHBCFG_DMAEN_Pos (5U)
+#define GAHBCFG_DMAEN_Msk (0x1UL << GAHBCFG_DMAEN_Pos) // 0x00000020
+#define GAHBCFG_DMAEN GAHBCFG_DMAEN_Msk // DMA enable
+#define GAHBCFG_TXFELVL_Pos (7U)
+#define GAHBCFG_TXFELVL_Msk (0x1UL << GAHBCFG_TXFELVL_Pos) // 0x00000080
+#define GAHBCFG_TXFELVL GAHBCFG_TXFELVL_Msk // TxFIFO empty level
+#define GAHBCFG_PTXFELVL_Pos (8U)
+#define GAHBCFG_PTXFELVL_Msk (0x1UL << GAHBCFG_PTXFELVL_Pos) // 0x00000100
+#define GAHBCFG_PTXFELVL GAHBCFG_PTXFELVL_Msk // Periodic TxFIFO empty level
+
+#define GSNPSID_ID_MASK TU_GENMASK(31, 16)
+
+/******************** Bit definition for GUSBCFG register ********************/
+#define GUSBCFG_TOCAL_Pos (0U)
+#define GUSBCFG_TOCAL_Msk (0x7UL << GUSBCFG_TOCAL_Pos) // 0x00000007
+#define GUSBCFG_TOCAL GUSBCFG_TOCAL_Msk // FS timeout calibration
+#define GUSBCFG_PHYIF16_Pos (3U)
+#define GUSBCFG_PHYIF16_Msk (0x1UL << GUSBCFG_PHYIF16_Pos) // 0x00000008
+#define GUSBCFG_PHYIF16 GUSBCFG_PHYIF16_Msk // PHY Interface (PHYIf)
+#define GUSBCFG_ULPI_UTMI_SEL_Pos (4U)
+#define GUSBCFG_ULPI_UTMI_SEL_Msk (0x1UL << GUSBCFG_ULPI_UTMI_SEL_Pos) // 0x00000010
+#define GUSBCFG_ULPI_UTMI_SEL GUSBCFG_ULPI_UTMI_SEL_Msk // ULPI or UTMI+ Select (ULPI_UTMI_Sel)
+#define GUSBCFG_PHYSEL_Pos (6U)
+#define GUSBCFG_PHYSEL_Msk (0x1UL << GUSBCFG_PHYSEL_Pos) // 0x00000040
+#define GUSBCFG_PHYSEL GUSBCFG_PHYSEL_Msk // USB 2.0 high-speed ULPI PHY or USB 1.1 full-speed serial transceiver select
+#define GUSBCFG_DDRSEL TU_BIT(7) // Single Data Rate (SDR) or Double Data Rate (DDR) or ULPI interface.
+#define GUSBCFG_SRPCAP_Pos (8U)
+#define GUSBCFG_SRPCAP_Msk (0x1UL << GUSBCFG_SRPCAP_Pos) // 0x00000100
+#define GUSBCFG_SRPCAP GUSBCFG_SRPCAP_Msk // SRP-capable
+#define GUSBCFG_HNPCAP_Pos (9U)
+#define GUSBCFG_HNPCAP_Msk (0x1UL << GUSBCFG_HNPCAP_Pos) // 0x00000200
+#define GUSBCFG_HNPCAP GUSBCFG_HNPCAP_Msk // HNP-capable
+#define GUSBCFG_TRDT_Pos (10U)
+#define GUSBCFG_TRDT_Msk (0xFUL << GUSBCFG_TRDT_Pos) // 0x00003C00
+#define GUSBCFG_TRDT GUSBCFG_TRDT_Msk // USB turnaround time
+#define GUSBCFG_PHYLPCS_Pos (15U)
+#define GUSBCFG_PHYLPCS_Msk (0x1UL << GUSBCFG_PHYLPCS_Pos) // 0x00008000
+#define GUSBCFG_PHYLPCS GUSBCFG_PHYLPCS_Msk // PHY Low-power clock select
+#define GUSBCFG_ULPIFSLS_Pos (17U)
+#define GUSBCFG_ULPIFSLS_Msk (0x1UL << GUSBCFG_ULPIFSLS_Pos) // 0x00020000
+#define GUSBCFG_ULPIFSLS GUSBCFG_ULPIFSLS_Msk // ULPI FS/LS select
+#define GUSBCFG_ULPIAR_Pos (18U)
+#define GUSBCFG_ULPIAR_Msk (0x1UL << GUSBCFG_ULPIAR_Pos) // 0x00040000
+#define GUSBCFG_ULPIAR GUSBCFG_ULPIAR_Msk // ULPI Auto-resume
+#define GUSBCFG_ULPICSM_Pos (19U)
+#define GUSBCFG_ULPICSM_Msk (0x1UL << GUSBCFG_ULPICSM_Pos) // 0x00080000
+#define GUSBCFG_ULPICSM GUSBCFG_ULPICSM_Msk // ULPI Clock SuspendM
+#define GUSBCFG_ULPIEVBUSD_Pos (20U)
+#define GUSBCFG_ULPIEVBUSD_Msk (0x1UL << GUSBCFG_ULPIEVBUSD_Pos) // 0x00100000
+#define GUSBCFG_ULPIEVBUSD GUSBCFG_ULPIEVBUSD_Msk // ULPI External VBUS Drive
+#define GUSBCFG_ULPIEVBUSI_Pos (21U)
+#define GUSBCFG_ULPIEVBUSI_Msk (0x1UL << GUSBCFG_ULPIEVBUSI_Pos) // 0x00200000
+#define GUSBCFG_ULPIEVBUSI GUSBCFG_ULPIEVBUSI_Msk // ULPI external VBUS indicator
+#define GUSBCFG_TSDPS_Pos (22U)
+#define GUSBCFG_TSDPS_Msk (0x1UL << GUSBCFG_TSDPS_Pos) // 0x00400000
+#define GUSBCFG_TSDPS GUSBCFG_TSDPS_Msk // TermSel DLine pulsing selection
+#define GUSBCFG_PCCI_Pos (23U)
+#define GUSBCFG_PCCI_Msk (0x1UL << GUSBCFG_PCCI_Pos) // 0x00800000
+#define GUSBCFG_PCCI GUSBCFG_PCCI_Msk // Indicator complement
+#define GUSBCFG_PTCI_Pos (24U)
+#define GUSBCFG_PTCI_Msk (0x1UL << GUSBCFG_PTCI_Pos) // 0x01000000
+#define GUSBCFG_PTCI GUSBCFG_PTCI_Msk // Indicator pass through
+#define GUSBCFG_ULPIIPD_Pos (25U)
+#define GUSBCFG_ULPIIPD_Msk (0x1UL << GUSBCFG_ULPIIPD_Pos) // 0x02000000
+#define GUSBCFG_ULPIIPD GUSBCFG_ULPIIPD_Msk // ULPI interface protect disable
+#define GUSBCFG_FHMOD_Pos (29U)
+#define GUSBCFG_FHMOD_Msk (0x1UL << GUSBCFG_FHMOD_Pos) // 0x20000000
+#define GUSBCFG_FHMOD GUSBCFG_FHMOD_Msk // Forced host mode
+#define GUSBCFG_FDMOD_Pos (30U)
+#define GUSBCFG_FDMOD_Msk (0x1UL << GUSBCFG_FDMOD_Pos) // 0x40000000
+#define GUSBCFG_FDMOD GUSBCFG_FDMOD_Msk // Forced peripheral mode
+#define GUSBCFG_CTXPKT_Pos (31U)
+#define GUSBCFG_CTXPKT_Msk (0x1UL << GUSBCFG_CTXPKT_Pos) // 0x80000000
+#define GUSBCFG_CTXPKT GUSBCFG_CTXPKT_Msk // Corrupt Tx packet
+
+/******************** Bit definition for GRSTCTL register ********************/
+#define GRSTCTL_CSRST_Pos (0U)
+#define GRSTCTL_CSRST_Msk (0x1UL << GRSTCTL_CSRST_Pos) // 0x00000001
+#define GRSTCTL_CSRST GRSTCTL_CSRST_Msk // Core soft reset
+#define GRSTCTL_HSRST_Pos (1U)
+#define GRSTCTL_HSRST_Msk (0x1UL << GRSTCTL_HSRST_Pos) // 0x00000002
+#define GRSTCTL_HSRST GRSTCTL_HSRST_Msk // HCLK soft reset
+#define GRSTCTL_FCRST_Pos (2U)
+#define GRSTCTL_FCRST_Msk (0x1UL << GRSTCTL_FCRST_Pos) // 0x00000004
+#define GRSTCTL_FCRST GRSTCTL_FCRST_Msk // Host frame counter reset
+#define GRSTCTL_RXFFLSH_Pos (4U)
+#define GRSTCTL_RXFFLSH_Msk (0x1UL << GRSTCTL_RXFFLSH_Pos) // 0x00000010
+#define GRSTCTL_RXFFLSH GRSTCTL_RXFFLSH_Msk // RxFIFO flush
+#define GRSTCTL_TXFFLSH_Pos (5U)
+#define GRSTCTL_TXFFLSH_Msk (0x1UL << GRSTCTL_TXFFLSH_Pos) // 0x00000020
+#define GRSTCTL_TXFFLSH GRSTCTL_TXFFLSH_Msk // TxFIFO flush
+#define GRSTCTL_TXFNUM_Pos (6U)
+#define GRSTCTL_TXFNUM_Msk (0x1FUL << GRSTCTL_TXFNUM_Pos) // 0x000007C0
+#define GRSTCTL_TXFNUM GRSTCTL_TXFNUM_Msk // TxFIFO number
+#define GRSTCTL_TXFNUM_0 (0x01UL << GRSTCTL_TXFNUM_Pos) // 0x00000040
+#define GRSTCTL_TXFNUM_1 (0x02UL << GRSTCTL_TXFNUM_Pos) // 0x00000080
+#define GRSTCTL_TXFNUM_2 (0x04UL << GRSTCTL_TXFNUM_Pos) // 0x00000100
+#define GRSTCTL_TXFNUM_3 (0x08UL << GRSTCTL_TXFNUM_Pos) // 0x00000200
+#define GRSTCTL_TXFNUM_4 (0x10UL << GRSTCTL_TXFNUM_Pos) // 0x00000400
+#define GRSTCTL_CSFTRST_DONE_Pos (29)
+#define GRSTCTL_CSFTRST_DONE (1u << GRSTCTL_CSFTRST_DONE_Pos) // Reset Done, only available from v4.20a
+#define GRSTCTL_DMAREQ_Pos (30U)
+#define GRSTCTL_DMAREQ_Msk (0x1UL << GRSTCTL_DMAREQ_Pos) // 0x40000000
+#define GRSTCTL_DMAREQ GRSTCTL_DMAREQ_Msk // DMA request signal
+#define GRSTCTL_AHBIDL_Pos (31U)
+#define GRSTCTL_AHBIDL_Msk (0x1UL << GRSTCTL_AHBIDL_Pos) // 0x80000000
+#define GRSTCTL_AHBIDL GRSTCTL_AHBIDL_Msk // AHB master idle
+
+/******************** Bit definition for DIEPMSK register ********************/
+#define DIEPMSK_XFRCM_Pos (0U)
+#define DIEPMSK_XFRCM_Msk (0x1UL << DIEPMSK_XFRCM_Pos) // 0x00000001
+#define DIEPMSK_XFRCM DIEPMSK_XFRCM_Msk // Transfer completed interrupt mask
+#define DIEPMSK_EPDM_Pos (1U)
+#define DIEPMSK_EPDM_Msk (0x1UL << DIEPMSK_EPDM_Pos) // 0x00000002
+#define DIEPMSK_EPDM DIEPMSK_EPDM_Msk // Endpoint disabled interrupt mask
+#define DIEPMSK_TOM_Pos (3U)
+#define DIEPMSK_TOM_Msk (0x1UL << DIEPMSK_TOM_Pos) // 0x00000008
+#define DIEPMSK_TOM DIEPMSK_TOM_Msk // Timeout condition mask (nonisochronous endpoints)
+#define DIEPMSK_ITTXFEMSK_Pos (4U)
+#define DIEPMSK_ITTXFEMSK_Msk (0x1UL << DIEPMSK_ITTXFEMSK_Pos) // 0x00000010
+#define DIEPMSK_ITTXFEMSK DIEPMSK_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask
+#define DIEPMSK_INEPNMM_Pos (5U)
+#define DIEPMSK_INEPNMM_Msk (0x1UL << DIEPMSK_INEPNMM_Pos) // 0x00000020
+#define DIEPMSK_INEPNMM DIEPMSK_INEPNMM_Msk // IN token received with EP mismatch mask
+#define DIEPMSK_INEPNEM_Pos (6U)
+#define DIEPMSK_INEPNEM_Msk (0x1UL << DIEPMSK_INEPNEM_Pos) // 0x00000040
+#define DIEPMSK_INEPNEM DIEPMSK_INEPNEM_Msk // IN endpoint NAK effective mask
+#define DIEPMSK_TXFURM_Pos (8U)
+#define DIEPMSK_TXFURM_Msk (0x1UL << DIEPMSK_TXFURM_Pos) // 0x00000100
+#define DIEPMSK_TXFURM DIEPMSK_TXFURM_Msk // FIFO underrun mask
+#define DIEPMSK_BIM_Pos (9U)
+#define DIEPMSK_BIM_Msk (0x1UL << DIEPMSK_BIM_Pos) // 0x00000200
+#define DIEPMSK_BIM DIEPMSK_BIM_Msk // BNA interrupt mask
+
+/******************** Bit definition for HPTXSTS register ********************/
+#define HPTXSTS_PTXFSAVL_Pos (0U)
+#define HPTXSTS_PTXFSAVL_Msk (0xFFFFUL << HPTXSTS_PTXFSAVL_Pos) // 0x0000FFFF
+#define HPTXSTS_PTXFSAVL HPTXSTS_PTXFSAVL_Msk // Periodic transmit data FIFO space available
+#define HPTXSTS_PTXQSAV_Pos (16U)
+#define HPTXSTS_PTXQSAV_Msk (0xFFUL << HPTXSTS_PTXQSAV_Pos) // 0x00FF0000
+#define HPTXSTS_PTXQSAV HPTXSTS_PTXQSAV_Msk // Periodic transmit request queue space available
+#define HPTXSTS_PTXQSAV_0 (0x01UL << HPTXSTS_PTXQSAV_Pos) // 0x00010000
+#define HPTXSTS_PTXQSAV_1 (0x02UL << HPTXSTS_PTXQSAV_Pos) // 0x00020000
+#define HPTXSTS_PTXQSAV_2 (0x04UL << HPTXSTS_PTXQSAV_Pos) // 0x00040000
+#define HPTXSTS_PTXQSAV_3 (0x08UL << HPTXSTS_PTXQSAV_Pos) // 0x00080000
+#define HPTXSTS_PTXQSAV_4 (0x10UL << HPTXSTS_PTXQSAV_Pos) // 0x00100000
+#define HPTXSTS_PTXQSAV_5 (0x20UL << HPTXSTS_PTXQSAV_Pos) // 0x00200000
+#define HPTXSTS_PTXQSAV_6 (0x40UL << HPTXSTS_PTXQSAV_Pos) // 0x00400000
+#define HPTXSTS_PTXQSAV_7 (0x80UL << HPTXSTS_PTXQSAV_Pos) // 0x00800000
+
+#define HPTXSTS_PTXQTOP_Pos (24U)
+#define HPTXSTS_PTXQTOP_Msk (0xFFUL << HPTXSTS_PTXQTOP_Pos) // 0xFF000000
+#define HPTXSTS_PTXQTOP HPTXSTS_PTXQTOP_Msk // Top of the periodic transmit request queue
+#define HPTXSTS_PTXQTOP_0 (0x01UL << HPTXSTS_PTXQTOP_Pos) // 0x01000000
+#define HPTXSTS_PTXQTOP_1 (0x02UL << HPTXSTS_PTXQTOP_Pos) // 0x02000000
+#define HPTXSTS_PTXQTOP_2 (0x04UL << HPTXSTS_PTXQTOP_Pos) // 0x04000000
+#define HPTXSTS_PTXQTOP_3 (0x08UL << HPTXSTS_PTXQTOP_Pos) // 0x08000000
+#define HPTXSTS_PTXQTOP_4 (0x10UL << HPTXSTS_PTXQTOP_Pos) // 0x10000000
+#define HPTXSTS_PTXQTOP_5 (0x20UL << HPTXSTS_PTXQTOP_Pos) // 0x20000000
+#define HPTXSTS_PTXQTOP_6 (0x40UL << HPTXSTS_PTXQTOP_Pos) // 0x40000000
+#define HPTXSTS_PTXQTOP_7 (0x80UL << HPTXSTS_PTXQTOP_Pos) // 0x80000000
+
+/******************** Bit definition for HAINT register ********************/
+#define HAINT_HAINT_Pos (0U)
+#define HAINT_HAINT_Msk (0xFFFFUL << HAINT_HAINT_Pos) // 0x0000FFFF
+#define HAINT_HAINT HAINT_HAINT_Msk // Channel interrupts
+
+/******************** Bit definition for DOEPMSK register ********************/
+#define DOEPMSK_XFRCM_Pos (0U)
+#define DOEPMSK_XFRCM_Msk (0x1UL << DOEPMSK_XFRCM_Pos) // 0x00000001
+#define DOEPMSK_XFRCM DOEPMSK_XFRCM_Msk // Transfer completed interrupt mask
+#define DOEPMSK_EPDM_Pos (1U)
+#define DOEPMSK_EPDM_Msk (0x1UL << DOEPMSK_EPDM_Pos) // 0x00000002
+#define DOEPMSK_EPDM DOEPMSK_EPDM_Msk // Endpoint disabled interrupt mask
+#define DOEPMSK_AHBERRM_Pos (2U)
+#define DOEPMSK_AHBERRM_Msk (0x1UL << DOEPMSK_AHBERRM_Pos) // 0x00000004
+#define DOEPMSK_AHBERRM DOEPMSK_AHBERRM_Msk // OUT transaction AHB Error interrupt mask
+#define DOEPMSK_STUPM_Pos (3U)
+#define DOEPMSK_STUPM_Msk (0x1UL << DOEPMSK_STUPM_Pos) // 0x00000008
+#define DOEPMSK_STUPM DOEPMSK_STUPM_Msk // SETUP phase done mask
+#define DOEPMSK_OTEPDM_Pos (4U)
+#define DOEPMSK_OTEPDM_Msk (0x1UL << DOEPMSK_OTEPDM_Pos) // 0x00000010
+#define DOEPMSK_OTEPDM DOEPMSK_OTEPDM_Msk // OUT token received when endpoint disabled mask
+#define DOEPMSK_OTEPSPRM_Pos (5U)
+#define DOEPMSK_OTEPSPRM_Msk (0x1UL << DOEPMSK_OTEPSPRM_Pos) // 0x00000020
+#define DOEPMSK_OTEPSPRM DOEPMSK_OTEPSPRM_Msk // Status Phase Received mask
+#define DOEPMSK_B2BSTUP_Pos (6U)
+#define DOEPMSK_B2BSTUP_Msk (0x1UL << DOEPMSK_B2BSTUP_Pos) // 0x00000040
+#define DOEPMSK_B2BSTUP DOEPMSK_B2BSTUP_Msk // Back-to-back SETUP packets received mask
+#define DOEPMSK_OPEM_Pos (8U)
+#define DOEPMSK_OPEM_Msk (0x1UL << DOEPMSK_OPEM_Pos) // 0x00000100
+#define DOEPMSK_OPEM DOEPMSK_OPEM_Msk // OUT packet error mask
+#define DOEPMSK_BOIM_Pos (9U)
+#define DOEPMSK_BOIM_Msk (0x1UL << DOEPMSK_BOIM_Pos) // 0x00000200
+#define DOEPMSK_BOIM DOEPMSK_BOIM_Msk // BNA interrupt mask
+#define DOEPMSK_BERRM_Pos (12U)
+#define DOEPMSK_BERRM_Msk (0x1UL << DOEPMSK_BERRM_Pos) // 0x00001000
+#define DOEPMSK_BERRM DOEPMSK_BERRM_Msk // Babble error interrupt mask
+#define DOEPMSK_NAKM_Pos (13U)
+#define DOEPMSK_NAKM_Msk (0x1UL << DOEPMSK_NAKM_Pos) // 0x00002000
+#define DOEPMSK_NAKM DOEPMSK_NAKM_Msk // OUT Packet NAK interrupt mask
+#define DOEPMSK_NYETM_Pos (14U)
+#define DOEPMSK_NYETM_Msk (0x1UL << DOEPMSK_NYETM_Pos) // 0x00004000
+#define DOEPMSK_NYETM DOEPMSK_NYETM_Msk // NYET interrupt mask
+
+/******************** Bit definition for GINTSTS register ********************/
+#define GINTSTS_CMOD_Pos (0U)
+#define GINTSTS_CMOD_Msk (0x1UL << GINTSTS_CMOD_Pos) // 0x00000001
+#define GINTSTS_CMOD GINTSTS_CMOD_Msk // Current mode of operation
+#define GINTSTS_MMIS_Pos (1U)
+#define GINTSTS_MMIS_Msk (0x1UL << GINTSTS_MMIS_Pos) // 0x00000002
+#define GINTSTS_MMIS GINTSTS_MMIS_Msk // Mode mismatch interrupt
+#define GINTSTS_OTGINT_Pos (2U)
+#define GINTSTS_OTGINT_Msk (0x1UL << GINTSTS_OTGINT_Pos) // 0x00000004
+#define GINTSTS_OTGINT GINTSTS_OTGINT_Msk // OTG interrupt
+#define GINTSTS_SOF_Pos (3U)
+#define GINTSTS_SOF_Msk (0x1UL << GINTSTS_SOF_Pos) // 0x00000008
+#define GINTSTS_SOF GINTSTS_SOF_Msk // Start of frame
+#define GINTSTS_RXFLVL_Pos (4U)
+#define GINTSTS_RXFLVL_Msk (0x1UL << GINTSTS_RXFLVL_Pos) // 0x00000010
+#define GINTSTS_RXFLVL GINTSTS_RXFLVL_Msk // RxFIFO nonempty
+#define GINTSTS_NPTXFE_Pos (5U)
+#define GINTSTS_NPTXFE_Msk (0x1UL << GINTSTS_NPTXFE_Pos) // 0x00000020
+#define GINTSTS_NPTXFE GINTSTS_NPTXFE_Msk // Nonperiodic TxFIFO empty
+#define GINTSTS_GINAKEFF_Pos (6U)
+#define GINTSTS_GINAKEFF_Msk (0x1UL << GINTSTS_GINAKEFF_Pos) // 0x00000040
+#define GINTSTS_GINAKEFF GINTSTS_GINAKEFF_Msk // Global IN nonperiodic NAK effective
+#define GINTSTS_BOUTNAKEFF_Pos (7U)
+#define GINTSTS_BOUTNAKEFF_Msk (0x1UL << GINTSTS_BOUTNAKEFF_Pos) // 0x00000080
+#define GINTSTS_BOUTNAKEFF GINTSTS_BOUTNAKEFF_Msk // Global OUT NAK effective
+#define GINTSTS_ESUSP_Pos (10U)
+#define GINTSTS_ESUSP_Msk (0x1UL << GINTSTS_ESUSP_Pos) // 0x00000400
+#define GINTSTS_ESUSP GINTSTS_ESUSP_Msk // Early suspend
+#define GINTSTS_USBSUSP_Pos (11U)
+#define GINTSTS_USBSUSP_Msk (0x1UL << GINTSTS_USBSUSP_Pos) // 0x00000800
+#define GINTSTS_USBSUSP GINTSTS_USBSUSP_Msk // USB suspend
+#define GINTSTS_USBRST_Pos (12U)
+#define GINTSTS_USBRST_Msk (0x1UL << GINTSTS_USBRST_Pos) // 0x00001000
+#define GINTSTS_USBRST GINTSTS_USBRST_Msk // USB reset
+#define GINTSTS_ENUMDNE_Pos (13U)
+#define GINTSTS_ENUMDNE_Msk (0x1UL << GINTSTS_ENUMDNE_Pos) // 0x00002000
+#define GINTSTS_ENUMDNE GINTSTS_ENUMDNE_Msk // Enumeration done
+#define GINTSTS_ISOODRP_Pos (14U)
+#define GINTSTS_ISOODRP_Msk (0x1UL << GINTSTS_ISOODRP_Pos) // 0x00004000
+#define GINTSTS_ISOODRP GINTSTS_ISOODRP_Msk // Isochronous OUT packet dropped interrupt
+#define GINTSTS_EOPF_Pos (15U)
+#define GINTSTS_EOPF_Msk (0x1UL << GINTSTS_EOPF_Pos) // 0x00008000
+#define GINTSTS_EOPF GINTSTS_EOPF_Msk // End of periodic frame interrupt
+#define GINTSTS_IEPINT_Pos (18U)
+#define GINTSTS_IEPINT_Msk (0x1UL << GINTSTS_IEPINT_Pos) // 0x00040000
+#define GINTSTS_IEPINT GINTSTS_IEPINT_Msk // IN endpoint interrupt
+#define GINTSTS_OEPINT_Pos (19U)
+#define GINTSTS_OEPINT_Msk (0x1UL << GINTSTS_OEPINT_Pos) // 0x00080000
+#define GINTSTS_OEPINT GINTSTS_OEPINT_Msk // OUT endpoint interrupt
+#define GINTSTS_IISOIXFR_Pos (20U)
+#define GINTSTS_IISOIXFR_Msk (0x1UL << GINTSTS_IISOIXFR_Pos) // 0x00100000
+#define GINTSTS_IISOIXFR GINTSTS_IISOIXFR_Msk // Incomplete isochronous IN transfer
+#define GINTSTS_PXFR_INCOMPISOOUT_Pos (21U)
+#define GINTSTS_PXFR_INCOMPISOOUT_Msk (0x1UL << GINTSTS_PXFR_INCOMPISOOUT_Pos) // 0x00200000
+#define GINTSTS_PXFR_INCOMPISOOUT GINTSTS_PXFR_INCOMPISOOUT_Msk // Incomplete periodic transfer
+#define GINTSTS_DATAFSUSP_Pos (22U)
+#define GINTSTS_DATAFSUSP_Msk (0x1UL << GINTSTS_DATAFSUSP_Pos) // 0x00400000
+#define GINTSTS_DATAFSUSP GINTSTS_DATAFSUSP_Msk // Data fetch suspended
+#define GINTSTS_RSTDET_Pos (23U)
+#define GINTSTS_RSTDET_Msk (0x1UL << GINTSTS_RSTDET_Pos) // 0x00800000
+#define GINTSTS_RSTDET GINTSTS_RSTDET_Msk // Reset detected interrupt
+#define GINTSTS_HPRTINT_Pos (24U)
+#define GINTSTS_HPRTINT_Msk (0x1UL << GINTSTS_HPRTINT_Pos) // 0x01000000
+#define GINTSTS_HPRTINT GINTSTS_HPRTINT_Msk // Host port interrupt
+#define GINTSTS_HCINT_Pos (25U)
+#define GINTSTS_HCINT_Msk (0x1UL << GINTSTS_HCINT_Pos) // 0x02000000
+#define GINTSTS_HCINT GINTSTS_HCINT_Msk // Host channels interrupt
+#define GINTSTS_PTXFE_Pos (26U)
+#define GINTSTS_PTXFE_Msk (0x1UL << GINTSTS_PTXFE_Pos) // 0x04000000
+#define GINTSTS_PTXFE GINTSTS_PTXFE_Msk // Periodic TxFIFO empty
+#define GINTSTS_LPMINT_Pos (27U)
+#define GINTSTS_LPMINT_Msk (0x1UL << GINTSTS_LPMINT_Pos) // 0x08000000
+#define GINTSTS_LPMINT GINTSTS_LPMINT_Msk // LPM interrupt
+#define GINTSTS_CIDSCHG_Pos (28U)
+#define GINTSTS_CIDSCHG_Msk (0x1UL << GINTSTS_CIDSCHG_Pos) // 0x10000000
+#define GINTSTS_CIDSCHG GINTSTS_CIDSCHG_Msk // Connector ID status change
+#define GINTSTS_DISCINT_Pos (29U)
+#define GINTSTS_DISCINT_Msk (0x1UL << GINTSTS_DISCINT_Pos) // 0x20000000
+#define GINTSTS_DISCINT GINTSTS_DISCINT_Msk // Disconnect detected interrupt
+#define GINTSTS_SRQINT_Pos (30U)
+#define GINTSTS_SRQINT_Msk (0x1UL << GINTSTS_SRQINT_Pos) // 0x40000000
+#define GINTSTS_SRQINT GINTSTS_SRQINT_Msk // Session request/new session detected interrupt
+#define GINTSTS_WKUINT_Pos (31U)
+#define GINTSTS_WKUINT_Msk (0x1UL << GINTSTS_WKUINT_Pos) // 0x80000000
+#define GINTSTS_WKUINT GINTSTS_WKUINT_Msk // Resume/remote wakeup detected interrupt
+
+/******************** Bit definition for GINTMSK register ********************/
+#define GINTMSK_MMISM_Pos (1U)
+#define GINTMSK_MMISM_Msk (0x1UL << GINTMSK_MMISM_Pos) // 0x00000002
+#define GINTMSK_MMISM GINTMSK_MMISM_Msk // Mode mismatch interrupt mask
+#define GINTMSK_OTGINT_Pos (2U)
+#define GINTMSK_OTGINT_Msk (0x1UL << GINTMSK_OTGINT_Pos) // 0x00000004
+#define GINTMSK_OTGINT GINTMSK_OTGINT_Msk // OTG interrupt mask
+#define GINTMSK_SOFM_Pos (3U)
+#define GINTMSK_SOFM_Msk (0x1UL << GINTMSK_SOFM_Pos) // 0x00000008
+#define GINTMSK_SOFM GINTMSK_SOFM_Msk // Start of frame mask
+#define GINTMSK_RXFLVLM_Pos (4U)
+#define GINTMSK_RXFLVLM_Msk (0x1UL << GINTMSK_RXFLVLM_Pos) // 0x00000010
+#define GINTMSK_RXFLVLM GINTMSK_RXFLVLM_Msk // Receive FIFO nonempty mask
+#define GINTMSK_NPTXFEM_Pos (5U)
+#define GINTMSK_NPTXFEM_Msk (0x1UL << GINTMSK_NPTXFEM_Pos) // 0x00000020
+#define GINTMSK_NPTXFEM GINTMSK_NPTXFEM_Msk // Nonperiodic TxFIFO empty mask
+#define GINTMSK_GINAKEFFM_Pos (6U)
+#define GINTMSK_GINAKEFFM_Msk (0x1UL << GINTMSK_GINAKEFFM_Pos) // 0x00000040
+#define GINTMSK_GINAKEFFM GINTMSK_GINAKEFFM_Msk // Global nonperiodic IN NAK effective mask
+#define GINTMSK_GONAKEFFM_Pos (7U)
+#define GINTMSK_GONAKEFFM_Msk (0x1UL << GINTMSK_GONAKEFFM_Pos) // 0x00000080
+#define GINTMSK_GONAKEFFM GINTMSK_GONAKEFFM_Msk // Global OUT NAK effective mask
+#define GINTMSK_ESUSPM_Pos (10U)
+#define GINTMSK_ESUSPM_Msk (0x1UL << GINTMSK_ESUSPM_Pos) // 0x00000400
+#define GINTMSK_ESUSPM GINTMSK_ESUSPM_Msk // Early suspend mask
+#define GINTMSK_USBSUSPM_Pos (11U)
+#define GINTMSK_USBSUSPM_Msk (0x1UL << GINTMSK_USBSUSPM_Pos) // 0x00000800
+#define GINTMSK_USBSUSPM GINTMSK_USBSUSPM_Msk // USB suspend mask
+#define GINTMSK_USBRST_Pos (12U)
+#define GINTMSK_USBRST_Msk (0x1UL << GINTMSK_USBRST_Pos) // 0x00001000
+#define GINTMSK_USBRST GINTMSK_USBRST_Msk // USB reset mask
+#define GINTMSK_ENUMDNEM_Pos (13U)
+#define GINTMSK_ENUMDNEM_Msk (0x1UL << GINTMSK_ENUMDNEM_Pos) // 0x00002000
+#define GINTMSK_ENUMDNEM GINTMSK_ENUMDNEM_Msk // Enumeration done mask
+#define GINTMSK_ISOODRPM_Pos (14U)
+#define GINTMSK_ISOODRPM_Msk (0x1UL << GINTMSK_ISOODRPM_Pos) // 0x00004000
+#define GINTMSK_ISOODRPM GINTMSK_ISOODRPM_Msk // Isochronous OUT packet dropped interrupt mask
+#define GINTMSK_EOPFM_Pos (15U)
+#define GINTMSK_EOPFM_Msk (0x1UL << GINTMSK_EOPFM_Pos) // 0x00008000
+#define GINTMSK_EOPFM GINTMSK_EOPFM_Msk // End of periodic frame interrupt mask
+#define GINTMSK_EPMISM_Pos (17U)
+#define GINTMSK_EPMISM_Msk (0x1UL << GINTMSK_EPMISM_Pos) // 0x00020000
+#define GINTMSK_EPMISM GINTMSK_EPMISM_Msk // Endpoint mismatch interrupt mask
+#define GINTMSK_IEPINT_Pos (18U)
+#define GINTMSK_IEPINT_Msk (0x1UL << GINTMSK_IEPINT_Pos) // 0x00040000
+#define GINTMSK_IEPINT GINTMSK_IEPINT_Msk // IN endpoints interrupt mask
+#define GINTMSK_OEPINT_Pos (19U)
+#define GINTMSK_OEPINT_Msk (0x1UL << GINTMSK_OEPINT_Pos) // 0x00080000
+#define GINTMSK_OEPINT GINTMSK_OEPINT_Msk // OUT endpoints interrupt mask
+#define GINTMSK_IISOIXFRM_Pos (20U)
+#define GINTMSK_IISOIXFRM_Msk (0x1UL << GINTMSK_IISOIXFRM_Pos) // 0x00100000
+#define GINTMSK_IISOIXFRM GINTMSK_IISOIXFRM_Msk // Incomplete isochronous IN transfer mask
+#define GINTMSK_PXFRM_IISOOXFRM_Pos (21U)
+#define GINTMSK_PXFRM_IISOOXFRM_Msk (0x1UL << GINTMSK_PXFRM_IISOOXFRM_Pos) // 0x00200000
+#define GINTMSK_PXFRM_IISOOXFRM GINTMSK_PXFRM_IISOOXFRM_Msk // Incomplete periodic transfer mask
+#define GINTMSK_FSUSPM_Pos (22U)
+#define GINTMSK_FSUSPM_Msk (0x1UL << GINTMSK_FSUSPM_Pos) // 0x00400000
+#define GINTMSK_FSUSPM GINTMSK_FSUSPM_Msk // Data fetch suspended mask
+#define GINTMSK_RSTDEM_Pos (23U)
+#define GINTMSK_RSTDEM_Msk (0x1UL << GINTMSK_RSTDEM_Pos) // 0x00800000
+#define GINTMSK_RSTDEM GINTMSK_RSTDEM_Msk // Reset detected interrupt mask
+#define GINTMSK_PRTIM_Pos (24U)
+#define GINTMSK_PRTIM_Msk (0x1UL << GINTMSK_PRTIM_Pos) // 0x01000000
+#define GINTMSK_PRTIM GINTMSK_PRTIM_Msk // Host port interrupt mask
+#define GINTMSK_HCIM_Pos (25U)
+#define GINTMSK_HCIM_Msk (0x1UL << GINTMSK_HCIM_Pos) // 0x02000000
+#define GINTMSK_HCIM GINTMSK_HCIM_Msk // Host channels interrupt mask
+#define GINTMSK_PTXFEM_Pos (26U)
+#define GINTMSK_PTXFEM_Msk (0x1UL << GINTMSK_PTXFEM_Pos) // 0x04000000
+#define GINTMSK_PTXFEM GINTMSK_PTXFEM_Msk // Periodic TxFIFO empty mask
+#define GINTMSK_LPMINTM_Pos (27U)
+#define GINTMSK_LPMINTM_Msk (0x1UL << GINTMSK_LPMINTM_Pos) // 0x08000000
+#define GINTMSK_LPMINTM GINTMSK_LPMINTM_Msk // LPM interrupt Mask
+#define GINTMSK_CIDSCHGM_Pos (28U)
+#define GINTMSK_CIDSCHGM_Msk (0x1UL << GINTMSK_CIDSCHGM_Pos) // 0x10000000
+#define GINTMSK_CIDSCHGM GINTMSK_CIDSCHGM_Msk // Connector ID status change mask
+#define GINTMSK_DISCINT_Pos (29U)
+#define GINTMSK_DISCINT_Msk (0x1UL << GINTMSK_DISCINT_Pos) // 0x20000000
+#define GINTMSK_DISCINT GINTMSK_DISCINT_Msk // Disconnect detected interrupt mask
+#define GINTMSK_SRQIM_Pos (30U)
+#define GINTMSK_SRQIM_Msk (0x1UL << GINTMSK_SRQIM_Pos) // 0x40000000
+#define GINTMSK_SRQIM GINTMSK_SRQIM_Msk // Session request/new session detected interrupt mask
+#define GINTMSK_WUIM_Pos (31U)
+#define GINTMSK_WUIM_Msk (0x1UL << GINTMSK_WUIM_Pos) // 0x80000000
+#define GINTMSK_WUIM GINTMSK_WUIM_Msk // Resume/remote wakeup detected interrupt mask
+
+/******************** Bit definition for DAINT register ********************/
+#define DAINT_IEPINT_Pos (0U)
+#define DAINT_IEPINT_Msk (0xFFFFUL << DAINT_IEPINT_Pos) // 0x0000FFFF
+#define DAINT_IEPINT DAINT_IEPINT_Msk // IN endpoint interrupt bits
+#define DAINT_OEPINT_Pos (16U)
+#define DAINT_OEPINT_Msk (0xFFFFUL << DAINT_OEPINT_Pos) // 0xFFFF0000
+#define DAINT_OEPINT DAINT_OEPINT_Msk // OUT endpoint interrupt bits
+
+/******************** Bit definition for HAINTMSK register ********************/
+#define HAINTMSK_HAINTM_Pos (0U)
+#define HAINTMSK_HAINTM_Msk (0xFFFFUL << HAINTMSK_HAINTM_Pos) // 0x0000FFFF
+#define HAINTMSK_HAINTM HAINTMSK_HAINTM_Msk // Channel interrupt mask
+
+/******************** Bit definition for GRXSTSP register ********************/
+#define GRXSTSP_EPNUM_Pos (0U)
+#define GRXSTSP_EPNUM_Msk (0xFUL << GRXSTSP_EPNUM_Pos) // 0x0000000F
+#define GRXSTSP_EPNUM GRXSTSP_EPNUM_Msk // IN EP interrupt mask bits
+#define GRXSTSP_BCNT_Pos (4U)
+#define GRXSTSP_BCNT_Msk (0x7FFUL << GRXSTSP_BCNT_Pos) // 0x00007FF0
+#define GRXSTSP_BCNT GRXSTSP_BCNT_Msk // OUT EP interrupt mask bits
+#define GRXSTSP_DPID_Pos (15U)
+#define GRXSTSP_DPID_Msk (0x3UL << GRXSTSP_DPID_Pos) // 0x00018000
+#define GRXSTSP_DPID GRXSTSP_DPID_Msk // OUT EP interrupt mask bits
+#define GRXSTSP_PKTSTS_Pos (17U)
+#define GRXSTSP_PKTSTS_Msk (0xFUL << GRXSTSP_PKTSTS_Pos) // 0x001E0000
+#define GRXSTSP_PKTSTS GRXSTSP_PKTSTS_Msk // OUT EP interrupt mask bits
+
+#define GRXSTS_PKTSTS_GLOBALOUTNAK 1
+#define GRXSTS_PKTSTS_OUTRX 2
+#define GRXSTS_PKTSTS_HCHIN 2
+#define GRXSTS_PKTSTS_OUTDONE 3
+#define GRXSTS_PKTSTS_HCHIN_XFER_COMP 3
+#define GRXSTS_PKTSTS_SETUPDONE 4
+#define GRXSTS_PKTSTS_DATATOGGLEERR 5
+#define GRXSTS_PKTSTS_SETUPRX 6
+#define GRXSTS_PKTSTS_HCHHALTED 7
+
+
+/******************** Bit definition for DAINTMSK register ********************/
+#define DAINTMSK_IEPM_Pos (0U)
+#define DAINTMSK_IEPM_Msk (0xFFFFUL << DAINTMSK_IEPM_Pos) // 0x0000FFFF
+#define DAINTMSK_IEPM DAINTMSK_IEPM_Msk // IN EP interrupt mask bits
+#define DAINTMSK_OEPM_Pos (16U)
+#define DAINTMSK_OEPM_Msk (0xFFFFUL << DAINTMSK_OEPM_Pos) // 0xFFFF0000
+#define DAINTMSK_OEPM DAINTMSK_OEPM_Msk // OUT EP interrupt mask bits
+
+#if 0
+/******************** Bit definition for OTG register ********************/
+#define CHNUM_Pos (0U)
+#define CHNUM_Msk (0xFUL << CHNUM_Pos) // 0x0000000F
+#define CHNUM CHNUM_Msk // Channel number
+#define CHNUM_0 (0x1UL << CHNUM_Pos) // 0x00000001
+#define CHNUM_1 (0x2UL << CHNUM_Pos) // 0x00000002
+#define CHNUM_2 (0x4UL << CHNUM_Pos) // 0x00000004
+#define CHNUM_3 (0x8UL << CHNUM_Pos) // 0x00000008
+#define BCNT_Pos (4U)
+#define BCNT_Msk (0x7FFUL << BCNT_Pos) // 0x00007FF0
+#define BCNT BCNT_Msk // Byte count
+
+#define DPID_Pos (15U)
+#define DPID_Msk (0x3UL << DPID_Pos) // 0x00018000
+#define DPID DPID_Msk // Data PID
+#define DPID_0 (0x1UL << DPID_Pos) // 0x00008000
+#define DPID_1 (0x2UL << DPID_Pos) // 0x00010000
+
+#define PKTSTS_Pos (17U)
+#define PKTSTS_Msk (0xFUL << PKTSTS_Pos) // 0x001E0000
+#define PKTSTS PKTSTS_Msk // Packet status
+#define PKTSTS_0 (0x1UL << PKTSTS_Pos) // 0x00020000
+#define PKTSTS_1 (0x2UL << PKTSTS_Pos) // 0x00040000
+#define PKTSTS_2 (0x4UL << PKTSTS_Pos) // 0x00080000
+#define PKTSTS_3 (0x8UL << PKTSTS_Pos) // 0x00100000
+
+#define EPNUM_Pos (0U)
+#define EPNUM_Msk (0xFUL << EPNUM_Pos) // 0x0000000F
+#define EPNUM EPNUM_Msk // Endpoint number
+#define EPNUM_0 (0x1UL << EPNUM_Pos) // 0x00000001
+#define EPNUM_1 (0x2UL << EPNUM_Pos) // 0x00000002
+#define EPNUM_2 (0x4UL << EPNUM_Pos) // 0x00000004
+#define EPNUM_3 (0x8UL << EPNUM_Pos) // 0x00000008
+
+#define FRMNUM_Pos (21U)
+#define FRMNUM_Msk (0xFUL << FRMNUM_Pos) // 0x01E00000
+#define FRMNUM FRMNUM_Msk // Frame number
+#define FRMNUM_0 (0x1UL << FRMNUM_Pos) // 0x00200000
+#define FRMNUM_1 (0x2UL << FRMNUM_Pos) // 0x00400000
+#define FRMNUM_2 (0x4UL << FRMNUM_Pos) // 0x00800000
+#define FRMNUM_3 (0x8UL << FRMNUM_Pos) // 0x01000000
+#endif
+
+/******************** Bit definition for GRXFSIZ register ********************/
+#define GRXFSIZ_RXFD_Pos (0U)
+#define GRXFSIZ_RXFD_Msk (0xFFFFUL << GRXFSIZ_RXFD_Pos) // 0x0000FFFF
+#define GRXFSIZ_RXFD GRXFSIZ_RXFD_Msk // RxFIFO depth
+
+/******************** Bit definition for DVBUSDIS register ********************/
+#define DVBUSDIS_VBUSDT_Pos (0U)
+#define DVBUSDIS_VBUSDT_Msk (0xFFFFUL << DVBUSDIS_VBUSDT_Pos) // 0x0000FFFF
+#define DVBUSDIS_VBUSDT DVBUSDIS_VBUSDT_Msk // Device VBUS discharge time
+
+/******************** Bit definition for OTG register ********************/
+#define GNPTXFSIZ_NPTXFSA_Pos (0U)
+#define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFSA_Pos) // 0x0000FFFF
+#define GNPTXFSIZ_NPTXFSA GNPTXFSIZ_NPTXFSA_Msk // Nonperiodic transmit RAM start address
+#define GNPTXFSIZ_NPTXFD_Pos (16U)
+#define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFD_Pos) // 0xFFFF0000
+#define GNPTXFSIZ_NPTXFD GNPTXFSIZ_NPTXFD_Msk // Nonperiodic TxFIFO depth
+#define DIEPTXF0_TX0FSA_Pos (0U)
+#define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << DIEPTXF0_TX0FSA_Pos) // 0x0000FFFF
+#define DIEPTXF0_TX0FSA DIEPTXF0_TX0FSA_Msk // Endpoint 0 transmit RAM start address
+#define DIEPTXF0_TX0FD_Pos (16U)
+#define DIEPTXF0_TX0FD_Msk (0xFFFFUL << DIEPTXF0_TX0FD_Pos) // 0xFFFF0000
+#define DIEPTXF0_TX0FD DIEPTXF0_TX0FD_Msk // Endpoint 0 TxFIFO depth
+
+/******************** Bit definition for DVBUSPULSE register ********************/
+#define DVBUSPULSE_DVBUSP_Pos (0U)
+#define DVBUSPULSE_DVBUSP_Msk (0xFFFUL << DVBUSPULSE_DVBUSP_Pos) // 0x00000FFF
+#define DVBUSPULSE_DVBUSP DVBUSPULSE_DVBUSP_Msk // Device VBUS pulsing time
+
+/******************** Bit definition for GNPTXSTS register ********************/
+#define GNPTXSTS_NPTXFSAV_Pos (0U)
+#define GNPTXSTS_NPTXFSAV_Msk (0xFFFFUL << GNPTXSTS_NPTXFSAV_Pos) // 0x0000FFFF
+#define GNPTXSTS_NPTXFSAV GNPTXSTS_NPTXFSAV_Msk // Nonperiodic TxFIFO space available
+
+#define GNPTXSTS_NPTQXSAV_Pos (16U)
+#define GNPTXSTS_NPTQXSAV_Msk (0xFFUL << GNPTXSTS_NPTQXSAV_Pos) // 0x00FF0000
+#define GNPTXSTS_NPTQXSAV GNPTXSTS_NPTQXSAV_Msk // Nonperiodic transmit request queue space available
+#define GNPTXSTS_NPTQXSAV_0 (0x01UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00010000
+#define GNPTXSTS_NPTQXSAV_1 (0x02UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00020000
+#define GNPTXSTS_NPTQXSAV_2 (0x04UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00040000
+#define GNPTXSTS_NPTQXSAV_3 (0x08UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00080000
+#define GNPTXSTS_NPTQXSAV_4 (0x10UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00100000
+#define GNPTXSTS_NPTQXSAV_5 (0x20UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00200000
+#define GNPTXSTS_NPTQXSAV_6 (0x40UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00400000
+#define GNPTXSTS_NPTQXSAV_7 (0x80UL << GNPTXSTS_NPTQXSAV_Pos) // 0x00800000
+
+#define GNPTXSTS_NPTXQTOP_Pos (24U)
+#define GNPTXSTS_NPTXQTOP_Msk (0x7FUL << GNPTXSTS_NPTXQTOP_Pos) // 0x7F000000
+#define GNPTXSTS_NPTXQTOP GNPTXSTS_NPTXQTOP_Msk // Top of the nonperiodic transmit request queue
+#define GNPTXSTS_NPTXQTOP_0 (0x01UL << GNPTXSTS_NPTXQTOP_Pos) // 0x01000000
+#define GNPTXSTS_NPTXQTOP_1 (0x02UL << GNPTXSTS_NPTXQTOP_Pos) // 0x02000000
+#define GNPTXSTS_NPTXQTOP_2 (0x04UL << GNPTXSTS_NPTXQTOP_Pos) // 0x04000000
+#define GNPTXSTS_NPTXQTOP_3 (0x08UL << GNPTXSTS_NPTXQTOP_Pos) // 0x08000000
+#define GNPTXSTS_NPTXQTOP_4 (0x10UL << GNPTXSTS_NPTXQTOP_Pos) // 0x10000000
+#define GNPTXSTS_NPTXQTOP_5 (0x20UL << GNPTXSTS_NPTXQTOP_Pos) // 0x20000000
+#define GNPTXSTS_NPTXQTOP_6 (0x40UL << GNPTXSTS_NPTXQTOP_Pos) // 0x40000000
+
+/******************** Bit definition for DTHRCTL register ********************/
+#define DTHRCTL_NONISOTHREN_Pos (0U)
+#define DTHRCTL_NONISOTHREN_Msk (0x1UL << DTHRCTL_NONISOTHREN_Pos) // 0x00000001
+#define DTHRCTL_NONISOTHREN DTHRCTL_NONISOTHREN_Msk // Nonisochronous IN endpoints threshold enable
+#define DTHRCTL_ISOTHREN_Pos (1U)
+#define DTHRCTL_ISOTHREN_Msk (0x1UL << DTHRCTL_ISOTHREN_Pos) // 0x00000002
+#define DTHRCTL_ISOTHREN DTHRCTL_ISOTHREN_Msk // ISO IN endpoint threshold enable
+
+#define DTHRCTL_TXTHRLEN_Pos (2U)
+#define DTHRCTL_TXTHRLEN_Msk (0x1FFUL << DTHRCTL_TXTHRLEN_Pos) // 0x000007FC
+#define DTHRCTL_TXTHRLEN DTHRCTL_TXTHRLEN_Msk // Transmit threshold length
+#define DTHRCTL_TXTHRLEN_0 (0x001UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000004
+#define DTHRCTL_TXTHRLEN_1 (0x002UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000008
+#define DTHRCTL_TXTHRLEN_2 (0x004UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000010
+#define DTHRCTL_TXTHRLEN_3 (0x008UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000020
+#define DTHRCTL_TXTHRLEN_4 (0x010UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000040
+#define DTHRCTL_TXTHRLEN_5 (0x020UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000080
+#define DTHRCTL_TXTHRLEN_6 (0x040UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000100
+#define DTHRCTL_TXTHRLEN_7 (0x080UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000200
+#define DTHRCTL_TXTHRLEN_8 (0x100UL << DTHRCTL_TXTHRLEN_Pos) // 0x00000400
+#define DTHRCTL_RXTHREN_Pos (16U)
+#define DTHRCTL_RXTHREN_Msk (0x1UL << DTHRCTL_RXTHREN_Pos) // 0x00010000
+#define DTHRCTL_RXTHREN DTHRCTL_RXTHREN_Msk // Receive threshold enable
+
+#define DTHRCTL_RXTHRLEN_Pos (17U)
+#define DTHRCTL_RXTHRLEN_Msk (0x1FFUL << DTHRCTL_RXTHRLEN_Pos) // 0x03FE0000
+#define DTHRCTL_RXTHRLEN DTHRCTL_RXTHRLEN_Msk // Receive threshold length
+#define DTHRCTL_RXTHRLEN_0 (0x001UL << DTHRCTL_RXTHRLEN_Pos) // 0x00020000
+#define DTHRCTL_RXTHRLEN_1 (0x002UL << DTHRCTL_RXTHRLEN_Pos) // 0x00040000
+#define DTHRCTL_RXTHRLEN_2 (0x004UL << DTHRCTL_RXTHRLEN_Pos) // 0x00080000
+#define DTHRCTL_RXTHRLEN_3 (0x008UL << DTHRCTL_RXTHRLEN_Pos) // 0x00100000
+#define DTHRCTL_RXTHRLEN_4 (0x010UL << DTHRCTL_RXTHRLEN_Pos) // 0x00200000
+#define DTHRCTL_RXTHRLEN_5 (0x020UL << DTHRCTL_RXTHRLEN_Pos) // 0x00400000
+#define DTHRCTL_RXTHRLEN_6 (0x040UL << DTHRCTL_RXTHRLEN_Pos) // 0x00800000
+#define DTHRCTL_RXTHRLEN_7 (0x080UL << DTHRCTL_RXTHRLEN_Pos) // 0x01000000
+#define DTHRCTL_RXTHRLEN_8 (0x100UL << DTHRCTL_RXTHRLEN_Pos) // 0x02000000
+#define DTHRCTL_ARPEN_Pos (27U)
+#define DTHRCTL_ARPEN_Msk (0x1UL << DTHRCTL_ARPEN_Pos) // 0x08000000
+#define DTHRCTL_ARPEN DTHRCTL_ARPEN_Msk // Arbiter parking enable
+
+/******************** Bit definition for DIEPEMPMSK register ********************/
+#define DIEPEMPMSK_INEPTXFEM_Pos (0U)
+#define DIEPEMPMSK_INEPTXFEM_Msk (0xFFFFUL << DIEPEMPMSK_INEPTXFEM_Pos) // 0x0000FFFF
+#define DIEPEMPMSK_INEPTXFEM DIEPEMPMSK_INEPTXFEM_Msk // IN EP Tx FIFO empty interrupt mask bits
+
+/******************** Bit definition for DEACHINT register ********************/
+#define DEACHINT_IEP1INT_Pos (1U)
+#define DEACHINT_IEP1INT_Msk (0x1UL << DEACHINT_IEP1INT_Pos) // 0x00000002
+#define DEACHINT_IEP1INT DEACHINT_IEP1INT_Msk // IN endpoint 1interrupt bit
+#define DEACHINT_OEP1INT_Pos (17U)
+#define DEACHINT_OEP1INT_Msk (0x1UL << DEACHINT_OEP1INT_Pos) // 0x00020000
+#define DEACHINT_OEP1INT DEACHINT_OEP1INT_Msk // OUT endpoint 1 interrupt bit
+
+/******************** Bit definition for GCCFG register ********************/
+#define STM32_GCCFG_DCDET_Pos (0U)
+#define STM32_GCCFG_DCDET_Msk (0x1UL << STM32_GCCFG_DCDET_Pos) // 0x00000001
+#define STM32_GCCFG_DCDET STM32_GCCFG_DCDET_Msk // Data contact detection (DCD) status
+
+#define STM32_GCCFG_PDET_Pos (1U)
+#define STM32_GCCFG_PDET_Msk (0x1UL << STM32_GCCFG_PDET_Pos) // 0x00000002
+#define STM32_GCCFG_PDET STM32_GCCFG_PDET_Msk // Primary detection (PD) status
+
+#define STM32_GCCFG_SDET_Pos (2U)
+#define STM32_GCCFG_SDET_Msk (0x1UL << STM32_GCCFG_SDET_Pos) // 0x00000004
+#define STM32_GCCFG_SDET STM32_GCCFG_SDET_Msk // Secondary detection (SD) status
+
+#define STM32_GCCFG_PS2DET_Pos (3U)
+#define STM32_GCCFG_PS2DET_Msk (0x1UL << STM32_GCCFG_PS2DET_Pos) // 0x00000008
+#define STM32_GCCFG_PS2DET STM32_GCCFG_PS2DET_Msk // DM pull-up detection status
+
+#define STM32_GCCFG_PWRDWN_Pos (16U)
+#define STM32_GCCFG_PWRDWN_Msk (0x1UL << STM32_GCCFG_PWRDWN_Pos) // 0x00010000
+#define STM32_GCCFG_PWRDWN STM32_GCCFG_PWRDWN_Msk // Power down
+
+#define STM32_GCCFG_BCDEN_Pos (17U)
+#define STM32_GCCFG_BCDEN_Msk (0x1UL << STM32_GCCFG_BCDEN_Pos) // 0x00020000
+#define STM32_GCCFG_BCDEN STM32_GCCFG_BCDEN_Msk // Battery charging detector (BCD) enable
+
+#define STM32_GCCFG_DCDEN_Pos (18U)
+#define STM32_GCCFG_DCDEN_Msk (0x1UL << STM32_GCCFG_DCDEN_Pos) // 0x00040000
+#define STM32_GCCFG_DCDEN STM32_GCCFG_DCDEN_Msk // Data contact detection (DCD) mode enable*/
+
+#define STM32_GCCFG_PDEN_Pos (19U)
+#define STM32_GCCFG_PDEN_Msk (0x1UL << STM32_GCCFG_PDEN_Pos) // 0x00080000
+#define STM32_GCCFG_PDEN STM32_GCCFG_PDEN_Msk // Primary detection (PD) mode enable*/
+
+#define STM32_GCCFG_SDEN_Pos (20U)
+#define STM32_GCCFG_SDEN_Msk (0x1UL << STM32_GCCFG_SDEN_Pos) // 0x00100000
+#define STM32_GCCFG_SDEN STM32_GCCFG_SDEN_Msk // Secondary detection (SD) mode enable
+
+#define STM32_GCCFG_VBDEN_Pos (21U)
+#define STM32_GCCFG_VBDEN_Msk (0x1UL << STM32_GCCFG_VBDEN_Pos) // 0x00200000
+#define STM32_GCCFG_VBDEN STM32_GCCFG_VBDEN_Msk // VBUS mode enable
+
+#define STM32_GCCFG_OTGIDEN_Pos (22U)
+#define STM32_GCCFG_OTGIDEN_Msk (0x1UL << STM32_GCCFG_OTGIDEN_Pos) // 0x00400000
+#define STM32_GCCFG_OTGIDEN STM32_GCCFG_OTGIDEN_Msk // OTG Id enable
+
+#define STM32_GCCFG_PHYHSEN_Pos (23U)
+#define STM32_GCCFG_PHYHSEN_Msk (0x1UL << STM32_GCCFG_PHYHSEN_Pos) // 0x00800000
+#define STM32_GCCFG_PHYHSEN STM32_GCCFG_PHYHSEN_Msk // HS PHY enable
+
+// TODO stm32u5a5 SDEN is 22nd bit, conflict with 20th bit above
+//#define STM32_GCCFG_SDEN_Pos (22U)
+//#define STM32_GCCFG_SDEN_Msk (0x1U << STM32_GCCFG_SDEN_Pos) // 0x00400000
+//#define STM32_GCCFG_SDEN STM32_GCCFG_SDEN_Msk // Secondary detection (PD) mode enable
+
+// TODO stm32u5a5 VBVALOVA is 23rd bit, conflict with PHYHSEN bit above
+#define STM32_GCCFG_VBVALOVAL_Pos (23U)
+#define STM32_GCCFG_VBVALOVAL_Msk (0x1U << STM32_GCCFG_VBVALOVAL_Pos) // 0x00800000
+#define STM32_GCCFG_VBVALOVAL STM32_GCCFG_VBVALOVAL_Msk // Value of VBUSVLDEXT0 femtoPHY input
+
+#define STM32_GCCFG_VBVALEXTOEN_Pos (24U)
+#define STM32_GCCFG_VBVALEXTOEN_Msk (0x1U << STM32_GCCFG_VBVALEXTOEN_Pos) // 0x01000000
+#define STM32_GCCFG_VBVALEXTOEN STM32_GCCFG_VBVALEXTOEN_Msk // Enables of VBUSVLDEXT0 femtoPHY input override
+
+#define STM32_GCCFG_PULLDOWNEN_Pos (25U)
+#define STM32_GCCFG_PULLDOWNEN_Msk (0x1U << STM32_GCCFG_PULLDOWNEN_Pos) // 0x02000000
+#define STM32_GCCFG_PULLDOWNEN STM32_GCCFG_PULLDOWNEN_Msk // Enables of femtoPHY pulldown resistors, used when ID PAD is disabled
+
+
+/******************** Bit definition for DEACHINTMSK register ********************/
+#define DEACHINTMSK_IEP1INTM_Pos (1U)
+#define DEACHINTMSK_IEP1INTM_Msk (0x1UL << DEACHINTMSK_IEP1INTM_Pos) // 0x00000002
+#define DEACHINTMSK_IEP1INTM DEACHINTMSK_IEP1INTM_Msk // IN Endpoint 1 interrupt mask bit
+#define DEACHINTMSK_OEP1INTM_Pos (17U)
+#define DEACHINTMSK_OEP1INTM_Msk (0x1UL << DEACHINTMSK_OEP1INTM_Pos) // 0x00020000
+#define DEACHINTMSK_OEP1INTM DEACHINTMSK_OEP1INTM_Msk // OUT Endpoint 1 interrupt mask bit
+
+/******************** Bit definition for CID register ********************/
+#define CID_PRODUCT_ID_Pos (0U)
+#define CID_PRODUCT_ID_Msk (0xFFFFFFFFUL << CID_PRODUCT_ID_Pos) // 0xFFFFFFFF
+#define CID_PRODUCT_ID CID_PRODUCT_ID_Msk // Product ID field
+
+/******************** Bit definition for GLPMCFG register ********************/
+#define GLPMCFG_LPMEN_Pos (0U)
+#define GLPMCFG_LPMEN_Msk (0x1UL << GLPMCFG_LPMEN_Pos) // 0x00000001
+#define GLPMCFG_LPMEN GLPMCFG_LPMEN_Msk // LPM support enable
+#define GLPMCFG_LPMACK_Pos (1U)
+#define GLPMCFG_LPMACK_Msk (0x1UL << GLPMCFG_LPMACK_Pos) // 0x00000002
+#define GLPMCFG_LPMACK GLPMCFG_LPMACK_Msk // LPM Token acknowledge enable
+#define GLPMCFG_BESL_Pos (2U)
+#define GLPMCFG_BESL_Msk (0xFUL << GLPMCFG_BESL_Pos) // 0x0000003C
+#define GLPMCFG_BESL GLPMCFG_BESL_Msk // BESL value received with last ACKed LPM Token
+#define GLPMCFG_REMWAKE_Pos (6U)
+#define GLPMCFG_REMWAKE_Msk (0x1UL << GLPMCFG_REMWAKE_Pos) // 0x00000040
+#define GLPMCFG_REMWAKE GLPMCFG_REMWAKE_Msk // bRemoteWake value received with last ACKed LPM Token
+#define GLPMCFG_L1SSEN_Pos (7U)
+#define GLPMCFG_L1SSEN_Msk (0x1UL << GLPMCFG_L1SSEN_Pos) // 0x00000080
+#define GLPMCFG_L1SSEN GLPMCFG_L1SSEN_Msk // L1 shallow sleep enable
+#define GLPMCFG_BESLTHRS_Pos (8U)
+#define GLPMCFG_BESLTHRS_Msk (0xFUL << GLPMCFG_BESLTHRS_Pos) // 0x00000F00
+#define GLPMCFG_BESLTHRS GLPMCFG_BESLTHRS_Msk // BESL threshold
+#define GLPMCFG_L1DSEN_Pos (12U)
+#define GLPMCFG_L1DSEN_Msk (0x1UL << GLPMCFG_L1DSEN_Pos) // 0x00001000
+#define GLPMCFG_L1DSEN GLPMCFG_L1DSEN_Msk // L1 deep sleep enable
+#define GLPMCFG_LPMRSP_Pos (13U)
+#define GLPMCFG_LPMRSP_Msk (0x3UL << GLPMCFG_LPMRSP_Pos) // 0x00006000
+#define GLPMCFG_LPMRSP GLPMCFG_LPMRSP_Msk // LPM response
+#define GLPMCFG_SLPSTS_Pos (15U)
+#define GLPMCFG_SLPSTS_Msk (0x1UL << GLPMCFG_SLPSTS_Pos) // 0x00008000
+#define GLPMCFG_SLPSTS GLPMCFG_SLPSTS_Msk // Port sleep status
+#define GLPMCFG_L1RSMOK_Pos (16U)
+#define GLPMCFG_L1RSMOK_Msk (0x1UL << GLPMCFG_L1RSMOK_Pos) // 0x00010000
+#define GLPMCFG_L1RSMOK GLPMCFG_L1RSMOK_Msk // Sleep State Resume OK
+#define GLPMCFG_LPMCHIDX_Pos (17U)
+#define GLPMCFG_LPMCHIDX_Msk (0xFUL << GLPMCFG_LPMCHIDX_Pos) // 0x001E0000
+#define GLPMCFG_LPMCHIDX GLPMCFG_LPMCHIDX_Msk // LPM Channel Index
+#define GLPMCFG_LPMRCNT_Pos (21U)
+#define GLPMCFG_LPMRCNT_Msk (0x7UL << GLPMCFG_LPMRCNT_Pos) // 0x00E00000
+#define GLPMCFG_LPMRCNT GLPMCFG_LPMRCNT_Msk // LPM retry count
+#define GLPMCFG_SNDLPM_Pos (24U)
+#define GLPMCFG_SNDLPM_Msk (0x1UL << GLPMCFG_SNDLPM_Pos) // 0x01000000
+#define GLPMCFG_SNDLPM GLPMCFG_SNDLPM_Msk // Send LPM transaction
+#define GLPMCFG_LPMRCNTSTS_Pos (25U)
+#define GLPMCFG_LPMRCNTSTS_Msk (0x7UL << GLPMCFG_LPMRCNTSTS_Pos) // 0x0E000000
+#define GLPMCFG_LPMRCNTSTS GLPMCFG_LPMRCNTSTS_Msk // LPM retry count status
+#define GLPMCFG_ENBESL_Pos (28U)
+#define GLPMCFG_ENBESL_Msk (0x1UL << GLPMCFG_ENBESL_Pos) // 0x10000000
+#define GLPMCFG_ENBESL GLPMCFG_ENBESL_Msk // Enable best effort service latency
+
+/******************** Bit definition for DIEPEACHMSK1 register ********************/
+#define DIEPEACHMSK1_XFRCM_Pos (0U)
+#define DIEPEACHMSK1_XFRCM_Msk (0x1UL << DIEPEACHMSK1_XFRCM_Pos) // 0x00000001
+#define DIEPEACHMSK1_XFRCM DIEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask
+#define DIEPEACHMSK1_EPDM_Pos (1U)
+#define DIEPEACHMSK1_EPDM_Msk (0x1UL << DIEPEACHMSK1_EPDM_Pos) // 0x00000002
+#define DIEPEACHMSK1_EPDM DIEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask
+#define DIEPEACHMSK1_TOM_Pos (3U)
+#define DIEPEACHMSK1_TOM_Msk (0x1UL << DIEPEACHMSK1_TOM_Pos) // 0x00000008
+#define DIEPEACHMSK1_TOM DIEPEACHMSK1_TOM_Msk // Timeout condition mask (nonisochronous endpoints)
+#define DIEPEACHMSK1_ITTXFEMSK_Pos (4U)
+#define DIEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DIEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010
+#define DIEPEACHMSK1_ITTXFEMSK DIEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask
+#define DIEPEACHMSK1_INEPNMM_Pos (5U)
+#define DIEPEACHMSK1_INEPNMM_Msk (0x1UL << DIEPEACHMSK1_INEPNMM_Pos) // 0x00000020
+#define DIEPEACHMSK1_INEPNMM DIEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask
+#define DIEPEACHMSK1_INEPNEM_Pos (6U)
+#define DIEPEACHMSK1_INEPNEM_Msk (0x1UL << DIEPEACHMSK1_INEPNEM_Pos) // 0x00000040
+#define DIEPEACHMSK1_INEPNEM DIEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask
+#define DIEPEACHMSK1_TXFURM_Pos (8U)
+#define DIEPEACHMSK1_TXFURM_Msk (0x1UL << DIEPEACHMSK1_TXFURM_Pos) // 0x00000100
+#define DIEPEACHMSK1_TXFURM DIEPEACHMSK1_TXFURM_Msk // FIFO underrun mask
+#define DIEPEACHMSK1_BIM_Pos (9U)
+#define DIEPEACHMSK1_BIM_Msk (0x1UL << DIEPEACHMSK1_BIM_Pos) // 0x00000200
+#define DIEPEACHMSK1_BIM DIEPEACHMSK1_BIM_Msk // BNA interrupt mask
+#define DIEPEACHMSK1_NAKM_Pos (13U)
+#define DIEPEACHMSK1_NAKM_Msk (0x1UL << DIEPEACHMSK1_NAKM_Pos) // 0x00002000
+#define DIEPEACHMSK1_NAKM DIEPEACHMSK1_NAKM_Msk // NAK interrupt mask
+
+/******************** Bit definition for HPRT register ********************/
+#define HPRT_PCSTS_Pos (0U)
+#define HPRT_PCSTS_Msk (0x1UL << HPRT_PCSTS_Pos) // 0x00000001
+#define HPRT_PCSTS HPRT_PCSTS_Msk // Port connect status
+#define HPRT_PCDET_Pos (1U)
+#define HPRT_PCDET_Msk (0x1UL << HPRT_PCDET_Pos) // 0x00000002
+#define HPRT_PCDET HPRT_PCDET_Msk // Port connect detected
+#define HPRT_PENA_Pos (2U)
+#define HPRT_PENA_Msk (0x1UL << HPRT_PENA_Pos) // 0x00000004
+#define HPRT_PENA HPRT_PENA_Msk // Port enable
+#define HPRT_PENCHNG_Pos (3U)
+#define HPRT_PENCHNG_Msk (0x1UL << HPRT_PENCHNG_Pos) // 0x00000008
+#define HPRT_PENCHNG HPRT_PENCHNG_Msk // Port enable/disable change
+#define HPRT_POCA_Pos (4U)
+#define HPRT_POCA_Msk (0x1UL << HPRT_POCA_Pos) // 0x00000010
+#define HPRT_POCA HPRT_POCA_Msk // Port overcurrent active
+#define HPRT_POCCHNG_Pos (5U)
+#define HPRT_POCCHNG_Msk (0x1UL << HPRT_POCCHNG_Pos) // 0x00000020
+#define HPRT_POCCHNG HPRT_POCCHNG_Msk // Port overcurrent change
+#define HPRT_PRES_Pos (6U)
+#define HPRT_PRES_Msk (0x1UL << HPRT_PRES_Pos) // 0x00000040
+#define HPRT_PRES HPRT_PRES_Msk // Port resume
+#define HPRT_PSUSP_Pos (7U)
+#define HPRT_PSUSP_Msk (0x1UL << HPRT_PSUSP_Pos) // 0x00000080
+#define HPRT_PSUSP HPRT_PSUSP_Msk // Port suspend
+#define HPRT_PRST_Pos (8U)
+#define HPRT_PRST_Msk (0x1UL << HPRT_PRST_Pos) // 0x00000100
+#define HPRT_PRST HPRT_PRST_Msk // Port reset
+
+#define HPRT_PLSTS_Pos (10U)
+#define HPRT_PLSTS_Msk (0x3UL << HPRT_PLSTS_Pos) // 0x00000C00
+#define HPRT_PLSTS HPRT_PLSTS_Msk // Port line status
+#define HPRT_PLSTS_0 (0x1UL << HPRT_PLSTS_Pos) // 0x00000400
+#define HPRT_PLSTS_1 (0x2UL << HPRT_PLSTS_Pos) // 0x00000800
+#define HPRT_PPWR_Pos (12U)
+#define HPRT_PPWR_Msk (0x1UL << HPRT_PPWR_Pos) // 0x00001000
+#define HPRT_PPWR HPRT_PPWR_Msk // Port power
+
+#define HPRT_PTCTL_Pos (13U)
+#define HPRT_PTCTL_Msk (0xFUL << HPRT_PTCTL_Pos) // 0x0001E000
+#define HPRT_PTCTL HPRT_PTCTL_Msk // Port test control
+#define HPRT_PTCTL_0 (0x1UL << HPRT_PTCTL_Pos) // 0x00002000
+#define HPRT_PTCTL_1 (0x2UL << HPRT_PTCTL_Pos) // 0x00004000
+#define HPRT_PTCTL_2 (0x4UL << HPRT_PTCTL_Pos) // 0x00008000
+#define HPRT_PTCTL_3 (0x8UL << HPRT_PTCTL_Pos) // 0x00010000
+
+#define HPRT_PSPD_Pos (17U)
+#define HPRT_PSPD_Msk (0x3UL << HPRT_PSPD_Pos) // 0x00060000
+#define HPRT_PSPD HPRT_PSPD_Msk // Port speed
+#define HPRT_PSPD_0 (0x1UL << HPRT_PSPD_Pos) // 0x00020000
+#define HPRT_PSPD_1 (0x2UL << HPRT_PSPD_Pos) // 0x00040000
+
+/******************** Bit definition for DOEPEACHMSK1 register ********************/
+#define DOEPEACHMSK1_XFRCM_Pos (0U)
+#define DOEPEACHMSK1_XFRCM_Msk (0x1UL << DOEPEACHMSK1_XFRCM_Pos) // 0x00000001
+#define DOEPEACHMSK1_XFRCM DOEPEACHMSK1_XFRCM_Msk // Transfer completed interrupt mask
+#define DOEPEACHMSK1_EPDM_Pos (1U)
+#define DOEPEACHMSK1_EPDM_Msk (0x1UL << DOEPEACHMSK1_EPDM_Pos) // 0x00000002
+#define DOEPEACHMSK1_EPDM DOEPEACHMSK1_EPDM_Msk // Endpoint disabled interrupt mask
+#define DOEPEACHMSK1_TOM_Pos (3U)
+#define DOEPEACHMSK1_TOM_Msk (0x1UL << DOEPEACHMSK1_TOM_Pos) // 0x00000008
+#define DOEPEACHMSK1_TOM DOEPEACHMSK1_TOM_Msk // Timeout condition mask
+#define DOEPEACHMSK1_ITTXFEMSK_Pos (4U)
+#define DOEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << DOEPEACHMSK1_ITTXFEMSK_Pos) // 0x00000010
+#define DOEPEACHMSK1_ITTXFEMSK DOEPEACHMSK1_ITTXFEMSK_Msk // IN token received when TxFIFO empty mask
+#define DOEPEACHMSK1_INEPNMM_Pos (5U)
+#define DOEPEACHMSK1_INEPNMM_Msk (0x1UL << DOEPEACHMSK1_INEPNMM_Pos) // 0x00000020
+#define DOEPEACHMSK1_INEPNMM DOEPEACHMSK1_INEPNMM_Msk // IN token received with EP mismatch mask
+#define DOEPEACHMSK1_INEPNEM_Pos (6U)
+#define DOEPEACHMSK1_INEPNEM_Msk (0x1UL << DOEPEACHMSK1_INEPNEM_Pos) // 0x00000040
+#define DOEPEACHMSK1_INEPNEM DOEPEACHMSK1_INEPNEM_Msk // IN endpoint NAK effective mask
+#define DOEPEACHMSK1_TXFURM_Pos (8U)
+#define DOEPEACHMSK1_TXFURM_Msk (0x1UL << DOEPEACHMSK1_TXFURM_Pos) // 0x00000100
+#define DOEPEACHMSK1_TXFURM DOEPEACHMSK1_TXFURM_Msk // OUT packet error mask
+#define DOEPEACHMSK1_BIM_Pos (9U)
+#define DOEPEACHMSK1_BIM_Msk (0x1UL << DOEPEACHMSK1_BIM_Pos) // 0x00000200
+#define DOEPEACHMSK1_BIM DOEPEACHMSK1_BIM_Msk // BNA interrupt mask
+#define DOEPEACHMSK1_BERRM_Pos (12U)
+#define DOEPEACHMSK1_BERRM_Msk (0x1UL << DOEPEACHMSK1_BERRM_Pos) // 0x00001000
+#define DOEPEACHMSK1_BERRM DOEPEACHMSK1_BERRM_Msk // Bubble error interrupt mask
+#define DOEPEACHMSK1_NAKM_Pos (13U)
+#define DOEPEACHMSK1_NAKM_Msk (0x1UL << DOEPEACHMSK1_NAKM_Pos) // 0x00002000
+#define DOEPEACHMSK1_NAKM DOEPEACHMSK1_NAKM_Msk // NAK interrupt mask
+#define DOEPEACHMSK1_NYETM_Pos (14U)
+#define DOEPEACHMSK1_NYETM_Msk (0x1UL << DOEPEACHMSK1_NYETM_Pos) // 0x00004000
+#define DOEPEACHMSK1_NYETM DOEPEACHMSK1_NYETM_Msk // NYET interrupt mask
+
+/******************** Bit definition for HPTXFSIZ register ********************/
+#define HPTXFSIZ_PTXSA_Pos (0U)
+#define HPTXFSIZ_PTXSA_Msk (0xFFFFUL << HPTXFSIZ_PTXSA_Pos) // 0x0000FFFF
+#define HPTXFSIZ_PTXSA HPTXFSIZ_PTXSA_Msk // Host periodic TxFIFO start address
+#define HPTXFSIZ_PTXFD_Pos (16U)
+#define HPTXFSIZ_PTXFD_Msk (0xFFFFUL << HPTXFSIZ_PTXFD_Pos) // 0xFFFF0000
+#define HPTXFSIZ_PTXFD HPTXFSIZ_PTXFD_Msk // Host periodic TxFIFO depth
+
+/******************** Bit definition for DIEPCTL register ********************/
+#define DIEPCTL_MPSIZ_Pos (0U)
+#define DIEPCTL_MPSIZ_Msk (0x7FFUL << DIEPCTL_MPSIZ_Pos) // 0x000007FF
+#define DIEPCTL_MPSIZ DIEPCTL_MPSIZ_Msk // Maximum packet size
+#define DIEPCTL_USBAEP_Pos (15U)
+#define DIEPCTL_USBAEP_Msk (0x1UL << DIEPCTL_USBAEP_Pos) // 0x00008000
+#define DIEPCTL_USBAEP DIEPCTL_USBAEP_Msk // USB active endpoint
+#define DIEPCTL_EONUM_DPID_Pos (16U)
+#define DIEPCTL_EONUM_DPID_Msk (0x1UL << DIEPCTL_EONUM_DPID_Pos) // 0x00010000
+#define DIEPCTL_EONUM_DPID DIEPCTL_EONUM_DPID_Msk // Even/odd frame
+#define DIEPCTL_NAKSTS_Pos (17U)
+#define DIEPCTL_NAKSTS_Msk (0x1UL << DIEPCTL_NAKSTS_Pos) // 0x00020000
+#define DIEPCTL_NAKSTS DIEPCTL_NAKSTS_Msk // NAK status
+
+#define DIEPCTL_EPTYP_Pos (18U)
+#define DIEPCTL_EPTYP_Msk (0x3UL << DIEPCTL_EPTYP_Pos) // 0x000C0000
+#define DIEPCTL_EPTYP DIEPCTL_EPTYP_Msk // Endpoint type
+#define DIEPCTL_EPTYP_0 (0x1UL << DIEPCTL_EPTYP_Pos) // 0x00040000
+#define DIEPCTL_EPTYP_1 (0x2UL << DIEPCTL_EPTYP_Pos) // 0x00080000
+#define DIEPCTL_STALL_Pos (21U)
+#define DIEPCTL_STALL_Msk (0x1UL << DIEPCTL_STALL_Pos) // 0x00200000
+#define DIEPCTL_STALL DIEPCTL_STALL_Msk // STALL handshake
+
+#define DIEPCTL_TXFNUM_Pos (22U)
+#define DIEPCTL_TXFNUM_Msk (0xFUL << DIEPCTL_TXFNUM_Pos) // 0x03C00000
+#define DIEPCTL_TXFNUM DIEPCTL_TXFNUM_Msk // TxFIFO number
+#define DIEPCTL_TXFNUM_0 (0x1UL << DIEPCTL_TXFNUM_Pos) // 0x00400000
+#define DIEPCTL_TXFNUM_1 (0x2UL << DIEPCTL_TXFNUM_Pos) // 0x00800000
+#define DIEPCTL_TXFNUM_2 (0x4UL << DIEPCTL_TXFNUM_Pos) // 0x01000000
+#define DIEPCTL_TXFNUM_3 (0x8UL << DIEPCTL_TXFNUM_Pos) // 0x02000000
+#define DIEPCTL_CNAK_Pos (26U)
+#define DIEPCTL_CNAK_Msk (0x1UL << DIEPCTL_CNAK_Pos) // 0x04000000
+#define DIEPCTL_CNAK DIEPCTL_CNAK_Msk // Clear NAK
+#define DIEPCTL_SNAK_Pos (27U)
+#define DIEPCTL_SNAK_Msk (0x1UL << DIEPCTL_SNAK_Pos) // 0x08000000
+#define DIEPCTL_SNAK DIEPCTL_SNAK_Msk // Set NAK
+#define DIEPCTL_SD0PID_SEVNFRM_Pos (28U)
+#define DIEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DIEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000
+#define DIEPCTL_SD0PID_SEVNFRM DIEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID
+#define DIEPCTL_SODDFRM_Pos (29U)
+#define DIEPCTL_SODDFRM_Msk (0x1UL << DIEPCTL_SODDFRM_Pos) // 0x20000000
+#define DIEPCTL_SODDFRM DIEPCTL_SODDFRM_Msk // Set odd frame
+#define DIEPCTL_EPDIS_Pos (30U)
+#define DIEPCTL_EPDIS_Msk (0x1UL << DIEPCTL_EPDIS_Pos) // 0x40000000
+#define DIEPCTL_EPDIS DIEPCTL_EPDIS_Msk // Endpoint disable
+#define DIEPCTL_EPENA_Pos (31U)
+#define DIEPCTL_EPENA_Msk (0x1UL << DIEPCTL_EPENA_Pos) // 0x80000000
+#define DIEPCTL_EPENA DIEPCTL_EPENA_Msk // Endpoint enable
+
+/******************** Bit definition for HCCHAR register ********************/
+#define HCCHAR_MPSIZ_Pos (0U)
+#define HCCHAR_MPSIZ_Msk (0x7FFUL << HCCHAR_MPSIZ_Pos) // 0x000007FF
+#define HCCHAR_MPSIZ HCCHAR_MPSIZ_Msk // Maximum packet size
+
+#define HCCHAR_EPNUM_Pos (11U)
+#define HCCHAR_EPNUM_Msk (0xFUL << HCCHAR_EPNUM_Pos) // 0x00007800
+#define HCCHAR_EPNUM HCCHAR_EPNUM_Msk // Endpoint number
+#define HCCHAR_EPNUM_0 (0x1UL << HCCHAR_EPNUM_Pos) // 0x00000800
+#define HCCHAR_EPNUM_1 (0x2UL << HCCHAR_EPNUM_Pos) // 0x00001000
+#define HCCHAR_EPNUM_2 (0x4UL << HCCHAR_EPNUM_Pos) // 0x00002000
+#define HCCHAR_EPNUM_3 (0x8UL << HCCHAR_EPNUM_Pos) // 0x00004000
+#define HCCHAR_EPDIR_Pos (15U)
+#define HCCHAR_EPDIR_Msk (0x1UL << HCCHAR_EPDIR_Pos) // 0x00008000
+#define HCCHAR_EPDIR HCCHAR_EPDIR_Msk // Endpoint direction
+#define HCCHAR_LSDEV_Pos (17U)
+#define HCCHAR_LSDEV_Msk (0x1UL << HCCHAR_LSDEV_Pos) // 0x00020000
+#define HCCHAR_LSDEV HCCHAR_LSDEV_Msk // Low-speed device
+
+#define HCCHAR_EPTYP_Pos (18U)
+#define HCCHAR_EPTYP_Msk (0x3UL << HCCHAR_EPTYP_Pos) // 0x000C0000
+#define HCCHAR_EPTYP HCCHAR_EPTYP_Msk // Endpoint type
+#define HCCHAR_EPTYP_0 (0x1UL << HCCHAR_EPTYP_Pos) // 0x00040000
+#define HCCHAR_EPTYP_1 (0x2UL << HCCHAR_EPTYP_Pos) // 0x00080000
+
+#define HCCHAR_MC_Pos (20U)
+#define HCCHAR_MC_Msk (0x3UL << HCCHAR_MC_Pos) // 0x00300000
+#define HCCHAR_MC HCCHAR_MC_Msk // Multi Count (MC) / Error Count (EC)
+#define HCCHAR_MC_0 (0x1UL << HCCHAR_MC_Pos) // 0x00100000
+#define HCCHAR_MC_1 (0x2UL << HCCHAR_MC_Pos) // 0x00200000
+
+#define HCCHAR_DAD_Pos (22U)
+#define HCCHAR_DAD_Msk (0x7FUL << HCCHAR_DAD_Pos) // 0x1FC00000
+#define HCCHAR_DAD HCCHAR_DAD_Msk // Device address
+#define HCCHAR_DAD_0 (0x01UL << HCCHAR_DAD_Pos) // 0x00400000
+#define HCCHAR_DAD_1 (0x02UL << HCCHAR_DAD_Pos) // 0x00800000
+#define HCCHAR_DAD_2 (0x04UL << HCCHAR_DAD_Pos) // 0x01000000
+#define HCCHAR_DAD_3 (0x08UL << HCCHAR_DAD_Pos) // 0x02000000
+#define HCCHAR_DAD_4 (0x10UL << HCCHAR_DAD_Pos) // 0x04000000
+#define HCCHAR_DAD_5 (0x20UL << HCCHAR_DAD_Pos) // 0x08000000
+#define HCCHAR_DAD_6 (0x40UL << HCCHAR_DAD_Pos) // 0x10000000
+#define HCCHAR_ODDFRM_Pos (29U)
+#define HCCHAR_ODDFRM_Msk (0x1UL << HCCHAR_ODDFRM_Pos) // 0x20000000
+#define HCCHAR_ODDFRM HCCHAR_ODDFRM_Msk // Odd frame
+#define HCCHAR_CHDIS_Pos (30U)
+#define HCCHAR_CHDIS_Msk (0x1UL << HCCHAR_CHDIS_Pos) // 0x40000000
+#define HCCHAR_CHDIS HCCHAR_CHDIS_Msk // Channel disable
+#define HCCHAR_CHENA_Pos (31U)
+#define HCCHAR_CHENA_Msk (0x1UL << HCCHAR_CHENA_Pos) // 0x80000000
+#define HCCHAR_CHENA HCCHAR_CHENA_Msk // Channel enable
+
+/******************** Bit definition for HCSPLT register ********************/
+
+#define HCSPLT_PRTADDR_Pos (0U)
+#define HCSPLT_PRTADDR_Msk (0x7FUL << HCSPLT_PRTADDR_Pos) // 0x0000007F
+#define HCSPLT_PRTADDR HCSPLT_PRTADDR_Msk // Port address
+#define HCSPLT_PRTADDR_0 (0x01UL << HCSPLT_PRTADDR_Pos) // 0x00000001
+#define HCSPLT_PRTADDR_1 (0x02UL << HCSPLT_PRTADDR_Pos) // 0x00000002
+#define HCSPLT_PRTADDR_2 (0x04UL << HCSPLT_PRTADDR_Pos) // 0x00000004
+#define HCSPLT_PRTADDR_3 (0x08UL << HCSPLT_PRTADDR_Pos) // 0x00000008
+#define HCSPLT_PRTADDR_4 (0x10UL << HCSPLT_PRTADDR_Pos) // 0x00000010
+#define HCSPLT_PRTADDR_5 (0x20UL << HCSPLT_PRTADDR_Pos) // 0x00000020
+#define HCSPLT_PRTADDR_6 (0x40UL << HCSPLT_PRTADDR_Pos) // 0x00000040
+
+#define HCSPLT_HUBADDR_Pos (7U)
+#define HCSPLT_HUBADDR_Msk (0x7FUL << HCSPLT_HUBADDR_Pos) // 0x00003F80
+#define HCSPLT_HUBADDR HCSPLT_HUBADDR_Msk // Hub address
+#define HCSPLT_HUBADDR_0 (0x01UL << HCSPLT_HUBADDR_Pos) // 0x00000080
+#define HCSPLT_HUBADDR_1 (0x02UL << HCSPLT_HUBADDR_Pos) // 0x00000100
+#define HCSPLT_HUBADDR_2 (0x04UL << HCSPLT_HUBADDR_Pos) // 0x00000200
+#define HCSPLT_HUBADDR_3 (0x08UL << HCSPLT_HUBADDR_Pos) // 0x00000400
+#define HCSPLT_HUBADDR_4 (0x10UL << HCSPLT_HUBADDR_Pos) // 0x00000800
+#define HCSPLT_HUBADDR_5 (0x20UL << HCSPLT_HUBADDR_Pos) // 0x00001000
+#define HCSPLT_HUBADDR_6 (0x40UL << HCSPLT_HUBADDR_Pos) // 0x00002000
+
+#define HCSPLT_XACTPOS_Pos (14U)
+#define HCSPLT_XACTPOS_Msk (0x3UL << HCSPLT_XACTPOS_Pos) // 0x0000C000
+#define HCSPLT_XACTPOS HCSPLT_XACTPOS_Msk // XACTPOS
+#define HCSPLT_XACTPOS_0 (0x1UL << HCSPLT_XACTPOS_Pos) // 0x00004000
+#define HCSPLT_XACTPOS_1 (0x2UL << HCSPLT_XACTPOS_Pos) // 0x00008000
+#define HCSPLT_COMPLSPLT_Pos (16U)
+#define HCSPLT_COMPLSPLT_Msk (0x1UL << HCSPLT_COMPLSPLT_Pos) // 0x00010000
+#define HCSPLT_COMPLSPLT HCSPLT_COMPLSPLT_Msk // Do complete split
+#define HCSPLT_SPLITEN_Pos (31U)
+#define HCSPLT_SPLITEN_Msk (0x1UL << HCSPLT_SPLITEN_Pos) // 0x80000000
+#define HCSPLT_SPLITEN HCSPLT_SPLITEN_Msk // Split enable
+
+/******************** Bit definition for HCINT register ********************/
+#define HCINT_XFRC_Pos (0U)
+#define HCINT_XFRC_Msk (0x1UL << HCINT_XFRC_Pos) // 0x00000001
+#define HCINT_XFRC HCINT_XFRC_Msk // Transfer completed
+#define HCINT_CHH_Pos (1U)
+#define HCINT_CHH_Msk (0x1UL << HCINT_CHH_Pos) // 0x00000002
+#define HCINT_CHH HCINT_CHH_Msk // Channel halted
+#define HCINT_AHBERR_Pos (2U)
+#define HCINT_AHBERR_Msk (0x1UL << HCINT_AHBERR_Pos) // 0x00000004
+#define HCINT_AHBERR HCINT_AHBERR_Msk // AHB error
+#define HCINT_STALL_Pos (3U)
+#define HCINT_STALL_Msk (0x1UL << HCINT_STALL_Pos) // 0x00000008
+#define HCINT_STALL HCINT_STALL_Msk // STALL response received interrupt
+#define HCINT_NAK_Pos (4U)
+#define HCINT_NAK_Msk (0x1UL << HCINT_NAK_Pos) // 0x00000010
+#define HCINT_NAK HCINT_NAK_Msk // NAK response received interrupt
+#define HCINT_ACK_Pos (5U)
+#define HCINT_ACK_Msk (0x1UL << HCINT_ACK_Pos) // 0x00000020
+#define HCINT_ACK HCINT_ACK_Msk // ACK response received/transmitted interrupt
+#define HCINT_NYET_Pos (6U)
+#define HCINT_NYET_Msk (0x1UL << HCINT_NYET_Pos) // 0x00000040
+#define HCINT_NYET HCINT_NYET_Msk // Response received interrupt
+#define HCINT_TXERR_Pos (7U)
+#define HCINT_TXERR_Msk (0x1UL << HCINT_TXERR_Pos) // 0x00000080
+#define HCINT_TXERR HCINT_TXERR_Msk // Transaction error
+#define HCINT_BBERR_Pos (8U)
+#define HCINT_BBERR_Msk (0x1UL << HCINT_BBERR_Pos) // 0x00000100
+#define HCINT_BBERR HCINT_BBERR_Msk // Babble error
+#define HCINT_FRMOR_Pos (9U)
+#define HCINT_FRMOR_Msk (0x1UL << HCINT_FRMOR_Pos) // 0x00000200
+#define HCINT_FRMOR HCINT_FRMOR_Msk // Frame overrun
+#define HCINT_DTERR_Pos (10U)
+#define HCINT_DTERR_Msk (0x1UL << HCINT_DTERR_Pos) // 0x00000400
+#define HCINT_DTERR HCINT_DTERR_Msk // Data toggle error
+
+/******************** Bit definition for DIEPINT register ********************/
+#define DIEPINT_XFRC_Pos (0U)
+#define DIEPINT_XFRC_Msk (0x1UL << DIEPINT_XFRC_Pos) // 0x00000001
+#define DIEPINT_XFRC DIEPINT_XFRC_Msk // Transfer completed interrupt
+#define DIEPINT_EPDISD_Pos (1U)
+#define DIEPINT_EPDISD_Msk (0x1UL << DIEPINT_EPDISD_Pos) // 0x00000002
+#define DIEPINT_EPDISD DIEPINT_EPDISD_Msk // Endpoint disabled interrupt
+#define DIEPINT_AHBERR_Pos (2U)
+#define DIEPINT_AHBERR_Msk (0x1UL << DIEPINT_AHBERR_Pos) // 0x00000004
+#define DIEPINT_AHBERR DIEPINT_AHBERR_Msk // AHB Error (AHBErr) during an IN transaction
+#define DIEPINT_TOC_Pos (3U)
+#define DIEPINT_TOC_Msk (0x1UL << DIEPINT_TOC_Pos) // 0x00000008
+#define DIEPINT_TOC DIEPINT_TOC_Msk // Timeout condition
+#define DIEPINT_ITTXFE_Pos (4U)
+#define DIEPINT_ITTXFE_Msk (0x1UL << DIEPINT_ITTXFE_Pos) // 0x00000010
+#define DIEPINT_ITTXFE DIEPINT_ITTXFE_Msk // IN token received when TxFIFO is empty
+#define DIEPINT_INEPNM_Pos (5U)
+#define DIEPINT_INEPNM_Msk (0x1UL << DIEPINT_INEPNM_Pos) // 0x00000020
+#define DIEPINT_INEPNM DIEPINT_INEPNM_Msk // IN token received with EP mismatch
+#define DIEPINT_INEPNE_Pos (6U)
+#define DIEPINT_INEPNE_Msk (0x1UL << DIEPINT_INEPNE_Pos) // 0x00000040
+#define DIEPINT_INEPNE DIEPINT_INEPNE_Msk // IN endpoint NAK effective
+#define DIEPINT_TXFE_Pos (7U)
+#define DIEPINT_TXFE_Msk (0x1UL << DIEPINT_TXFE_Pos) // 0x00000080
+#define DIEPINT_TXFE DIEPINT_TXFE_Msk // Transmit FIFO empty
+#define DIEPINT_TXFIFOUDRN_Pos (8U)
+#define DIEPINT_TXFIFOUDRN_Msk (0x1UL << DIEPINT_TXFIFOUDRN_Pos) // 0x00000100
+#define DIEPINT_TXFIFOUDRN DIEPINT_TXFIFOUDRN_Msk // Transmit Fifo Underrun
+#define DIEPINT_BNA_Pos (9U)
+#define DIEPINT_BNA_Msk (0x1UL << DIEPINT_BNA_Pos) // 0x00000200
+#define DIEPINT_BNA DIEPINT_BNA_Msk // Buffer not available interrupt
+#define DIEPINT_PKTDRPSTS_Pos (11U)
+#define DIEPINT_PKTDRPSTS_Msk (0x1UL << DIEPINT_PKTDRPSTS_Pos) // 0x00000800
+#define DIEPINT_PKTDRPSTS DIEPINT_PKTDRPSTS_Msk // Packet dropped status
+#define DIEPINT_BERR_Pos (12U)
+#define DIEPINT_BERR_Msk (0x1UL << DIEPINT_BERR_Pos) // 0x00001000
+#define DIEPINT_BERR DIEPINT_BERR_Msk // Babble error interrupt
+#define DIEPINT_NAK_Pos (13U)
+#define DIEPINT_NAK_Msk (0x1UL << DIEPINT_NAK_Pos) // 0x00002000
+#define DIEPINT_NAK DIEPINT_NAK_Msk // NAK interrupt
+
+/******************** Bit definition for HCINTMSK register ********************/
+#define HCINTMSK_XFRCM_Pos (0U)
+#define HCINTMSK_XFRCM_Msk (0x1UL << HCINTMSK_XFRCM_Pos) // 0x00000001
+#define HCINTMSK_XFRCM HCINTMSK_XFRCM_Msk // Transfer completed mask
+#define HCINTMSK_CHHM_Pos (1U)
+#define HCINTMSK_CHHM_Msk (0x1UL << HCINTMSK_CHHM_Pos) // 0x00000002
+#define HCINTMSK_CHHM HCINTMSK_CHHM_Msk // Channel halted mask
+#define HCINTMSK_AHBERR_Pos (2U)
+#define HCINTMSK_AHBERR_Msk (0x1UL << HCINTMSK_AHBERR_Pos) // 0x00000004
+#define HCINTMSK_AHBERR HCINTMSK_AHBERR_Msk // AHB error
+#define HCINTMSK_STALLM_Pos (3U)
+#define HCINTMSK_STALLM_Msk (0x1UL << HCINTMSK_STALLM_Pos) // 0x00000008
+#define HCINTMSK_STALLM HCINTMSK_STALLM_Msk // STALL response received interrupt mask
+#define HCINTMSK_NAKM_Pos (4U)
+#define HCINTMSK_NAKM_Msk (0x1UL << HCINTMSK_NAKM_Pos) // 0x00000010
+#define HCINTMSK_NAKM HCINTMSK_NAKM_Msk // NAK response received interrupt mask
+#define HCINTMSK_ACKM_Pos (5U)
+#define HCINTMSK_ACKM_Msk (0x1UL << HCINTMSK_ACKM_Pos) // 0x00000020
+#define HCINTMSK_ACKM HCINTMSK_ACKM_Msk // ACK response received/transmitted interrupt mask
+#define HCINTMSK_NYET_Pos (6U)
+#define HCINTMSK_NYET_Msk (0x1UL << HCINTMSK_NYET_Pos) // 0x00000040
+#define HCINTMSK_NYET HCINTMSK_NYET_Msk // response received interrupt mask
+#define HCINTMSK_TXERRM_Pos (7U)
+#define HCINTMSK_TXERRM_Msk (0x1UL << HCINTMSK_TXERRM_Pos) // 0x00000080
+#define HCINTMSK_TXERRM HCINTMSK_TXERRM_Msk // Transaction error mask
+#define HCINTMSK_BBERRM_Pos (8U)
+#define HCINTMSK_BBERRM_Msk (0x1UL << HCINTMSK_BBERRM_Pos) // 0x00000100
+#define HCINTMSK_BBERRM HCINTMSK_BBERRM_Msk // Babble error mask
+#define HCINTMSK_FRMORM_Pos (9U)
+#define HCINTMSK_FRMORM_Msk (0x1UL << HCINTMSK_FRMORM_Pos) // 0x00000200
+#define HCINTMSK_FRMORM HCINTMSK_FRMORM_Msk // Frame overrun mask
+#define HCINTMSK_DTERRM_Pos (10U)
+#define HCINTMSK_DTERRM_Msk (0x1UL << HCINTMSK_DTERRM_Pos) // 0x00000400
+#define HCINTMSK_DTERRM HCINTMSK_DTERRM_Msk // Data toggle error mask
+
+/******************** Bit definition for DIEPTSIZ register ********************/
+
+#define DIEPTSIZ_XFRSIZ_Pos (0U)
+#define DIEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DIEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF
+#define DIEPTSIZ_XFRSIZ DIEPTSIZ_XFRSIZ_Msk // Transfer size
+#define DIEPTSIZ_PKTCNT_Pos (19U)
+#define DIEPTSIZ_PKTCNT_Msk (0x3FFUL << DIEPTSIZ_PKTCNT_Pos) // 0x1FF80000
+#define DIEPTSIZ_PKTCNT DIEPTSIZ_PKTCNT_Msk // Packet count
+#define DIEPTSIZ_MULCNT_Pos (29U)
+#define DIEPTSIZ_MULCNT_Msk (0x3UL << DIEPTSIZ_MULCNT_Pos) // 0x60000000
+#define DIEPTSIZ_MULCNT DIEPTSIZ_MULCNT_Msk // Packet count
+ /******************** Bit definition for HCTSIZ register ********************/
+#define HCTSIZ_XFRSIZ_Pos (0U)
+#define HCTSIZ_XFRSIZ_Msk (0x7FFFFUL << HCTSIZ_XFRSIZ_Pos) // 0x0007FFFF
+#define HCTSIZ_XFRSIZ HCTSIZ_XFRSIZ_Msk // Transfer size
+#define HCTSIZ_PKTCNT_Pos (19U)
+#define HCTSIZ_PKTCNT_Msk (0x3FFUL << HCTSIZ_PKTCNT_Pos) // 0x1FF80000
+#define HCTSIZ_PKTCNT HCTSIZ_PKTCNT_Msk // Packet count
+#define HCTSIZ_DOPING_Pos (31U)
+#define HCTSIZ_DOPING_Msk (0x1UL << HCTSIZ_DOPING_Pos) // 0x80000000
+#define HCTSIZ_DOPING HCTSIZ_DOPING_Msk // Do PING
+#define HCTSIZ_DPID_Pos (29U)
+#define HCTSIZ_DPID_Msk (0x3UL << HCTSIZ_DPID_Pos) // 0x60000000
+#define HCTSIZ_DPID HCTSIZ_DPID_Msk // Data PID
+#define HCTSIZ_DPID_0 (0x1UL << HCTSIZ_DPID_Pos) // 0x20000000
+#define HCTSIZ_DPID_1 (0x2UL << HCTSIZ_DPID_Pos) // 0x40000000
+
+/******************** Bit definition for DIEPDMA register ********************/
+#define DIEPDMA_DMAADDR_Pos (0U)
+#define DIEPDMA_DMAADDR_Msk (0xFFFFFFFFUL << DIEPDMA_DMAADDR_Pos) // 0xFFFFFFFF
+#define DIEPDMA_DMAADDR DIEPDMA_DMAADDR_Msk // DMA address
+
+/******************** Bit definition for HCDMA register ********************/
+#define HCDMA_DMAADDR_Pos (0U)
+#define HCDMA_DMAADDR_Msk (0xFFFFFFFFUL << HCDMA_DMAADDR_Pos) // 0xFFFFFFFF
+#define HCDMA_DMAADDR HCDMA_DMAADDR_Msk // DMA address
+
+ /******************** Bit definition for DTXFSTS register ********************/
+#define DTXFSTS_INEPTFSAV_Pos (0U)
+#define DTXFSTS_INEPTFSAV_Msk (0xFFFFUL << DTXFSTS_INEPTFSAV_Pos) // 0x0000FFFF
+#define DTXFSTS_INEPTFSAV DTXFSTS_INEPTFSAV_Msk // IN endpoint TxFIFO space available
+
+ /******************** Bit definition for DIEPTXF register ********************/
+#define DIEPTXF_INEPTXSA_Pos (0U)
+#define DIEPTXF_INEPTXSA_Msk (0xFFFFUL << DIEPTXF_INEPTXSA_Pos) // 0x0000FFFF
+#define DIEPTXF_INEPTXSA DIEPTXF_INEPTXSA_Msk // IN endpoint FIFOx transmit RAM start address
+#define DIEPTXF_INEPTXFD_Pos (16U)
+#define DIEPTXF_INEPTXFD_Msk (0xFFFFUL << DIEPTXF_INEPTXFD_Pos) // 0xFFFF0000
+#define DIEPTXF_INEPTXFD DIEPTXF_INEPTXFD_Msk // IN endpoint TxFIFO depth
+
+/******************** Bit definition for DOEPCTL register ********************/
+#define DOEPCTL_MPSIZ_Pos (0U)
+#define DOEPCTL_MPSIZ_Msk (0x7FFUL << DOEPCTL_MPSIZ_Pos) // 0x000007FF
+#define DOEPCTL_MPSIZ DOEPCTL_MPSIZ_Msk // Maximum packet size //Bit 1
+#define DOEPCTL_USBAEP_Pos (15U)
+#define DOEPCTL_USBAEP_Msk (0x1UL << DOEPCTL_USBAEP_Pos) // 0x00008000
+#define DOEPCTL_USBAEP DOEPCTL_USBAEP_Msk // USB active endpoint
+#define DOEPCTL_NAKSTS_Pos (17U)
+#define DOEPCTL_NAKSTS_Msk (0x1UL << DOEPCTL_NAKSTS_Pos) // 0x00020000
+#define DOEPCTL_NAKSTS DOEPCTL_NAKSTS_Msk // NAK status
+#define DOEPCTL_SD0PID_SEVNFRM_Pos (28U)
+#define DOEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << DOEPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000
+#define DOEPCTL_SD0PID_SEVNFRM DOEPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID
+#define DOEPCTL_SODDFRM_Pos (29U)
+#define DOEPCTL_SODDFRM_Msk (0x1UL << DOEPCTL_SODDFRM_Pos) // 0x20000000
+#define DOEPCTL_SODDFRM DOEPCTL_SODDFRM_Msk // Set odd frame
+#define DOEPCTL_EPTYP_Pos (18U)
+#define DOEPCTL_EPTYP_Msk (0x3UL << DOEPCTL_EPTYP_Pos) // 0x000C0000
+#define DOEPCTL_EPTYP DOEPCTL_EPTYP_Msk // Endpoint type
+#define DOEPCTL_EPTYP_0 (0x1UL << DOEPCTL_EPTYP_Pos) // 0x00040000
+#define DOEPCTL_EPTYP_1 (0x2UL << DOEPCTL_EPTYP_Pos) // 0x00080000
+#define DOEPCTL_SNPM_Pos (20U)
+#define DOEPCTL_SNPM_Msk (0x1UL << DOEPCTL_SNPM_Pos) // 0x00100000
+#define DOEPCTL_SNPM DOEPCTL_SNPM_Msk // Snoop mode
+#define DOEPCTL_STALL_Pos (21U)
+#define DOEPCTL_STALL_Msk (0x1UL << DOEPCTL_STALL_Pos) // 0x00200000
+#define DOEPCTL_STALL DOEPCTL_STALL_Msk // STALL handshake
+#define DOEPCTL_CNAK_Pos (26U)
+#define DOEPCTL_CNAK_Msk (0x1UL << DOEPCTL_CNAK_Pos) // 0x04000000
+#define DOEPCTL_CNAK DOEPCTL_CNAK_Msk // Clear NAK
+#define DOEPCTL_SNAK_Pos (27U)
+#define DOEPCTL_SNAK_Msk (0x1UL << DOEPCTL_SNAK_Pos) // 0x08000000
+#define DOEPCTL_SNAK DOEPCTL_SNAK_Msk // Set NAK
+#define DOEPCTL_EPDIS_Pos (30U)
+#define DOEPCTL_EPDIS_Msk (0x1UL << DOEPCTL_EPDIS_Pos) // 0x40000000
+#define DOEPCTL_EPDIS DOEPCTL_EPDIS_Msk // Endpoint disable
+#define DOEPCTL_EPENA_Pos (31U)
+#define DOEPCTL_EPENA_Msk (0x1UL << DOEPCTL_EPENA_Pos) // 0x80000000
+#define DOEPCTL_EPENA DOEPCTL_EPENA_Msk // Endpoint enable
+
+/******************** Bit definition for DOEPINT register ********************/
+#define DOEPINT_XFRC_Pos (0U)
+#define DOEPINT_XFRC_Msk (0x1UL << DOEPINT_XFRC_Pos) // 0x00000001
+#define DOEPINT_XFRC DOEPINT_XFRC_Msk // Transfer completed interrupt
+#define DOEPINT_EPDISD_Pos (1U)
+#define DOEPINT_EPDISD_Msk (0x1UL << DOEPINT_EPDISD_Pos) // 0x00000002
+#define DOEPINT_EPDISD DOEPINT_EPDISD_Msk // Endpoint disabled interrupt
+#define DOEPINT_AHBERR_Pos (2U)
+#define DOEPINT_AHBERR_Msk (0x1UL << DOEPINT_AHBERR_Pos) // 0x00000004
+#define DOEPINT_AHBERR DOEPINT_AHBERR_Msk // AHB Error (AHBErr) during an OUT transaction
+#define DOEPINT_STUP_Pos (3U)
+#define DOEPINT_STUP_Msk (0x1UL << DOEPINT_STUP_Pos) // 0x00000008
+#define DOEPINT_STUP DOEPINT_STUP_Msk // SETUP phase done
+#define DOEPINT_OTEPDIS_Pos (4U)
+#define DOEPINT_OTEPDIS_Msk (0x1UL << DOEPINT_OTEPDIS_Pos) // 0x00000010
+#define DOEPINT_OTEPDIS DOEPINT_OTEPDIS_Msk // OUT token received when endpoint disabled
+#define DOEPINT_OTEPSPR_Pos (5U)
+#define DOEPINT_OTEPSPR_Msk (0x1UL << DOEPINT_OTEPSPR_Pos) // 0x00000020
+#define DOEPINT_OTEPSPR DOEPINT_OTEPSPR_Msk // Status Phase Received For Control Write
+#define DOEPINT_B2BSTUP_Pos (6U)
+#define DOEPINT_B2BSTUP_Msk (0x1UL << DOEPINT_B2BSTUP_Pos) // 0x00000040
+#define DOEPINT_B2BSTUP DOEPINT_B2BSTUP_Msk // Back-to-back SETUP packets received
+#define DOEPINT_OUTPKTERR_Pos (8U)
+#define DOEPINT_OUTPKTERR_Msk (0x1UL << DOEPINT_OUTPKTERR_Pos) // 0x00000100
+#define DOEPINT_OUTPKTERR DOEPINT_OUTPKTERR_Msk // OUT packet error
+#define DOEPINT_NAK_Pos (13U)
+#define DOEPINT_NAK_Msk (0x1UL << DOEPINT_NAK_Pos) // 0x00002000
+#define DOEPINT_NAK DOEPINT_NAK_Msk // NAK Packet is transmitted by the device
+#define DOEPINT_NYET_Pos (14U)
+#define DOEPINT_NYET_Msk (0x1UL << DOEPINT_NYET_Pos) // 0x00004000
+#define DOEPINT_NYET DOEPINT_NYET_Msk // NYET interrupt
+#define DOEPINT_STPKTRX_Pos (15U)
+#define DOEPINT_STPKTRX_Msk (0x1UL << DOEPINT_STPKTRX_Pos) // 0x00008000
+#define DOEPINT_STPKTRX DOEPINT_STPKTRX_Msk // Setup Packet Received
+
+/******************** Bit definition for DOEPTSIZ register ********************/
+#define DOEPTSIZ_XFRSIZ_Pos (0U)
+#define DOEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << DOEPTSIZ_XFRSIZ_Pos) // 0x0007FFFF
+#define DOEPTSIZ_XFRSIZ DOEPTSIZ_XFRSIZ_Msk // Transfer size
+#define DOEPTSIZ_PKTCNT_Pos (19U)
+#define DOEPTSIZ_PKTCNT_Msk (0x3FFUL << DOEPTSIZ_PKTCNT_Pos) // 0x1FF80000
+#define DOEPTSIZ_PKTCNT DOEPTSIZ_PKTCNT_Msk // Packet count
+
+#define DOEPTSIZ_STUPCNT_Pos (29U)
+#define DOEPTSIZ_STUPCNT_Msk (0x3UL << DOEPTSIZ_STUPCNT_Pos) // 0x60000000
+#define DOEPTSIZ_STUPCNT DOEPTSIZ_STUPCNT_Msk // SETUP packet count
+#define DOEPTSIZ_STUPCNT_0 (0x1UL << DOEPTSIZ_STUPCNT_Pos) // 0x20000000
+#define DOEPTSIZ_STUPCNT_1 (0x2UL << DOEPTSIZ_STUPCNT_Pos) // 0x40000000
+
+/******************** Bit definition for PCGCTL register ********************/
+#define PCGCTL_IF_DEV_MODE TU_BIT(31)
+#define PCGCTL_P2HD_PRT_SPD_MASK (0x3ul << 29)
+#define PCGCTL_P2HD_PRT_SPD_SHIFT 29
+#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3ul << 27)
+#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27
+#define PCGCTL_MAC_DEV_ADDR_MASK (0x7ful << 20)
+#define PCGCTL_MAC_DEV_ADDR_SHIFT 20
+#define PCGCTL_MAX_TERMSEL TU_BIT(19)
+#define PCGCTL_MAX_XCVRSELECT_MASK (0x3ul << 17)
+#define PCGCTL_MAX_XCVRSELECT_SHIFT 17
+#define PCGCTL_PORT_POWER TU_BIT(16)
+#define PCGCTL_PRT_CLK_SEL_MASK (0x3ul << 14)
+#define PCGCTL_PRT_CLK_SEL_SHIFT 14
+#define PCGCTL_ESS_REG_RESTORED TU_BIT(13)
+#define PCGCTL_EXTND_HIBER_SWITCH TU_BIT(12)
+#define PCGCTL_EXTND_HIBER_PWRCLMP TU_BIT(11)
+#define PCGCTL_ENBL_EXTND_HIBER TU_BIT(10)
+#define PCGCTL_RESTOREMODE TU_BIT(9)
+#define PCGCTL_RESETAFTSUSP TU_BIT(8)
+#define PCGCTL_DEEP_SLEEP TU_BIT(7)
+#define PCGCTL_PHY_IN_SLEEP TU_BIT(6)
+#define PCGCTL_ENBL_SLEEP_GATING TU_BIT(5)
+#define PCGCTL_RSTPDWNMODULE TU_BIT(3)
+#define PCGCTL_PWRCLMP TU_BIT(2)
+#define PCGCTL_GATEHCLK TU_BIT(1)
+#define PCGCTL_STOPPCLK TU_BIT(0)
+
+#define PCGCTL1_TIMER (0x3ul << 1)
+#define PCGCTL1_GATEEN TU_BIT(0)
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_xmc.h b/src/portable/synopsys/dwc2/dwc2_xmc.h
new file mode 100644
index 000000000..63419abf7
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_xmc.h
@@ -0,0 +1,88 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Rafael Silva (@perigoso)
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _DWC2_XMC_H_
+#define _DWC2_XMC_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "xmc_device.h"
+
+#define DWC2_EP_MAX 7
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ // Note: XMC has some custom control registers before DWC registers
+ { .reg_base = USB0_BASE, .irqnum = USB0_0_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 2048 }
+};
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_enable(uint8_t rhport)
+{
+ NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_disable (uint8_t rhport)
+{
+ NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum);
+}
+
+static inline void dwc2_remote_wakeup_delay(void)
+{
+ // try to delay for 1 ms
+// uint32_t count = SystemCoreClock / 1000;
+// while ( count-- ) __NOP();
+}
+
+// MCU specific PHY init, called BEFORE core reset
+static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+ (void) dwc2;
+ (void) hs_phy_type;
+
+ // Enable PHY
+ //USB->ROUTE = USB_ROUTE_PHYPEN;
+}
+
+// MCU specific PHY update, it is called AFTER init() and core reset
+static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+ (void) dwc2;
+ (void) hs_phy_type;
+
+ // XMC Manual: turn around must be 5 (reset & default value)
+ // dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c
index 12b9144bf..12d610bd6 100644
--- a/src/portable/template/dcd_template.c
+++ b/src/portable/template/dcd_template.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2018, hathach (tinyusb.org)
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if CFG_TUSB_MCU == OPT_MCU_NONE
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_NONE
#include "device/dcd.h"
@@ -82,6 +82,14 @@ void dcd_disconnect(uint8_t rhport)
(void) rhport;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -94,6 +102,11 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
return false;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+}
+
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
@@ -128,4 +141,6 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
(void) ep_addr;
}
+
+
#endif
diff --git a/src/portable/template/hcd_template.c b/src/portable/template/hcd_template.c
new file mode 100644
index 000000000..b073d6057
--- /dev/null
+++ b/src/portable/template/hcd_template.c
@@ -0,0 +1,163 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && CFG_TUSB_MCU == OPT_MCU_NONE
+
+#include "host/hcd.h"
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+// optional hcd configuration, called by tuh_configure()
+bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
+ (void) rhport;
+ (void) cfg_id;
+ (void) cfg_param;
+
+ return false;
+}
+
+// Initialize controller to host mode
+bool hcd_init(uint8_t rhport) {
+ (void) rhport;
+
+ return false;
+}
+
+// Interrupt Handler
+void hcd_int_handler(uint8_t rhport, bool in_isr) {
+ (void) rhport;
+ (void) in_isr;
+}
+
+// Enable USB interrupt
+void hcd_int_enable (uint8_t rhport) {
+ (void) rhport;
+}
+
+// Disable USB interrupt
+void hcd_int_disable(uint8_t rhport) {
+ (void) rhport;
+}
+
+// Get frame number (1ms)
+uint32_t hcd_frame_number(uint8_t rhport) {
+ (void) rhport;
+
+ return 0;
+}
+
+//--------------------------------------------------------------------+
+// Port API
+//--------------------------------------------------------------------+
+
+// Get the current connect status of roothub port
+bool hcd_port_connect_status(uint8_t rhport) {
+ (void) rhport;
+
+ return false;
+}
+
+// Reset USB bus on the port. Return immediately, bus reset sequence may not be complete.
+// 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) {
+ (void) rhport;
+}
+
+// Complete bus reset sequence, may be required by some controllers
+void hcd_port_reset_end(uint8_t rhport) {
+ (void) rhport;
+}
+
+// Get port link speed
+tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
+ (void) rhport;
+
+ return TUSB_SPEED_FULL;
+}
+
+// HCD closes all opened endpoints belong to this device
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
+ (void) rhport;
+ (void) dev_addr;
+}
+
+//--------------------------------------------------------------------+
+// Endpoints API
+//--------------------------------------------------------------------+
+
+// Open an endpoint
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_desc;
+
+ return false;
+}
+
+// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+ (void) buffer;
+ (void) buflen;
+
+ return false;
+}
+
+// Abort a queued transfer. Note: it can only abort transfer that has not been started
+// Return true if a queued transfer is aborted, false if there is no transfer to abort
+bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+
+ return false;
+}
+
+// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) setup_packet;
+
+ return false;
+}
+
+// clear stall, data toggle is also reset to DATA0
+bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+
+ return false;
+}
+
+#endif
diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
index 027ed26c9..8005f5f7b 100644
--- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
+++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
@@ -27,7 +27,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MSP430x5xx )
+#if CFG_TUD_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MSP430x5xx )
#include "msp430.h"
#include "device/dcd.h"
@@ -94,7 +94,8 @@ static void bus_reset(void)
USBOEPCNT_0 &= ~NAK;
USBIEPCNT_0 &= ~NAK;
- USBCTL |= FEN; // Enable responding to packets.
+ // Enable responding to packets.
+ USBCTL |= FEN;
// Dedicated buffers in hardware for SETUP and EP0, no setup needed.
// Now safe to respond to SETUP packets.
@@ -103,6 +104,28 @@ static void bus_reset(void)
USBKEYPID = 0;
}
+// Controls reset behavior of the USB module on receipt of a bus reset event.
+// - enable: When true, bus reset events will cause a reset the USB module.
+static void enable_functional_reset(const bool enable)
+{
+ // Check whether or not the USB configuration registers were
+ // locked prior to this function being called so that, if
+ // necessary, the lock state can be restored on exit.
+ bool unlocked = (USBKEYPID == 0xA528) ? true : false;
+
+ if(!unlocked) USBKEYPID = USBKEY;
+
+ if(enable)
+ {
+ USBCTL |= FRSTE;
+ }
+ else
+ {
+ USBCTL &= ~FRSTE;
+ }
+
+ if(!unlocked) USBKEYPID = 0;
+}
/*------------------------------------------------------------------*/
/* Controller API
@@ -131,11 +154,14 @@ void dcd_init (uint8_t rhport)
USBVECINT = 0;
- // Enable reset and wait for it before continuing.
- USBIE |= RSTRIE;
-
- // Enable pullup.
- USBCNF |= PUR_EN;
+ if(USBPWRCTL & USBBGVBV) {// Bus power detected?
+ USBPWRCTL |= VBOFFIE; // Enable bus-power-removed interrupt.
+ USBIE |= RSTRIE; // Enable reset and wait for it before continuing.
+ USBCNF |= PUR_EN; // Enable pullup.
+ } else {
+ USBPWRCTL |= VBONIE; // Enable bus-power-applied interrupt.
+ USBCNF &= ~USB_EN; // Disable USB module until bus power is detected.
+ }
USBKEYPID = 0;
}
@@ -222,6 +248,14 @@ void dcd_disconnect(uint8_t rhport)
dcd_int_enable(rhport);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
@@ -242,7 +276,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
}
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->max_size = desc_edpt->wMaxPacketSize.size;
+ xfer->max_size = tu_edpt_packet_size(desc_edpt);
// Buffer allocation scheme:
// For simplicity, only single buffer for now, since tinyusb currently waits
@@ -275,7 +309,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
// Also, DBUF got set on OUT EP 2 while debugging. Only OUT EPs seem to be
// affected at this time. USB RAM directly precedes main RAM; perhaps I'm
// overwriting registers via buffer overflow w/ my debugging code?
- ep_regs[SIZXY] = desc_edpt->wMaxPacketSize.size;
+ ep_regs[SIZXY] = tu_edpt_packet_size(desc_edpt);
ep_regs[BCTX] |= NAK;
ep_regs[BBAX] = buf_base;
ep_regs[CNF] &= ~(TOGGLE | STALL | DBUF); // ISO xfers not supported on
@@ -298,6 +332,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
(void) rhport;
@@ -541,6 +581,7 @@ static void transmit_packet(uint8_t ep_num)
}
// Then actually commit to transmit a packet.
+ uint8_t * base = (xfer->buffer + xfer->queued_len);
uint16_t remaining = xfer->total_len - xfer->queued_len;
uint8_t xfer_size = (xfer->max_size < xfer->total_len) ? xfer->max_size : remaining;
@@ -554,7 +595,6 @@ static void transmit_packet(uint8_t ep_num)
if(ep_num == 0)
{
volatile uint8_t * ep0in_buf = &USBIEP0BUF;
- uint8_t * base = (xfer->buffer + xfer->queued_len);
for(uint16_t i = 0; i < xfer_size; i++)
{
ep0in_buf[i] = base[i];
@@ -576,7 +616,6 @@ static void transmit_packet(uint8_t ep_num)
else
#endif
{
- uint8_t * base = (xfer->buffer + xfer->queued_len);
for(int i = 0; i < xfer_size; i++)
{
ep_buf[i] = base[i];
@@ -597,14 +636,76 @@ static void handle_setup_packet(void)
_setup_packet[i] = setup_buf[i];
}
- // Clearing SETUPIFG by reading USBVECINT does not set NAK, so now that we
- // have a SETUP packet, force NAKs until tinyusb can handle the SETUP
- // packet and prepare for a new xfer.
+ // Force NAKs until tinyusb can handle the SETUP packet and prepare for a new xfer.
USBIEPCNT_0 |= NAK;
USBOEPCNT_0 |= NAK;
+
+ // Clear SETUPIFG to avoid handling in the USBVECINT switch statement.
+ // When handled there the NAKs applied to the endpoints above are
+ // cleared by hardware and the host will receive stale/duplicate data.
+ //
+ // Excerpt from MSP430x5xx and MSP430x6xx Family User's Guide:
+ //
+ // "...the SETUPIFG is cleared upon reading USBIV. In addition, the NAK on
+ // input endpoint 0 and output endpoint 0 is also cleared."
+ USBIEPCNF_0 &= ~UBME; // Errata USB10 workaround.
+ USBOEPCNF_0 &= ~UBME; // Errata USB10 workaround.
+ USBIFG &= ~SETUPIFG;
+ USBIEPCNF_0 |= UBME; // Errata USB10 workaround.
+ USBOEPCNF_0 |= UBME; // Errata USB10 workaround.
dcd_event_setup_received(0, (uint8_t*) &_setup_packet[0], true);
}
+#if CFG_TUSB_OS == OPT_OS_NONE
+TU_ATTR_ALWAYS_INLINE static inline void tu_delay(uint32_t ms) {
+ // msp430 can run up to 25Mhz -> 40ns per cycle. 1 ms = 25000 cycles
+ // each loop need 4 cycle: 1 sub, 1 cmp, 1 jump, 1 nop
+ volatile uint32_t cycles = (25000 * ms) >> 2;
+ while (cycles > 0) {
+ cycles--;
+ asm("nop");
+ }
+}
+#else
+#define tu_delay(ms) osal_task_delay(ms)
+#endif
+
+static void handle_bus_power_event(void *param) {
+ (void) param;
+
+ tu_delay(5); // Bus power settling delay.
+
+ USBKEYPID = USBKEY;
+
+ if(USBPWRCTL & USBBGVBV) { // Event caused by application of bus power.
+ USBPWRCTL |= VBOFFIE; // Enable bus-power-removed interrupt.
+ USBPLLDIVB = USBPLLDIVB; // For some reason the PLL will *NOT* lock unless the divider
+ // register is re-written. The assumption here is that this
+ // register was already properly configured during board-level
+ // initialization.
+ USBPLLCTL |= (UPLLEN | UPFDEN); // Enable the PLL.
+
+ uint16_t attempts = 0;
+ do { // Poll the PLL, checking for a successful lock.
+ USBPLLIR = 0;
+ tu_delay(1);
+ attempts++;
+ } while ((attempts < 10) && (USBPLLIR != 0));
+
+ // A successful lock is indicated by all PLL-related interrupt flags being cleared.
+ if(!USBPLLIR) {
+ dcd_init(0); // Re-initialize the USB module.
+ }
+ } else { // Event caused by removal of bus power.
+ USBPWRCTL |= VBONIE; // Enable bus-power-applied interrupt.
+ USBPLLCTL &= ~(UPLLEN | UPFDEN); // Disable the PLL.
+ USBCNF = 0; // Disable the USB module.
+ dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, false);
+ }
+
+ USBKEYPID = 0;
+}
+
void dcd_int_handler(uint8_t rhport)
{
(void) rhport;
@@ -615,18 +716,51 @@ void dcd_int_handler(uint8_t rhport)
if(setup_status)
{
+ enable_functional_reset(true);
handle_setup_packet();
}
- uint16_t curr_vector = USBVECINT;
+ // Workaround possible bug in MSP430 GCC 9.3.0 where volatile variable
+ // USBVECINT is read from twice when only once is intended. The second
+ // (garbage) read seems to be triggered by certain switch statement
+ // configurations.
+ uint16_t curr_vector;
+ #if __GNUC__ > 9 || (__GNUC__ == 9 && __GNUC_MINOR__ > 2)
+ asm volatile ("mov %1, %0"
+ : "=r" (curr_vector)
+ : "m" (USBVECINT));
+ #else
+ curr_vector = USBVECINT;
+ #endif
switch(curr_vector)
{
+ case USBVECINT_NONE:
+ break;
+
case USBVECINT_RSTR:
+ enable_functional_reset(false); // Errata USB4 workaround.
bus_reset();
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
break;
+ case USBVECINT_PWR_VBUSOn:
+ case USBVECINT_PWR_VBUSOff: {
+ USBKEYPID = USBKEY;
+ // Prevent (possibly) unstable power from generating spurious interrupts.
+ USBPWRCTL &= ~(VBONIE | VBOFFIE);
+ USBKEYPID = 0;
+
+ dcd_event_t event;
+
+ event.rhport = 0;
+ event.event_id = USBD_EVENT_FUNC_CALL;
+ event.func_call.func = handle_bus_power_event;
+
+ dcd_event_handler(&event, true);
+ }
+ break;
+
// Clear the (hardware-enforced) NAK on EP 0 after a SETUP packet
// is received. At this point, even though the hardware is no longer
// forcing NAKs, the EP0 NAK bits should still be set to avoid
@@ -651,10 +785,12 @@ void dcd_int_handler(uint8_t rhport)
break;
case USBVECINT_INPUT_ENDPOINT0:
+ enable_functional_reset(true);
transmit_packet(0);
break;
case USBVECINT_OUTPUT_ENDPOINT0:
+ enable_functional_reset(true);
receive_packet(0);
break;
@@ -686,7 +822,6 @@ void dcd_int_handler(uint8_t rhport)
default:
while(true);
- break;
}
}
diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c
index b68f04faa..58628a8bb 100644
--- a/src/portable/valentyusb/eptri/dcd_eptri.c
+++ b/src/portable/valentyusb/eptri/dcd_eptri.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -24,6 +24,10 @@
* This file is part of the TinyUSB stack.
*/
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI)
+
#ifndef DEBUG
#define DEBUG 0
#endif
@@ -32,10 +36,6 @@
#define LOG_USB 0
#endif
-#include "tusb_option.h"
-
-#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI)
-
#include "device/dcd.h"
#include "dcd_eptri.h"
#include "csr.h"
@@ -314,13 +314,13 @@ static void dcd_reset(void)
usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_RESET_OFFSET);
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_RESET_OFFSET);
- memset((void *)rx_buffer, 0, sizeof(rx_buffer));
- memset((void *)rx_buffer_max, 0, sizeof(rx_buffer_max));
- memset((void *)rx_buffer_offset, 0, sizeof(rx_buffer_offset));
+ memset((void *)(uintptr_t) rx_buffer, 0, sizeof(rx_buffer));
+ memset((void *)(uintptr_t) rx_buffer_max, 0, sizeof(rx_buffer_max));
+ memset((void *)(uintptr_t) rx_buffer_offset, 0, sizeof(rx_buffer_offset));
- memset((void *)tx_buffer, 0, sizeof(tx_buffer));
- memset((void *)tx_buffer_max, 0, sizeof(tx_buffer_max));
- memset((void *)tx_buffer_offset, 0, sizeof(tx_buffer_offset));
+ memset((void *)(uintptr_t) tx_buffer, 0, sizeof(tx_buffer));
+ memset((void *)(uintptr_t) tx_buffer_max, 0, sizeof(tx_buffer_max));
+ memset((void *)(uintptr_t) tx_buffer_offset, 0, sizeof(tx_buffer_offset));
tx_ep = 0;
tx_active = false;
@@ -401,6 +401,13 @@ void dcd_disconnect(uint8_t rhport)
usb_pullup_out_write(0);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
//--------------------------------------------------------------------+
// DCD Endpoint Port
@@ -429,6 +436,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
@@ -452,7 +465,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
enable = 1;
usb_out_ctrl_write((0 << CSR_USB_OUT_CTRL_STALL_OFFSET) | (enable << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | tu_edpt_number(ep_addr));
}
- // IN endpoints will get unstalled when more data is written.
+ // IN endpoints will get un-stalled when more data is written.
}
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
diff --git a/src/portable/valentyusb/eptri/dcd_eptri.h b/src/portable/valentyusb/eptri/dcd_eptri.h
index 0fa6ecc64..d67635d7c 100644
--- a/src/portable/valentyusb/eptri/dcd_eptri.h
+++ b/src/portable/valentyusb/eptri/dcd_eptri.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
diff --git a/src/portable/wch/ch32_usbhs_reg.h b/src/portable/wch/ch32_usbhs_reg.h
new file mode 100644
index 000000000..9b956231f
--- /dev/null
+++ b/src/portable/wch/ch32_usbhs_reg.h
@@ -0,0 +1,349 @@
+#ifndef _USB_CH32_USBHS_REG_H
+#define _USB_CH32_USBHS_REG_H
+
+#if (CFG_TUSB_MCU == OPT_MCU_CH32V307)
+#include <ch32v30x.h>
+#elif (CFG_TUSB_MCU == OPT_MCU_CH32F20X)
+#include <ch32f20x.h>
+#endif
+
+/******************* GLOBAL ******************/
+
+// USB CONTROL
+#define USBHS_CONTROL_OFFSET 0x00
+#define USBHS_DMA_EN (1 << 0)
+#define USBHS_ALL_CLR (1 << 1)
+#define USBHS_FORCE_RST (1 << 2)
+#define USBHS_INT_BUSY_EN (1 << 3)
+#define USBHS_DEV_PU_EN (1 << 4)
+#define USBHS_SPEED_MASK (3 << 5)
+#define USBHS_FULL_SPEED (0 << 5)
+#define USBHS_HIGH_SPEED (1 << 5)
+#define USBHS_LOW_SPEED (2 << 5)
+#define USBHS_HOST_MODE (1 << 7)
+
+// USB_INT_EN
+#define USBHS_INT_EN_OFFSET 0x02
+#define USBHS_BUS_RST_EN (1 << 0)
+#define USBHS_DETECT_EN (1 << 0)
+#define USBHS_TRANSFER_EN (1 << 1)
+#define USBHS_SUSPEND_EN (1 << 2)
+#define USBHS_SOF_ACT_EN (1 << 3)
+#define USBHS_FIFO_OV_EN (1 << 4)
+#define USBHS_SETUP_ACT_EN (1 << 5)
+#define USBHS_ISO_ACT_EN (1 << 6)
+#define USBHS_DEV_NAK_EN (1 << 7)
+
+// USB DEV AD
+#define USBHS_DEV_AD_OFFSET 0x03
+// USB FRAME_NO
+#define USBHS_FRAME_NO_OFFSET 0x04
+// USB SUSPEND
+#define USBHS_SUSPEND_OFFSET 0x06
+#define USBHS_DEV_REMOTE_WAKEUP (1 << 2)
+#define USBHS_LINESTATE_MASK (2 << 4) /* Read Only */
+
+// RESERVED0
+
+// USB SPEED TYPE
+#define USBHS_SPEED_TYPE_OFFSET 0x08
+#define USBSPEED_MASK (0x03)
+
+// USB_MIS_ST
+#define USBHS_MIS_ST_OFFSET 0x09
+#define USBHS_SPLIT_CAN (1 << 0)
+#define USBHS_ATTACH (1 << 1)
+#define USBHS_SUSPEND (1 << 2)
+#define USBHS_BUS_RESET (1 << 3)
+#define USBHS_R_FIFO_RDY (1 << 4)
+#define USBHS_SIE_FREE (1 << 5)
+#define USBHS_SOF_ACT (1 << 6)
+#define USBHS_SOF_PRES (1 << 7)
+
+// INT_FLAG
+#define USBHS_INT_FLAG_OFFSET 0x0A
+#define USBHS_BUS_RST_FLAG (1 << 0)
+#define USBHS_DETECT_FLAG (1 << 0)
+#define USBHS_TRANSFER_FLAG (1 << 1)
+#define USBHS_SUSPEND_FLAG (1 << 2)
+#define USBHS_HST_SOF_FLAG (1 << 3)
+#define USBHS_FIFO_OV_FLAG (1 << 4)
+#define USBHS_SETUP_FLAG (1 << 5)
+#define USBHS_ISO_ACT_FLAG (1 << 6)
+
+// INT_ST
+#define USBHS_INT_ST_OFFSET 0x0B
+#define USBHS_DEV_UIS_IS_NAK (1 << 7)
+#define USBHS_DEV_UIS_TOG_OK (1 << 6)
+#define MASK_UIS_TOKEN (3 << 4)
+#define MASK_UIS_ENDP (0x0F)
+#define MASK_UIS_H_RES (0x0F)
+
+#define USBHS_TOGGLE_OK (0x40)
+#define USBHS_HOST_RES (0x0f)
+
+//USB_RX_LEN
+#define USBHS_RX_LEN_OFFSET 0x0C
+/******************* DEVICE ******************/
+
+//UEP_CONFIG
+#define USBHS_UEP_CONFIG_OFFSET 0x10
+#define USBHS_EP0_T_EN (1 << 0)
+#define USBHS_EP0_R_EN (1 << 16)
+
+#define USBHS_EP1_T_EN (1 << 1)
+#define USBHS_EP1_R_EN (1 << 17)
+
+#define USBHS_EP2_T_EN (1 << 2)
+#define USBHS_EP2_R_EN (1 << 18)
+
+#define USBHS_EP3_T_EN (1 << 3)
+#define USBHS_EP3_R_EN (1 << 19)
+
+#define USBHS_EP4_T_EN (1 << 4)
+#define USBHS_EP4_R_EN (1 << 20)
+
+#define USBHS_EP5_T_EN (1 << 5)
+#define USBHS_EP5_R_EN (1 << 21)
+
+#define USBHS_EP6_T_EN (1 << 6)
+#define USBHS_EP6_R_EN (1 << 22)
+
+#define USBHS_EP7_T_EN (1 << 7)
+#define USBHS_EP7_R_EN (1 << 23)
+
+#define USBHS_EP8_T_EN (1 << 8)
+#define USBHS_EP8_R_EN (1 << 24)
+
+#define USBHS_EP9_T_EN (1 << 9)
+#define USBHS_EP9_R_EN (1 << 25)
+
+#define USBHS_EP10_T_EN (1 << 10)
+#define USBHS_EP10_R_EN (1 << 26)
+
+#define USBHS_EP11_T_EN (1 << 11)
+#define USBHS_EP11_R_EN (1 << 27)
+
+#define USBHS_EP12_T_EN (1 << 12)
+#define USBHS_EP12_R_EN (1 << 28)
+
+#define USBHS_EP13_T_EN (1 << 13)
+#define USBHS_EP13_R_EN (1 << 29)
+
+#define USBHS_EP14_T_EN (1 << 14)
+#define USBHS_EP14_R_EN (1 << 30)
+
+#define USBHS_EP15_T_EN (1 << 15)
+#define USBHS_EP15_R_EN (1 << 31)
+
+//UEP_TYPE
+#define USBHS_UEP_TYPE_OFFSET 0x14
+#define USBHS_EP0_T_TYP (1 << 0)
+#define USBHS_EP0_R_TYP (1 << 16)
+
+#define USBHS_EP1_T_TYP (1 << 1)
+#define USBHS_EP1_R_TYP (1 << 17)
+
+#define USBHS_EP2_T_TYP (1 << 2)
+#define USBHS_EP2_R_TYP (1 << 18)
+
+#define USBHS_EP3_T_TYP (1 << 3)
+#define USBHS_EP3_R_TYP (1 << 19)
+
+#define USBHS_EP4_T_TYP (1 << 4)
+#define USBHS_EP4_R_TYP (1 << 20)
+
+#define USBHS_EP5_T_TYP (1 << 5)
+#define USBHS_EP5_R_TYP (1 << 21)
+
+#define USBHS_EP6_T_TYP (1 << 6)
+#define USBHS_EP6_R_TYP (1 << 22)
+
+#define USBHS_EP7_T_TYP (1 << 7)
+#define USBHS_EP7_R_TYP (1 << 23)
+
+#define USBHS_EP8_T_TYP (1 << 8)
+#define USBHS_EP8_R_TYP (1 << 24)
+
+#define USBHS_EP9_T_TYP (1 << 8)
+#define USBHS_EP9_R_TYP (1 << 25)
+
+#define USBHS_EP10_T_TYP (1 << 10)
+#define USBHS_EP10_R_TYP (1 << 26)
+
+#define USBHS_EP11_T_TYP (1 << 11)
+#define USBHS_EP11_R_TYP (1 << 27)
+
+#define USBHS_EP12_T_TYP (1 << 12)
+#define USBHS_EP12_R_TYP (1 << 28)
+
+#define USBHS_EP13_T_TYP (1 << 13)
+#define USBHS_EP13_R_TYP (1 << 29)
+
+#define USBHS_EP14_T_TYP (1 << 14)
+#define USBHS_EP14_R_TYP (1 << 30)
+
+#define USBHS_EP15_T_TYP (1 << 15)
+#define USBHS_EP15_R_TYP (1 << 31)
+
+/* BUF_MOD UEP1~15 */
+#define USBHS_BUF_MOD_OFFSET 0x18
+#define USBHS_EP0_BUF_MOD (1 << 0)
+#define USBHS_EP0_ISO_BUF_MOD (1 << 16)
+
+#define USBHS_EP1_BUF_MOD (1 << 1)
+#define USBHS_EP1_ISO_BUF_MOD (1 << 17)
+
+#define USBHS_EP2_BUF_MOD (1 << 2)
+#define USBHS_EP2_ISO_BUF_MOD (1 << 18)
+
+#define USBHS_EP3_BUF_MOD (1 << 3)
+#define USBHS_EP3_ISO_BUF_MOD (1 << 19)
+
+#define USBHS_EP4_BUF_MOD (1 << 4)
+#define USBHS_EP4_ISO_BUF_MOD (1 << 20)
+
+#define USBHS_EP5_BUF_MOD (1 << 5)
+#define USBHS_EP5_ISO_BUF_MOD (1 << 21)
+
+#define USBHS_EP6_BUF_MOD (1 << 6)
+#define USBHS_EP6_ISO_BUF_MOD (1 << 22)
+
+#define USBHS_EP7_BUF_MOD (1 << 7)
+#define USBHS_EP7_ISO_BUF_MOD (1 << 23)
+
+#define USBHS_EP8_BUF_MOD (1 << 8)
+#define USBHS_EP8_ISO_BUF_MOD (1 << 24)
+
+#define USBHS_EP9_BUF_MOD (1 << 9)
+#define USBHS_EP9_ISO_BUF_MOD (1 << 25)
+
+#define USBHS_EP10_BUF_MOD (1 << 10)
+#define USBHS_EP10_ISO_BUF_MOD (1 << 26)
+
+#define USBHS_EP11_BUF_MOD (1 << 11)
+#define USBHS_EP11_ISO_BUF_MOD (1 << 27)
+
+#define USBHS_EP12_BUF_MOD (1 << 12)
+#define USBHS_EP12_ISO_BUF_MOD (1 << 28)
+
+#define USBHS_EP13_BUF_MOD (1 << 13)
+#define USBHS_EP13_ISO_BUF_MOD (1 << 29)
+
+#define USBHS_EP14_BUF_MOD (1 << 14)
+#define USBHS_EP14_ISO_BUF_MOD (1 << 30)
+
+#define USBHS_EP15_BUF_MOD (1 << 15)
+#define USBHS_EP15_ISO_BUF_MOD (1 << 31)
+//USBHS_EPn_T_EN USBHS_EPn_R_EN USBHS_EPn_BUF_MOD Description: Arrange from low to high with UEPn_DMA as the starting address
+// 0 0 x The endpoint is disabled and the UEPn_*_DMA buffers are not used.
+// 1 0 0 The first address of the receive (OUT) buffer is UEPn_RX_DMA
+// 1 0 1 RB_UEPn_RX_TOG[0]=0, use buffer UEPn_RX_DMA RB_UEPn_RX_TOG[0]=1, use buffer UEPn_TX_DMA
+// 0 1 0 The first address of the transmit (IN) buffer is UEPn_TX_DMA.
+// 0 1 1 RB_UEPn_TX_TOG[0]=0, use buffer UEPn_TX_DMA RB_UEPn_TX_TOG[0]=1, use buffer UEPn_RX_DMA
+
+/* USB0_DMA */
+#define USBHS_UEP0_DMA_OFFSET(n) (0x1C) // endpoint 0 DMA buffer address
+
+/* USBX_RX_DMA */
+#define USBHS_UEPx_RX_DMA_OFFSET(n) (0x1C + 4 * (n)) // endpoint x DMA buffer address
+
+#define USBHS_UEPx_TX_DMA_OFFSET(n) (0x58 + 4 * (n)) // endpoint x DMA buffer address
+
+#define USBHS_UEPx_MAX_LEN_OFFSET(n) (0x98 + 4 * (n)) // endpoint x DMA buffer address
+
+#define USBHS_UEPx_T_LEN_OFFSET(n) (0xD8 + 4 * (n)) // endpoint x DMA buffer address
+#define USBHS_UEPx_TX_CTRL_OFFSET(n) (0xD8 + 4 * (n) + 2) // endpoint x DMA buffer address
+#define USBHS_UEPx_RX_CTRL_OFFSET(n) (0xD8 + 4 * (n) + 3) // endpoint x DMA buffer address
+
+// UEPn_T_LEN
+#define USBHS_EP_T_LEN_MASK (0x7FF)
+
+//UEPn_TX_CTRL
+#define USBHS_EP_T_RES_MASK (3 << 0)
+#define USBHS_EP_T_RES_ACK (0 << 0)
+#define USBHS_EP_T_RES_NYET (1 << 0)
+#define USBHS_EP_T_RES_NAK (2 << 0)
+#define USBHS_EP_T_RES_STALL (3 << 0)
+
+#define USBHS_EP_T_TOG_MASK (3 << 3)
+#define USBHS_EP_T_TOG_0 (0 << 3)
+#define USBHS_EP_T_TOG_1 (1 << 3)
+#define USBHS_EP_T_TOG_2 (2 << 3)
+#define USBHS_EP_T_TOG_M (3 << 3)
+
+#define USBHS_EP_T_AUTOTOG (1 << 5)
+
+//UEPn_RX_CTRL
+#define USBHS_EP_R_RES_MASK (3 << 0)
+#define USBHS_EP_R_RES_ACK (0 << 0)
+#define USBHS_EP_R_RES_NYET (1 << 0)
+#define USBHS_EP_R_RES_NAK (2 << 0)
+#define USBHS_EP_R_RES_STALL (3 << 0)
+
+#define USBHS_EP_R_TOG_MASK (3 << 3)
+#define USBHS_EP_R_TOG_0 (0 << 3)
+#define USBHS_EP_R_TOG_1 (1 << 3)
+#define USBHS_EP_R_TOG_2 (2 << 3)
+#define USBHS_EP_R_TOG_M (3 << 3)
+
+#define USBHS_EP_R_AUTOTOG (1 << 5)
+
+#define USBHS_TOG_MATCH (1 << 6)
+
+/******************* HOST ******************/
+// USB HOST_CTRL
+#define USBHS_SEND_BUS_RESET (1 << 0)
+#define USBHS_SEND_BUS_SUSPEND (1 << 1)
+#define USBHS_SEND_BUS_RESUME (1 << 2)
+#define USBHS_REMOTE_WAKE (1 << 3)
+#define USBHS_PHY_SUSPENDM (1 << 4)
+#define USBHS_UH_SOFT_FREE (1 << 6)
+#define USBHS_SEND_SOF_EN (1 << 7)
+
+//UH_CONFIG
+#define USBHS_HOST_TX_EN (1 << 3)
+#define USBHS_HOST_RX_EN (1 << 18)
+
+// HOST_EP_TYPE
+#define USBHS_ENDP_TX_ISO (1 << 3)
+#define USBHS_ENDP_RX_ISO (1 << (16 + 2))
+
+// R32_UH_EP_PID
+#define USBHS_HOST_MASK_TOKEN (0x0f)
+#define USBHS_HOST_MASK_ENDP (0x0f << 4)
+
+//R8_UH_RX_CTRL
+#define USBHS_EP_R_RES_MASK (3 << 0)
+#define USBHS_EP_R_RES_ACK (0 << 0)
+#define USBHS_EP_R_RES_NYET (1 << 0)
+#define USBHS_EP_R_RES_NAK (2 << 0)
+#define USBHS_EP_R_RES_STALL (3 << 0)
+
+#define USBHS_UH_R_RES_NO (1 << 2)
+#define USBHS_UH_R_TOG_1 (1 << 3)
+#define USBHS_UH_R_TOG_2 (2 << 3)
+#define USBHS_UH_R_TOG_3 (3 << 3)
+#define USBHS_UH_R_TOG_AUTO (1 << 5)
+#define USBHS_UH_R_DATA_NO (1 << 6)
+//R8_UH_TX_CTRL
+#define USBHS_UH_T_RES_MASK (3 << 0)
+#define USBHS_UH_T_RES_ACK (0 << 0)
+#define USBHS_UH_T_RES_NYET (1 << 0)
+#define USBHS_UH_T_RES_NAK (2 << 0)
+#define USBHS_UH_T_RES_STALL (3 << 0)
+
+#define USBHS_UH_T_RES_NO (1 << 2)
+#define USBHS_UH_T_TOG_1 (1 << 3)
+#define USBHS_UH_T_TOG_2 (2 << 3)
+#define USBHS_UH_T_TOG_3 (3 << 3)
+#define USBHS_UH_T_TOG_AUTO (1 << 5)
+#define USBHS_UH_T_DATA_NO (1 << 6)
+
+// 00: OUT, 01:SOF, 10:IN, 11:SETUP
+#define PID_OUT 0
+#define PID_SOF 1
+#define PID_IN 2
+#define PID_SETUP 3
+
+#endif
diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c
new file mode 100644
index 000000000..1f1c0b876
--- /dev/null
+++ b/src/portable/wch/dcd_ch32_usbhs.c
@@ -0,0 +1,391 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Greg Davill
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && ((CFG_TUSB_MCU == OPT_MCU_CH32V307) || (CFG_TUSB_MCU == OPT_MCU_CH32F20X))
+#include "device/dcd.h"
+
+#include "ch32_usbhs_reg.h"
+
+
+// Max number of bi-directional endpoints including EP0
+#define EP_MAX 16
+
+typedef struct {
+ uint8_t *buffer;
+ // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
+ uint16_t total_len;
+ uint16_t queued_len;
+ uint16_t max_size;
+ bool short_packet;
+} xfer_ctl_t;
+
+#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
+static xfer_ctl_t xfer_status[EP_MAX][2];
+
+#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep)*2)
+#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep)*4)
+#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep)*4)
+#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep)*2)
+
+#define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1))
+#define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1))
+
+/* Endpoint Buffer */
+TU_ATTR_ALIGNED(4) uint8_t EP0_DatabufHD[64]; // ep0(64)
+
+volatile uint8_t USBHS_Dev_Endp0_Tog = 0x01;
+
+void dcd_init(uint8_t rhport) {
+ (void)rhport;
+
+ memset(&xfer_status, 0, sizeof(xfer_status));
+
+ USBHSD->HOST_CTRL = 0x00;
+ USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM;
+
+ USBHSD->CONTROL = 0;
+
+#if TUD_OPT_HIGH_SPEED
+ USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
+#else
+ #error OPT_MODE_FULL_SPEED not currently supported on CH32
+ USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED;
+#endif
+
+ USBHSD->INT_EN = 0;
+ USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_DETECT_EN | USBHS_SUSPEND_EN;
+
+ /* ALL endpoint enable */
+ USBHSD->ENDP_CONFIG = 0xffffffff;
+
+ USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
+ USBHSD->ENDP_TYPE = 0x00;
+ USBHSD->BUF_MODE = 0x00;
+
+ USBHSD->UEP0_MAX_LEN = 64;
+
+ USBHSD->UEP0_DMA = (uint32_t)EP0_DatabufHD;
+
+ USBHSD->UEP0_TX_LEN = 0;
+ USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_NAK;
+ USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
+
+ for (int ep = 1; ep < EP_MAX; ep++) {
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
+ EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+
+ EP_RX_MAX_LEN(ep) = 512;
+ }
+
+ USBHSD->DEV_AD = 0;
+ USBHSD->CONTROL |= USBHS_DEV_PU_EN;
+}
+
+void dcd_int_enable(uint8_t rhport) {
+ (void)rhport;
+
+ NVIC_EnableIRQ(USBHS_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport) {
+ (void)rhport;
+
+ NVIC_DisableIRQ(USBHS_IRQn);
+}
+
+void dcd_edpt_close_all(uint8_t rhport) {
+ (void)rhport;
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
+ (void)dev_addr;
+
+ // Response with zlp status
+ dcd_edpt_xfer(rhport, 0x80, NULL, 0);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) {
+ (void)rhport;
+
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
+ request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ USBHSD->DEV_AD = (uint8_t)request->wValue;
+ }
+
+ EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK;
+ EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK;
+}
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt) {
+ (void)rhport;
+
+ uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
+ uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
+
+ TU_ASSERT(epnum < EP_MAX);
+
+ xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
+ xfer->max_size = tu_edpt_packet_size(desc_edpt);
+
+ if (epnum != 0) {
+ if (tu_edpt_dir(desc_edpt->bEndpointAddress) == TUSB_DIR_OUT) {
+ EP_RX_CTRL(epnum) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_ACK;
+ } else {
+ EP_TX_LEN(epnum) = 0;
+ EP_TX_CTRL(epnum) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ }
+ }
+
+ return true;
+}
+
+int usbd_ep_close(const uint8_t ep) {
+ (void)ep;
+
+ return 0;
+}
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void)rhport;
+
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ if (epnum == 0) {
+ if (dir == TUSB_DIR_OUT) {
+ USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_STALL;
+ } else {
+ USBHSD->UEP0_TX_LEN = 0;
+ USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_STALL;
+ }
+ } else {
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_STALL;
+
+ } else {
+ EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~USBHS_EP_T_RES_MASK) | USBHS_EP_T_RES_STALL;
+ }
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void)rhport;
+
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ if (epnum == 0) {
+ if (dir == TUSB_DIR_OUT) {
+ USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
+ } else {
+ }
+ } else {
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~(USBHS_EP_R_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_ACK;
+
+ } else {
+ EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_NAK;
+ }
+ }
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) {
+ (void)rhport;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
+ xfer->buffer = buffer;
+ // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
+ xfer->total_len = total_bytes;
+ xfer->queued_len = 0;
+ xfer->short_packet = false;
+
+ // uint16_t num_packets = (total_bytes / xfer->max_size);
+ uint16_t short_packet_size = total_bytes % (xfer->max_size + 1);
+
+ // Zero-size packet is special case.
+ if (short_packet_size == 0 || (total_bytes == 0)) {
+ xfer->short_packet = true;
+ }
+
+ if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
+ if (!total_bytes) {
+ xfer->short_packet = true;
+ if (epnum == 0) {
+ USBHSD->UEP0_TX_LEN = 0;
+ USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
+ USBHS_Dev_Endp0_Tog ^= 1;
+ } else {
+ EP_TX_LEN(epnum) = 0;
+ EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
+ }
+ } else {
+ if (epnum == 0) {
+ xfer->queued_len += short_packet_size;
+ memcpy(&EP0_DatabufHD[0], buffer, short_packet_size);
+
+ USBHSD->UEP0_TX_LEN = short_packet_size;
+ USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
+ USBHS_Dev_Endp0_Tog ^= 1;
+ } else {
+ xfer->queued_len += short_packet_size;
+
+ EP_TX_DMA_ADDR(epnum) = (uint32_t)buffer;
+ USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << epnum);
+ EP_TX_LEN(epnum) = short_packet_size;
+ EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
+ }
+ }
+ } else { /* TUSB_DIR_OUT */
+ if (epnum == 0) {
+ uint32_t read_count = USBHSD->RX_LEN;
+ read_count = TU_MIN(read_count, total_bytes);
+
+ if ((total_bytes == 8)) {
+ read_count = 8;
+ memcpy(buffer, &EP0_DatabufHD[0], 8);
+ } else {
+ memcpy(buffer, &EP0_DatabufHD[0], read_count);
+ }
+ } else {
+ EP_RX_DMA_ADDR(epnum) = (uint32_t)xfer->buffer;
+ USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << epnum);
+ }
+
+ // usbd_ep_read(ep_addr, buffer, total_bytes, &ret_bytes);
+ }
+ return true;
+}
+
+
+static void receive_packet(xfer_ctl_t *xfer, uint16_t xfer_size) {
+ // xfer->queued_len = xfer->total_len - remaining;
+
+ uint16_t remaining = xfer->total_len - xfer->queued_len;
+ uint16_t to_recv_size;
+
+ if (remaining <= xfer->max_size) {
+ // Avoid buffer overflow.
+ to_recv_size = (xfer_size > remaining) ? remaining : xfer_size;
+ } else {
+ // Room for full packet, choose recv_size based on what the microcontroller
+ // claims.
+ to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
+ }
+
+ if (to_recv_size) {
+ }
+
+ xfer->queued_len += xfer_size;
+
+ // Per USB spec, a short OUT packet (including length 0) is always
+ // indicative of the end of a transfer (at least for ctl, bulk, int).
+ xfer->short_packet = (xfer_size < xfer->max_size);
+}
+
+void dcd_int_handler(uint8_t rhport) {
+ (void)rhport;
+
+ uint32_t end_num, rx_token;
+ uint8_t intflag = 0;
+
+ intflag = USBHSD->INT_FG;
+
+ if (intflag & USBHS_TRANSFER_FLAG) {
+
+ end_num = (USBHSD->INT_ST) & MASK_UIS_ENDP;
+ rx_token = (((USBHSD->INT_ST) & MASK_UIS_TOKEN) >> 4) & 0x03;
+
+ uint8_t endp = end_num | (rx_token == PID_IN ? TUSB_DIR_IN_MASK : 0);
+
+ xfer_ctl_t *xfer = XFER_CTL_BASE(end_num, tu_edpt_dir(endp));
+
+ if (rx_token == PID_OUT) {
+ uint16_t rx_len = USBHSD->RX_LEN;
+
+ receive_packet(xfer, rx_len);
+
+ if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
+ xfer->short_packet = false;
+
+ dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+ }
+
+ if (end_num == 0) {
+ USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
+ }
+
+ } else if (rx_token == PID_IN) {
+ if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
+ xfer->short_packet = false;
+ xfer->total_len = 0;
+ dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+
+ EP_TX_CTRL(end_num) = (EP_TX_CTRL(end_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK;
+
+ if (end_num == 0) {
+ }
+ } else {
+ dcd_edpt_xfer(0, endp, xfer->buffer + xfer->queued_len, xfer->total_len - xfer->queued_len);
+ }
+ }
+
+ USBHSD->INT_FG = USBHS_TRANSFER_FLAG; /* Clear flag */
+ } else if (intflag & USBHS_SETUP_FLAG) {
+ USBHS_Dev_Endp0_Tog = 1;
+ dcd_event_setup_received(0, EP0_DatabufHD, true);
+
+ USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */
+ } else if (intflag & USBHS_DETECT_FLAG) {
+ USBHS_Dev_Endp0_Tog = 1;
+
+ xfer_status[0][TUSB_DIR_OUT].max_size = 64;
+ xfer_status[0][TUSB_DIR_IN].max_size = 64;
+
+ dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true);
+
+ USBHSD->DEV_AD = 0;
+ USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
+
+ USBHSD->INT_FG = USBHS_DETECT_FLAG; /* Clear flag */
+ } else if (intflag & USBHS_SUSPEND_FLAG) {
+ dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SUSPEND };
+ dcd_event_handler(&event, true);
+
+ USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */
+ }
+}
+
+#endif