summaryrefslogtreecommitdiff
path: root/src/portable
diff options
context:
space:
mode:
Diffstat (limited to 'src/portable')
-rw-r--r--src/portable/analog/max3421/hcd_max3421.c226
-rw-r--r--src/portable/analog/max3421/hcd_max3421.h63
-rw-r--r--src/portable/bridgetek/ft9xx/dcd_ft9xx.c5
-rw-r--r--src/portable/chipidea/ci_fs/dcd_ci_fs.c5
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_imxrt.h25
-rw-r--r--src/portable/chipidea/ci_hs/dcd_ci_hs.c55
-rw-r--r--src/portable/chipidea/ci_hs/hcd_ci_hs.c9
-rw-r--r--src/portable/dialog/da146xx/dcd_da146xx.c10
-rw-r--r--src/portable/ehci/ehci.c261
-rw-r--r--src/portable/ehci/ehci.h278
-rw-r--r--src/portable/espressif/esp32sx/dcd_esp32sx.c6
-rw-r--r--src/portable/mentor/musb/dcd_musb.c766
-rw-r--r--src/portable/mentor/musb/hcd_musb.c23
-rw-r--r--src/portable/mentor/musb/musb_max32.h150
-rw-r--r--src/portable/mentor/musb/musb_msp432e.h40
-rw-r--r--src/portable/mentor/musb/musb_ti.h (renamed from src/portable/mentor/musb/musb_tm4c.h)54
-rw-r--r--src/portable/mentor/musb/musb_type.h2840
-rw-r--r--src/portable/microchip/pic/README.md51
-rw-r--r--src/portable/microchip/pic/dcd_pic.c122
-rw-r--r--src/portable/microchip/pic32mz/dcd_pic32mz.c5
-rw-r--r--src/portable/microchip/samd/dcd_samd.c8
-rw-r--r--src/portable/microchip/samg/dcd_samg.c52
-rw-r--r--src/portable/microchip/samx7x/dcd_samx7x.c5
-rw-r--r--src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c5
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c29
-rw-r--r--src/portable/nuvoton/nuc120/dcd_nuc120.c6
-rw-r--r--src/portable/nuvoton/nuc121/dcd_nuc121.c6
-rw-r--r--src/portable/nuvoton/nuc505/dcd_nuc505.c6
-rw-r--r--src/portable/nxp/khci/dcd_khci.c8
-rw-r--r--src/portable/nxp/khci/hcd_khci.c14
-rw-r--r--src/portable/nxp/lpc17_40/dcd_lpc17_40.c11
-rw-r--r--src/portable/nxp/lpc17_40/hcd_lpc17_40.c1
-rw-r--r--src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c11
-rw-r--r--src/portable/ohci/ohci.c10
-rw-r--r--src/portable/raspberrypi/pio_usb/dcd_pio_usb.c7
-rw-r--r--src/portable/raspberrypi/pio_usb/hcd_pio_usb.c8
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c159
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c56
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c2
-rw-r--r--src/portable/renesas/rusb2/dcd_rusb2.c12
-rw-r--r--src/portable/renesas/rusb2/hcd_rusb2.c9
-rw-r--r--src/portable/renesas/rusb2/rusb2_common.c1
-rw-r--r--src/portable/sony/cxd56/dcd_cxd56.c6
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c6
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_stm32.h42
-rw-r--r--src/portable/sunxi/dcd_sunxi_musb.c7
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c1371
-rw-r--r--src/portable/synopsys/dwc2/dwc2_bcm.h2
-rw-r--r--src/portable/synopsys/dwc2/dwc2_common.c311
-rw-r--r--src/portable/synopsys/dwc2/dwc2_common.h101
-rw-r--r--src/portable/synopsys/dwc2/dwc2_esp32.h137
-rw-r--r--src/portable/synopsys/dwc2/dwc2_info.md113
-rwxr-xr-x[-rw-r--r--]src/portable/synopsys/dwc2/dwc2_info.py207
-rw-r--r--src/portable/synopsys/dwc2/dwc2_stm32.h30
-rw-r--r--src/portable/synopsys/dwc2/dwc2_type.h1254
-rw-r--r--src/portable/synopsys/dwc2/hcd_dwc2.c1366
-rw-r--r--src/portable/template/dcd_template.c65
-rw-r--r--src/portable/template/hcd_template.c50
-rw-r--r--src/portable/ti/msp430x5xx/dcd_msp430x5xx.c18
-rw-r--r--src/portable/valentyusb/eptri/dcd_eptri.c11
-rw-r--r--src/portable/wch/dcd_ch32_usbfs.c8
-rw-r--r--src/portable/wch/dcd_ch32_usbhs.c5
62 files changed, 5741 insertions, 4789 deletions
diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c
index d9b8e1fc3..bb33200f2 100644
--- a/src/portable/analog/max3421/hcd_max3421.c
+++ b/src/portable/analog/max3421/hcd_max3421.c
@@ -168,14 +168,14 @@ enum {
};
enum {
- MAX_NAK_DEFAULT = 1 // Number of NAK per endpoint per usb frame
+ MAX_NAK_DEFAULT = 1 // Number of NAK per endpoint per usb frame to save CPU/SPI bus usage
};
enum {
EP_STATE_IDLE = 0,
EP_STATE_COMPLETE = 1,
EP_STATE_ABORTING = 2,
- EP_STATE_ATTEMPT_1 = 3, // pending 1st attempt
+ EP_STATE_ATTEMPT_1 = 3, // Number of attempts to transfer in a frame. Incremented after each NAK
EP_STATE_ATTEMPT_MAX = 15
};
@@ -183,17 +183,20 @@ enum {
//
//--------------------------------------------------------------------+
+typedef 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_t;
+
+TU_VERIFY_STATIC(sizeof(hxfr_bm_t) == 1, "size is not correct");
+
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;
-
+ union {
+ hxfr_bm_t hxfr_bm;
uint8_t hxfr;
};
@@ -219,7 +222,16 @@ typedef struct {
uint8_t hien;
uint8_t mode;
uint8_t peraddr;
- uint8_t hxfr;
+ union {
+ hxfr_bm_t hxfr_bm;
+ uint8_t hxfr;
+ };
+
+ // owner of data in SNDFIFO, for retrying NAKed without re-writing to FIFO
+ struct {
+ uint8_t daddr;
+ uint8_t hxfr;
+ }sndfifo_owner;
atomic_flag busy; // busy transferring
@@ -241,28 +253,6 @@ static tuh_configure_max3421_t _tuh_cfg = {
};
//--------------------------------------------------------------------+
-// 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
//--------------------------------------------------------------------+
@@ -317,33 +307,9 @@ bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_is
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 -------------//
+//--------------------------------------------------------------------
+// Register 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
@@ -377,6 +343,47 @@ TU_ATTR_ALWAYS_INLINE static inline void sndbc_write(uint8_t rhport, uint8_t dat
reg_write(rhport, SNDBC_ADDR, data, in_isr);
}
+//--------------------------------------------------------------------
+// FIFO access (receive, send, setup)
+//--------------------------------------------------------------------
+static void hwfifo_write(uint8_t rhport, uint8_t reg, const uint8_t* buffer, uint8_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);
+}
+
+// Write to SNDFIFO if len > 0 and update SNDBC
+TU_ATTR_ALWAYS_INLINE static inline void hwfifo_send(uint8_t rhport, const uint8_t* buffer, uint8_t len, bool in_isr) {
+ if (len) {
+ hwfifo_write(rhport, SNDFIFO_ADDR, buffer, len, in_isr);
+ }
+ sndbc_write(rhport, len, in_isr);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void hwfifo_setup(uint8_t rhport, const uint8_t* buffer, bool in_isr) {
+ hwfifo_write(rhport, SUDFIFO_ADDR, buffer, 8, in_isr);
+}
+
+static void hwfifo_receive(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);
+}
+
//--------------------------------------------------------------------+
// Endpoint helper
//--------------------------------------------------------------------+
@@ -417,7 +424,7 @@ static void free_ep(uint8_t daddr) {
}
}
-// Check if endpoint has an queued transfer and not reach max NAK
+// Check if endpoint has a queued transfer and not reach max NAK in this frame
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) &&
@@ -465,8 +472,8 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
}
// Initialize controller to host mode
-bool hcd_init(uint8_t rhport) {
- (void) rhport;
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
tuh_max3421_int_api(rhport, false);
@@ -487,6 +494,7 @@ bool hcd_init(uint8_t rhport) {
reg_write(rhport, PINCTL_ADDR, _tuh_cfg.pinctl | PINCTL_FDUPSPI, false);
// v1 is 0x01, v2 is 0x12, v3 is 0x13
+ // Note: v1 and v2 has host OUT errata whose workaround is not implemented in this driver
uint8_t const revision = reg_read(rhport, REVISION_ADDR, false);
TU_LOG2_HEX(revision);
TU_ASSERT(revision == 0x01 || revision == 0x12 || revision == 0x13, false);
@@ -602,6 +610,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
if (daddr == 0 && ep_num == 0) {
ep = &_hcd_data.ep[0];
}else {
+ if (NULL != find_ep_not_addr0(daddr, ep_num, ep_dir)) {
+ return true; // already opened
+ }
ep = allocate_ep();
TU_ASSERT(ep);
ep->daddr = daddr;
@@ -615,22 +626,60 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport;
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr);
+ max3421_ep_t * ep = find_ep_not_addr0(daddr, ep_num, ep_dir);
+
+ if (!ep) {
+ return false; // not opened
+ }
+
+ tu_memclr(ep, sizeof(max3421_ep_t));
+
+ return true;
+}
+
+/* The microcontroller repeatedly writes the SNDFIFO register R2 to load the FIFO with up to 64 data bytes.
+ * Then the microcontroller writes the SNDBC register, which this does three things:
+ * 1. Tells the MAX3421E SIE (Serial Interface Engine) how many bytes in the FIFO to send.
+ * 2. Connects the SNDFIFO and SNDBC register to the USB logic for USB transmission.
+ * 3. Clears the SNDBAVIRQ interrupt flag. If the second FIFO is available for µC loading, the SNDBAVIRQ immediately re-asserts.
+
+ +-----------+
+ --->| SNDBC-A |
+ / | SNDFIFO-A |
+ / +-----------+
+ +------+ +-------------+ / +----------+
+ | MCU |------>| R2: SNDFIFO |---- << Write R7 Flip >> ---| MAX3241E |
+ |(hcd) | | R7: SNDBC | / | SIE |
+ +------+ +-------------+ / +----------+
+ +-----------+ /
+ | SNDBC-B | /
+ | SNDFIFO-B |<---
+ +-----------+
+ Note: xact_out() is called when starting a new transfer, continue a transfer (isr) or retry a transfer (NAK)
+ For NAK retry, we do not need to write to FIFO or SNDBC register again.
+*/
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
+ // TODO: double buffering for ISO transfer
if (switch_ep) {
peraddr_write(rhport, ep->daddr, in_isr);
-
- uint8_t const hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0);
+ const uint8_t 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);
+ // Only write to sndfifo and sdnbc register if it is not a NAKed retry
+ if (!(ep->daddr == _hcd_data.sndfifo_owner.daddr && ep->hxfr == _hcd_data.sndfifo_owner.hxfr)) {
+ // skip SNDBAV IRQ check, overwrite sndfifo if needed
+ const uint8_t xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size);
+ hwfifo_send(rhport, ep->buf, xact_len, in_isr);
}
- sndbc_write(rhport, xact_len, in_isr);
+ _hcd_data.sndfifo_owner.daddr = ep->daddr;
+ _hcd_data.sndfifo_owner.hxfr = ep->hxfr;
+
hxfr_write(rhport, ep->hxfr, in_isr);
}
@@ -648,7 +697,7 @@ static void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_is
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);
+ hwfifo_setup(rhport, ep->buf, in_isr);
hxfr_write(rhport, HXFR_SETUP, in_isr);
}
@@ -662,7 +711,7 @@ static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool
// status
if (ep->buf == NULL || ep->total_len == 0) {
- uint8_t const hxfr = (uint8_t) (HXFR_HS | (ep->hxfr & HXFR_OUT_NIN));
+ const uint8_t hxfr = (uint8_t) (HXFR_HS | (ep->hxfr & HXFR_OUT_NIN));
peraddr_write(rhport, ep->daddr, in_isr);
hxfr_write(rhport, hxfr, in_isr);
return;
@@ -823,11 +872,11 @@ static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t re
}
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;
+ const uint8_t hrsl = reg_read(rhport, HRSL_ADDR, in_isr);
+ const uint8_t hresult = hrsl & HRSL_RESULT_MASK;
+ const uint8_t ep_num = _hcd_data.hxfr_bm.ep_num;
+ const uint8_t hxfr_type = _hcd_data.hxfr & 0xf0;
+ const uint8_t 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, );
@@ -842,7 +891,8 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
// control endpoint -> retry immediately and return
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
return;
- } else if (EP_STATE_ATTEMPT_1 <= ep->state && ep->state < EP_STATE_ATTEMPT_MAX) {
+ }
+ if (EP_STATE_ATTEMPT_1 <= ep->state && ep->state < EP_STATE_ATTEMPT_MAX) {
ep->state++;
}
}
@@ -853,7 +903,6 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
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
@@ -896,11 +945,15 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
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);
+ hxfr_write(rhport, _hcd_data.hxfr, in_isr); // more to transfer
}
} else {
// SETUP or OUT transfer
+
+ // clear sndfifo owner since data is sent
+ _hcd_data.sndfifo_owner.daddr = 0xff;
+ _hcd_data.sndfifo_owner.hxfr = 0xff;
+
uint8_t xact_len;
if (hxfr_type & HXFR_SETUP) {
@@ -917,8 +970,7 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
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);
+ xact_out(rhport, ep, false, in_isr); // more to transfer
}
}
}
@@ -978,16 +1030,16 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
// 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;
+ const uint8_t ep_num = _hcd_data.hxfr_bm.ep_num;
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);
+ const 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);
+ hwfifo_receive(rhport, ep->buf, xact_len, in_isr);
ep->buf += xact_len;
ep->xferred_len += xact_len;
}
diff --git a/src/portable/analog/max3421/hcd_max3421.h b/src/portable/analog/max3421/hcd_max3421.h
new file mode 100644
index 000000000..4631fa21a
--- /dev/null
+++ b/src/portable/analog/max3421/hcd_max3421.h
@@ -0,0 +1,63 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 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_HCD_MAX3421_H
+#define TUSB_HCD_MAX3421_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// SPI transfer API with MAX3421E are implemented by application
+// - spi_cs_api(), spi_xfer_api(), int_api()
+//--------------------------------------------------------------------+
+
+// 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 for read/write MAX3421 registers
+// are implemented by this driver, can be used by application
+//--------------------------------------------------------------------+
+
+// 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);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c
index f02415904..34a8be3b6 100644
--- a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c
+++ b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c
@@ -517,8 +517,8 @@ static uint16_t _ft9xx_dusb_out(uint8_t ep_number, uint8_t *buffer, uint16_t len
*------------------------------------------------------------------*/
// Initialize controller to device mode
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
TU_LOG2("FT9xx initialisation\r\n");
_dcd_ft9xx_attach();
@@ -526,6 +526,7 @@ void dcd_init(uint8_t rhport)
interrupt_attach(interrupt_usb_device, (int8_t)interrupt_usb_device, _ft9xx_usbd_ISR);
dcd_connect(rhport);
+ return true;
}
// Enable device interrupt
diff --git a/src/portable/chipidea/ci_fs/dcd_ci_fs.c b/src/portable/chipidea/ci_fs/dcd_ci_fs.c
index 02f813ab5..11ddb683f 100644
--- a/src/portable/chipidea/ci_fs/dcd_ci_fs.c
+++ b/src/portable/chipidea/ci_fs/dcd_ci_fs.c
@@ -267,9 +267,9 @@ static void process_bus_resume(uint8_t rhport)
/*------------------------------------------------------------------*/
/* Device API
*------------------------------------------------------------------*/
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
// 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
@@ -296,6 +296,7 @@ void dcd_init(uint8_t rhport)
dcd_connect(rhport);
// NVIC_ClearPendingIRQ(CIFS_IRQN);
+ return true;
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
diff --git a/src/portable/chipidea/ci_hs/ci_hs_imxrt.h b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
index c59c107ff..75d1d55b8 100644
--- a/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
+++ b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
@@ -56,14 +56,23 @@ static const ci_hs_controller_t _ci_controller[] =
#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)
+#define CI_DCD_INT_ENABLE(_p) NVIC_EnableIRQ ((IRQn_Type)_ci_controller[_p].irqnum)
+#define CI_DCD_INT_DISABLE(_p) NVIC_DisableIRQ((IRQn_Type)_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)
+#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ ((IRQn_Type)_ci_controller[_p].irqnum)
+#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ((IRQn_Type)_ci_controller[_p].irqnum)
//------------- DCache -------------//
+#if CFG_TUD_MEM_DCACHE_ENABLE || CFG_TUH_MEM_DCACHE_ENABLE
+#if __CORTEX_M == 7
+TU_ATTR_ALWAYS_INLINE static inline uint32_t round_up_to_cache_line_size(uint32_t size) {
+ if (size & (CFG_TUD_MEM_DCACHE_LINE_SIZE-1)) {
+ size = (size & ~(CFG_TUD_MEM_DCACHE_LINE_SIZE-1)) + CFG_TUD_MEM_DCACHE_LINE_SIZE;
+ }
+ return size;
+}
+
TU_ATTR_ALWAYS_INLINE static inline bool imxrt_is_cache_mem(uintptr_t addr) {
return !(0x20000000 <= addr && addr < 0x20100000);
}
@@ -72,6 +81,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool imxrt_dcache_clean(void const* addr, ui
const uintptr_t addr32 = (uintptr_t) addr;
if (imxrt_is_cache_mem(addr32)) {
TU_ASSERT(tu_is_aligned32(addr32));
+ data_size = round_up_to_cache_line_size(data_size);
SCB_CleanDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size);
}
return true;
@@ -84,6 +94,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool imxrt_dcache_invalidate(void const* add
// *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));
+ data_size = round_up_to_cache_line_size(data_size);
SCB_InvalidateDCache_by_Addr((void*) addr32, (int32_t) data_size);
}
return true;
@@ -93,9 +104,15 @@ TU_ATTR_ALWAYS_INLINE static inline bool imxrt_dcache_clean_invalidate(void cons
const uintptr_t addr32 = (uintptr_t) addr;
if (imxrt_is_cache_mem(addr32)) {
TU_ASSERT(tu_is_aligned32(addr32));
+ data_size = round_up_to_cache_line_size(data_size);
SCB_CleanInvalidateDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size);
}
return true;
}
+#elif __CORTEX_M == 4
+#error "Secondary M4 core's cache controller is not supported yet."
+#endif
+#endif
+
#endif
diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
index 93e1d78dd..a716dc24c 100644
--- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
@@ -34,43 +34,31 @@
#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);
- }
+#if CFG_TUD_MEM_DCACHE_ENABLE
+bool dcd_dcache_clean(void const* addr, uint32_t data_size) {
+ return imxrt_dcache_clean(addr, data_size);
+}
- void dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
- imxrt_dcache_clean_invalidate(addr, data_size);
- }
+bool dcd_dcache_invalidate(void const* addr, uint32_t data_size) {
+ return imxrt_dcache_invalidate(addr, data_size);
+}
-#else
+bool dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
+ return imxrt_dcache_clean_invalidate(addr, data_size);
+}
+#endif
-#if TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
+#elif 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
//--------------------------------------------------------------------+
@@ -234,13 +222,13 @@ static void bus_reset(uint8_t rhport)
dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
}
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
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, );
+ TU_ASSERT(ci_ep_count(dcd_reg) <= TUP_DCD_ENDPOINT_MAX);
// Reset controller
dcd_reg->USBCMD |= USBCMD_RESET;
@@ -268,6 +256,8 @@ void dcd_init(uint8_t rhport)
usbcmd |= USBCMD_RUN_STOP; // run
dcd_reg->USBCMD = usbcmd;
+
+ return true;
}
void dcd_int_enable(uint8_t rhport)
@@ -323,9 +313,7 @@ void dcd_sof_enable(uint8_t rhport, bool en)
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);
+ dcd_dcache_clean_invalidate((uint32_t*) tu_align((uint32_t) data_ptr, 4), total_bytes);
tu_memclr(p_qtd, sizeof(dcd_qtd_t));
@@ -491,7 +479,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
return true;
}
+#if !CFG_TUD_MEM_DCACHE_ENABLE
// fifo has to be aligned to 4k boundary
+// It's incompatible with dcache enabled transfer, since neither address nor size is aligned to cache line
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);
@@ -537,8 +527,6 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
page++;
}
}
-
- dcd_dcache_clean_invalidate((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), total_bytes - fifo_info.len_wrap + 31);
}
else
{
@@ -553,6 +541,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
return true;
}
+#endif
//--------------------------------------------------------------------+
// ISR
diff --git a/src/portable/chipidea/ci_hs/hcd_ci_hs.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
index 462cbd301..c4c342a70 100644
--- a/src/portable/chipidea/ci_hs/hcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
@@ -42,6 +42,7 @@
#include "ci_hs_imxrt.h"
+#if CFG_TUH_MEM_DCACHE_ENABLE
bool hcd_dcache_clean(void const* addr, uint32_t data_size) {
return imxrt_dcache_clean(addr, data_size);
}
@@ -53,6 +54,7 @@ bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) {
bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
return imxrt_dcache_clean_invalidate(addr, data_size);
}
+#endif
#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
@@ -70,7 +72,8 @@ bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
// Controller API
//--------------------------------------------------------------------+
-bool hcd_init(uint8_t rhport) {
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
ci_hs_regs_t *hcd_reg = CI_HS_REG(rhport);
// Reset controller
@@ -82,7 +85,9 @@ bool hcd_init(uint8_t rhport) {
// LPC18XX/43XX need to set VBUS Power Select to HIGH
// RHPORT1 is fullspeed only (need external PHY for Highspeed)
hcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT;
- if ( rhport == 1 ) hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
+ if (rhport == 1) {
+ hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
+ }
#else
hcd_reg->USBMODE = USBMODE_CM_HOST;
#endif
diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c
index d1e85c2df..56ecb7575 100644
--- a/src/portable/dialog/da146xx/dcd_da146xx.c
+++ b/src/portable/dialog/da146xx/dcd_da146xx.c
@@ -804,15 +804,16 @@ static void handle_ep0_nak(void)
/*------------------------------------------------------------------*/
/* Controller API
*------------------------------------------------------------------*/
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
_dcd.init_called = true;
- if (_dcd.vbus_present)
- {
+ if (_dcd.vbus_present) {
dcd_connect(rhport);
}
+
+ return true;
}
void dcd_int_enable(uint8_t rhport)
@@ -895,6 +896,7 @@ 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);
void tusb_vbus_changed(bool present)
{
if (present && !_dcd.vbus_present)
diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c
index 01bbf62bf..7451f69a3 100644
--- a/src/portable/ehci/ehci.c
+++ b/src/portable/ehci/ehci.c
@@ -62,8 +62,7 @@
#define QHD_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX + CFG_TUH_HUB)
#define QTD_MAX QHD_MAX
-typedef struct
-{
+typedef struct {
ehci_link_t period_framelist[FRAMELIST_SIZE];
// TODO only implement 1 ms & 2 ms & 4 ms, 8 ms (framelist)
@@ -139,6 +138,12 @@ 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);
+TU_ATTR_ALWAYS_INLINE static inline bool qhd_is_periodic(ehci_qhd_t const *qhd) {
+ return qhd->int_smask != 0;
+}
+TU_ATTR_ALWAYS_INLINE static inline uint8_t qhd_ep_addr(ehci_qhd_t const *qhd) {
+ return tu_edpt_addr(qhd->ep_number, qhd->pid);
+}
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);
@@ -146,9 +151,10 @@ static void qtd_init (ehci_qtd_t* qtd, void const* 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);
+TU_ATTR_ALWAYS_INLINE static inline void list_insert (ehci_link_t *current, ehci_link_t *entry, uint8_t type);
+TU_ATTR_ALWAYS_INLINE static inline void list_remove(ehci_link_t* head, ehci_link_t* prev, ehci_qhd_t* qhd);
+static void list_remove_qhd_by_addr(ehci_link_t *list_head, uint8_t dev_addr, uint8_t ep_addr);
static void ehci_disable_schedule(ehci_registers_t* regs, bool is_period) {
// maybe have a timeout for status
@@ -175,15 +181,12 @@ static void ehci_enable_schedule(ehci_registers_t* regs, bool is_period) {
//--------------------------------------------------------------------+
// HCD API
//--------------------------------------------------------------------+
-
-uint32_t hcd_frame_number(uint8_t rhport)
-{
+uint32_t hcd_frame_number(uint8_t rhport) {
(void) rhport;
return (ehci_data.uframe_number + ehci_data.regs->frame_index) >> 3;
}
-void hcd_port_reset(uint8_t rhport)
-{
+void hcd_port_reset(uint8_t rhport) {
(void) rhport;
ehci_registers_t* regs = ehci_data.regs;
@@ -204,8 +207,7 @@ void hcd_port_reset(uint8_t rhport)
regs->portsc = portsc;
}
-void hcd_port_reset_end(uint8_t rhport)
-{
+void hcd_port_reset_end(uint8_t rhport) {
(void) rhport;
ehci_registers_t* regs = ehci_data.regs;
@@ -221,32 +223,29 @@ void hcd_port_reset_end(uint8_t rhport)
regs->portsc = portsc;
}
-bool hcd_port_connect_status(uint8_t rhport)
-{
+bool hcd_port_connect_status(uint8_t rhport) {
(void) rhport;
return ehci_data.regs->portsc_bm.current_connect_status;
}
-tusb_speed_t hcd_port_speed_get(uint8_t rhport)
-{
+tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
(void) rhport;
return (tusb_speed_t) ehci_data.regs->portsc_bm.nxp_port_speed; // NXP specific port speed
}
// Close all opened endpoint belong to this device
-void hcd_device_close(uint8_t rhport, uint8_t daddr)
-{
+void hcd_device_close(uint8_t rhport, uint8_t daddr) {
// skip dev0
if (daddr == 0) {
return;
}
- // Remove from async list
- list_remove_qhd_by_daddr((ehci_link_t *) list_get_async_head(rhport), daddr);
+ // Remove from async list all endpoints of this device
+ list_remove_qhd_by_addr((ehci_link_t *) list_get_async_head(rhport), daddr, TUSB_INDEX_INVALID_8);
- // 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_daddr((ehci_link_t *) &ehci_data.period_head_arr[i], daddr);
+ // Remove from all interval period list of this device
+ 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], daddr, TUSB_INDEX_INVALID_8);
}
// Async doorbell (EHCI 4.8.2 for operational details)
@@ -358,12 +357,10 @@ bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
}
#if 0
-static void ehci_stop(uint8_t rhport)
-{
+static void ehci_stop(uint8_t rhport) {
(void) rhport;
ehci_registers_t* regs = ehci_data.regs;
-
regs->command_bm.run_stop = 0;
// USB Spec: controller has to stop within 16 uframe = 2 frames
@@ -375,41 +372,46 @@ static void ehci_stop(uint8_t rhport)
// Endpoint API
//--------------------------------------------------------------------+
-bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
-{
- (void) rhport;
-
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) {
// TODO not support ISO yet
TU_ASSERT (ep_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
//------------- Prepare Queue Head -------------//
- ehci_qhd_t *p_qhd = (ep_desc->bEndpointAddress == 0) ? qhd_control(dev_addr) : qhd_find_free();
+ ehci_qhd_t *p_qhd;
+ if (ep_desc->bEndpointAddress == 0) {
+ p_qhd = qhd_control(dev_addr);
+ } else {
+ if (NULL != qhd_get_from_addr(dev_addr, ep_desc->bEndpointAddress)) {
+ return true; // already opened
+ }
+ p_qhd = qhd_find_free();
+ }
TU_ASSERT(p_qhd);
-
qhd_init(p_qhd, dev_addr, ep_desc);
- // control of dev0 is always present as async head
- if ( dev_addr == 0 ) return true;
+ // control of dev0 always exists as async head
+ if (dev_addr == 0) {
+ return true;
+ }
// Insert to list
ehci_link_t * list_head = NULL;
-
- switch (ep_desc->bmAttributes.xfer)
- {
+ switch (ep_desc->bmAttributes.xfer) {
case TUSB_XFER_CONTROL:
case TUSB_XFER_BULK:
- list_head = (ehci_link_t*) list_get_async_head(rhport);
- break;
+ list_head = (ehci_link_t *) list_get_async_head(rhport);
+ break;
case TUSB_XFER_INTERRUPT:
list_head = list_get_period_head(rhport, p_qhd->interval_ms);
- break;
+ break;
case TUSB_XFER_ISOCHRONOUS:
// TODO iso is not supported
- break;
+ break;
- default: break;
+ default:
+ break;
}
TU_ASSERT(list_head);
@@ -421,8 +423,23 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return true;
}
-bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
-{
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ ehci_qhd_t* qhd = qhd_get_from_addr(daddr, ep_addr);
+ TU_VERIFY(qhd != NULL);
+
+ ehci_link_t * list_head;
+ if (qhd_is_periodic(qhd)) {
+ // interrupt endpoint
+ list_head = list_get_period_head(rhport, qhd->interval_ms);;
+ } else {
+ list_head = (ehci_link_t *) list_get_async_head(rhport);
+ }
+
+ list_remove_qhd_by_addr(list_head, daddr, ep_addr);
+ return true;
+}
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) {
(void) rhport;
ehci_qhd_t* qhd = &ehci_data.control[dev_addr].qhd;
@@ -444,14 +461,14 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
return true;
}
-bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
-{
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) {
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
ehci_qhd_t* qhd = qhd_get_from_addr(dev_addr, ep_addr);
+ TU_VERIFY(qhd != NULL);
ehci_qtd_t* qtd;
if (epnum == 0) {
@@ -540,8 +557,7 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
// 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.
TU_ATTR_ALWAYS_INLINE static inline
-void async_advance_isr(uint8_t rhport)
-{
+void async_advance_isr(uint8_t rhport) {
(void) rhport;
ehci_qhd_t *qhd_pool = ehci_data.qhd_pool;
@@ -612,8 +628,7 @@ void qhd_xfer_complete_isr(ehci_qhd_t * qhd) {
}
TU_ATTR_ALWAYS_INLINE static inline
-void proccess_async_xfer_isr(ehci_qhd_t * const list_head)
-{
+void proccess_async_xfer_isr(ehci_qhd_t * const list_head) {
ehci_qhd_t *qhd = list_head;
do {
@@ -623,8 +638,7 @@ void proccess_async_xfer_isr(ehci_qhd_t * const list_head)
}
TU_ATTR_ALWAYS_INLINE static inline
-void process_period_xfer_isr(uint8_t rhport, uint32_t interval_ms)
-{
+void process_period_xfer_isr(uint8_t rhport, uint32_t interval_ms) {
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);
@@ -726,51 +740,55 @@ TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_next(ehci_link_t const *p_
return (ehci_link_t*) tu_align32(p_link->address);
}
-TU_ATTR_ALWAYS_INLINE 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);
+TU_ATTR_ALWAYS_INLINE static inline void list_insert(ehci_link_t *current, ehci_link_t *entry, uint8_t type) {
+ entry->address = current->address;
+ current->address = ((uint32_t) entry) | (type << 1);
}
-// 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;
+// Remove a queue head from the list.
+// Per EHCI 4.8.2 the removed qhd's next is linked to list head (which always reachable by Host Controller)
+// TODO support iTD/siTD
+TU_ATTR_ALWAYS_INLINE static inline void list_remove(ehci_link_t* head, ehci_link_t* prev, ehci_qhd_t* qhd) {
+ // TODO deactivate all TD, wait for QHD to inactive before removal
+ prev->address = qhd->next.address;
+
+ // link the removed qhd's next to list head
+ qhd->next.address = ((uint32_t) head) | (EHCI_QTYPE_QHD << 1);
+
+ if (qhd_is_periodic(qhd)) {
+ // 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));
+}
+
+// Remove queue head belong to this device address
+static void list_remove_qhd_by_addr(ehci_link_t *list_head, uint8_t dev_addr, uint8_t ep_addr) {
+ ehci_link_t *prev = list_head;
while (prev && !prev->terminate) {
- ehci_qhd_t* qhd = (ehci_qhd_t*) (uintptr_t) list_next(prev);
+ 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) {
+ 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 {
+ // ep_addr is 0xff means all endpoints of this device address
+ if (qhd->dev_addr == dev_addr &&
+ (ep_addr == TUSB_INDEX_INVALID_8 || qhd_ep_addr(qhd) == ep_addr)) {
+ list_remove(list_head, prev, qhd);
+ } else {
prev = list_next(prev);
}
}
}
-
//--------------------------------------------------------------------+
// Queue Header helper
//--------------------------------------------------------------------+
@@ -782,8 +800,10 @@ TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_control(uint8_t dev_addr) {
// 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];
+ for (uint32_t i = 0; i < QHD_MAX; i++) {
+ if (!ehci_data.qhd_pool[i].used) {
+ return &ehci_data.qhd_pool[i];
+ }
}
return NULL;
}
@@ -800,10 +820,9 @@ static ehci_qhd_t *qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr) {
}
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) ) {
+ for (uint32_t i = 0; i < QHD_MAX; i++) {
+ if ((qhd_pool[i].dev_addr == dev_addr) &&
+ ep_addr == qhd_ep_addr(&qhd_pool[i])) {
return &qhd_pool[i];
}
}
@@ -812,8 +831,7 @@ static ehci_qhd_t *qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr) {
}
// 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)
-{
+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) {
tu_memclr(p_qhd, sizeof(ehci_qhd_t));
@@ -830,39 +848,43 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
p_qhd->ep_number = tu_edpt_number(ep_desc->bEndpointAddress);
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->head_list_flag = (dev_addr == 0) ? 1 : 0; // addr0's endpoint is the static async list head
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;
- // Bulk/Control -> smask = cmask = 0
- // TODO Isochronous
- if (TUSB_XFER_INTERRUPT == xfer_type)
- {
- if (TUSB_SPEED_HIGH == p_qhd->ep_speed)
- {
- TU_ASSERT( interval <= 16, );
- if ( interval < 4) // sub millisecond interval
- {
- p_qhd->interval_ms = 0;
- p_qhd->int_smask = (interval == 1) ? TU_BIN8(11111111) :
- (interval == 2) ? TU_BIN8(10101010) : TU_BIN8(01000100);
- }else
- {
- p_qhd->interval_ms = (uint8_t) tu_min16( 1 << (interval-4), 255 );
- p_qhd->int_smask = TU_BIT(interval % 8);
+ switch (xfer_type) {
+ case TUSB_XFER_CONTROL:
+ case TUSB_XFER_BULK:
+ p_qhd->int_smask = p_qhd->fl_int_cmask = 0;
+ break;
+
+ case TUSB_XFER_INTERRUPT:
+ if (TUSB_SPEED_HIGH == p_qhd->ep_speed) {
+ TU_ASSERT(interval <= 16, );
+ if (interval < 4) {
+ // sub millisecond interval
+ p_qhd->interval_ms = 0;
+ p_qhd->int_smask = (interval == 1) ? TU_BIN8(11111111) :
+ (interval == 2) ? TU_BIN8(10101010): TU_BIN8(01000100);
+ } else {
+ p_qhd->interval_ms = (uint8_t) tu_min16(1 << (interval - 4), 255);
+ p_qhd->int_smask = TU_BIT(interval % 8);
+ }
+ } else {
+ TU_ASSERT(0 != interval, );
+ // Full/Low: 4.12.2.1 (EHCI) case 1 schedule start split at 1 us & complete split at 2,3,4 uframes
+ p_qhd->int_smask = 0x01;
+ p_qhd->fl_int_cmask = TU_BIN8(11100);
+ p_qhd->interval_ms = interval;
}
- }else
- {
- TU_ASSERT( 0 != interval, );
- // Full/Low: 4.12.2.1 (EHCI) case 1 schedule start split at 1 us & complete split at 2,3,4 uframes
- p_qhd->int_smask = 0x01;
- p_qhd->fl_int_cmask = TU_BIN8(11100);
- p_qhd->interval_ms = interval;
- }
- }else
- {
- p_qhd->int_smask = p_qhd->fl_int_cmask = 0;
+ break;
+
+ case TUSB_XFER_ISOCHRONOUS:
+ // TODO not support ISO yet
+ break;
+
+ default: break;
}
p_qhd->fl_hub_addr = devtree_info.hub_addr;
@@ -880,8 +902,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
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)
- {
+ 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
}
}
diff --git a/src/portable/ehci/ehci.h b/src/portable/ehci/ehci.h
index 457adc1d3..87659701b 100644
--- a/src/portable/ehci/ehci.h
+++ b/src/portable/ehci/ehci.h
@@ -49,15 +49,14 @@
// TODO merge OHCI with EHCI
enum {
- EHCI_MAX_ITD = 4,
+ EHCI_MAX_ITD = 4,
EHCI_MAX_SITD = 16
};
//--------------------------------------------------------------------+
// EHCI Data Structure
//--------------------------------------------------------------------+
-enum
-{
+enum {
EHCI_QTYPE_ITD = 0 ,
EHCI_QTYPE_QHD ,
EHCI_QTYPE_SITD ,
@@ -65,8 +64,7 @@ enum
};
/// EHCI PID
-enum
-{
+enum {
EHCI_PID_OUT = 0 ,
EHCI_PID_IN ,
EHCI_PID_SETUP
@@ -74,187 +72,182 @@ enum
/// Link pointer
typedef union {
- uint32_t address;
- struct {
- uint32_t terminate : 1;
- uint32_t type : 2;
- };
-}ehci_link_t;
+ uint32_t address;
+ struct {
+ uint32_t terminate : 1;
+ uint32_t type : 2;
+ };
+} 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
-{
- // Word 0: Next QTD Pointer
- ehci_link_t next;
-
- // Word 1: Alternate Next QTD Pointer (not used)
- union{
- ehci_link_t alternate;
- struct {
- uint32_t : 5;
- uint32_t used : 1;
- uint32_t : 10;
- uint32_t expected_bytes : 16;
- };
- };
+typedef struct {
+ // Word 0 Next QTD Pointer
+ ehci_link_t next;
- // 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 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
- volatile uint32_t halted : 1 ; ///< Serious error or STALL received
- volatile uint32_t active : 1 ; ///< Start transfer, clear by HC when complete
+ // Word 1 Alternate Next QTD Pointer (not used)
+ union {
+ ehci_link_t alternate;
+ struct {
+ uint32_t : 5;
+ uint32_t used : 1;
+ uint32_t : 10;
+ uint32_t expected_bytes : 16;
+ };
+ };
- uint32_t pid : 2 ; ///< 0: OUT, 1: IN, 2 Setup
- volatile uint32_t err_count : 2 ; ///< Error Counter of consecutive errors
- 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 Toggle bit
+ // 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 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
+ volatile uint32_t halted : 1; // Serious error or STALL received
+ volatile uint32_t active : 1; // Start transfer, clear by HC when complete
+ uint32_t pid : 2; // 0: OUT, 1: IN, 2 Setup
+ volatile uint32_t err_count : 2; // Error Counter of consecutive errors
+ 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 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
- uint32_t buffer[5];
+ // 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];
} ehci_qtd_t;
TU_VERIFY_STATIC( sizeof(ehci_qtd_t) == 32, "size is not correct" );
/// Queue Head
-typedef struct TU_ATTR_ALIGNED(32)
-{
- // Word 0: Next QHD
- ehci_link_t next;
+typedef struct TU_ATTR_ALIGNED(32) {
+ // Word 0 Next QHD
+ ehci_link_t next;
- // Word 1: Endpoint Characteristics
- uint32_t dev_addr : 7 ; ///< device address
- uint32_t fl_inactive_next_xact : 1 ; ///< Only valid for Periodic with Full/Slow speed
- uint32_t ep_number : 4 ; ///< EP number
- uint32_t ep_speed : 2 ; ///< 0: Full, 1: Low, 2: High
- uint32_t data_toggle_control : 1 ; ///< 0: use DT in qHD, 1: use DT in qTD
- uint32_t head_list_flag : 1 ; ///< Head of the queue
- uint32_t max_packet_size : 11 ; ///< Max packet size
- uint32_t fl_ctrl_ep_flag : 1 ; ///< 1 if is Full/Low speed control endpoint
- uint32_t nak_reload : 4 ; ///< Used by HC
+ // Word 1 Endpoint Characteristics
+ uint32_t dev_addr : 7; // device address
+ uint32_t fl_inactive_next_xact : 1; // Only valid for Periodic with Full/Slow speed
+ uint32_t ep_number : 4; // EP number
+ uint32_t ep_speed : 2; // Full (0), Low (1), High (2)
+ uint32_t data_toggle_control : 1; // 0 use DT in qHD, 1 use DT in qTD
+ uint32_t head_list_flag : 1; // Head of the queue
+ uint32_t max_packet_size : 11; // Max packet size
+ uint32_t fl_ctrl_ep_flag : 1; // 1 if is Full/Low speed control endpoint
+ uint32_t nak_reload : 4; // Used by HC
- // Word 2: Endpoint Capabilities
- uint32_t int_smask : 8 ; ///< Interrupt Schedule Mask
- uint32_t fl_int_cmask : 8 ; ///< Split Completion Mask for Full/Slow speed
- uint32_t fl_hub_addr : 7 ; ///< Hub Address for Full/Slow speed
- uint32_t fl_hub_port : 7 ; ///< Hub Port for Full/Slow speed
- uint32_t mult : 2 ; ///< Transaction per micro frame
+ // Word 2 Endpoint Capabilities
+ uint32_t int_smask : 8; // Interrupt Schedule Mask
+ uint32_t fl_int_cmask : 8; // Split Completion Mask for Full/Slow speed
+ uint32_t fl_hub_addr : 7; // Hub Address for Full/Slow speed
+ uint32_t fl_hub_port : 7; // Hub Port for Full/Slow speed
+ uint32_t mult : 2; // Transaction per micro frame
- // Word 3: Current qTD Pointer
- volatile uint32_t qtd_addr;
+ // Word 3 Current qTD Pointer
+ volatile uint32_t qtd_addr;
- // Word 4-11: Transfer Overlay
- volatile ehci_qtd_t qtd_overlay;
+ // Word 4-11 Transfer Overlay
+ volatile ehci_qtd_t qtd_overlay;
- //--------------------------------------------------------------------+
+ //--------------------------------------------------------------------+
/// Due to the fact QHD is 32 bytes aligned but occupies only 48 bytes
- /// thus there are 16 bytes padding free that we can make use of.
+ /// thus there are 16 bytes padding free that we can make use of.
//--------------------------------------------------------------------+
- 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 millisecond)
+ 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 millisecond)
- uint8_t TU_RESERVED[4];
+ uint8_t TU_RESERVED[4];
// 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_qtd_t *volatile attached_qtd;
} ehci_qhd_t;
-
TU_VERIFY_STATIC( sizeof(ehci_qhd_t) == 64, "size is not correct" );
/// Highspeed Isochronous Transfer Descriptor (section 3.3)
typedef struct TU_ATTR_ALIGNED(32) {
- // Word 0: Next Link Pointer
- ehci_link_t next;
+ // Word 0: Next Link Pointer
+ ehci_link_t next;
- // Word 1-8: iTD Transaction Status and Control List
- struct {
- // iTD Control
- volatile uint32_t offset : 12 ; ///< This field is a value that is an offset, expressed in bytes, from the beginning of a buffer.
- volatile uint32_t page_select : 3 ; ///< These bits are set by software to indicate which of the buffer page pointers the offset field in this slot should be concatenated to produce the starting memory address for this transaction. The valid range of values for this field is 0 to 6
- uint32_t int_on_complete : 1 ; ///< If this bit is set to a one, it specifies that when this transaction completes, the Host Controller should issue an interrupt at the next interrupt threshold
- volatile uint32_t length : 12 ; ///< For an OUT, this field is the number of data bytes the host controller will send during the transaction. The host controller is not required to update this field to reflect the actual number of bytes transferred during the transfer
- ///< For an IN, the initial value of the field is the number of bytes the host expects the endpoint to deliver. During the status update, the host controller writes back the number of bytes successfully received. The value in this register is the actual byte count
- // iTD Status
- volatile uint32_t error : 1 ; ///< Set to a one by the Host Controller during status update in the case where the host did not receive a valid response from the device (Timeout, CRC, Bad PID, etc.). This bit may only be set for isochronous IN transactions.
- volatile uint32_t babble_err : 1 ; ///< Set to a 1 by the Host Controller during status update when a babble is detected during the transaction
- volatile uint32_t buffer_err : 1 ; ///< Set to a 1 by the Host Controller during status update to indicate that the Host Controller is unable to keep up with the reception of incoming data (overrun) or is unable to supply data fast enough during transmission (underrun).
- volatile uint32_t active : 1 ; ///< Set to 1 by software to enable the execution of an isochronous transaction by the Host Controller
- } xact[8];
+ // Word 1-8: iTD Transaction Status and Control List
+ struct {
+ // iTD Control
+ volatile uint32_t offset : 12; // offset in bytes, from the beginning of a buffer.
+ volatile uint32_t page_select : 3; // buffer page pointers the offset field in this slot should be concatenated to produce the starting memory address for this transaction. The valid range of values for this field is 0 to 6
+ uint32_t int_on_complete : 1; // If this bit is set to a one, it specifies that when this transaction completes, the Host Controller should issue an interrupt at the next interrupt threshold
+ volatile uint32_t length : 12; // For an OUT, this field is the number of data bytes the host controller will send during the transaction. The host controller is not required to update this field to reflect the actual number of bytes transferred during the transfer
+ // For an IN, the initial value of the field is the number of bytes the host expects the endpoint to deliver. During the status update, the host controller writes back the number of bytes successfully received. The value in this register is the actual byte count
+ // iTD Status
+ volatile uint32_t error : 1; // Set to a one by the Host Controller during status update in the case where the host did not receive a valid response from the device (Timeout, CRC, Bad PID, etc.). This bit may only be set for isochronous IN transactions.
+ volatile uint32_t babble_err : 1; // Set to a 1 by the Host Controller during status update when a babble is detected during the transaction
+ volatile uint32_t buffer_err : 1; // Set to a 1 by the Host Controller during status update to indicate that the Host Controller is unable to keep up with the reception of incoming data (overrun) or is unable to supply data fast enough during transmission (underrun).
+ volatile uint32_t active : 1; // Set to 1 by software to enable the execution of an isochronous transaction by the Host Controller
+ } xact[8];
- // Word 9-15 Buffer Page Pointer List (Plus)
- uint32_t BufferPointer[7];
+ // Word 9-15 Buffer Page Pointer List (Plus)
+ uint32_t BufferPointer[7];
-// // FIXME: Store meta data into buffer pointer reserved for saving memory
-// /*---------- HCD Area ----------*/
-// uint32_t used;
-// uint32_t IhdIdx;
-// uint32_t reserved[6];
+ // FIXME: Store meta data into buffer pointer reserved for saving memory
+ //---------- HCD Area ----------
+ // uint32_t used;
+ // uint32_t IhdIdx;
+ // uint32_t reserved[6];
} ehci_itd_t;
-
TU_VERIFY_STATIC( sizeof(ehci_itd_t) == 64, "size is not correct" );
/// Split (Full-Speed) Isochronous Transfer Descriptor
-typedef struct TU_ATTR_ALIGNED(32)
-{
+typedef struct TU_ATTR_ALIGNED(32) {
// Word 0: Next Link Pointer
- ehci_link_t next;
+ ehci_link_t next;
- // Word 1: siTD Endpoint Characteristics
- uint32_t dev_addr : 7; ///< This field selects the specific device serving as the data source or sink.
- uint32_t : 1; ///< reserved
- uint32_t ep_number : 4; ///< This 4-bit field selects the particular endpoint number on the device serving as the data source or sink.
- uint32_t : 4; ///< This field is reserved and should be set to zero.
- uint32_t hub_addr : 7; ///< This field holds the device address of the transaction translators’ hub.
- uint32_t : 1; ///< reserved
- uint32_t port_number : 7; ///< This field is the port number of the recipient transaction translator.
- uint32_t direction : 1; ///< 0 = OUT; 1 = IN. This field encodes whether the full-speed transaction should be an IN or OUT.
+ // Word 1: siTD Endpoint Characteristics
+ uint32_t dev_addr : 7; ///< This field selects the specific device serving as the data source or sink.
+ uint32_t : 1; ///< reserved
+ uint32_t ep_number : 4; ///< This 4-bit field selects the particular endpoint number on the device serving as the data source or sink.
+ uint32_t : 4; ///< This field is reserved and should be set to zero.
+ uint32_t hub_addr : 7; ///< This field holds the device address of the transaction translators’ hub.
+ uint32_t : 1; ///< reserved
+ uint32_t port_number : 7; ///< This field is the port number of the recipient transaction translator.
+ uint32_t direction : 1; ///< 0 = OUT; 1 = IN. This field encodes whether the full-speed transaction should be an IN or OUT.
- // Word 2: Micro-frame Schedule Control
- uint8_t int_smask ; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute complete-split transactions
- uint8_t fl_int_cmask; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute start-split transactions.
- uint16_t reserved ; ///< reserved
+ // Word 2: Micro-frame Schedule Control
+ uint8_t int_smask ; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute complete-split transactions
+ uint8_t fl_int_cmask; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute start-split transactions.
+ uint16_t reserved ; ///< reserved
- // Word 3: siTD Transfer Status and Control
- // 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 ;
- volatile uint32_t xact_err : 1 ;
- volatile uint32_t babble_err : 1 ;
- volatile uint32_t buffer_err : 1 ;
- volatile uint32_t error : 1 ;
- volatile uint32_t active : 1 ;
- // Micro-frame Schedule Control
- volatile uint32_t cmask_progress : 8 ; ///< This field is used by the host controller to record which split-completes have been executed. See Section 4.12.3.3.2 for behavioral requirements.
- volatile uint32_t total_bytes : 10 ; ///< This field is initialized by software to the total number of bytes expected in this transfer. Maximum value is 1023
- volatile uint32_t : 4 ; ///< reserved
- volatile uint32_t page_select : 1 ; ///< Used to indicate which data page pointer should be concatenated with the CurrentOffsetfield to construct a data buffer pointer
- uint32_t int_on_complete : 1 ; ///< Do not interrupt when transaction is complete. 1 = Do interrupt when transaction is complete
- uint32_t : 0 ; // padding to the end of current storage unit
+ // Word 3: siTD Transfer Status and Control
+ // 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 ;
+ volatile uint32_t xact_err : 1 ;
+ volatile uint32_t babble_err : 1 ;
+ volatile uint32_t buffer_err : 1 ;
+ volatile uint32_t error : 1 ;
+ volatile uint32_t active : 1 ;
+ // Micro-frame Schedule Control
+ volatile uint32_t cmask_progress : 8 ; ///< This field is used by the host controller to record which split-completes have been executed. See Section 4.12.3.3.2 for behavioral requirements.
+ volatile uint32_t total_bytes : 10 ; ///< This field is initialized by software to the total number of bytes expected in this transfer. Maximum value is 1023
+ volatile uint32_t : 4 ; ///< reserved
+ volatile uint32_t page_select : 1 ; ///< Used to indicate which data page pointer should be concatenated with the CurrentOffsetfield to construct a data buffer pointer
+ uint32_t int_on_complete : 1 ; ///< Do not interrupt when transaction is complete. 1 = Do interrupt when transaction is complete
+ uint32_t : 0 ; // padding to the end of current storage unit
- /// Word 4-5: Buffer Pointer List
- uint32_t buffer[2]; // buffer[1] TP: Transaction Position - T-Count: Transaction Count
+ /// Word 4-5: Buffer Pointer List
+ uint32_t buffer[2]; // buffer[1] TP: Transaction Position - T-Count: Transaction Count
- /*---------- Word 6 ----------*/
- ehci_link_t back;
+ /*---------- Word 6 ----------*/
+ ehci_link_t back;
- /// SITD is 32-byte aligned but occupies only 28 --> 4 bytes for storing extra data
- uint8_t used;
- uint8_t ihd_idx;
- uint8_t reserved2[2];
+ /// SITD is 32-byte aligned but occupies only 28 --> 4 bytes for storing extra data
+ uint8_t used;
+ uint8_t ihd_idx;
+ uint8_t reserved2[2];
} ehci_sitd_t;
TU_VERIFY_STATIC( sizeof(ehci_sitd_t) == 32, "size is not correct" );
@@ -315,8 +308,7 @@ enum {
EHCI_PORTSC_MASK_OVER_CURRENT_CHANGE
};
-typedef volatile struct
-{
+typedef volatile struct {
union {
uint32_t command; // 0x00
diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c
index f912bef89..1b6aae026 100644
--- a/src/portable/espressif/esp32sx/dcd_esp32sx.c
+++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c
@@ -172,8 +172,8 @@ static void enum_done_processing(void)
/*------------------------------------------------------------------*/
/* Controller API
*------------------------------------------------------------------*/
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
ESP_LOGV(TAG, "DCD init - Start");
// A. Disconnect
@@ -207,9 +207,11 @@ void dcd_init(uint8_t rhport)
USB_USBRSTMSK_M |
USB_ENUMDONEMSK_M |
USB_RESETDETMSK_M |
+ USB_WKUPINT_M |
USB_DISCONNINTMSK_M; // host most only
dcd_connect(rhport);
+ return true;
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c
index a817c5d6e..4fce08dd9 100644
--- a/src/portable/mentor/musb/dcd_musb.c
+++ b/src/portable/mentor/musb/dcd_musb.c
@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2021 Koji KITAYAMA
+ * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc)
*
* 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,8 +27,10 @@
#include "tusb_option.h"
-#if CFG_TUD_ENABLED && \
- TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_MUSB)
+
+#define MUSB_DEBUG 2
+#define MUSB_REGS(rhport) ((musb_regs_t*) MUSB_BASES[rhport])
#if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED)
/* GCC warns that an address may be unaligned, even though
@@ -35,48 +38,30 @@
_Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");
#endif
+#include "musb_type.h"
#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
-
+// Following symbols must be defined by port header
+// - musb_dcd_int_enable/disable/clear/get_enable
+// - musb_dcd_int_handler_enter/exit
+#if defined(TUP_USBIP_MUSB_TI)
+ #include "musb_ti.h"
+#elif defined(TUP_USBIP_MUSB_ADI)
+ #include "musb_max32.h"
#else
- #error "Unsupported MCUs"
+ #error "Unsupported MCU"
#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;
+#define REQUEST_TYPE_INVALID (0xFFu)
typedef union {
- uint8_t u8;
- uint16_t u16;
- uint32_t u32;
+ volatile uint8_t u8;
+ volatile uint16_t u16;
+ volatile uint32_t u32;
} hw_fifo_t;
typedef struct TU_ATTR_PACKED
@@ -92,134 +77,97 @@ typedef struct
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] */
+ pipe_state_t pipe[2][TUP_DCD_ENDPOINT_MAX-1]; /* 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;
+//--------------------------------------------------------------------
+// HW FIFO Helper
+// Note: Index register is already set by caller
+//--------------------------------------------------------------------
-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;
-}
+#if MUSB_CFG_DYNAMIC_FIFO
-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;
+// musb is configured to use dynamic FIFO sizing.
+// FF Size is encodded: 1 << (fifo_size[3:0] + 3) = 8 << fifo_size[3:0]
+// FF Address is 8*ff_addr[12:0]
+// First 64 bytes are reserved for EP0
+static uint32_t alloced_fifo_bytes;
+
+// ffsize is log2(mps) - 3 (round up)
+TU_ATTR_ALWAYS_INLINE static inline uint8_t hwfifo_byte2size(uint16_t nbytes) {
+ uint8_t ffsize = 28 - tu_min8(28, __builtin_clz(nbytes));
+ if ((8u << ffsize) < nbytes) {
+ ++ffsize;
}
+ return ffsize;
}
-static inline unsigned free_block_size(free_block_t const *blk)
-{
- return blk->end - blk->beg;
+TU_ATTR_ALWAYS_INLINE static inline void hwfifo_reset(musb_regs_t* musb, unsigned epnum, unsigned is_rx) {
+ (void) epnum;
+ musb->fifo_size[is_rx] = 0;
+ musb->fifo_addr[is_rx] = 0;
}
-#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;
+TU_ATTR_ALWAYS_INLINE static inline bool hwfifo_config(musb_regs_t* musb, unsigned epnum, unsigned is_rx, unsigned mps,
+ bool double_packet) {
+ (void) epnum;
+ uint8_t ffsize = hwfifo_byte2size(mps);
+ mps = 8 << ffsize; // round up to the next power of 2
+
+ if (double_packet) {
+ ffsize |= MUSB_FIFOSZ_DOUBLE_PACKET;
+ mps <<= 1;
}
+
+ TU_ASSERT(alloced_fifo_bytes + mps <= MUSB_CFG_DYNAMIC_FIFO_SIZE);
+ musb->fifo_addr[is_rx] = alloced_fifo_bytes / 8;
+ musb->fifo_size[is_rx] = ffsize;
+
+ alloced_fifo_bytes += mps;
+ return true;
}
+
#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;
+TU_ATTR_ALWAYS_INLINE static inline void hwfifo_reset(musb_regs_t* musb, unsigned epnum, unsigned is_rx) {
+ (void) musb; (void) epnum; (void) is_rx;
+ // nothing to do for static FIFO
+}
- /* 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);
+TU_ATTR_ALWAYS_INLINE static inline bool hwfifo_config(musb_regs_t* musb, unsigned epnum, unsigned is_rx, unsigned mps,
+ bool double_packet) {
+ (void) epnum; (void) mps;
+ if (!double_packet) {
+ #if defined(TUP_USBIP_MUSB_ADI)
+ musb->indexed_csr.maxp_csr[is_rx].csrh |= MUSB_CSRH_DISABLE_DOUBLE_PACKET(is_rx);
+ #else
+ if (is_rx) {
+ musb->rx_doulbe_packet_disable |= 1u << epnum;
+ } else {
+ musb->tx_double_packet_disable |= 1u << epnum;
}
+ #endif
}
- 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;
+ return true;
}
-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;
+#endif
+
+// Flush FIFO and clear data toggle
+TU_ATTR_ALWAYS_INLINE static inline void hwfifo_flush(musb_regs_t* musb, unsigned epnum, unsigned is_rx, bool clear_dtog) {
+ (void) epnum;
+ const uint8_t csrl_dtog = clear_dtog ? MUSB_CSRL_CLEAR_DATA_TOGGLE(is_rx) : 0;
+ musb_ep_maxp_csr_t* maxp_csr = &musb->indexed_csr.maxp_csr[is_rx];
+ // may need to flush twice for double packet
+ for (unsigned i=0; i<2; i++) {
+ if (maxp_csr->csrl & MUSB_CSRL_PACKET_READY(is_rx)) {
+ maxp_csr->csrl = MUSB_CSRL_FLUSH_FIFO(is_rx) | csrl_dtog;
+ }
+ }
}
static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
@@ -284,11 +232,14 @@ static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigne
ops[dir].tu_fifo_advance(f, total_len - rem);
}
-static void process_setup_packet(uint8_t rhport)
-{
+static void process_setup_packet(uint8_t rhport) {
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+
+ // Read setup packet
uint32_t *p = (void*)&_dcd.setup_packet;
- p[0] = USB0->FIFO0_WORD;
- p[1] = USB0->FIFO0_WORD;
+ volatile uint32_t *fifo_ptr = &musb_regs->fifo[0];
+ p[0] = *fifo_ptr;
+ p[1] = *fifo_ptr;
_dcd.pipe0.buf = NULL;
_dcd.pipe0.length = 0;
@@ -299,12 +250,16 @@ static void process_setup_packet(uint8_t rhport)
_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;
+ if (len && dir_in) {
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, 0);
+ ep_csr->csr0l = MUSB_CSRL0_RXRDYC;
+ }
}
-static bool handle_xfer_in(uint_fast8_t ep_addr)
+static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr)
{
- unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ unsigned epnum = tu_edpt_number(ep_addr);
+ unsigned epnum_minus1 = epnum - 1;
pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
const unsigned rem = pipe->remaining;
@@ -313,44 +268,49 @@ static bool handle_xfer_in(uint_fast8_t ep_addr)
return true;
}
- volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1);
- const unsigned mps = regs->TXMAXP;
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum);
+ const unsigned mps = ep_csr->tx_maxp;
const unsigned len = TU_MIN(mps, rem);
void *buf = pipe->buf;
+ volatile void *fifo_ptr = &musb_regs->fifo[epnum];
// 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);
+ pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_IN);
} else {
- pipe_write_packet(buf, &USB0->FIFO1_WORD + epnum_minus1, len);
+ pipe_write_packet(buf, fifo_ptr, 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);
+ ep_csr->tx_csrl = MUSB_TXCSRL1_TXRDY;
+ // TU_LOG1(" TXCSRL%d = %x %d\r\n", epnum, ep_csr->tx_csrl, rem - len);
return false;
}
-static bool handle_xfer_out(uint_fast8_t ep_addr)
+static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr)
{
- unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ unsigned epnum = tu_edpt_number(ep_addr);
+ unsigned epnum_minus1 = epnum - 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);
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum);
+ // TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, ep_csr->rx_csrl);
- TU_ASSERT(regs->RXCSRL & USB_RXCSRL1_RXRDY);
+ TU_ASSERT(ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY);
- const unsigned mps = regs->RXMAXP;
+ const unsigned mps = ep_csr->rx_maxp;
const unsigned rem = pipe->remaining;
- const unsigned vld = regs->RXCOUNT;
+ const unsigned vld = ep_csr->rx_count;
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
void *buf = pipe->buf;
+ volatile void *fifo_ptr = &musb_regs->fifo[epnum];
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);
+ pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_OUT);
} else {
- pipe_read_packet(buf, &USB0->FIFO1_WORD + epnum_minus1, len);
+ pipe_read_packet(buf, fifo_ptr, len);
pipe->buf = buf + len;
}
pipe->remaining = rem - len;
@@ -359,15 +319,14 @@ static bool handle_xfer_out(uint_fast8_t ep_addr)
pipe->buf = NULL;
return NULL != buf;
}
- regs->RXCSRL = 0; /* Clear RXRDY bit */
+ ep_csr->rx_csrl = 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 epnum = tu_edpt_number(ep_addr);
+ unsigned epnum_minus1 = epnum - 1;
unsigned dir_in = tu_edpt_dir(ep_addr);
pipe_state_t *pipe = &_dcd.pipe[dir_in][epnum_minus1];
@@ -376,10 +335,11 @@ static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16
pipe->remaining = total_bytes;
if (dir_in) {
- handle_xfer_in(ep_addr);
+ handle_xfer_in(rhport, ep_addr);
} else {
- volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1);
- if (regs->RXCSRL & USB_RXCSRL1_RXRDY) regs->RXCSRL = 0;
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum);
+ if (ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY) ep_csr->rx_csrl = 0;
}
return true;
}
@@ -388,7 +348,8 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
{
(void)rhport;
TU_ASSERT(total_bytes <= 64); /* Current implementation supports for only up to 64 bytes. */
-
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, 0);
const unsigned req = _dcd.setup_packet.bmRequestType;
TU_ASSERT(req != REQUEST_TYPE_INVALID || total_bytes == 0);
@@ -399,7 +360,7 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
* 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);
+ // TU_LOG1(" STATUS OUT ep_csr->csr0l = %x\r\n", ep_csr->csr0l);
_dcd.status_out = 0;
if (req == REQUEST_TYPE_INVALID) {
dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false);
@@ -415,8 +376,9 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
TU_ASSERT(total_bytes <= _dcd.remaining_ctrl);
const unsigned rem = _dcd.remaining_ctrl;
const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes);
+ volatile void *fifo_ptr = &musb_regs->fifo[0];
if (dir_in) {
- pipe_write_packet(buffer, &USB0->FIFO0_WORD, len);
+ pipe_write_packet(buffer, fifo_ptr, len);
_dcd.pipe0.buf = buffer + len;
_dcd.pipe0.length = len;
@@ -427,45 +389,48 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
_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;
+ ep_csr->csr0l = MUSB_CSRL0_TXRDY | MUSB_CSRL0_DATAEND;
} else {
- USB0->CSRL0 = USB_CSRL0_TXRDY; /* Flush TX FIFO to return ACK. */
+ ep_csr->csr0l = MUSB_CSRL0_TXRDY; /* Flush TX FIFO to return ACK. */
}
- // TU_LOG1(" IN USB0->CSRL0 = %x\r\n", USB0->CSRL0);
+ // TU_LOG1(" IN ep_csr->csr0l = %x\r\n", ep_csr->csr0l);
} else {
- // TU_LOG1(" OUT USB0->CSRL0 = %x\r\n", USB0->CSRL0);
+ // TU_LOG1(" OUT ep_csr->csr0l = %x\r\n", ep_csr->csr0l);
_dcd.pipe0.buf = buffer;
_dcd.pipe0.length = len;
_dcd.pipe0.remaining = len;
- USB0->CSRL0 = USB_CSRL0_RXRDYC; /* Clear RX FIFO to return ACK. */
+ ep_csr->csr0l = MUSB_CSRL0_RXRDYC; /* Clear RX FIFO to return ACK. */
}
} else if (dir_in) {
- // TU_LOG1(" STATUS IN USB0->CSRL0 = %x\r\n", USB0->CSRL0);
+ // TU_LOG1(" STATUS IN ep_csr->csr0l = %x\r\n", ep_csr->csr0l);
_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;
+ ep_csr->csr0l = MUSB_CSRL0_RXRDYC | MUSB_CSRL0_DATAEND;
}
return true;
}
static void process_ep0(uint8_t rhport)
{
- uint_fast8_t csrl = USB0->CSRL0;
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, 0);
+ uint_fast8_t csrl = ep_csr->csr0l;
- // TU_LOG1(" EP0 USB0->CSRL0 = %x\r\n", csrl);
+ // TU_LOG1(" EP0 ep_csr->csr0l = %x\r\n", csrl);
+ // 21.1.5: endpoint 0 service routine as peripheral
- if (csrl & USB_CSRL0_STALLED) {
+ if (csrl & MUSB_CSRL0_STALLED) {
/* Returned STALL packet to HOST. */
- USB0->CSRL0 = 0; /* Clear STALL */
+ ep_csr->csr0l = 0; /* Clear STALL */
return;
}
unsigned req = _dcd.setup_packet.bmRequestType;
- if (csrl & USB_CSRL0_SETEND) {
+ if (csrl & MUSB_CSRL0_SETEND) {
TU_LOG1(" ABORT by the next packets\r\n");
- USB0->CSRL0 = USB_CSRL0_SETENDC;
+ ep_csr->csr0l = MUSB_CSRL0_SETENDC;
if (req != REQUEST_TYPE_INVALID && _dcd.pipe0.buf) {
/* DATA stage was aborted by receiving STATUS or SETUP packet. */
_dcd.pipe0.buf = NULL;
@@ -476,23 +441,24 @@ static void process_ep0(uint8_t rhport)
XFER_RESULT_SUCCESS, true);
}
req = REQUEST_TYPE_INVALID;
- if (!(csrl & USB_CSRL0_RXRDY)) return; /* Received SETUP packet */
+ if (!(csrl & MUSB_CSRL0_RXRDY)) return; /* Received SETUP packet */
}
- if (csrl & USB_CSRL0_RXRDY) {
+ if (csrl & MUSB_CSRL0_RXRDY) {
/* Received SETUP or DATA OUT packet */
if (req == REQUEST_TYPE_INVALID) {
/* SETUP */
- TU_ASSERT(sizeof(tusb_control_request_t) == USB0->COUNT0,);
+ TU_ASSERT(sizeof(tusb_control_request_t) == ep_csr->count0,);
process_setup_packet(rhport);
return;
}
if (_dcd.pipe0.buf) {
/* DATA OUT */
- const unsigned vld = USB0->COUNT0;
+ const unsigned vld = ep_csr->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);
+ volatile void *fifo_ptr = &musb_regs->fifo[0];
+ pipe_read_packet(_dcd.pipe0.buf, fifo_ptr, len);
_dcd.pipe0.remaining = rem - len;
_dcd.remaining_ctrl -= len;
@@ -512,7 +478,7 @@ static void process_ep0(uint8_t rhport)
/* 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;
+ musb_regs->faddr = (uint8_t)_dcd.setup_packet.wValue;
}
_dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
dcd_event_xfer_complete(rhport,
@@ -534,118 +500,149 @@ static void process_ep0(uint8_t rhport)
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;
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned epn_minus1 = epn - 1;
- volatile hw_endpoint_t *regs = edpt_regs(epn_minus1);
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epn);
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);
+ // TU_LOG1(" TX CSRL%d = %x\r\n", epn, ep_csr->tx_csrl);
+ if (ep_csr->tx_csrl & MUSB_TXCSRL1_STALLED) {
+ ep_csr->tx_csrl &= ~(MUSB_TXCSRL1_STALLED | MUSB_TXCSRL1_UNDRN);
return;
}
- completed = handle_xfer_in(ep_addr);
+ completed = handle_xfer_in(rhport, 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);
+ // TU_LOG1(" RX CSRL%d = %x\r\n", epn, ep_csr->rx_csrl);
+ if (ep_csr->rx_csrl & MUSB_RXCSRL1_STALLED) {
+ ep_csr->rx_csrl &= ~(MUSB_RXCSRL1_STALLED | MUSB_RXCSRL1_OVER);
return;
}
- completed = handle_xfer_out(ep_addr);
+ completed = handle_xfer_out(rhport, ep_addr);
}
if (completed) {
- pipe_state_t *pipe = &_dcd.pipe[dir_in][tu_edpt_number(ep_addr) - 1];
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][epn_minus1];
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. */
+// Upon BUS RESET is detected, hardware havs already done:
+// faddr = 0, index = 0, flushes all ep fifos, clears all ep csr, enabled all ep interrupts
+static void process_bus_reset(uint8_t rhport) {
+ musb_regs_t* musb = MUSB_REGS(rhport);
+
+#if MUSB_CFG_DYNAMIC_FIFO
+ alloced_fifo_bytes = CFG_TUD_ENDPOINT0_SIZE;
+#endif
+
+ /* 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;
+ musb->intr_txen = 1; /* Enable only EP0 */
+ musb->intr_rxen = 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;
+ musb->index = i;
+ hwfifo_reset(musb, i, 0);
+ hwfifo_reset(musb, i, 1);
}
- dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+ dcd_event_bus_reset(rhport, (musb->power & MUSB_POWER_HSMODE) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL, true);
}
/*------------------------------------------------------------------
* Device API
*------------------------------------------------------------------*/
-void dcd_init(uint8_t rhport)
-{
- (void)rhport;
- USB0->IE |= USB_IE_SUSPND;
- NVIC_ClearPendingIRQ(USB0_IRQn);
+#if CFG_TUSB_DEBUG >= MUSB_DEBUG
+void print_musb_info(musb_regs_t* musb_regs) {
+ // print version, epinfo, raminfo, config_data0, fifo_size
+ TU_LOG1("musb version = %u.%u\r\n", musb_regs->hwvers_bit.major, musb_regs->hwvers_bit.minor);
+ TU_LOG1("Number of endpoints: %u TX, %u RX\r\n", musb_regs->epinfo_bit.tx_ep_num, musb_regs->epinfo_bit.rx_ep_num);
+ TU_LOG1("RAM Info: %u DMA Channel, %u RAM address width\r\n", musb_regs->raminfo_bit.dma_channel, musb_regs->raminfo_bit.ram_bits);
+
+ musb_regs->index = 0;
+ TU_LOG1("config_data0 = 0x%x\r\n", musb_regs->indexed_csr.config_data0);
+#if MUSB_CFG_DYNAMIC_FIFO
+ TU_LOG1("Dynamic FIFO configuration\r\n");
+#else
+ for (uint8_t i=1; i <= musb_regs->epinfo_bit.tx_ep_num; i++) {
+ musb_regs->index = i;
+ TU_LOG1("FIFO %u Size: TX %u RX %u\r\n", i, musb_regs->indexed_csr.fifo_size_bit.tx, musb_regs->indexed_csr.fifo_size_bit.rx);
+ }
+#endif
+}
+#endif
+
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+
+#if CFG_TUSB_DEBUG >= MUSB_DEBUG
+ print_musb_info(musb_regs);
+#endif
+
+ musb_regs->intr_usben |= MUSB_IE_SUSPND;
+ musb_dcd_int_clear(rhport);
+ musb_dcd_phy_init(rhport);
dcd_connect(rhport);
+ return true;
}
-void dcd_int_enable(uint8_t rhport)
-{
- (void)rhport;
- NVIC_EnableIRQ(USB0_IRQn);
+void dcd_int_enable(uint8_t rhport) {
+ musb_dcd_int_enable(rhport);
}
-void dcd_int_disable(uint8_t rhport)
-{
- (void)rhport;
- NVIC_DisableIRQ(USB0_IRQn);
+void dcd_int_disable(uint8_t rhport) {
+ musb_dcd_int_disable(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;
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, 0);
+
_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;
+ ep_csr->csr0l = MUSB_CSRL0_RXRDYC | MUSB_CSRL0_DATAEND;
}
// Wake up host
-void dcd_remote_wakeup(uint8_t rhport)
-{
- (void)rhport;
- USB0->POWER |= USB_POWER_RESUME;
+void dcd_remote_wakeup(uint8_t rhport) {
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ musb_regs->power |= MUSB_POWER_RESUME;
unsigned cnt = SystemCoreClock / 1000;
while (cnt--) __NOP();
- USB0->POWER &= ~USB_POWER_RESUME;
+ musb_regs->power &= ~MUSB_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;
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ musb_regs->power |= TUD_OPT_HIGH_SPEED ? MUSB_POWER_HSENAB : 0;
+ musb_regs->power |= MUSB_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;
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ musb_regs->power &= ~MUSB_POWER_SOFTCONN;
}
void dcd_sof_enable(uint8_t rhport, bool en)
@@ -659,129 +656,119 @@ void dcd_sof_enable(uint8_t rhport, bool en)
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
+// static void edpt_setup(musb_regs_t* musb, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_size){
+// const unsigned epn = tu_edpt_number(ep_addr);
+// const unsigned dir_in = tu_edpt_dir(ep_addr);
+// }
// Configure endpoint's registers according to descriptor
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
-{
- (void) rhport;
-
+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_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);
+ musb_regs_t* musb = MUSB_REGS(rhport);
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn);
+ const uint8_t is_rx = 1 - dir_in;
+ musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[is_rx];
+
+ maxp_csr->maxp = mps;
+ maxp_csr->csrh = 0;
+#if MUSB_CFG_SHARED_FIFO
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);
+ maxp_csr->csrh |= MUSB_CSRH_TX_MODE;
}
+#endif
- /* 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);
+ hwfifo_flush(musb, epn, is_rx, true);
- 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;
- }
+ TU_ASSERT(hwfifo_config(musb, epn, is_rx, mps, false));
+ musb->intren_ep[is_rx] |= TU_BIT(epn);
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;
+bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ musb_regs_t* musb = MUSB_REGS(rhport);
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn);
+ const uint8_t is_rx = 1 - dir_in;
+ ep_csr->maxp_csr[is_rx].csrh = 0;
+ return hwfifo_config(musb, epn, is_rx, largest_packet_size, true);
+}
- 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;
+bool dcd_edpt_iso_activate(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_in = tu_edpt_dir(ep_addr);
+ const unsigned mps = tu_edpt_packet_size(ep_desc);
- USB0->EPIDX = i;
- USB0->TXFIFOSZ = 0;
- USB0->TXFIFOADD = 0;
- USB0->RXFIFOSZ = 0;
- USB0->RXFIFOADD = 0;
+ unsigned const ie = musb_dcd_get_int_enable(rhport);
+ musb_dcd_int_disable(rhport);
+
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+
+ musb_regs_t* musb = MUSB_REGS(rhport);
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn);
+ const uint8_t is_rx = 1 - dir_in;
+ musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[is_rx];
+
+ maxp_csr->maxp = mps;
+ maxp_csr->csrh |= MUSB_CSRH_ISO;
+#if MUSB_CFG_SHARED_FIFO
+ if (dir_in) {
+ maxp_csr->csrh |= MUSB_CSRH_TX_MODE;
}
- if (ie) NVIC_EnableIRQ(USB0_IRQn);
+#endif
+
+ hwfifo_flush(musb, epn, is_rx, true);
+
+#if MUSB_CFG_DYNAMIC_FIFO
+ // fifo space is already allocated, keep the address and just change packet size
+ musb->fifo_size[is_rx] = hwfifo_byte2size(mps) | MUSB_FIFOSZ_DOUBLE_PACKET;
+#endif
+
+ musb->intren_ep[is_rx] |= TU_BIT(epn);
+
+ if (ie) musb_dcd_int_enable(rhport);
+
+ return true;
}
-void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+void dcd_edpt_close_all(uint8_t rhport)
{
- (void)rhport;
- unsigned const epn = tu_edpt_number(ep_addr);
- unsigned const dir_in = tu_edpt_dir(ep_addr);
+ musb_regs_t* musb = MUSB_REGS(rhport);
+ unsigned const ie = musb_dcd_get_int_enable(rhport);
+ musb_dcd_int_disable(rhport);
- 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;
+ musb->intr_txen = 1; /* Enable only EP0 */
+ musb->intr_rxen = 0;
+ for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb, i);
+ for (unsigned d = 0; d < 2; d++) {
+ musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[d];
+ hwfifo_flush(musb, i, d, true);
+ hwfifo_reset(musb, i, d);
+ maxp_csr->maxp = 0;
+ maxp_csr->csrh = 0;
+ }
+ }
- 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;
+#if MUSB_CFG_DYNAMIC_FIFO
+ alloced_fifo_bytes = CFG_TUD_ENDPOINT0_SIZE;
+#endif
- USB0->EPIDX = epn;
- USB0->RXFIFOSZ = 0;
- USB0->RXFIFOADD = 0;
- }
- if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ if (ie) musb_dcd_int_enable(rhport);
}
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
@@ -791,18 +778,22 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
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);
+ unsigned const ie = musb_dcd_get_int_enable(rhport);
+ musb_dcd_int_disable(rhport);
+
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
+ } else {
ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes);
- if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ }
+
+ if (ie) musb_dcd_int_enable(rhport);
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
+// 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;
@@ -810,99 +801,104 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
// 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);
+ unsigned const ie = musb_dcd_get_int_enable(rhport);
+ musb_dcd_int_disable(rhport);
_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);
+ if (ie) musb_dcd_int_enable(rhport);
return ret;
}
// Stall endpoint
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
-{
- (void)rhport;
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
+ unsigned const ie = musb_dcd_get_int_enable(rhport);
+ musb_dcd_int_disable(rhport);
+
unsigned const epn = tu_edpt_number(ep_addr);
- unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
- NVIC_DisableIRQ(USB0_IRQn);
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epn);
+
if (0 == epn) {
if (!ep_addr) { /* Ignore EP80 */
_dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
_dcd.pipe0.buf = NULL;
- USB0->CSRL0 = USB_CSRL0_STALL;
+ ep_csr->csr0l = MUSB_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;
- }
+ const uint8_t is_rx = 1 - tu_edpt_dir(ep_addr);
+ ep_csr->maxp_csr[is_rx].csrl = MUSB_CSRL_SEND_STALL(is_rx);
}
- if (ie) NVIC_EnableIRQ(USB0_IRQn);
+
+ if (ie) musb_dcd_int_enable(rhport);
}
// 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 ie = musb_dcd_get_int_enable(rhport);
+ musb_dcd_int_disable(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);
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epn);
+ const uint8_t is_rx = 1 - tu_edpt_dir(ep_addr);
+
+ ep_csr->maxp_csr[is_rx].csrl = MUSB_CSRL_CLEAR_DATA_TOGGLE(is_rx);
+
+ if (ie) musb_dcd_int_enable(rhport);
}
/*-------------------------------------------------------------------
* ISR
*-------------------------------------------------------------------*/
-void dcd_int_handler(uint8_t rhport)
-{
- uint_fast8_t is, txis, rxis;
+void dcd_int_handler(uint8_t rhport) {
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+ const uint8_t saved_index = musb_regs->index; // save endpoint index
+
+ //Part specific ISR setup/entry
+ musb_dcd_int_handler_enter(rhport);
- is = USB0->IS; /* read and clear interrupt status */
- txis = USB0->TXIS; /* read and clear interrupt status */
- rxis = USB0->RXIS; /* read and clear interrupt status */
+ uint_fast8_t intr_usb = musb_regs->intr_usb; // a read will clear this interrupt status
+ uint_fast8_t intr_tx = musb_regs->intr_tx; // a read will clear this interrupt status
+ uint_fast8_t intr_rx = musb_regs->intr_rx; // a read will clear this 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) {
+ intr_usb &= musb_regs->intr_usben; /* Clear disabled interrupts */
+ if (intr_usb & MUSB_IS_DISCON) {
}
- if (is & USB_IS_SOF) {
+ if (intr_usb & MUSB_IS_SOF) {
dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
}
- if (is & USB_IS_RESET) {
+ if (intr_usb & MUSB_IS_RESET) {
process_bus_reset(rhport);
}
- if (is & USB_IS_RESUME) {
+ if (intr_usb & MUSB_IS_RESUME) {
dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
}
- if (is & USB_IS_SUSPEND) {
+ if (intr_usb & MUSB_IS_SUSPEND) {
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
}
- txis &= USB0->TXIE; /* Clear disabled interrupts */
- if (txis & USB_TXIE_EP0) {
+ intr_tx &= musb_regs->intr_txen; /* Clear disabled interrupts */
+ if (intr_tx & TU_BIT(0)) {
process_ep0(rhport);
- txis &= ~TU_BIT(0);
+ intr_tx &= ~TU_BIT(0);
}
- while (txis) {
- unsigned const num = __builtin_ctz(txis);
+ while (intr_tx) {
+ unsigned const num = __builtin_ctz(intr_tx);
process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_IN));
- txis &= ~TU_BIT(num);
+ intr_tx &= ~TU_BIT(num);
}
- rxis &= USB0->RXIE; /* Clear disabled interrupts */
- while (rxis) {
- unsigned const num = __builtin_ctz(rxis);
+
+ intr_rx &= musb_regs->intr_rxen; /* Clear disabled interrupts */
+ while (intr_rx) {
+ unsigned const num = __builtin_ctz(intr_rx);
process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_OUT));
- rxis &= ~TU_BIT(num);
+ intr_rx &= ~TU_BIT(num);
}
+
+ musb_regs->index = saved_index; // restore endpoint index
}
#endif
diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c
index 5312c2812..811043d74 100644
--- a/src/portable/mentor/musb/hcd_musb.c
+++ b/src/portable/mentor/musb/hcd_musb.c
@@ -37,16 +37,10 @@ _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");
#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
+#include "musb_type.h"
+#if TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+ #include "musb_ti.h"
#else
#error "Unsupported MCUs"
#endif
@@ -562,9 +556,9 @@ static void process_pipe_rx(uint8_t rhport, uint_fast8_t pipenum)
* Host API
*------------------------------------------------------------------*/
-bool hcd_init(uint8_t rhport)
-{
- (void)rhport;
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rhport;
+ (void) rh_init;
NVIC_ClearPendingIRQ(USB0_IRQn);
_hcd.bmRequestType = REQUEST_TYPE_INVALID;
@@ -810,6 +804,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
{
(void)rhport;
diff --git a/src/portable/mentor/musb/musb_max32.h b/src/portable/mentor/musb/musb_max32.h
new file mode 100644
index 000000000..35849b5f8
--- /dev/null
+++ b/src/portable/mentor/musb/musb_max32.h
@@ -0,0 +1,150 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc)
+ *
+ * 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_MAX32_H_
+#define TUSB_MUSB_MAX32_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mxc_device.h"
+#include "usbhs_regs.h"
+
+#define MUSB_CFG_SHARED_FIFO 1 // shared FIFO for TX and RX endpoints
+#define MUSB_CFG_DYNAMIC_FIFO 0 // dynamic EP FIFO sizing
+
+const uintptr_t MUSB_BASES[] = { MXC_BASE_USBHS };
+
+#if CFG_TUD_ENABLED
+#define USBHS_M31_CLOCK_RECOVERY
+
+// Mapping of IRQ numbers to port. Currently just 1.
+static const IRQn_Type musb_irqs[] = {
+ USB_IRQn
+};
+
+TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_enable(uint8_t rhport) {
+ NVIC_EnableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_disable(uint8_t rhport) {
+ NVIC_DisableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline unsigned musb_dcd_get_int_enable(uint8_t rhport) {
+ #ifdef NVIC_GetEnableIRQ // only defined in CMSIS 5
+ return NVIC_GetEnableIRQ(musb_irqs[rhport]);
+ #else
+ uint32_t IRQn = (uint32_t) musb_irqs[rhport];
+ return ((NVIC->ISER[IRQn >> 5UL] & (1UL << (IRQn & 0x1FUL))) != 0UL) ? 1UL : 0UL;
+ #endif
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_clear(uint8_t rhport) {
+ NVIC_ClearPendingIRQ(musb_irqs[rhport]);
+}
+
+static inline void musb_dcd_int_handler_enter(uint8_t rhport) {
+ mxc_usbhs_regs_t* hs_phy = MXC_USBHS;
+ uint32_t mxm_int, mxm_int_en, mxm_is;
+
+ //Handle PHY specific events
+ mxm_int = hs_phy->mxm_int;
+ mxm_int_en = hs_phy->mxm_int_en;
+ mxm_is = mxm_int & mxm_int_en;
+ hs_phy->mxm_int = mxm_is;
+
+ if (mxm_is & MXC_F_USBHS_MXM_INT_NOVBUS) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+ }
+}
+
+static inline void musb_dcd_phy_init(uint8_t rhport) {
+ (void) rhport;
+ mxc_usbhs_regs_t* hs_phy = MXC_USBHS;
+
+ // Interrupt for VBUS disconnect
+ hs_phy->mxm_int_en |= MXC_F_USBHS_MXM_INT_EN_NOVBUS;
+
+ musb_dcd_int_clear(rhport);
+
+ // Unsuspend the MAC
+ hs_phy->mxm_suspend = 0;
+
+ // Configure PHY
+ hs_phy->m31_phy_xcfgi_31_0 = (0x1 << 3) | (0x1 << 11);
+ hs_phy->m31_phy_xcfgi_63_32 = 0;
+ hs_phy->m31_phy_xcfgi_95_64 = 0x1 << (72 - 64);
+ hs_phy->m31_phy_xcfgi_127_96 = 0;
+
+ #ifdef USBHS_M31_CLOCK_RECOVERY
+ hs_phy->m31_phy_noncry_rstb = 1;
+ hs_phy->m31_phy_noncry_en = 1;
+ hs_phy->m31_phy_outclksel = 0;
+ hs_phy->m31_phy_coreclkin = 0;
+ hs_phy->m31_phy_xtlsel = 2; /* Select 25 MHz clock */
+ #else
+ hs_phy->m31_phy_noncry_rstb = 0;
+ hs_phy->m31_phy_noncry_en = 0;
+ hs_phy->m31_phy_outclksel = 1;
+ hs_phy->m31_phy_coreclkin = 1;
+ hs_phy->m31_phy_xtlsel = 3; /* Select 30 MHz clock */
+ #endif
+ hs_phy->m31_phy_pll_en = 1;
+ hs_phy->m31_phy_oscouten = 1;
+
+ /* Reset PHY */
+ hs_phy->m31_phy_ponrst = 0;
+ hs_phy->m31_phy_ponrst = 1;
+}
+
+// static inline void musb_dcd_setup_fifo(uint8_t rhport, unsigned epnum, unsigned dir_in, unsigned mps) {
+// (void) mps;
+//
+// //Most likely the caller has already grabbed the right register block. But
+// //as a precaution save and restore the register bank anyways
+// unsigned saved_index = musb_periph_inst[rhport]->index;
+//
+// musb_periph_inst[rhport]->index = epnum;
+//
+// //Disable double buffering
+// if (dir_in) {
+// musb_periph_inst[rhport]->incsru |= (MXC_F_USBHS_INCSRU_DPKTBUFDIS | MXC_F_USBHS_INCSRU_MODE);
+// } else {
+// musb_periph_inst[rhport]->outcsru |= (MXC_F_USBHS_OUTCSRU_DPKTBUFDIS);
+// }
+//
+// musb_periph_inst[rhport]->index = saved_index;
+// }
+
+#endif // CFG_TUD_ENABLED
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // TUSB_MUSB_MAX32_H_
diff --git a/src/portable/mentor/musb/musb_msp432e.h b/src/portable/mentor/musb/musb_msp432e.h
deleted file mode 100644
index fce21de88..000000000
--- a/src/portable/mentor/musb/musb_msp432e.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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_ti.h
index 65a1751b0..d17e836ee 100644
--- a/src/portable/mentor/musb/musb_tm4c.h
+++ b/src/portable/mentor/musb/musb_ti.h
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
- * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_MUSB_TM4C_H_
-#define _TUSB_MUSB_TM4C_H_
+#ifndef TUSB_MUSB_TI_H_
+#define TUSB_MUSB_TI_H_
#ifdef __cplusplus
extern "C" {
@@ -33,13 +33,59 @@
#if CFG_TUSB_MCU == OPT_MCU_TM4C123
#include "TM4C123.h"
+ #define FIFO0_WORD FIFO0
+ #define FIFO1_WORD FIFO1
//#elif CFG_TUSB_MCU == OPT_MCU_TM4C129
+#elif CFG_TUSB_MCU == OPT_MCU_MSP432E4
+ #include "msp.h"
#else
#error "Unsupported MCUs"
#endif
+#define MUSB_CFG_SHARED_FIFO 0
+#define MUSB_CFG_DYNAMIC_FIFO 1
+#define MUSB_CFG_DYNAMIC_FIFO_SIZE 4096
+
+const uintptr_t MUSB_BASES[] = { USB0_BASE };
+
+// Header supports both device and host modes. Only include what's necessary
+#if CFG_TUD_ENABLED
+
+// Mapping of IRQ numbers to port. Currently just 1.
+static const IRQn_Type musb_irqs[] = {
+ USB0_IRQn
+};
+
+static inline void musb_dcd_phy_init(uint8_t rhport){
+ (void)rhport;
+ //Nothing to do for this part
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_enable(uint8_t rhport) {
+ NVIC_EnableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_disable(uint8_t rhport) {
+ NVIC_DisableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline unsigned musb_dcd_get_int_enable(uint8_t rhport) {
+ return NVIC_GetEnableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_clear(uint8_t rhport) {
+ NVIC_ClearPendingIRQ(musb_irqs[rhport]);
+}
+
+static inline void musb_dcd_int_handler_enter(uint8_t rhport) {
+ (void)rhport;
+ //Nothing to do for this part
+}
+
+#endif // CFG_TUD_ENABLED
+
#ifdef __cplusplus
}
#endif
-#endif
+#endif // TUSB_MUSB_TI_H_
diff --git a/src/portable/mentor/musb/musb_type.h b/src/portable/mentor/musb/musb_type.h
index 8f83305a5..4e448c0ed 100644
--- a/src/portable/mentor/musb/musb_type.h
+++ b/src/portable/mentor/musb/musb_type.h
@@ -1,3 +1,29 @@
+/*
+ * 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.
+ */
+
/******************************************************************************
*
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
@@ -32,2590 +58,696 @@
*
*******************************************************************************/
-#ifndef _TUSB_MUSB_TYPE_H_
-#define _TUSB_MUSB_TYPE_H_
+#ifndef TUSB_MUSB_TYPE_H_
+#define TUSB_MUSB_TYPE_H_
+
+#include "stdint.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
+#ifndef __IO
+ #define __IO volatile
+#endif
-//*****************************************************************************
-//
-// 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
+#ifndef __I
+ #define __I volatile const
+#endif
-//*****************************************************************************
-//
-// 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
+#ifndef __O
+ #define __O volatile
+#endif
-//*****************************************************************************
-//
-// 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
+#ifndef __R
+ #define __R volatile const
+#endif
-//*****************************************************************************
-//
-// 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
+typedef struct TU_ATTR_PACKED {
+ __IO uint16_t maxp; // 0x00, 0x04: MAXP
+ __IO uint8_t csrl; // 0x02, 0x06: CSRL
+ __IO uint8_t csrh; // 0x03, 0x07: CSRH
+}musb_ep_maxp_csr_t;
-//*****************************************************************************
-//
-// 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
+// 0: TX (device IN, host OUT)
+// 1: RX (device OUT, host IN)
+typedef struct TU_ATTR_PACKED {
+ union {
+ struct {
+ __IO uint16_t tx_maxp; // 0x00: TXMAXP
+ union {
+ __IO uint8_t csr0l; // 0x02: CSR0
+ __IO uint8_t tx_csrl; // 0x02: TX CSRL
+ };
+ union {
+ __IO uint8_t csr0h; // 0x03: CSR0H
+ __IO uint8_t tx_csrh; // 0x03: TX CSRH
+ };
-//*****************************************************************************
-//
-// 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
+ __IO uint16_t rx_maxp; // 0x04: RX MAXP
+ __IO uint8_t rx_csrl; // 0x06: RX CSRL
+ __IO uint8_t rx_csrh; // 0x07: RX CSRH
+ };
-//*****************************************************************************
-//
-// 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
+ musb_ep_maxp_csr_t maxp_csr[2];
+ };
-//*****************************************************************************
-//
-// 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
+ union {
+ __IO uint16_t count0; // 0x08: COUNT0
+ __IO uint16_t rx_count; // 0x08: RX COUNT
+ };
+ union {
+ __IO uint8_t type0; // 0x0A: TYPE0 (host only)
+ __IO uint8_t tx_type; // 0x0A: TX TYPE
+ };
+ __IO uint8_t tx_interval; // 0x0B: TX INTERVAL
+ __IO uint8_t rx_type; // 0x0C: RX TYPE
+ __IO uint8_t rx_interval; // 0x0D: RX INTERVAL
+ __IO uint8_t reserved_0x0e; // 0x0E: Reserved
+ union {
+ __IO uint8_t config_data0; // 0x0F: CONFIG DATA
+ struct {
+ __IO uint8_t utmi_data_width : 1; // [0] UTMI Data Width
+ __IO uint8_t softconn_en : 1; // [1] Soft Connect Enable
+ __IO uint8_t dynamic_fifo : 1; // [2] Dynamic FIFO Sizing
+ __IO uint8_t hb_tx_en : 1; // [3] High Bandwidth TX ISO Enable
+ __IO uint8_t hb_rx_en : 1; // [4] High Bandwidth RX ISO Enable
+ __IO uint8_t big_endian : 1; // [5] Big Endian
+ __IO uint8_t mp_tx_en : 1; // [6] Auto splitting BULK TX Enable
+ __IO uint8_t mp_rx_en : 1; // [7] Auto amalgamation BULK RX Enable
+ } config_data0_bit;
-//*****************************************************************************
-//
-// 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
+ __IO uint8_t fifo_size; // 0x0F: FIFO_SIZE
+ struct {
+ __IO uint8_t tx : 4; // [3:0] TX FIFO Size
+ __IO uint8_t rx : 4; // [7:4] RX FIFO Size
+ }fifo_size_bit;
+ };
+} musb_ep_csr_t;
-//*****************************************************************************
-//
-// 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
+TU_VERIFY_STATIC(sizeof(musb_ep_csr_t) == 16, "size is not correct");
-//*****************************************************************************
-//
-// 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
+typedef struct TU_ATTR_PACKED {
+ //------------- Common -------------//
+ __IO uint8_t faddr; // 0x00: FADDR
+ union {
+ __IO uint8_t power; // 0x01: POWER
+ struct {
+ __IO uint8_t suspend_mode_en : 1; // [0] SUSPEND Mode Enable
+ __IO uint8_t suspend_mode : 1; // [1] SUSPEND Mode
+ __IO uint8_t resume_mode : 1; // [2] RESUME
+ __IO uint8_t reset : 1; // [3] RESET
+ __IO uint8_t highspeed_mode : 1; // [4] High Speed Mode
+ __IO uint8_t highspeed_en : 1; // [5] High Speed Enable
+ __IO uint8_t soft_conn : 1; // [6] Soft Connect/Disconnect
+ __IO uint8_t iso_update : 1; // [7] Isochronous Update
+ } power_bit;
+ };
-//*****************************************************************************
-//
-// 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
+ union {
+ struct {
+ __IO uint16_t intr_tx; // 0x02: INTR_TX
+ __IO uint16_t intr_rx; // 0x04: INTR_RX
+ };
-//*****************************************************************************
-//
-// 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
+ __IO uint16_t intr_ep[2]; // 0x02-0x05: INTR_EP0-1
+ };
-//*****************************************************************************
-//
-// 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
+ union {
+ struct {
+ __IO uint16_t intr_txen; // 0x06: INTR_TXEN
+ __IO uint16_t intr_rxen; // 0x08: INTR_RXEN
+ };
-//*****************************************************************************
-//
-// 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
+ __IO uint16_t intren_ep[2]; // 0x06-0x09: INTREN_EP0-1
+ };
-//*****************************************************************************
-//
-// 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
+ __IO uint8_t intr_usb; // 0x0A: INTRUSB
+ __IO uint8_t intr_usben; // 0x0B: INTRUSBEN
-//*****************************************************************************
-//
-// 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
+ __IO uint16_t frame; // 0x0C: FRAME
+ __IO uint8_t index; // 0x0E: INDEX
+ __IO uint8_t testmode; // 0x0F: TESTMODE
-//*****************************************************************************
-//
-// 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
+ //------------- Endpoint CSR (indexed) -------------//
+ musb_ep_csr_t indexed_csr; // 0x10-0x1F: Indexed CSR 0-15
-//*****************************************************************************
-//
-// 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
+ //------------- FIFOs -------------//
+ __IO uint32_t fifo[16]; // 0x20-0x5C: FIFO 0-15
-//*****************************************************************************
-//
-// 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
+ // Common (2)
+ __IO uint8_t devctl; // 0x60: DEVCTL
+ __IO uint8_t misc; // 0x61: MISC
-//*****************************************************************************
-//
-// 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
+ //------------- Dynammic FIFO (indexed) -------------//
+ union {
+ struct {
+ __IO uint8_t txfifo_sz; // 0x62: TXFIFO_SZ
+ __IO uint8_t rxfifo_sz; // 0x63: RXFIFO_SZ
+ };
+ __IO uint8_t fifo_size[2];
+ };
-//*****************************************************************************
-//
-// 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
+ union {
+ struct {
+ __IO uint16_t txfifo_addr; // 0x64: TXFIFO_ADDR
+ __IO uint16_t rxfifo_addr; // 0x66: RXFIFO_ADDR
+ };
+ __IO uint16_t fifo_addr[2];
+ };
-//*****************************************************************************
-//
-// 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
+ //------------- Additional Control and Configuration -------------//
+ union {
+ __O uint32_t vcontrol; // 0x68: PHY VCONTROL
+ __IO uint32_t vstatus; // 0x68: PHY VSTATUS
+ };
+ union {
+ __IO uint16_t hwvers; // 0x6C: HWVERS
+ struct {
+ __IO uint16_t minor : 10; // [9:0] Minor
+ __IO uint16_t major : 5; // [14:10] Major
+ __IO uint16_t rc : 1; // [15] Release Candidate
+ } hwvers_bit;
+ };
+ __R uint16_t rsv_0x6e_0x77[5]; // 0x6E-0x77: Reserved
-//*****************************************************************************
-//
-// 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
+ //------------- Additional Configuration -------------//
+ union {
+ __IO uint8_t epinfo; // 0x78: EPINFO
+ struct {
+ __IO uint8_t tx_ep_num : 4; // [3:0] TX Endpoints
+ __IO uint8_t rx_ep_num : 4; // [7:4] RX Endpoints
+ } epinfo_bit;
+ };
+ union {
+ __IO uint8_t raminfo; // 0x79: RAMINFO
+ struct {
+ __IO uint8_t ram_bits : 4; // [3:0] RAM Address Bus Width
+ __IO uint8_t dma_channel : 4; // [7:4] DMA Channels
+ }raminfo_bit;
+ };
+ union {
+ __IO uint8_t link_info; // 0x7A: LINK_INFO
+ __IO uint8_t adi_softreset; // 0x7A: AnalogDevice SOFTRESET
+ };
+ __IO uint8_t vplen; // 0x7B: VPLEN
+ __IO uint8_t hs_eof1; // 0x7C: HS_EOF1
+ __IO uint8_t fs_eof1; // 0x7D: FS_EOF1
+ __IO uint8_t ls_eof1; // 0x7E: LS_EOF1
+ __IO uint8_t soft_rst; // 0x7F: SOFT_RST
-//*****************************************************************************
-//
-// 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
+ //------------- Target Endpoints (multipoint option) -------------//
+ __IO uint16_t ctuch; // 0x80: CTUCH
+ __IO uint16_t cthsrtn; // 0x82: CTHSRTN
+ __R uint32_t rsv_0x84_0xff[31]; // 0x84-0xFF: Reserved
-//*****************************************************************************
-//
-// 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
+ //------------- Non-Indexed Endpoint CSRs -------------//
+ // TI tm4c can access this directly, but should use indexed_csr for portability
+ musb_ep_csr_t abs_csr[16]; // 0x100-0x1FF: EP0-15 CSR
-//*****************************************************************************
-//
-// 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
+ //------------- DMA -------------//
+ __IO uint8_t dma_intr; // 0x200: DMA_INTR
+ __R uint8_t rsv_0x201_0x203[3]; // 0x201-0x203: Reserved
+ struct {
+ __IO uint16_t cntl; // 0x204: DMA_CNTL
+ __IO uint16_t rsv_0x206; // 0x206: Reserved
+ __IO uint32_t addr; // 0x208: DMA_ADDR
+ __IO uint32_t count; // 0x20C: DMA_COUNT
+ __IO uint32_t rsv_0x210; // 0x210: Reserved
+ }dma[8];
+ __R uint32_t rsv_0x284_0x2FF[31]; // 0x284-0x2FF: Reserved
-//*****************************************************************************
-//
-// 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
+ //------------- Extended -------------//
+ __R uint32_t rsv_0x300; // 0x300: Reserved
+ struct {
+ __IO uint16_t count; // 0x304: REQ_PACKET_COUNT
+ __R uint16_t rsv_0x306; // 0x306: Reserved
+ }req_packet[15];
-//*****************************************************************************
-//
-// 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
+ __IO uint16_t rx_doulbe_packet_disable; // 0x340: RX_DOUBLE_PACKET_DISABLE
+ __IO uint16_t tx_double_packet_disable; // 0x342: TX_DOUBLE_PACKET_DISABLE
-//*****************************************************************************
-//
-// 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
+ __IO uint16_t chirp_timeout; // 0x344: CHIRP_TIMEOUT
+ __IO uint16_t hs_to_utm; // 0x346: HS_TO_UTM delay
+ __IO uint16_t hs_timeout_adder; // 0x348: HS_TIMEOUT_ADDER
-//*****************************************************************************
-//
-// 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
+ __R uint8_t rsv_34A_34f[6]; // 0x34A-0x34F: Reserved
+} musb_regs_t;
-//*****************************************************************************
-//
-// 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
+TU_VERIFY_STATIC(sizeof(musb_regs_t) == 0x350, "size is not correct");
-//*****************************************************************************
-//
-// 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
+//--------------------------------------------------------------------+
+// Helper
+//--------------------------------------------------------------------+
+TU_ATTR_ALWAYS_INLINE static inline musb_ep_csr_t* get_ep_csr(musb_regs_t* musb_regs, unsigned epnum) {
+ musb_regs->index = epnum;
+ return &musb_regs->indexed_csr;
+}
-//*****************************************************************************
-//
-// 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
+//--------------------------------------------------------------------+
+// Register Bit Field
+//--------------------------------------------------------------------+
-//*****************************************************************************
-//
-// 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
+// 0x01: Power
+#define MUSB_POWER_ISOUP 0x0080 // Isochronous Update
+#define MUSB_POWER_SOFTCONN 0x0040 // Soft Connect/Disconnect
+#define MUSB_POWER_HSENAB 0x0020 // High Speed Enable
+#define MUSB_POWER_HSMODE 0x0010 // High Speed Enable
+#define MUSB_POWER_RESET 0x0008 // RESET Signaling
+#define MUSB_POWER_RESUME 0x0004 // RESUME Signaling
+#define MUSB_POWER_SUSPEND 0x0002 // SUSPEND Mode
+#define MUSB_POWER_PWRDNPHY 0x0001 // Power Down PHY
-//*****************************************************************************
-//
-// 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
+// Interrupt TX/RX Status and Enable: each bit is for an endpoint
-//*****************************************************************************
-//
-// 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
+// 0x6c: HWVERS
+#define MUSB_HWVERS_RC_SHIFT 15
+#define MUSB_HWVERS_RC_MASK 0x8000
+#define MUSB_HWVERS_MAJOR_SHIFT 10
+#define MUSB_HWVERS_MAJOR_MASK 0x7C00
+#define MUSB_HWVERS_MINOR_SHIFT 0
+#define MUSB_HWVERS_MINOR_MASK 0x03FF
-//*****************************************************************************
-//
-// 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
+// 0x12, 0x16: TX/RX CSRL
+#define MUSB_CSRL_PACKET_READY(_rx) (1u << 0)
+#define MUSB_CSRL_FLUSH_FIFO(_rx) (1u << ((_rx) ? 4 : 3))
+#define MUSB_CSRL_SEND_STALL(_rx) (1u << ((_rx) ? 5 : 4))
+#define MUSB_CSRL_STALLED(_rx) (1u << ((_rx) ? 6 : 5))
+#define MUSB_CSRL_CLEAR_DATA_TOGGLE(_rx) (1u << ((_rx) ? 7 : 6))
-//*****************************************************************************
-//
-// 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
+// 0x13, 0x17: TX/RX CSRH
+#define MUSB_CSRH_DISABLE_DOUBLE_PACKET(_rx) (1u << 1)
+#define MUSB_CSRH_TX_MODE (1u << 5) // 1 = TX, 0 = RX. only relevant for SHARED FIFO
+#define MUSB_CSRH_ISO (1u << 6)
-//*****************************************************************************
-//
-// 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
+// 0x62, 0x63: TXFIFO_SZ, RXFIFO_SZ
+#define MUSB_FIFOSZ_DOUBLE_PACKET (1u << 4)
-//*****************************************************************************
-//
-// 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.
+// The following are defines for the bit fields in the MUSB_O_IS 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
+#define MUSB_IS_VBUSERR 0x0080 // VBUS Error (OTG only)
+#define MUSB_IS_SESREQ 0x0040 // SESSION REQUEST (OTG only)
+#define MUSB_IS_DISCON 0x0020 // Session Disconnect (OTG only)
+#define MUSB_IS_CONN 0x0010 // Session Connect
+#define MUSB_IS_SOF 0x0008 // Start of Frame
+#define MUSB_IS_BABBLE 0x0004 // Babble Detected
+#define MUSB_IS_RESET 0x0004 // RESET Signaling Detected
+#define MUSB_IS_RESUME 0x0002 // RESUME Signaling Detected
+#define MUSB_IS_SUSPEND 0x0001 // SUSPEND Signaling Detected
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RXMAXP5 register.
+// The following are defines for the bit fields in the MUSB_O_IE register.
//
//*****************************************************************************
-#define USB_RXMAXP5_MAXLOAD_M 0x000007FF // Maximum Payload
-#define USB_RXMAXP5_MAXLOAD_S 0
+#define MUSB_IE_VBUSERR 0x0080 // Enable VBUS Error Interrupt (OTG only)
+#define MUSB_IE_SESREQ 0x0040 // Enable Session Request (OTG only)
+#define MUSB_IE_DISCON 0x0020 // Enable Disconnect Interrupt
+#define MUSB_IE_CONN 0x0010 // Enable Connect Interrupt
+#define MUSB_IE_SOF 0x0008 // Enable Start-of-Frame Interrupt
+#define MUSB_IE_BABBLE 0x0004 // Enable Babble Interrupt
+#define MUSB_IE_RESET 0x0004 // Enable RESET Interrupt
+#define MUSB_IE_RESUME 0x0002 // Enable RESUME Interrupt
+#define MUSB_IE_SUSPND 0x0001 // Enable SUSPEND Interrupt
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RXCSRL5 register.
+// The following are defines for the bit fields in the MUSB_O_FRAME 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
+#define MUSB_FRAME_M 0x07FF // Frame Number
+#define MUSB_FRAME_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RXCSRH5 register.
+// The following are defines for the bit fields in the MUSB_O_TEST 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
+#define MUSB_TEST_FORCEH 0x0080 // Force Host Mode
+#define MUSB_TEST_FIFOACC 0x0040 // FIFO Access
+#define MUSB_TEST_FORCEFS 0x0020 // Force Full-Speed Mode
+#define MUSB_TEST_FORCEHS 0x0010 // Force High-Speed Mode
+#define MUSB_TEST_TESTPKT 0x0008 // Test Packet Mode Enable
+#define MUSB_TEST_TESTK 0x0004 // Test_K Mode Enable
+#define MUSB_TEST_TESTJ 0x0002 // Test_J Mode Enable
+#define MUSB_TEST_TESTSE0NAK 0x0001 // Test_SE0_NAK Test Mode Enable
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RXCOUNT5 register.
+// The following are defines for the bit fields in the MUSB_O_DEVCTL register.
//
//*****************************************************************************
-#define USB_RXCOUNT5_COUNT_M 0x00001FFF // Receive Packet Count
-#define USB_RXCOUNT5_COUNT_S 0
+#define MUSB_DEVCTL_DEV 0x0080 // Device Mode (OTG only)
+#define MUSB_DEVCTL_FSDEV 0x0040 // Full-Speed Device Detected
+#define MUSB_DEVCTL_LSDEV 0x0020 // Low-Speed Device Detected
+#define MUSB_DEVCTL_VBUS_M 0x0018 // VBUS Level (OTG only)
+#define MUSB_DEVCTL_VBUS_NONE 0x0000 // Below SessionEnd
+#define MUSB_DEVCTL_VBUS_SEND 0x0008 // Above SessionEnd, below AValid
+#define MUSB_DEVCTL_VBUS_AVALID 0x0010 // Above AValid, below VBUSValid
+#define MUSB_DEVCTL_VBUS_VALID 0x0018 // Above VBUSValid
+#define MUSB_DEVCTL_HOST 0x0004 // Host Mode
+#define MUSB_DEVCTL_HOSTREQ 0x0002 // Host Request (OTG only)
+#define MUSB_DEVCTL_SESSION 0x0001 // Session Start/End (OTG only)
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_TXTYPE5 register.
+// The following are defines for the bit fields in the MUSB_O_CCONF 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
+#define MUSB_CCONF_TXEDMA 0x0002 // TX Early DMA Enable
+#define MUSB_CCONF_RXEDMA 0x0001 // TX Early DMA Enable
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_TXINTERVAL5
+// The following are defines for the bit fields in the MUSB_O_ULPIVBUSCTL
// 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
+#define MUSB_ULPIVBUSCTL_USEEXTVBUSIND 0x0002 // Use External VBUS Indicator
+#define MUSB_ULPIVBUSCTL_USEEXTVBUS 0x0001 // Use External VBUS
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RXINTERVAL5
+// The following are defines for the bit fields in the MUSB_O_ULPIREGDATA
// 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
-
+#define MUSB_ULPIREGDATA_REGDATA_M 0x00FF // Register Data
+#define MUSB_ULPIREGDATA_REGDATA_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
+// The following are defines for the bit fields in the MUSB_O_ULPIREGADDR
// 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
+#define MUSB_ULPIREGADDR_ADDR_M 0x00FF // Register Address
+#define MUSB_ULPIREGADDR_ADDR_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
+// The following are defines for the bit fields in the MUSB_O_ULPIREGCTL
// 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
+#define MUSB_ULPIREGCTL_RDWR 0x0004 // Read/Write Control
+#define MUSB_ULPIREGCTL_REGCMPLT 0x0002 // Register Access Complete
+#define MUSB_ULPIREGCTL_REGACC 0x0001 // Initiate Register Access
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_TXMAXP7 register.
+// The following are defines for the bit fields in the MUSB_O_EPINFO register.
//
//*****************************************************************************
-#define USB_TXMAXP7_MAXLOAD_M 0x000007FF // Maximum Payload
-#define USB_TXMAXP7_MAXLOAD_S 0
+#define MUSB_EPINFO_RXEP_M 0x00F0 // RX Endpoints
+#define MUSB_EPINFO_TXEP_M 0x000F // TX Endpoints
+#define MUSB_EPINFO_RXEP_S 4
+#define MUSB_EPINFO_TXEP_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_TXCSRL7 register.
+// The following are defines for the bit fields in the MUSB_O_RAMINFO 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
+#define MUSB_RAMINFO_DMACHAN_M 0x00F0 // DMA Channels
+#define MUSB_RAMINFO_RAMBITS_M 0x000F // RAM Address Bus Width
+#define MUSB_RAMINFO_DMACHAN_S 4
+#define MUSB_RAMINFO_RAMBITS_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_TXCSRH7 register.
+// The following are defines for the bit fields in the MUSB_O_CONTIM 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
+#define MUSB_CONTIM_WTCON_M 0x00F0 // Connect Wait
+#define MUSB_CONTIM_WTID_M 0x000F // Wait ID
+#define MUSB_CONTIM_WTCON_S 4
+#define MUSB_CONTIM_WTID_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RXMAXP7 register.
+// The following are defines for the bit fields in the MUSB_O_VPLEN register.
//
//*****************************************************************************
-#define USB_RXMAXP7_MAXLOAD_M 0x000007FF // Maximum Payload
-#define USB_RXMAXP7_MAXLOAD_S 0
+#define MUSB_VPLEN_VPLEN_M 0x00FF // VBUS Pulse Length
+#define MUSB_VPLEN_VPLEN_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RXCSRL7 register.
+// The following are defines for the bit fields in the MUSB_O_HSEOF 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
+#define MUSB_HSEOF_HSEOFG_M 0x00FF // HIgh-Speed End-of-Frame Gap
+#define MUSB_HSEOF_HSEOFG_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RXCSRH7 register.
+// The following are defines for the bit fields in the MUSB_O_FSEOF 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
+#define MUSB_FSEOF_FSEOFG_M 0x00FF // Full-Speed End-of-Frame Gap
+#define MUSB_FSEOF_FSEOFG_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RXCOUNT7 register.
+// The following are defines for the bit fields in the MUSB_O_LSEOF register.
//
//*****************************************************************************
-#define USB_RXCOUNT7_COUNT_M 0x00001FFF // Receive Packet Count
-#define USB_RXCOUNT7_COUNT_S 0
+#define MUSB_LSEOF_LSEOFG_M 0x00FF // Low-Speed End-of-Frame Gap
+#define MUSB_LSEOF_LSEOFG_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_TXTYPE7 register.
+// The following are defines for the bit fields in the MUSB_O_CSRL0 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
+#define MUSB_CSRL0_NAKTO 0x0080 // NAK Timeout
+#define MUSB_CSRL0_SETENDC 0x0080 // Setup End Clear
+#define MUSB_CSRL0_STATUS 0x0040 // STATUS Packet
+#define MUSB_CSRL0_RXRDYC 0x0040 // RXRDY Clear
+#define MUSB_CSRL0_REQPKT 0x0020 // Request Packet
+#define MUSB_CSRL0_STALL 0x0020 // Send Stall
+#define MUSB_CSRL0_SETEND 0x0010 // Setup End
+#define MUSB_CSRL0_ERROR 0x0010 // Error
+#define MUSB_CSRL0_DATAEND 0x0008 // Data End
+#define MUSB_CSRL0_SETUP 0x0008 // Setup Packet
+#define MUSB_CSRL0_STALLED 0x0004 // Endpoint Stalled
+#define MUSB_CSRL0_TXRDY 0x0002 // Transmit Packet Ready
+#define MUSB_CSRL0_RXRDY 0x0001 // Receive Packet Ready
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_TXINTERVAL7
-// register.
+// The following are defines for the bit fields in the MUSB_O_CSRH0 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
+#define MUSB_CSRH0_DISPING 0x0008 // PING Disable
+#define MUSB_CSRH0_DTWE 0x0004 // Data Toggle Write Enable
+#define MUSB_CSRH0_DT 0x0002 // Data Toggle
+#define MUSB_CSRH0_FLUSH 0x0001 // Flush FIFO
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RXTYPE7 register.
+// The following are defines for the bit fields in the MUSB_O_TYPE0 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
+#define MUSB_TYPE0_SPEED_M 0x00C0 // Operating Speed
+#define MUSB_TYPE0_SPEED_HIGH 0x0040 // High
+#define MUSB_TYPE0_SPEED_FULL 0x0080 // Full
+#define MUSB_TYPE0_SPEED_LOW 0x00C0 // Low
//*****************************************************************************
//
-// 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.
+// The following are defines for the bit fields in the MUSB_O_NAKLMT 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
+#define MUSB_NAKLMT_NAKLMT_M 0x001F // EP0 NAK Limit
+#define MUSB_NAKLMT_NAKLMT_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_DMAADDR3 register.
+// The following are defines for the bit fields in the MUSB_O_TXCSRL1 register.
//
//*****************************************************************************
-#define USB_DMAADDR3_ADDR_M 0xFFFFFFFC // DMA Address
-#define USB_DMAADDR3_ADDR_S 2
+#define MUSB_TXCSRL1_NAKTO 0x0080 // NAK Timeout
+#define MUSB_TXCSRL1_CLRDT 0x0040 // Clear Data Toggle
+#define MUSB_TXCSRL1_STALLED 0x0020 // Endpoint Stalled
+#define MUSB_TXCSRL1_STALL 0x0010 // Send STALL
+#define MUSB_TXCSRL1_SETUP 0x0010 // Setup Packet
+#define MUSB_TXCSRL1_FLUSH 0x0008 // Flush FIFO
+#define MUSB_TXCSRL1_ERROR 0x0004 // Error
+#define MUSB_TXCSRL1_UNDRN 0x0004 // Underrun
+#define MUSB_TXCSRL1_FIFONE 0x0002 // FIFO Not Empty
+#define MUSB_TXCSRL1_TXRDY 0x0001 // Transmit Packet Ready
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_DMACOUNT3
-// register.
+// The following are defines for the bit fields in the MUSB_O_TXCSRH1 register.
//
//*****************************************************************************
-#define USB_DMACOUNT3_COUNT_M 0xFFFFFFFC // DMA Count
-#define USB_DMACOUNT3_COUNT_S 2
+#define MUSB_TXCSRH1_AUTOSET 0x0080 // Auto Set
+#define MUSB_TXCSRH1_ISO 0x0040 // Isochronous Transfers
+#define MUSB_TXCSRH1_MODE 0x0020 // Mode
+#define MUSB_TXCSRH1_DMAEN 0x0010 // DMA Request Enable
+#define MUSB_TXCSRH1_FDT 0x0008 // Force Data Toggle
+#define MUSB_TXCSRH1_DMAMOD 0x0004 // DMA Request Mode
+#define MUSB_TXCSRH1_DTWE 0x0002 // Data Toggle Write Enable
+#define MUSB_TXCSRH1_DT 0x0001 // Data Toggle
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_DMACTL4 register.
+// The following are defines for the bit fields in the MUSB_O_RXCSRL1 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
+#define MUSB_RXCSRL1_CLRDT 0x0080 // Clear Data Toggle
+#define MUSB_RXCSRL1_STALLED 0x0040 // Endpoint Stalled
+#define MUSB_RXCSRL1_STALL 0x0020 // Send STALL
+#define MUSB_RXCSRL1_REQPKT 0x0020 // Request Packet
+#define MUSB_RXCSRL1_FLUSH 0x0010 // Flush FIFO
+#define MUSB_RXCSRL1_DATAERR 0x0008 // Data Error
+#define MUSB_RXCSRL1_NAKTO 0x0008 // NAK Timeout
+#define MUSB_RXCSRL1_OVER 0x0004 // Overrun
+#define MUSB_RXCSRL1_ERROR 0x0004 // Error
+#define MUSB_RXCSRL1_FULL 0x0002 // FIFO Full
+#define MUSB_RXCSRL1_RXRDY 0x0001 // Receive Packet Ready
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_DMAADDR4 register.
+// The following are defines for the bit fields in the MUSB_O_RXCSRH1 register.
//
//*****************************************************************************
-#define USB_DMAADDR4_ADDR_M 0xFFFFFFFC // DMA Address
-#define USB_DMAADDR4_ADDR_S 2
+#define MUSB_RXCSRH1_AUTOCL 0x0080 // Auto Clear
+#define MUSB_RXCSRH1_AUTORQ 0x0040 // Auto Request
+#define MUSB_RXCSRH1_ISO 0x0040 // Isochronous Transfers
+#define MUSB_RXCSRH1_DMAEN 0x0020 // DMA Request Enable
+#define MUSB_RXCSRH1_DISNYET 0x0010 // Disable NYET
+#define MUSB_RXCSRH1_PIDERR 0x0010 // PID Error
+#define MUSB_RXCSRH1_DMAMOD 0x0008 // DMA Request Mode
+#define MUSB_RXCSRH1_DTWE 0x0004 // Data Toggle Write Enable
+#define MUSB_RXCSRH1_DT 0x0002 // Data Toggle
+#define MUSB_RXCSRH1_INCOMPRX 0x0001 // Incomplete RX Transmission Status
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_DMACOUNT4
-// register.
+// The following are defines for the bit fields in the MUSB_O_TXTYPE1 register.
//
//*****************************************************************************
-#define USB_DMACOUNT4_COUNT_M 0xFFFFFFFC // DMA Count
-#define USB_DMACOUNT4_COUNT_S 2
+#define MUSB_TXTYPE1_SPEED_M 0x00C0 // Operating Speed
+#define MUSB_TXTYPE1_SPEED_DFLT 0x0000 // Default
+#define MUSB_TXTYPE1_SPEED_HIGH 0x0040 // High
+#define MUSB_TXTYPE1_SPEED_FULL 0x0080 // Full
+#define MUSB_TXTYPE1_SPEED_LOW 0x00C0 // Low
+#define MUSB_TXTYPE1_PROTO_M 0x0030 // Protocol
+#define MUSB_TXTYPE1_PROTO_CTRL 0x0000 // Control
+#define MUSB_TXTYPE1_PROTO_ISOC 0x0010 // Isochronous
+#define MUSB_TXTYPE1_PROTO_BULK 0x0020 // Bulk
+#define MUSB_TXTYPE1_PROTO_INT 0x0030 // Interrupt
+#define MUSB_TXTYPE1_TEP_M 0x000F // Target Endpoint Number
+#define MUSB_TXTYPE1_TEP_S 0
//*****************************************************************************
//
-// 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
+// The following are defines for the bit fields in the MUSB_O_TXINTERVAL1
// register.
//
//*****************************************************************************
-#define USB_DMACOUNT5_COUNT_M 0xFFFFFFFC // DMA Count
-#define USB_DMACOUNT5_COUNT_S 2
+#define MUSB_TXINTERVAL1_NAKLMT_M 0x00FF // NAK Limit
+#define MUSB_TXINTERVAL1_TXPOLL_M 0x00FF // TX Polling
+#define MUSB_TXINTERVAL1_TXPOLL_S 0
+#define MUSB_TXINTERVAL1_NAKLMT_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_DMACTL6 register.
+// The following are defines for the bit fields in the MUSB_O_RXTYPE1 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
+#define MUSB_RXTYPE1_SPEED_M 0x00C0 // Operating Speed
+#define MUSB_RXTYPE1_SPEED_DFLT 0x0000 // Default
+#define MUSB_RXTYPE1_SPEED_HIGH 0x0040 // High
+#define MUSB_RXTYPE1_SPEED_FULL 0x0080 // Full
+#define MUSB_RXTYPE1_SPEED_LOW 0x00C0 // Low
+#define MUSB_RXTYPE1_PROTO_M 0x0030 // Protocol
+#define MUSB_RXTYPE1_PROTO_CTRL 0x0000 // Control
+#define MUSB_RXTYPE1_PROTO_ISOC 0x0010 // Isochronous
+#define MUSB_RXTYPE1_PROTO_BULK 0x0020 // Bulk
+#define MUSB_RXTYPE1_PROTO_INT 0x0030 // Interrupt
+#define MUSB_RXTYPE1_TEP_M 0x000F // Target Endpoint Number
+#define MUSB_RXTYPE1_TEP_S 0
//*****************************************************************************
//
-// 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
+// The following are defines for the bit fields in the MUSB_O_RXINTERVAL1
// register.
//
//*****************************************************************************
-#define USB_DMACOUNT6_COUNT_M 0xFFFFFFFC // DMA Count
-#define USB_DMACOUNT6_COUNT_S 2
+#define MUSB_RXINTERVAL1_TXPOLL_M 0x00FF // RX Polling
+#define MUSB_RXINTERVAL1_NAKLMT_M 0x00FF // NAK Limit
+#define MUSB_RXINTERVAL1_TXPOLL_S 0
+#define MUSB_RXINTERVAL1_NAKLMT_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_DMACTL7 register.
+// The following are defines for the bit fields in the MUSB_O_DMACTL0 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
+#define MUSB_DMACTL0_BRSTM_M 0x0600 // Burst Mode
+#define MUSB_DMACTL0_BRSTM_ANY 0x0000 // Bursts of unspecified length
+#define MUSB_DMACTL0_BRSTM_INC4 0x0200 // INCR4 or unspecified length
+#define MUSB_DMACTL0_BRSTM_INC8 0x0400 // INCR8, INCR4 or unspecified
// length
-#define USB_DMACTL7_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or
+#define MUSB_DMACTL0_BRSTM_INC16 0x0600 // 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
+#define MUSB_DMACTL0_ERR 0x0100 // Bus Error Bit
+#define MUSB_DMACTL0_EP_M 0x00F0 // Endpoint number
+#define MUSB_DMACTL0_IE 0x0008 // DMA Interrupt Enable
+#define MUSB_DMACTL0_MODE 0x0004 // DMA Transfer Mode
+#define MUSB_DMACTL0_DIR 0x0002 // DMA Direction
+#define MUSB_DMACTL0_ENABLE 0x0001 // DMA Transfer Enable
+#define MUSB_DMACTL0_EP_S 4
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RQPKTCOUNT6
-// register.
+// The following are defines for the bit fields in the MUSB_O_DMAADDR0 register.
//
//*****************************************************************************
-#define USB_RQPKTCOUNT6_COUNT_M 0x0000FFFF // Block Transfer Packet Count
-#define USB_RQPKTCOUNT6_COUNT_S 0
+#define MUSB_DMAADDR0_ADDR_M 0xFFFFFFFC // DMA Address
+#define MUSB_DMAADDR0_ADDR_S 2
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RQPKTCOUNT7
+// The following are defines for the bit fields in the MUSB_O_DMACOUNT0
// register.
//
//*****************************************************************************
-#define USB_RQPKTCOUNT7_COUNT_M 0x0000FFFF // Block Transfer Packet Count
-#define USB_RQPKTCOUNT7_COUNT_S 0
+#define MUSB_DMACOUNT0_COUNT_M 0xFFFFFFFC // DMA Count
+#define MUSB_DMACOUNT0_COUNT_S 2
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_RXDPKTBUFDIS
-// register.
+// The following are defines for the bit fields in the MUSB_O_CTO 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
+#define MUSB_CTO_CCTV_M 0xFFFF // Configurable Chirp Timeout Value
+#define MUSB_CTO_CCTV_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_TXDPKTBUFDIS
-// register.
+// The following are defines for the bit fields in the MUSB_O_HHSRTN 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
+#define MUSB_HHSRTN_HHSRTN_M 0xFFFF // 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
+#define MUSB_HHSRTN_HHSRTN_S 0
//*****************************************************************************
//
-// The following are defines for the bit fields in the USB_O_CC register.
+// The following are defines for the bit fields in the MUSB_O_HSBT 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
+#define MUSB_HSBT_HSBT_M 0x000F // High Speed Timeout Adder
+#define MUSB_HSBT_HSBT_S 0
#ifdef __cplusplus
}
diff --git a/src/portable/microchip/pic/README.md b/src/portable/microchip/pic/README.md
new file mode 100644
index 000000000..7ba6a4a96
--- /dev/null
+++ b/src/portable/microchip/pic/README.md
@@ -0,0 +1,51 @@
+# Microchip PIC Chipidea FS Driver
+
+This driver adds support for Microchip PIC microcontrollers with full-speed Chipidea USB peripheral to the TinyUSB stack. It supports the following families:
+
+- PIC32MX (untested)
+- PIC32MM
+- PIC32MK (untested)
+- PIC24FJ
+- PIC24EP (untested)
+- dsPIC33EP (untested)
+
+Currently only the device mode is supported.
+
+
+## Important Notes
+
+### Handling of shared VBUS & GPIO pin
+
+Some PICs have the USB VBUS pin bonded with a GPIO pin in the chip package. This driver does **NOT** handle the potential conflict between the VBUS and GPIO functionalities.
+
+Developers must ensure that the GPIO pin is tristated when the VBUS pin is managed by the USB peripheral in order to prevent damaging the chip.
+
+This design choice allows developers the flexibility to use the GPIO functionality for controlling VBUS in device mode if desired.
+
+
+## TODO
+
+### Handle USB remote wakeup timing correctly
+
+The Chipidea FS IP doesn't handle the RESUME signal automatically and it must be managed in software. It needs to be asserted for exactly 10ms, and this is impossible to do without per-device support due to BSP differences. For now, a simple for-based loop is used.
+
+### 8-bit PIC support
+
+The 8-bit PICs also uses the Chipidea FS IP. Technically it's possible to support them as well.
+
+Possible difficulties:
+- Memory size constraints (1KB/8KB ballpark)
+- A third BDT layout (now we have two)
+- Different compiler-specific directives
+- Compiler bugs if you use SDCC
+
+
+## Author
+[ReimuNotMoe](https://github.com/ReimuNotMoe) at SudoMaker, Ltd.
+
+
+## Credits
+
+This driver is based on:
+- Microchip's USB driver (usb_device.c)
+- TinyUSB's NXP KHCI driver (dcd_khci.c)
diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c
index ccc27c3c9..b4a698199 100644
--- a/src/portable/microchip/pic/dcd_pic.c
+++ b/src/portable/microchip/pic/dcd_pic.c
@@ -1,8 +1,11 @@
/*
* The MIT License (MIT)
*
- * Copyright (c) 2020 Koji Kitayama
- * Copyright (c) 2022 Reimu NotMoe <[email protected]>
+ * Copyright (c) 2022-2024 SudoMaker, Ltd.
+ * Author: Mike Yang (Reimu NotMoe) <[email protected]>
+ *
+ * Based on usb_device.c - Copyright (c) 2015 Microchip Technology Inc.
+ * Based on dcd_khci.c - 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
@@ -313,12 +316,23 @@ 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, );
+
+ // Abandon any previous control transfers that might have been using EP0.
+ // Ordinarily, nothing actually needs abandoning, since the previous control
+ // transfer would have completed successfully prior to the host sending the
+ // next SETUP packet. However, in a timeout error case, or after an EP0
+ // STALL event, one or more UOWN bits might still be set. If so, we should
+ // clear the UOWN bits, so the EP0 IN/OUT endpoints are in a known inactive
+ // state, ready for re-arming by the `dcd_edpt_xfer' function that will be
+ // called next.
_dcd.bdt[0][0][out_odd].data = 0;
+ _dcd.bdt[0][0][out_odd].own = 0;
_dcd.bdt[0][0][out_odd ^ 1].data = 1;
_dcd.bdt[0][1][in_odd].data = 1;
+ _dcd.bdt[0][1][in_odd].own = 0;
_dcd.bdt[0][1][in_odd ^ 1].data = 0;
+ _dcd.bdt[0][1][in_odd ^ 1].own = 0;
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT),
_dcd.setup_packet, sizeof(_dcd.setup_packet));
}
@@ -470,18 +484,17 @@ static void process_bus_resume(uint8_t rhport)
/*------------------------------------------------------------------*/
/* Device API
*------------------------------------------------------------------*/
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
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
+ // The USBBUSY bit is present on PIC32s and we're required to check it
+ // prior to powering on the USB peripheral (see DS61126F page 27)
+ while (U1PWRCbits.USBBUSY);
U1PWRCSET = _U1PWRC_USBPWR_MASK;
#else
U1PWRCbits.USBPWR = 1;
@@ -502,6 +515,20 @@ void dcd_init(uint8_t rhport)
U1IE = _U1IE_URSTIE_MASK;
dcd_connect(rhport);
+ return true;
+}
+
+bool dcd_deinit(uint8_t rhport)
+{
+ U1CON = 0;
+ U1IE = 0;
+ U1OTGIE = 0;
+#if TU_PIC_INT_SIZE == 4
+ U1PWRCCLR = _U1PWRC_USUSPEND_MASK | _U1PWRC_USBPWR_MASK;
+#else
+ U1PWRC &= ~(_U1PWRC_USUSPEND_MASK | _U1PWRC_USBPWR_MASK);
+#endif
+ return true;
}
void dcd_int_enable(uint8_t rhport)
@@ -528,8 +555,25 @@ void dcd_remote_wakeup(uint8_t rhport)
#else
U1CONbits.RESUME = 1;
#endif
- unsigned cnt = 25000000 / 1000;
+
+ // FIXME: Assert RESUME signal correctly, requires device-specific handling
+ // For now we use a hardcoded cycle-based delay which attempts to delay 10ms
+ // at the most common CPU frequencies. On PIC32s we assume the loop body
+ // takes 3 cycles. On 16-bit PICs we assume the XC16 compiler is in use and
+ // use its `__delay_ms' function.
+
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ uint32_t cnt = 24000000 / 1000 / 3;
while (cnt--) asm volatile("nop");
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ uint32_t cnt = 40000000 / 1000 / 3;
+ while (cnt--) asm volatile("nop");
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ uint32_t cnt = 120000000 / 1000 / 3;
+ while (cnt--) asm volatile("nop");
+#else
+ __delay_ms(10);
+#endif
#if TU_PIC_INT_SIZE == 4
U1CONCLR = _U1CON_RESUME_MASK;
@@ -737,8 +781,11 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
//--------------------------------------------------------------------+
void dcd_int_handler(uint8_t rhport)
{
- uint32_t is = U1IR;
- uint32_t msk = U1IE;
+ uint32_t is, msk;
+
+ // Part 1 - "USB interrupts"
+ is = U1IR;
+ msk = U1IE;
U1IR = is & ~msk;
is &= msk;
@@ -746,7 +793,7 @@ void dcd_int_handler(uint8_t rhport)
if (is & _U1IR_UERRIF_MASK) {
uint32_t es = U1EIR;
U1EIR = es;
- U1IR = is; /* discard any pending events */
+ U1IR = is; /* discard any pending events */
}
if (is & _U1IR_URSTIF_MASK) {
@@ -757,29 +804,66 @@ void dcd_int_handler(uint8_t 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
+
+ /*
+ * NOTE: Do not clear U1OTGIRbits.ACTVIF here!
+ * Reason:
+ * ACTVIF is only generated once an IDLEIF has been generated.
+ * This is a 1:1 ratio interrupt generation.
+ * For every IDLEIF, there will be only one ACTVIF regardless of
+ * the number of subsequent bus transitions.
+ *
+ * If the ACTIF is cleared here, a problem could occur when:
+ * [ IDLE ][bus activity ->
+ * <--- 3 ms -----> ^
+ * ^ ACTVIF=1
+ * IDLEIF=1
+ * # # # # (#=Program polling flags)
+ * ^
+ * This polling loop will see both
+ * IDLEIF=1 and ACTVIF=1.
+ * However, the program services IDLEIF first
+ * because ACTIVIE=0.
+ * If this routine clears the only ACTIVIF,
+ * then it can never get out of the suspend
+ * mode.
+ */
+ U1OTGIESET = _U1OTGIE_ACTVIE_MASK;
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);
+ U1IR = _U1IR_STALLIF_MASK;
}
if (is & _U1IR_TRNIF_MASK) {
process_tokdne(rhport);
}
+ // Part 2 - "USB OTG interrupts"
+ is = U1OTGIR;
+ msk = U1OTGIE;
+
+ U1OTGIR = is & ~msk;
+ is &= msk;
+
+ if (is & _U1OTGIR_ACTVIF_MASK) {
+#if TU_PIC_INT_SIZE == 4
+ U1OTGIECLR = _U1OTGIE_ACTVIE_MASK;
+#else
+ U1OTGIE &= ~_U1OTGIE_ACTVIE_MASK;
+#endif
+ U1OTGIR = _U1OTGIR_ACTVIF_MASK;
+ process_bus_resume(rhport);
+ }
+
intr_clear(rhport);
}
diff --git a/src/portable/microchip/pic32mz/dcd_pic32mz.c b/src/portable/microchip/pic32mz/dcd_pic32mz.c
index 9ad755670..8709baf67 100644
--- a/src/portable/microchip/pic32mz/dcd_pic32mz.c
+++ b/src/portable/microchip/pic32mz/dcd_pic32mz.c
@@ -120,8 +120,8 @@ static ep0_stage_t ep0_get_stage(void)
/*------------------------------------------------------------------*/
/* Controller API
*------------------------------------------------------------------*/
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
// Disable endpoint interrupts for now
USB_REGS->INTRRXEbits.w = 0;
USB_REGS->INTRTXEbits.w = 0;
@@ -129,6 +129,7 @@ void dcd_init(uint8_t rhport)
USB_REGS->INTRUSBEbits.w = 7;
dcd_connect(rhport);
+ return true;
}
void dcd_int_enable(uint8_t rhport)
diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c
index 005b63faf..357aa1549 100644
--- a/src/portable/microchip/samd/dcd_samd.c
+++ b/src/portable/microchip/samd/dcd_samd.c
@@ -78,9 +78,9 @@ static void bus_reset(void)
/*------------------------------------------------------------------*/
/* Controller API
*------------------------------------------------------------------*/
-void dcd_init (uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
// Reset to get in a clean state.
USB->DEVICE.CTRLA.bit.SWRST = true;
@@ -102,6 +102,8 @@ void dcd_init (uint8_t rhport)
USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending
USB->DEVICE.INTENSET.reg = /* USB_DEVICE_INTENSET_SOF | */ USB_DEVICE_INTENSET_EORST;
+
+ return true;
}
#if CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAME5X
@@ -333,7 +335,7 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
//--------------------------------------------------------------------+
// Interrupt Handler
//--------------------------------------------------------------------+
-void maybe_transfer_complete(void) {
+static void maybe_transfer_complete(void) {
uint32_t epints = USB->DEVICE.EPINTSMRY.reg;
for (uint8_t epnum = 0; epnum < USB_EPT_NUM; epnum++) {
diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c
index e3fa51e31..a5c768839 100644
--- a/src/portable/microchip/samg/dcd_samg.c
+++ b/src/portable/microchip/samg/dcd_samg.c
@@ -52,37 +52,31 @@ typedef struct
// Endpoint 0-5, each can only be either OUT or In
xfer_desc_t _dcd_xfer[EP_COUNT];
-void xfer_epsize_set(xfer_desc_t* xfer, uint16_t epsize)
-{
+TU_ATTR_ALWAYS_INLINE static inline void xfer_epsize_set(xfer_desc_t* xfer, uint16_t epsize) {
xfer->epsize = epsize;
}
-void xfer_begin(xfer_desc_t* xfer, uint8_t * buffer, uint16_t total_bytes)
-{
+TU_ATTR_ALWAYS_INLINE static inline void xfer_begin(xfer_desc_t* xfer, uint8_t * buffer, uint16_t total_bytes) {
xfer->buffer = buffer;
// xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
xfer->total_len = total_bytes;
xfer->actual_len = 0;
}
-void xfer_end(xfer_desc_t* xfer)
-{
+TU_ATTR_ALWAYS_INLINE static inline void xfer_end(xfer_desc_t* xfer) {
xfer->buffer = NULL;
// xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
xfer->total_len = 0;
xfer->actual_len = 0;
}
-uint16_t xfer_packet_len(xfer_desc_t* xfer)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint16_t xfer_packet_len(xfer_desc_t* xfer) {
// also cover zero-length packet
return tu_min16(xfer->total_len - xfer->actual_len, xfer->epsize);
}
-void xfer_packet_done(xfer_desc_t* xfer)
-{
+TU_ATTR_ALWAYS_INLINE static inline void xfer_packet_done(xfer_desc_t* xfer) {
uint16_t const xact_len = xfer_packet_len(xfer);
-
xfer->buffer += xact_len;
xfer->actual_len += xact_len;
}
@@ -90,19 +84,15 @@ void xfer_packet_done(xfer_desc_t* xfer)
//------------- Transaction helpers -------------//
// Write data to EP FIFO, return number of written bytes
-static void xact_ep_write(uint8_t epnum, uint8_t* buffer, uint16_t xact_len)
-{
- for(uint16_t i=0; i<xact_len; i++)
- {
+static void xact_ep_write(uint8_t epnum, uint8_t* buffer, uint16_t xact_len) {
+ for(uint16_t i=0; i<xact_len; i++) {
UDP->UDP_FDR[epnum] = (uint32_t) buffer[i];
}
}
// Read data from EP FIFO
-static void xact_ep_read(uint8_t epnum, uint8_t* buffer, uint16_t xact_len)
-{
- for(uint16_t i=0; i<xact_len; i++)
- {
+static void xact_ep_read(uint8_t epnum, uint8_t* buffer, uint16_t xact_len) {
+ for(uint16_t i=0; i<xact_len; i++) {
buffer[i] = (uint8_t) UDP->UDP_FDR[epnum];
}
}
@@ -112,24 +102,24 @@ static void xact_ep_read(uint8_t epnum, uint8_t* buffer, uint16_t xact_len)
#define CSR_NO_EFFECT_1_ALL (UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1 | UDP_CSR_STALLSENT | UDP_CSR_RXSETUP | UDP_CSR_TXCOMP)
// Per Specs: CSR need synchronization each write
-static inline void csr_write(uint8_t epnum, uint32_t value)
-{
+TU_ATTR_ALWAYS_INLINE static inline void csr_write(uint8_t epnum, uint32_t value) {
uint32_t const csr = value;
UDP->UDP_CSR[epnum] = csr;
volatile uint32_t nop_count;
- for (nop_count = 0; nop_count < 20; nop_count ++) __NOP();
+ for (nop_count = 0; nop_count < 20; nop_count ++) {
+ __NOP();
+ }
}
// Per Specs: CSR need synchronization each write
-static inline void csr_set(uint8_t epnum, uint32_t mask)
+TU_ATTR_ALWAYS_INLINE static inline void csr_set(uint8_t epnum, uint32_t mask)
{
csr_write(epnum, UDP->UDP_CSR[epnum] | CSR_NO_EFFECT_1_ALL | mask);
}
// Per Specs: CSR need synchronization each write
-static inline void csr_clear(uint8_t epnum, uint32_t mask)
-{
+TU_ATTR_ALWAYS_INLINE static inline void csr_clear(uint8_t epnum, uint32_t mask) {
csr_write(epnum, (UDP->UDP_CSR[epnum] | CSR_NO_EFFECT_1_ALL) & ~mask);
}
@@ -155,10 +145,13 @@ static void bus_reset(void)
}
// Initialize controller to device mode
-void dcd_init (uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rhport;
+ (void) rh_init;
+
tu_memclr(_dcd_xfer, sizeof(_dcd_xfer));
dcd_connect(rhport);
+ return true;
}
// Enable device interrupt
@@ -277,6 +270,11 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
return true;
}
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport; (void) ep_addr;
+ // TODO implement dcd_edpt_close()
+}
+
void dcd_edpt_close_all (uint8_t rhport)
{
(void) rhport;
diff --git a/src/portable/microchip/samx7x/dcd_samx7x.c b/src/portable/microchip/samx7x/dcd_samx7x.c
index 9586df84d..8aec1568d 100644
--- a/src/portable/microchip/samx7x/dcd_samx7x.c
+++ b/src/portable/microchip/samx7x/dcd_samx7x.c
@@ -104,9 +104,10 @@ TU_ATTR_ALWAYS_INLINE static inline void CleanInValidateCache(uint32_t *addr, in
//------------------------------------------------------------------
// Initialize controller to device mode
-void dcd_init (uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
dcd_connect(rhport);
+ return true;
}
// Enable device interrupt
diff --git a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
index d5c0daaeb..1ce3da27e 100644
--- a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
+++ b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
@@ -245,9 +245,9 @@ static void process_bus_active(uint8_t rhport)
/*------------------------------------------------------------------*/
/* Device API
*------------------------------------------------------------------*/
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
tu_memclr(&_dcd, sizeof(_dcd));
USB_OTG_FS->BDT_PAGE_01 = (uint8_t)((uintptr_t)_dcd.bdt >> 8);
@@ -256,6 +256,7 @@ void dcd_init(uint8_t rhport)
dcd_connect(rhport);
NVIC_ClearPendingIRQ(USB_FS_IRQn);
+ return true;
}
#define USB_DEVICE_INTERRUPT_PRIORITY (3U)
void dcd_int_enable(uint8_t rhport)
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 1cc5c1836..9e5f5117f 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -39,8 +39,8 @@
#endif
#include "nrf.h"
-#include "nrf_clock.h"
-#include "nrfx_usbd_errata.h"
+#include "nrfx_clock.h"
+#include "nrf_erratas.h"
#ifdef __GNUC__
#pragma GCC diagnostic pop
@@ -230,9 +230,11 @@ static void xact_in_dma(uint8_t epnum) {
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
-void dcd_init(uint8_t rhport) {
- TU_LOG2("dcd init\r\n");
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
+ TU_LOG2("dcd init\r\n");
+ return true;
}
void dcd_int_enable(uint8_t rhport) {
@@ -441,11 +443,11 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
bool const control_status = (epnum == 0 && total_bytes == 0 && dir != tu_edpt_dir(NRF_USBD->BMREQUESTTYPE));
if (control_status) {
- // Status Phase also requires EasyDMA has to be available as well !!!!
- edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS);
-
// 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, is_in_isr());
+
+ // Status Phase also requires EasyDMA has to be available as well !!!!
+ edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS);
} else if (dir == TUSB_DIR_OUT) {
xfer->started = true;
if (epnum == 0) {
@@ -528,7 +530,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
/*------------------------------------------------------------------*/
/* Interrupt Handler
*------------------------------------------------------------------*/
-void bus_reset(void) {
+static void bus_reset(void) {
// 6.35.6 USB controller automatically disabled all endpoints (except control)
NRF_USBD->EPOUTEN = 1UL;
NRF_USBD->EPINEN = 1UL;
@@ -899,6 +901,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 {
@@ -923,7 +926,7 @@ void tusb_hal_nrf_power_event(uint32_t event) {
#ifdef NRF52_SERIES // NRF53 does not need this errata
// ERRATA 171, 187, 166
- if (nrfx_usbd_errata_187()) {
+ if (nrf52_errata_187()) {
// CRITICAL_REGION_ENTER();
if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
*((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
@@ -935,7 +938,7 @@ void tusb_hal_nrf_power_event(uint32_t event) {
// CRITICAL_REGION_EXIT();
}
- if (nrfx_usbd_errata_171()) {
+ if (nrf52_errata_171()) {
// CRITICAL_REGION_ENTER();
if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
*((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
@@ -971,7 +974,7 @@ void tusb_hal_nrf_power_event(uint32_t event) {
__DSB(); // for sync
#ifdef NRF52_SERIES
- if (nrfx_usbd_errata_171()) {
+ if (nrf52_errata_171()) {
// CRITICAL_REGION_ENTER();
if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
*((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
@@ -984,7 +987,7 @@ void tusb_hal_nrf_power_event(uint32_t event) {
// CRITICAL_REGION_EXIT();
}
- if (nrfx_usbd_errata_187()) {
+ if (nrf52_errata_187()) {
// CRITICAL_REGION_ENTER();
if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
*((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
@@ -996,7 +999,7 @@ void tusb_hal_nrf_power_event(uint32_t event) {
// CRITICAL_REGION_EXIT();
}
- if (nrfx_usbd_errata_166()) {
+ if (nrf52_errata_166()) {
*((volatile uint32_t*) (NRF_USBD_BASE + 0x800)) = 0x7E3;
*((volatile uint32_t*) (NRF_USBD_BASE + 0x804)) = 0x40;
diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c
index fb12122e0..b0b6fe857 100644
--- a/src/portable/nuvoton/nuc120/dcd_nuc120.c
+++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c
@@ -201,9 +201,9 @@ static const uint32_t enabled_irqs = USBD_INTSTS_FLDET_STS_Msk | USBD_INTSTS_BUS
NUC100/NUC120 TinyUSB API driver implementation
*/
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
USBD->ATTR = 0x7D0;
@@ -215,6 +215,8 @@ void dcd_init(uint8_t rhport)
USBD->INTSTS = enabled_irqs;
USBD->INTEN = enabled_irqs;
+
+ return true;
}
void dcd_int_enable(uint8_t rhport)
diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c
index 873b1b7ef..f4af97ca7 100644
--- a/src/portable/nuvoton/nuc121/dcd_nuc121.c
+++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c
@@ -209,9 +209,9 @@ enum {
NUC121/NUC125/NUC126 TinyUSB API driver implementation
*/
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
#ifdef SUPPORT_LPM
USBD->ATTR = 0x7D0 | USBD_LPMACK;
@@ -227,6 +227,8 @@ void dcd_init(uint8_t rhport)
USBD->INTSTS = ENABLED_IRQS;
USBD->INTEN = ENABLED_IRQS;
+
+ return true;
}
void dcd_int_enable(uint8_t rhport)
diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c
index 3a92c9794..1c98a0a49 100644
--- a/src/portable/nuvoton/nuc505/dcd_nuc505.c
+++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c
@@ -279,9 +279,9 @@ static const uint32_t enabled_irqs = USBD_GINTEN_USBIEN_Msk | \
NUC505 TinyUSB API driver implementation
*/
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
/* configure interrupts in their initial state; BUSINTEN and CEPINTEN will be subsequently and dynamically re-written as needed */
USBD->GINTEN = enabled_irqs;
@@ -291,6 +291,8 @@ void dcd_init(uint8_t rhport)
bus_reset();
usb_attach();
+
+ return true;
}
void dcd_int_enable(uint8_t rhport)
diff --git a/src/portable/nxp/khci/dcd_khci.c b/src/portable/nxp/khci/dcd_khci.c
index ef61146aa..3d5e195a9 100644
--- a/src/portable/nxp/khci/dcd_khci.c
+++ b/src/portable/nxp/khci/dcd_khci.c
@@ -265,9 +265,9 @@ static void process_bus_resume(uint8_t rhport)
/*------------------------------------------------------------------*/
/* Device API
*------------------------------------------------------------------*/
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
// 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
@@ -294,6 +294,8 @@ void dcd_init(uint8_t rhport)
dcd_connect(rhport);
NVIC_ClearPendingIRQ(USB0_IRQn);
+
+ return true;
}
void dcd_int_enable(uint8_t rhport)
@@ -563,7 +565,7 @@ void dcd_int_handler(uint8_t rhport)
if (is & USB_ISTAT_SOFTOK_MASK) {
KHCI->ISTAT = USB_ISTAT_SOFTOK_MASK;
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ dcd_event_sof(rhport, tu_u16(KHCI->FRMNUMH, KHCI->FRMNUML), true);
}
if (is & USB_ISTAT_STALL_MASK) {
diff --git a/src/portable/nxp/khci/hcd_khci.c b/src/portable/nxp/khci/hcd_khci.c
index 57684b259..c3c901c5d 100644
--- a/src/portable/nxp/khci/hcd_khci.c
+++ b/src/portable/nxp/khci/hcd_khci.c
@@ -140,7 +140,7 @@ typedef struct
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)
+static int find_pipe(uint8_t dev_addr, uint8_t ep_addr)
{
/* Find the target pipe */
int num;
@@ -368,10 +368,9 @@ static void process_bus_reset(uint8_t rhport)
/*------------------------------------------------------------------*/
/* Host API
*------------------------------------------------------------------*/
-bool hcd_init(uint8_t rhport)
-{
- (void)rhport;
-
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rhport;
+ (void) rh_init;
KHCI->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
while (KHCI->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
@@ -542,6 +541,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
/* 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)
diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
index b880c2870..855c59cd1 100644
--- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
+++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
@@ -167,9 +167,9 @@ static void bus_reset(void)
tu_memclr(&_dcd, sizeof(dcd_data_t));
}
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
//------------- user manual 11.13 usb device controller initialization -------------//
// step 6 : set up control endpoint
@@ -186,6 +186,8 @@ void dcd_init(uint8_t rhport)
// Clear pending IRQ
NVIC_ClearPendingIRQ(USB_IRQn);
+
+ return true;
}
void dcd_int_enable(uint8_t rhport)
@@ -335,6 +337,11 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport; (void) ep_addr;
+ // TODO implement dcd_edpt_close()
+}
+
void dcd_edpt_close_all (uint8_t rhport)
{
(void) rhport;
diff --git a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
index 372dcf51f..090d1ba69 100644
--- a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
+++ b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
@@ -30,6 +30,7 @@
(CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
#include "chip.h"
+#include "host/hcd.h"
void hcd_int_enable(uint8_t rhport)
{
diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
index cc18cf59b..7c637ce0c 100644
--- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
+++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
@@ -289,20 +289,22 @@ static void edpt_reset_all(uint8_t rhport)
}
prepare_setup_packet(rhport);
}
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
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->INTSTAT = dcd_reg->INTSTAT; // clear all pending interrupt
dcd_reg->INTEN = INT_DEVICE_STATUS_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);
+
+ return true;
}
void dcd_int_enable(uint8_t rhport)
@@ -561,7 +563,8 @@ void dcd_int_handler(uint8_t rhport)
uint32_t const cmd_stat = dcd_reg->DEVCMDSTAT;
- uint32_t int_status = dcd_reg->INTSTAT & dcd_reg->INTEN;
+ uint32_t int_status = dcd_reg->INTSTAT;
+ int_status &= dcd_reg->INTEN;
dcd_reg->INTSTAT = int_status; // Acknowledge handled interrupt
if (int_status == 0) return;
diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c
index c59d4755e..672ad0443 100644
--- a/src/portable/ohci/ohci.c
+++ b/src/portable/ohci/ohci.c
@@ -178,9 +178,9 @@ TU_ATTR_ALWAYS_INLINE static inline void *_virt_addr(void *physical_address)
}
// Initialization according to 5.1.1.4
-bool hcd_init(uint8_t rhport)
-{
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
//------------- Data Structure init -------------//
tu_memclr(&ohci_data, sizeof(ohci_data_t));
@@ -451,7 +451,6 @@ static void td_insert_to_ed(ohci_ed_t* p_ed, ohci_gtd_t * p_gtd)
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
-
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
{
(void) rhport;
@@ -486,6 +485,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
{
(void) rhport;
diff --git a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
index e6daf6827..60afbd435 100644
--- a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
+++ b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
@@ -50,12 +50,13 @@ static usb_descriptor_buffers_t desc;
*------------------------------------------------------------------*/
// Initialize controller to device mode
-void dcd_init (uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
-
+ (void) rh_init;
static pio_usb_configuration_t config = PIO_USB_DEFAULT_CONFIG;
usb_device = pio_usb_device_init(&config, &desc);
+
+ return true;
}
// Enable device interrupt
diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
index f4de3c51d..225a44dcf 100644
--- a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
+++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
@@ -55,8 +55,9 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void *cfg_param) {
return true;
}
-bool hcd_init(uint8_t rhport) {
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
// To run USB SOF interrupt in core1, call this init in core1
pio_usb_host_init(&pio_host_cfg);
@@ -121,6 +122,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return pio_usb_host_endpoint_open(pio_rhport, dev_addr, (uint8_t const *) desc_ep, need_pre);
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_endpoint_close(pio_rhport, daddr, ep_addr);
+}
+
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);
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index bc0deee32..358ce84bc 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -46,7 +46,6 @@
/*------------------------------------------------------------------*/
/* Low level controller
*------------------------------------------------------------------*/
-
// Init these in dcd_init
static uint8_t* next_buffer_ptr;
@@ -66,58 +65,31 @@ TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_addr(
return hw_endpoint_get_by_num(num, dir);
}
-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;
+// Allocate from the USB buffer space (max 3840 bytes)
+static void hw_endpoint_alloc(struct hw_endpoint* ep, size_t size) {
+ // round up size to multiple of 64
+ size = tu_round_up(ep->wMaxPacketSize, 64);
// double buffered Bulk endpoint
- if (transfer_type == TUSB_XFER_BULK) {
+ if (ep->transfer_type == TUSB_XFER_BULK) {
size *= 2u;
}
+ // assign buffer
ep->hw_data_buf = next_buffer_ptr;
next_buffer_ptr += size;
- 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);
-
- pico_info(" Allocated %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
-
- // 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;
-
- *ep->endpoint_control = reg;
+ hard_assert(next_buffer_ptr < usb_dpram->epx_data + sizeof(usb_dpram->epx_data));
+ pico_info(" Allocated %d bytes (0x%p)\r\n", size, ep->hw_data_buf);
}
-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));
-
- // 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];
- }
-}
-
-static void hw_endpoint_close(uint8_t ep_addr) {
- struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
- _hw_endpoint_close(ep);
+// Enable endpoint
+TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_enable(struct hw_endpoint* ep) {
+ uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->hw_data_buf);
+ *ep->endpoint_control = reg;
}
+// main processing for dcd_edpt_iso_activate
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);
@@ -156,9 +128,18 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t t
} else {
ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out;
}
+ }
+}
- // alloc a buffer and fill in endpoint control register
- _hw_endpoint_alloc(ep, transfer_type);
+// Init, allocate buffer and enable endpoint
+static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
+ hw_endpoint_init(ep_addr, wMaxPacketSize, transfer_type);
+ const uint8_t num = tu_edpt_number(ep_addr);
+ if (num != 0) {
+ // EP0 is already enabled
+ hw_endpoint_alloc(ep, ep->wMaxPacketSize);
+ hw_endpoint_enable(ep);
}
}
@@ -167,6 +148,32 @@ static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t* buffer, uint16_t total_by
hw_endpoint_xfer_start(ep, buffer, total_bytes);
}
+static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) {
+ // Abort any pending transfer
+ // 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.
+ const uint8_t dir = tu_edpt_dir(ep->ep_addr);
+ const uint8_t epnum = tu_edpt_number(ep->ep_addr);
+ const uint32_t abort_mask = TU_BIT((epnum << 1) | (dir ? 0 : 1));
+ if (rp2040_chip_version() >= 2) {
+ usb_hw_set->abort = abort_mask;
+ while ((usb_hw->abort_done & abort_mask) != abort_mask) {}
+ }
+
+ uint32_t buf_ctrl = USB_BUF_CTRL_SEL; // reset to buffer 0
+ if (ep->next_pid) {
+ buf_ctrl |= USB_BUF_CTRL_DATA1_PID;
+ }
+
+ _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl);
+ hw_endpoint_reset_transfer(ep);
+
+ if (rp2040_chip_version() >= 2) {
+ usb_hw_clear->abort_done = abort_mask;
+ usb_hw_clear->abort = abort_mask;
+ }
+}
+
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);
@@ -197,25 +204,10 @@ TU_ATTR_ALWAYS_INLINE static inline void reset_ep0(void) {
// 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);
+ ep->next_pid = 1u;
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) {}
- }
-
- _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_abort_xfer(ep); // Abort any pending transfer per USB specs
}
- ep->next_pid = 1u;
}
}
@@ -369,7 +361,8 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
#define PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY 0xff
#endif
-void dcd_init(uint8_t rhport) {
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
assert(rhport == 0);
TU_LOG(2, "Chip Version B%u\r\n", rp2040_chip_version());
@@ -386,8 +379,8 @@ void dcd_init(uint8_t rhport) {
// 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);
+ hw_endpoint_open(0x0, 64, TUSB_XFER_CONTROL);
+ hw_endpoint_open(0x80, 64, TUSB_XFER_CONTROL);
// Init non-control endpoints
reset_non_control_endpoints();
@@ -405,6 +398,7 @@ void dcd_init(uint8_t rhport) {
(FORCE_VBUS_DETECT ? 0 : USB_INTS_DEV_CONN_DIS_BITS);
dcd_connect(rhport);
+ return true;
}
bool dcd_deinit(uint8_t rhport) {
@@ -491,9 +485,36 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req
}
}
-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);
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
+ (void) rhport;
+ const uint8_t xfer_type = desc_edpt->bmAttributes.xfer;
+ TU_VERIFY(xfer_type != TUSB_XFER_ISOCHRONOUS);
+ hw_endpoint_open(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), xfer_type);
+ return true;
+}
+
+// New API: Allocate packet buffer used by ISO endpoints
+// Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering
+bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
+ (void) rhport;
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
+ hw_endpoint_init(ep_addr, largest_packet_size, TUSB_XFER_ISOCHRONOUS);
+ hw_endpoint_alloc(ep, largest_packet_size);
+ return true;
+}
+
+// New API: Configure and enable an ISO endpoint according to descriptor
+bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) {
+ (void) rhport;
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_desc->bEndpointAddress);
+ TU_ASSERT(ep->hw_data_buf != NULL); // must be inited and allocated previously
+
+ if (ep->active) {
+ hw_endpoint_abort_xfer(ep); // abort any pending transfer
+ }
+
+ ep->wMaxPacketSize = ep_desc->wMaxPacketSize;
+ hw_endpoint_enable(ep);
return true;
}
@@ -538,12 +559,6 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
}
}
-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 __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport) {
(void) rhport;
dcd_rp2040_irq();
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index 222dbbbf0..cd8c905d5 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -375,9 +375,9 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
//--------------------------------------------------------------------+
// HCD API
//--------------------------------------------------------------------+
-bool hcd_init(uint8_t rhport)
-{
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
pico_trace("hcd_init %d\n", rhport);
assert(rhport == 0);
@@ -459,28 +459,33 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport)
}
// 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 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];
+ // reset epx if it is currently active with unplugged device
+ if (epx.configured && epx.active && epx.dev_addr == dev_addr) {
+ epx.configured = false;
+ *epx.endpoint_control = 0;
+ *epx.buffer_control = 0;
+ hw_endpoint_reset_transfer(&epx);
+ }
- 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;
+ // dev0 only has ep0
+ if (dev_addr != 0) {
+ 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);
+ // unconfigure the endpoint
+ ep->configured = false;
+ *ep->endpoint_control = 0;
+ *ep->buffer_control = 0;
+ hw_endpoint_reset_transfer(ep);
+ }
}
}
}
@@ -509,7 +514,6 @@ void hcd_int_disable(uint8_t rhport)
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
-
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
{
(void) rhport;
@@ -530,6 +534,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
{
(void) rhport;
@@ -557,7 +566,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
}
// If a normal transfer (non-interrupt) then initiate using
- // sie ctrl registers. Otherwise interrupt ep registers should
+ // sie ctrl registers. Otherwise, interrupt ep registers should
// already be configured
if ( ep == &epx )
{
@@ -597,13 +606,12 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
(void) rhport;
// Copy data into setup packet buffer
- for ( uint8_t i = 0; i < 8; i++ )
- {
+ 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);
+ struct hw_endpoint * ep = _hw_endpoint_allocate( (uint8_t) TUSB_XFER_CONTROL);
TU_ASSERT(ep);
// EPX should be inactive
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index 43f48da39..9d0bd762d 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -110,7 +110,7 @@ void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoi
*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()) {
+ if (!is_host_mode()) {
busy_wait_at_least_cycles(12);
}
}
diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c
index 7c6044ca0..ecd28973c 100644
--- a/src/portable/renesas/rusb2/dcd_rusb2.c
+++ b/src/portable/renesas/rusb2/dcd_rusb2.c
@@ -657,14 +657,14 @@ static void enable_interrupt(uint32_t pswi)
}
#endif
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
rusb2_reg_t* rusb = RUSB2_REG(rhport);
rusb2_module_start(rhport, true);
-// We disable SOF for now until needed later on.
-// Since TinyUSB doesn't use SOF for now, and this interrupt often (1ms interval)
-_dcd.sof_enabled = false;
+ // We disable SOF for now until needed later on.
+ // Since TinyUSB doesn't use SOF for now, and this interrupt often (1ms interval)
+ _dcd.sof_enabled = false;
#ifdef RUSB2_SUPPORT_HIGHSPEED
if ( rusb2_is_highspeed_rhport(rhport) ) {
@@ -719,6 +719,8 @@ _dcd.sof_enabled = false;
if (rusb->INTSTS0_b.VBSTS) {
dcd_connect(rhport);
}
+
+ return true;
}
void dcd_int_enable(uint8_t rhport) {
diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c
index f140da690..3e4b36981 100644
--- a/src/portable/renesas/rusb2/hcd_rusb2.c
+++ b/src/portable/renesas/rusb2/hcd_rusb2.c
@@ -466,8 +466,8 @@ static void enable_interrupt(uint32_t pswi)
}
#endif
-bool hcd_init(uint8_t rhport)
-{
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
rusb2_reg_t* rusb = RUSB2_REG(rhport);
rusb2_module_start(rhport, true);
@@ -718,6 +718,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
{
bool r;
diff --git a/src/portable/renesas/rusb2/rusb2_common.c b/src/portable/renesas/rusb2/rusb2_common.c
index 850060777..72e65736b 100644
--- a/src/portable/renesas/rusb2/rusb2_common.c
+++ b/src/portable/renesas/rusb2/rusb2_common.c
@@ -45,6 +45,7 @@ rusb2_controller_t rusb2_controller[] = {
};
// Application API for setting IRQ number. May throw warnings for missing prototypes.
+void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum);
void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum) {
rusb2_controller[rhport].irqnum = irqnum;
}
diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c
index 41814370e..b16509c6f 100644
--- a/src/portable/sony/cxd56/dcd_cxd56.c
+++ b/src/portable/sony/cxd56/dcd_cxd56.c
@@ -201,9 +201,9 @@ static void _dcd_resume(FAR struct usbdevclass_driver_s *driver, FAR struct usbd
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
}
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
usbdcd_driver.usbdevclass_driver.speed = USB_SPEED_HIGH;
usbdcd_driver.usbdevclass_driver.ops = &g_driverops;
@@ -211,6 +211,8 @@ void dcd_init(uint8_t rhport)
usbdcd_driver.setup_queue = osal_queue_create(&_setup_queue_def);
usbdev_register(&usbdcd_driver.usbdevclass_driver);
+
+ return true;
}
// Enable device interrupt
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index 6eea1ab32..ef58957bb 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -40,6 +40,7 @@
* F102, F103 512 byte buffer; no internal D+ pull-up (maybe many more changes?)
* F302xB/C, F303xB/C, F373 512 byte buffer; no internal D+ pull-up
* F302x6/8, F302xD/E2, F303xD/E 1024 byte buffer; no internal D+ pull-up
+ * C0 2048 byte buffer; 32-bit bus; host mode
* G0 2048 byte buffer; 32-bit bus; host mode
* G4 1024 byte buffer
* H5 2048 byte buffer; 32-bit bus; host mode
@@ -184,7 +185,8 @@ TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint8_t epnum, uint
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
-void dcd_init(uint8_t rhport) {
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
// Follow the RM mentions to use a special ordering of PDWN and FRES
for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
@@ -223,6 +225,8 @@ void dcd_init(uint8_t rhport) {
// Enable pull-up if supported
dcd_connect(rhport);
+
+ return true;
}
void dcd_sof_enable(uint8_t rhport, bool en) {
diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h
index 99fe8d55f..ccf31e035 100644
--- a/src/portable/st/stm32_fsdev/fsdev_stm32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h
@@ -104,6 +104,20 @@
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+#elif CFG_TUSB_MCU == OPT_MCU_STM32C0
+ #include "stm32c0xx.h"
+ #define FSDEV_PMA_SIZE (2048u)
+ #define USB USB_DRD_FS
+ #define USB_EP_CTR_RX USB_CHEP_VTRX
+ #define USB_EP_CTR_TX USB_CHEP_VTTX
+ #define USB_EPREG_MASK USB_CHEP_REG_MASK
+ #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_PMA_SIZE (2048u)
@@ -170,6 +184,30 @@
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+#elif CFG_TUSB_MCU == OPT_MCU_STM32U0
+ #include "stm32u0xx.h"
+ #define FSDEV_PMA_SIZE (2048u)
+ #define USB USB_DRD_FS
+
+ #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_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
+
#else
#error You are using an untested or unimplemented STM32 variant. Please update the driver.
// This includes U0
@@ -236,6 +274,8 @@ static const IRQn_Type fsdev_irq[] = {
#else
USB_UCPD1_2_IRQn,
#endif
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32C0
+ USB_DRD_FS_IRQn,
#elif TU_CHECK_MCU(OPT_MCU_STM32G4, OPT_MCU_STM32L1)
USB_HP_IRQn,
USB_LP_IRQn,
@@ -249,6 +289,8 @@ static const IRQn_Type fsdev_irq[] = {
USB_LP_IRQn,
#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
USB_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32U0
+ USB_DRD_FS_IRQn,
#else
#error Unknown arch in USB driver
#endif
diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c
index 6f36ad441..21f13b279 100644
--- a/src/portable/sunxi/dcd_sunxi_musb.c
+++ b/src/portable/sunxi/dcd_sunxi_musb.c
@@ -867,8 +867,9 @@ static void usb_isr_handler(void) {
dcd_int_handler(0);
}
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
+
dcd_disconnect(rhport);
USBC_HardwareReset();
USBC_PhyConfig();
@@ -895,6 +896,8 @@ void dcd_init(uint8_t rhport)
f1c100s_intc_set_isr(F1C100S_IRQ_USBOTG, usb_isr_handler);
dcd_connect(rhport);
+
+ return true;
}
// Connect by enabling internal pull-up resistor on D+/D-
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index 9a38b46dc..c461d9a79 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -31,56 +31,25 @@
#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"
+#if !(CFG_TUD_DWC2_SLAVE_ENABLE || CFG_TUD_DWC2_DMA_ENABLE)
+#error DWC2 require either CFG_TUD_DWC2_SLAVE_ENABLE or CFG_TUD_DWC2_DMA_ENABLE to be enabled
#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
+#include "device/dcd.h"
+#include "dwc2_common.h"
-#ifndef dcache_clean_invalidate
-#define dcache_clean_invalidate(_addr, _size)
+#if TU_CHECK_MCU(OPT_MCU_GD32VF103)
+ #define DWC2_EP_COUNT(_dwc2) DWC2_EP_MAX
+#else
+ #define DWC2_EP_COUNT(_dwc2) ((_dwc2)->ghwcfg2_bm.num_dev_ep + 1)
#endif
-static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2];
-
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
typedef struct {
uint8_t* buffer;
tu_fifo_t* ff;
@@ -92,157 +61,246 @@ typedef struct {
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
+typedef struct {
+ // EP0 transfers are limited to 1 packet - larger sizes has to be split
+ uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type
+ uint16_t dfifo_top; // top free location in DFIFO in words
+
+ // Number of IN endpoints active
+ uint8_t allocated_epin_count;
-// 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
+ bool sof_en;
+} dcd_data_t;
-// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by
-static bool _sof_en;
+static dcd_data_t _dcd_data;
-// 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;
+CFG_TUD_MEM_SECTION static struct {
+ TUD_EPBUF_DEF(setup_packet, 8);
+} _dcd_usbbuf;
+
+//--------------------------------------------------------------------
+// DMA
+//--------------------------------------------------------------------
+#if CFG_TUD_MEM_DCACHE_ENABLE
+bool dcd_dcache_clean(const void* addr, uint32_t data_size) {
+ TU_VERIFY(addr && data_size);
+ return dwc2_dcache_clean(addr, data_size);
+}
+
+bool dcd_dcache_invalidate(const void* addr, uint32_t data_size) {
+ TU_VERIFY(addr && data_size);
+ return dwc2_dcache_invalidate(addr, data_size);
}
-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) {}
+bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
+ TU_VERIFY(addr && data_size);
+ return dwc2_dcache_clean_invalidate(addr, data_size);
}
-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) {}
+#endif
+
+TU_ATTR_ALWAYS_INLINE static inline bool dma_device_enabled(const dwc2_regs_t* dwc2) {
+ (void) dwc2;
+ // Internal DMA only
+ return CFG_TUD_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA;
}
-static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) {
+static void dma_setup_prepare(uint8_t rhport) {
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);
+
+ if (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a) {
+ if(dwc2->epout[0].doepctl & DOEPCTL_EPENA) {
+ return;
+ }
+ }
+
+ // Receive only 1 packet
+ dwc2->epout[0].doeptsiz = (1 << DOEPTSIZ_STUPCNT_Pos) | (1 << DOEPTSIZ_PKTCNT_Pos) | (8 << DOEPTSIZ_XFRSIZ_Pos);
+ dwc2->epout[0].doepdma = (uintptr_t) _dcd_usbbuf.setup_packet;
+ dwc2->epout[0].doepctl |= DOEPCTL_EPENA | DOEPCTL_USBAEP;
+}
+
+//--------------------------------------------------------------------+
+// Data FIFO
+//--------------------------------------------------------------------+
+
+
+/* Device Data FIFO scheme
+
+ The FIFO is split up into
+ - EPInfo: for storing DMA metadata, only required when use DMA. Maximum size is called
+ EP_LOC_CNT = ep_fifo_size - ghwcfg3.dfifo_depth. For value less than EP_LOC_CNT, gdfifocfg must be configured before
+ gahbcfg.dmaen is set
+ - Buffer mode: 1 word per endpoint direction
+ - Scatter/Gather DMA: 4 words per endpoint direction
+ - TX FIFO: one fifo for each IN endpoint. Size is dynamic depending on packet size, starting from top with EP0 IN.
+ - Shared RX FIFO: a shared fifo for all OUT endpoints. Typically, can hold up to 2 packets of the largest EP size.
+
+ We allocated TX FIFO from top to bottom (using top pointer), this to allow the RX FIFO to grow dynamically which is
+ possible since the free space is located between the RX and TX FIFOs.
+
+ ---------------- ep_fifo_size
+ | DxEPIDMAn |
+ |-------------|-- gdfifocfg.EPINFOBASE (max is ghwcfg3.dfifo_depth)
+ | IN FIFO 0 | control EP
+ |-------------|
+ | IN FIFO 1 |
+ |-------------|
+ | . . . . |
+ |-------------|
+ | IN FIFO n |
+ |-------------|
+ | FREE |
+ |-------------|-- GRXFSIZ (expandable)
+ | 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
+ - All EP OUT shared a unique OUT FIFO which uses (for Slave or Buffer DMA, Scatt/Gather DMA use different formula):
+ - 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 + 2 x (Largest-EPsize/4 + 1) + 2 x EPOUTnum
+*/
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t calc_device_grxfsiz(uint16_t largest_ep_size, uint8_t ep_count) {
+ return 13 + 1 + 2 * ((largest_ep_size / 4) + 1) + 2 * ep_count;
+}
+
+static bool dfifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
+ const uint8_t ep_count = dwc2_controller->ep_count;
+ const uint8_t epnum = tu_edpt_number(ep_addr);
+ const uint8_t 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);
+ const uint16_t new_sz = calc_device_grxfsiz(4 * fifo_size, ep_count);
- // Enlarge RX FIFO
- dwc2->grxfsiz = sz;
+ // If size_rx needs to be extended check if there is enough free space
+ if (dwc2->grxfsiz < new_sz) {
+ TU_ASSERT(new_sz <= _dcd_data.dfifo_top);
+ dwc2->grxfsiz = new_sz; // Enlarge RX FIFO
}
} 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) {
+ // Check IN endpoints concurrently active limit
+ if(dwc2_controller->ep_in_count) {
+ TU_ASSERT(_dcd_data.allocated_epin_count < dwc2_controller->ep_in_count);
+ _dcd_data.allocated_epin_count++;
+ }
+
+ // If The TXFELVL is configured as half empty, the fifo must be twice the max_size.
+ if ((dwc2->gahbcfg & GAHBCFG_TX_FIFO_EPMTY_LVL) == 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);
+ TU_ASSERT(_dcd_data.dfifo_top >= fifo_size + dwc2->grxfsiz);
+ _dcd_data.dfifo_top -= fifo_size;
+ // TU_LOG(DWC2_DEBUG, " TX FIFO %u: allocated %u words at offset %u\r\n", epnum, fifo_size, dfifo_top);
- // 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);
+ if (epnum == 0) {
+ dwc2->dieptxf0 = (fifo_size << DIEPTXF0_TX0FD_Pos) | _dcd_data.dfifo_top;
+ } else {
+ // DIEPTXF starts at FIFO #1.
+ dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | _dcd_data.dfifo_top;
+ }
}
return true;
}
-static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) {
+static void dfifo_device_init(uint8_t rhport) {
+ const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
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);
+ dwc2->grxfsiz = calc_device_grxfsiz(CFG_TUD_ENDPOINT0_SIZE, dwc2_controller->ep_count);
+
+ // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per endpoint direction
+ const bool is_dma = dma_device_enabled(dwc2);
+ _dcd_data.dfifo_top = dwc2_controller->ep_fifo_size/4;
+ if (is_dma) {
+ _dcd_data.dfifo_top -= 2 * dwc2_controller->ep_count;
+ }
+ dwc2->gdfifocfg = (_dcd_data.dfifo_top << GDFIFOCFG_EPINFOBASE_SHIFT) | _dcd_data.dfifo_top;
+
+ // Allocate FIFO for EP0 IN
+ dfifo_alloc(rhport, 0x80, CFG_TUD_ENDPOINT0_SIZE);
+}
+
+
+//--------------------------------------------------------------------
+// Endpoint
+//--------------------------------------------------------------------
+static void edpt_activate(uint8_t rhport, const tusb_desc_endpoint_t* p_endpoint_desc) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ const uint8_t epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+ const uint8_t 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);
+ // Endpoint control
+ union {
+ uint32_t value;
+ dwc2_depctl_t bm;
+ } depctl;
+ depctl.value = 0;
- 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));
+ depctl.bm.mps = xfer->max_size;
+ depctl.bm.active = 1;
+ depctl.bm.type = p_endpoint_desc->bmAttributes.xfer;
+ if (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) {
+ depctl.bm.set_data0_iso_even = 1;
+ }
+ if (dir == TUSB_DIR_IN) {
+ depctl.bm.tx_fifo_num = epnum;
}
+
+ dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum];
+ dep->ctl = depctl.value;
+ dwc2->daintmsk |= TU_BIT(epnum + DAINT_SHIFT(dir));
}
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);
+ const uint8_t epnum = tu_edpt_number(ep_addr);
+ const uint8_t dir = tu_edpt_dir(ep_addr);
+ dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum];
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);
+ if ((epnum == 0) || !(dep->diepctl & DIEPCTL_EPENA)) {
+ dep->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) {}
+ dep->diepctl |= DIEPCTL_SNAK;
+ while ((dep->diepint & DIEPINT_INEPNE) == 0) {}
// Disable the endpoint.
- epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0);
- while ((epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0) {}
+ dep->diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0);
+ while ((dep->diepint & DIEPINT_EPDISD_Msk) == 0) {}
- epin[epnum].diepint = DIEPINT_EPDISD;
+ dep->diepint = DIEPINT_EPDISD;
}
// Flush the FIFO, and wait until we have confirmed it cleared.
- fifo_flush_tx(dwc2, epnum);
+ dfifo_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;
+ if ((epnum == 0) || !(dep->doepctl & DOEPCTL_EPENA)) {
+ dep->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
@@ -251,11 +309,11 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
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) {}
+ // Ditto here disable the endpoint.
+ dep->doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0);
+ while ((dep->doepint & DOEPINT_EPDISD_Msk) == 0) {}
- epout[epnum].doepint = DOEPINT_EPDISD;
+ dep->doepint = DOEPINT_EPDISD;
// Allow other OUT endpoints to keep receiving.
dwc2->dctl |= DCTL_CGONAK;
@@ -263,371 +321,124 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
}
}
-// Start of Bus Reset
-static void bus_reset(uint8_t rhport) {
+static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uint8_t dir) {
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;
+ xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir);
+ dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum];
- // 1. NAK for all OUT endpoints
- for (uint8_t n = 0; n < ep_count; n++) {
- dwc2->epout[n].doepctl |= DOEPCTL_SNAK;
- }
+ uint16_t num_packets;
+ uint16_t total_bytes;
- // 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;
+ // EP0 is limited to one packet per xfer
+ if (epnum == 0) {
+ total_bytes = tu_min16(_dcd_data.ep0_pending[dir], xfer->max_size);
+ _dcd_data.ep0_pending[dir] -= total_bytes;
+ num_packets = 1;
+ } else {
+ total_bytes = xfer->total_len;
+ num_packets = tu_div_ceil(total_bytes, xfer->max_size);
+ if (num_packets == 0) {
+ num_packets = 1; // zero length packet still count as 1
}
}
- 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;
-}
+ // transfer size: A full OUT transfer (multiple packets, possibly) triggers XFRC.
+ union {
+ uint32_t value;
+ dwc2_ep_tsize_t bm;
+ } deptsiz;
+ deptsiz.value = 0;
+ deptsiz.bm.xfer_size = total_bytes;
+ deptsiz.bm.packet_count = num_packets;
-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;
+ dep->tsiz = deptsiz.value;
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ // control
+ union {
+ dwc2_depctl_t bm;
+ uint32_t value;
+ } depctl;
+ depctl.value = dep->ctl;
- // 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;
+ depctl.bm.clear_nak = 1;
+ depctl.bm.enable = 1;
+ if (depctl.bm.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) {
+ const uint32_t odd_now = (dwc2->dsts_bm.frame_number & 1u);
+ if (odd_now) {
+ depctl.bm.set_data0_iso_even = 1;
+ } else {
+ depctl.bm.set_data1_iso_odd = 1;
+ }
}
- // 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);
+ const bool is_dma = dma_device_enabled(dwc2);
+ if(is_dma) {
+ if (dir == TUSB_DIR_IN && total_bytes != 0) {
+ dcd_dcache_clean(xfer->buffer, total_bytes);
}
+ dep->diepdma = (uintptr_t) xfer->buffer;
+ dep->diepctl = depctl.value; // enable endpoint
} 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);
+ dep->diepctl = depctl.value; // enable endpoint
- 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);
+ // Enable tx fifo empty interrupt only if there is data. Note must after depctl enable
+ if (dir == TUSB_DIR_IN && total_bytes != 0) {
+ dwc2->diepempmsk |= (1 << epnum);
}
}
}
-/*------------------------------------------------------------------*/
-/* 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");
+//--------------------------------------------------------------------
+// Controller API
+//--------------------------------------------------------------------
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
- // Select ULPI
- gusbcfg |= GUSBCFG_ULPI_UTMI_SEL;
+ tu_memclr(&_dcd_data, sizeof(_dcd_data));
- // ULPI 8-bit interface, single data rate
- gusbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
+ // Core Initialization
+ const bool is_highspeed = dwc2_core_is_highspeed(dwc2, TUSB_ROLE_DEVICE);
+ const bool is_dma = dma_device_enabled(dwc2);
+ TU_ASSERT(dwc2_core_init(rhport, is_highspeed, is_dma));
- // default internal VBUS Indicator and Drive
- gusbcfg &= ~(GUSBCFG_ULPIEVBUSD | GUSBCFG_ULPIEVBUSI);
+ //------------- 7.1 Device Initialization -------------//
+ // Set device max speed
+ uint32_t dcfg = dwc2->dcfg & ~DCFG_DSPD_Msk;
+ if (is_highspeed) {
+ dcfg |= DCFG_DSPD_HS << DCFG_DSPD_Pos;
- // Disable FS/LS ULPI
- gusbcfg &= ~(GUSBCFG_ULPIFSLS | GUSBCFG_ULPICSM);
+ // XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required
+ // when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347)
+ if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) {
+ dcfg |= DCFG_XCVRDLY;
+ }
} 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;
+ dcfg |= DCFG_DSPD_FS << DCFG_DSPD_Pos;
}
- // 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;
-
+ dcfg |= DCFG_NZLSOHSK; // send STALL back and discard if host send non-zlp during control status
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);
+ // Enable required interrupts
+ dwc2->gintmsk |= GINTMSK_OTGINT | GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM;
- // 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);
+ // TX FIFO empty level for interrupt is complete empty
+ uint32_t gahbcfg = dwc2->gahbcfg;
+ gahbcfg |= GAHBCFG_TX_FIFO_EPMTY_LVL;
+ gahbcfg |= GAHBCFG_GINT; // Enable global interrupt
+ dwc2->gahbcfg = gahbcfg;
dcd_connect(rhport);
+ return true;
}
void dcd_int_enable(uint8_t rhport) {
@@ -667,12 +478,34 @@ void dcd_remote_wakeup(uint8_t rhport) {
void dcd_connect(uint8_t rhport) {
(void) rhport;
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+#ifdef TUP_USBIP_DWC2_ESP32
+ usb_wrap_otg_conf_reg_t conf = USB_WRAP.otg_conf;
+ conf.pad_pull_override = 0;
+ conf.dp_pullup = 0;
+ conf.dp_pulldown = 0;
+ conf.dm_pullup = 0;
+ conf.dm_pulldown = 0;
+ USB_WRAP.otg_conf = conf;
+#endif
+
dwc2->dctl &= ~DCTL_SDIS;
}
void dcd_disconnect(uint8_t rhport) {
(void) rhport;
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+#ifdef TUP_USBIP_DWC2_ESP32
+ usb_wrap_otg_conf_reg_t conf = USB_WRAP.otg_conf;
+ conf.pad_pull_override = 1;
+ conf.dp_pullup = 0;
+ conf.dp_pulldown = 1;
+ conf.dm_pullup = 0;
+ conf.dm_pulldown = 1;
+ USB_WRAP.otg_conf = conf;
+#endif
+
dwc2->dctl |= DCTL_SDIS;
}
@@ -681,7 +514,7 @@ void dcd_sof_enable(uint8_t rhport, bool en) {
(void) rhport;
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
- _sof_en = en;
+ _dcd_data.sof_en = en;
if (en) {
dwc2->gintsts = GINTSTS_SOF;
@@ -696,7 +529,7 @@ void dcd_sof_enable(uint8_t rhport, bool en) {
*------------------------------------------------------------------*/
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)));
+ TU_ASSERT(dfifo_alloc(rhport, desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt)));
edpt_activate(rhport, desc_edpt);
return true;
}
@@ -706,43 +539,36 @@ 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;
+ _dcd_data.allocated_epin_count = 0;
+
// 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;
+ for (uint8_t d = 0; d < 2; d++) {
+ dwc2_dep_t* dep = &dwc2->ep[d][n];
+ if (dep->ctl & EPCTL_EPENA) {
+ dep->ctl |= EPCTL_SNAK | EPCTL_EPDIS;
+ }
+ xfer_status[n][1-d].max_size = 0;
}
- 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;
+ dfifo_flush_tx(dwc2, 0x10); // all tx fifo
+ dfifo_flush_rx(dwc2);
- fifo_flush_tx(dwc2, 0x10); // all tx fifo
- fifo_flush_rx(dwc2);
+ dfifo_device_init(rhport); // re-init dfifo
}
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));
+ TU_ASSERT(dfifo_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;
}
@@ -757,21 +583,12 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
// 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);
+ _dcd_data.ep0_pending[dir] = total_bytes;
}
+ // Schedule packets to be sent within interrupt
+ edpt_schedule_packets(rhport, epnum, dir);
+
return true;
}
@@ -791,346 +608,403 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t
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);
+ // TODO xfer fifo may only available for slave mode
+ edpt_schedule_packets(rhport, epnum, dir);
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) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
edpt_disable(rhport, ep_addr, true);
+ if((tu_edpt_number(ep_addr) == 0) && dma_device_enabled(dwc2)) {
+ dma_setup_prepare(rhport);
+ }
}
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);
+ dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum];
// 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;
- }
+ dep->ctl &= ~EPCTL_STALL;;
+ dep->ctl |= EPCTL_SD0PID_SEVNFRM;
}
-/*------------------------------------------------------------------*/
+//--------------------------------------------------------------------
+// Interrupt Handler
+//--------------------------------------------------------------------
-// Read a single data packet from receive FIFO
-static void read_fifo_packet(uint8_t rhport, uint8_t* dst, uint16_t len) {
- (void) rhport;
+// 7.4.1 Initialization on USB Reset
+static void handle_bus_reset(uint8_t rhport) {
+ dwc2_regs_t *dwc2 = DWC2_REG(rhport);
+ const uint8_t ep_count = DWC2_EP_COUNT(dwc2);
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
- volatile const uint32_t* rx_fifo = dwc2->fifo[0];
+ tu_memclr(xfer_status, sizeof(xfer_status));
+
+ _dcd_data.sof_en = false;
+ _dcd_data.allocated_epin_count = 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;
+ // 1. NAK for all OUT endpoints
+ for (uint8_t n = 0; n < ep_count; n++) {
+ dwc2->epout[n].doepctl |= DOEPCTL_SNAK;
}
- // 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);
+ // 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;
+ }
}
+
+ // 2. Set up interrupt mask for EP0
+ dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos);
+ dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM;
+ dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM;
+
+ // 4. Set up DFIFO
+ dfifo_flush_tx(dwc2, 0x10); // all tx fifo
+ dfifo_flush_rx(dwc2);
+ dfifo_device_init(rhport);
+
+ // 5. Reset device address
+ dwc2->dcfg_bm.address = 0;
+
+ // Fixed both control EP0 size to 64 bytes
+ dwc2->epin[0].ctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos);
+ dwc2->epout[0].ctl &= ~(0x03 << DOEPCTL_MPSIZ_Pos);
+
+ xfer_status[0][TUSB_DIR_OUT].max_size = 64;
+ xfer_status[0][TUSB_DIR_IN].max_size = 64;
+
+ if(dma_device_enabled(dwc2)) {
+ dma_setup_prepare(rhport);
+ } else {
+ dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
+ }
+
+ dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT;
}
-// 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;
+static void handle_enum_done(uint8_t rhport) {
+ dwc2_regs_t *dwc2 = DWC2_REG(rhport);
+ tusb_speed_t speed;
+ switch (dwc2->dsts_bm.enum_speed) {
+ case DCFG_SPEED_HIGH:
+ speed = TUSB_SPEED_HIGH;
+ break;
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
- volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num];
+ case DCFG_SPEED_LOW:
+ speed = TUSB_SPEED_LOW;
+ break;
- // 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;
+ case DCFG_SPEED_FULL_30_60MHZ:
+ case DCFG_SPEED_FULL_48MHZ:
+ default:
+ speed = TUSB_SPEED_FULL;
+ break;
}
- // 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);
+ // TODO must update GUSBCFG_TRDT according to link speed
+ dcd_event_bus_reset(rhport, speed, true);
+}
+
+#if 0
+TU_ATTR_ALWAYS_INLINE static inline void print_doepint(uint32_t doepint) {
+ const char* str[] = {
+ "XFRC", "DIS", "AHBERR", "SETUP_DONE",
+ "ORXED", "STATUS_RX", "SETUP_B2B", "RSV7",
+ "OPERR", "BNA", "RSV10", "ISODROP",
+ "BBLERR", "NAK", "NYET", "SETUP_RX"
+ };
- *tx_fifo = tmp_word;
+ for(uint32_t i=0; i<TU_ARRAY_SIZE(str); i++) {
+ if (doepint & TU_BIT(i)) {
+ TU_LOG1("%s ", str[i]);
+ }
}
+ TU_LOG1("\r\n");
}
+#endif
+#if CFG_TUD_DWC2_SLAVE_ENABLE
+// Process shared receive FIFO, this interrupt is only used in Slave mode
static void handle_rxflvl_irq(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
- volatile uint32_t const* rx_fifo = dwc2->fifo[0];
+ const volatile uint32_t* 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];
+ const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm;
+ const uint8_t epnum = grxstsp_bm.ep_ch_num;
-//#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
+ dwc2_dep_t* epout = &dwc2->epout[epnum];
- switch (pktsts) {
- // Global OUT NAK: do nothing
- case GRXSTS_PKTSTS_GLOBALOUTNAK:
+ switch (grxstsp_bm.packet_status) {
+ case GRXSTS_PKTSTS_GLOBAL_OUT_NAK:
+ // Global OUT NAK: do nothing
break;
- case GRXSTS_PKTSTS_SETUPRX:
+ case GRXSTS_PKTSTS_SETUP_RX: {
// 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);
+ uint32_t* setup = (uint32_t*)(uintptr_t) _dcd_usbbuf.setup_packet;
+ // We can receive up to three setup packets in succession, but only the last one is valid.
+ setup[0] = (*rx_fifo);
+ setup[1] = (*rx_fifo);
break;
+ }
- case GRXSTS_PKTSTS_SETUPDONE:
- // Setup packet done (Interrupt)
+ case GRXSTS_PKTSTS_SETUP_DONE:
+ // Setup packet done:
+ // After popping this out, dwc2 asserts a DOEPINT_SETUP interrupt which is handled by handle_epout_irq()
epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
break;
- case GRXSTS_PKTSTS_OUTRX: {
+ case GRXSTS_PKTSTS_RX_DATA: {
// Out packet received
+ const uint16_t byte_count = grxstsp_bm.byte_count;
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;
- }
+ if (byte_count) {
+ // Read packet off RxFIFO
+ if (xfer->ff) {
+ tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void*) (uintptr_t) rx_fifo, byte_count);
+ } else {
+ dfifo_read_packet(dwc2, xfer->buffer, byte_count);
+ xfer->buffer += byte_count;
+ }
- // 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;
+ // short packet, minus remaining bytes (xfer_size)
+ if (byte_count < xfer->max_size) {
+ xfer->total_len -= epout->tsiz_bm.xfer_size;
+ if (epnum == 0) {
+ xfer->total_len -= _dcd_data.ep0_pending[TUSB_DIR_OUT];
+ _dcd_data.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;
+ case GRXSTS_PKTSTS_RX_COMPLETE:
+ // Out packet done
+ // After this entry is popped from the receive FIFO, dwc2 asserts a Transfer Completed interrupt on
+ // the specified OUT endpoint which will be handled by handle_epout_irq()
+ break;
- 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;
+ default: break;
+ }
+}
- if (doepint & DOEPINT_OTEPSPR) clear_flags |= DOEPINT_OTEPSPR;
+static void handle_epout_slave(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepint_bm) {
+ if (doepint_bm.setup_phase_done) {
+ dcd_event_setup_received(rhport, _dcd_usbbuf.setup_packet, true);
+ return;
+ }
- epout->doepint = clear_flags;
+ // Normal OUT transfer complete
+ if (doepint_bm.xfer_complete) {
+ // only handle data skip if it is setup or status related
+ // Note: even though (xfer_complete + status_phase_rx) is for buffered DMA only, for STM32L47x (dwc2 v3.00a) they
+ // can is set when GRXSTS_PKTSTS_SETUP_RX is popped therefore they can bet set before/together with setup_phase_done
+ if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) {
+ xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
- // TU_LOG(DWC2_DEBUG, " FIX extra transfer complete on setup/data compete\r\n");
- }
+ if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_OUT]) {
+ // EP0 can only handle one packet, Schedule another packet to be received.
+ edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT);
+ } else {
+ dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true);
}
- break;
-
- default: // Invalid
- TU_BREAKPOINT();
- break;
+ }
}
}
-static void handle_epout_irq(uint8_t rhport) {
+static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepint_bm) {
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];
+ dwc2_dep_t* epin = &dwc2->epin[epnum];
+ xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
- uint32_t const doepint = epout->doepint;
+ if (diepint_bm.xfer_complete) {
+ if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_IN]) {
+ // EP0 can only handle one packet. Schedule another packet to be transmitted.
+ edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN);
+ } else {
+ dcd_event_xfer_complete(rhport, epnum | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
+ }
+ }
- // SETUP packet Setup Phase done.
- if (doepint & DOEPINT_STUP) {
- uint32_t clear_flag = DOEPINT_STUP;
+ // TX FIFO empty bit is read-only. It will only be cleared by hardware when written bytes is more than
+ // - 64 bytes or
+ // - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL)
+ if (diepint_bm.txfifo_empty && (dwc2->diepempmsk & (1 << epnum))) {
+ const uint16_t remain_packets = epin->tsiz_bm.packet_count;
- // STPKTRX is only available for version from 3_00a
- if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) {
- clear_flag |= DOEPINT_STPKTRX;
- }
+ // Process every single packet (only whole packets can be written to fifo)
+ for (uint16_t i = 0; i < remain_packets; i++) {
+ const uint16_t remain_bytes = (uint16_t) epin->tsiz_bm.xfer_size;
+ const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size);
- epout->doepint = clear_flag;
- dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true);
+ // Check if dtxfsts has enough space available
+ if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) {
+ break;
}
- // 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);
- }
+ // Push packet to Tx-FIFO
+ if (xfer->ff) {
+ volatile uint32_t* tx_fifo = dwc2->fifo[epnum];
+ tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*)(uintptr_t)tx_fifo, xact_bytes);
+ } else {
+ dfifo_write_packet(dwc2, epnum, xfer->buffer, xact_bytes);
+ xfer->buffer += xact_bytes;
}
}
+
+ // Turn off TXFE if all bytes are written.
+ if (epin->tsiz_bm.xfer_size == 0) {
+ dwc2->diepempmsk &= ~(1 << epnum);
+ }
}
}
+#endif
-static void handle_epin_irq(uint8_t rhport) {
+#if CFG_TUD_DWC2_DMA_ENABLE
+static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepint_bm) {
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 (doepint_bm.setup_phase_done) {
+ dma_setup_prepare(rhport);
+ dcd_dcache_invalidate(_dcd_usbbuf.setup_packet, 8);
+ dcd_event_setup_received(rhport, _dcd_usbbuf.setup_packet, true);
+ return;
+ }
- if (epin[n].diepint & DIEPINT_XFRC) {
- epin[n].diepint = DIEPINT_XFRC;
+ // OUT XFER complete
+ if (doepint_bm.xfer_complete) {
+ // only handle data skip if it is setup or status related
+ // Normal OUT transfer complete
+ if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) {
+ if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_OUT]) {
+ // EP0 can only handle one packet Schedule another packet to be received.
+ edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT);
+ } else {
+ dwc2_dep_t* epout = &dwc2->epout[epnum];
+ xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
- // 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);
+ // determine actual received bytes
+ const uint16_t remain = epout->tsiz_bm.xfer_size;
+ xfer->total_len -= remain;
+
+ // this is ZLP, so prepare EP0 for next setup
+ // TODO use status phase rx
+ if(epnum == 0 && xfer->total_len == 0) {
+ dma_setup_prepare(rhport);
}
- }
- // 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)
+ dcd_dcache_invalidate(xfer->buffer, xfer->total_len);
+ dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true);
+ }
+ }
+ }
+}
- uint16_t remaining_packets = (epin[n].dieptsiz & DIEPTSIZ_PKTCNT_Msk) >> DIEPTSIZ_PKTCNT_Pos;
+static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepint_bm) {
+ xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
- // 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;
+ if (diepint_bm.xfer_complete) {
+ if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_IN]) {
+ // EP0 can only handle one packet. Schedule another packet to be transmitted.
+ edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN);
+ } else {
+ if(epnum == 0) {
+ dma_setup_prepare(rhport);
+ }
+ dcd_event_xfer_complete(rhport, epnum | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
+ }
+ }
+}
+#endif
- // Packet can not be larger than ep max size
- uint16_t const packet_size = tu_min16(remaining_bytes, xfer->max_size);
+static void handle_ep_irq(uint8_t rhport, uint8_t dir) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ const bool is_dma = dma_device_enabled(dwc2);
+ const uint8_t ep_count = DWC2_EP_COUNT(dwc2);
+ const uint8_t daint_offset = (dir == TUSB_DIR_IN) ? DAINT_IEPINT_Pos : DAINT_OEPINT_Pos;
+ dwc2_dep_t* ep_base = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][0];
- // 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;
+ // DAINT for a given EP clears when DEPINTx is cleared.
+ // EPINT will be cleared when DAINT bits are cleared.
+ for (uint8_t epnum = 0; epnum < ep_count; epnum++) {
+ if (dwc2->daint & TU_BIT(daint_offset + epnum)) {
+ dwc2_dep_t* epout = &ep_base[epnum];
+ union {
+ uint32_t value;
+ dwc2_diepint_t diepint_bm;
+ dwc2_doepint_t doepint_bm;
+ } intr;
+ intr.value = epout->intr;
- // 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);
+ epout->intr = intr.value; // Clear interrupt
- // Increment pointer to xfer data
- xfer->buffer += packet_size;
- }
+ if (is_dma) {
+ #if CFG_TUD_DWC2_DMA_ENABLE
+ if (dir == TUSB_DIR_IN) {
+ handle_epin_dma(rhport, epnum, intr.diepint_bm);
+ } else {
+ handle_epout_dma(rhport, epnum, intr.doepint_bm);
}
-
- // Turn off TXFE if all bytes are written.
- if (((epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos) == 0) {
- dwc2->diepempmsk &= ~(1 << n);
+ #endif
+ } else {
+ #if CFG_TUD_DWC2_SLAVE_ENABLE
+ if (dir == TUSB_DIR_IN) {
+ handle_epin_slave(rhport, epnum, intr.diepint_bm);
+ } else {
+ handle_epout_slave(rhport, epnum, intr.doepint_bm);
}
+ #endif
}
}
}
}
+/* Interrupt Hierarchy
+ DIEPINT DIEPINT
+ \ /
+ \ /
+ DAINT
+ / \
+ / \
+ GINTSTS: OEPInt IEPInt | USBReset | EnumDone | USBSusp | WkUpInt | OTGInt | SOF | RXFLVL
+
+ Note: when OTG_MULTI_PROC_INTRPT = 1, Device Each endpoint interrupt deachint/deachmsk/diepeachmsk/doepeachmsk
+ are combined to generate dedicated interrupt line for each endpoint.
+ */
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;
+ const uint32_t gintmask = dwc2->gintmsk;
+ const uint32_t gintsts = dwc2->gintsts & gintmask;
- if (int_status & GINTSTS_USBRST) {
+ if (gintsts & GINTSTS_USBRST) {
// USBRST is start of reset.
dwc2->gintsts = GINTSTS_USBRST;
- bus_reset(rhport);
+ handle_bus_reset(rhport);
}
- if (int_status & GINTSTS_ENUMDNE) {
+ if (gintsts & 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);
+ handle_enum_done(rhport);
}
- if (int_status & GINTSTS_USBSUSP) {
+ if (gintsts & GINTSTS_USBSUSP) {
dwc2->gintsts = GINTSTS_USBSUSP;
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
}
- if (int_status & GINTSTS_WKUINT) {
+ if (gintsts & GINTSTS_WKUINT) {
dwc2->gintsts = GINTSTS_WKUINT;
dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
}
@@ -1138,9 +1012,9 @@ void dcd_int_handler(uint8_t rhport) {
// TODO check GINTSTS_DISCINT for disconnect detection
// if(int_status & GINTSTS_DISCINT)
- if (int_status & GINTSTS_OTGINT) {
+ if (gintsts & GINTSTS_OTGINT) {
// OTG INT bit is read-only
- uint32_t const otg_int = dwc2->gotgint;
+ const uint32_t otg_int = dwc2->gotgint;
if (otg_int & GOTGINT_SEDET) {
dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
@@ -1149,50 +1023,43 @@ void dcd_int_handler(uint8_t rhport) {
dwc2->gotgint = otg_int;
}
- if(int_status & GINTSTS_SOF) {
+ if(gintsts & 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) {
+ if (!_dcd_data.sof_en) {
dwc2->gintmsk &= ~GINTMSK_SOFM;
}
dcd_event_sof(rhport, frame, true);
}
+#if CFG_TUD_DWC2_SLAVE_ENABLE
// RxFIFO non-empty interrupt handling.
- if (int_status & GINTSTS_RXFLVL) {
+ if (gintsts & GINTSTS_RXFLVL) {
// RXFLVL bit is read-only
+ dwc2->gintmsk &= ~GINTMSK_RXFLVLM; // disable RXFLVL interrupt while reading
- // Mask out RXFLVL while reading data from FIFO
- dwc2->gintmsk &= ~GINTMSK_RXFLVLM;
-
- // Loop until all available packets were handled
do {
- handle_rxflvl_irq(rhport);
+ handle_rxflvl_irq(rhport); // read all packets
} while(dwc2->gintsts & GINTSTS_RXFLVL);
dwc2->gintmsk |= GINTMSK_RXFLVLM;
}
+#endif
// OUT endpoint interrupt handling.
- if (int_status & GINTSTS_OEPINT) {
+ if (gintsts & GINTSTS_OEPINT) {
// OEPINT is read-only, clear using DOEPINTn
- handle_epout_irq(rhport);
+ handle_ep_irq(rhport, TUSB_DIR_OUT);
}
// IN endpoint interrupt handling.
- if (int_status & GINTSTS_IEPINT) {
+ if (gintsts & GINTSTS_IEPINT) {
// IEPINT bit read-only, clear using DIEPINTn
- handle_epin_irq(rhport);
+ handle_ep_irq(rhport, TUSB_DIR_IN);
}
-
- // // Check for Incomplete isochronous IN transfer
- // if(int_status & GINTSTS_IISOIXFR) {
- // printf(" IISOIXFR!\r\n");
- //// TU_LOG(DWC2_DEBUG, " IISOIXFR!\r\n");
- // }
}
#if CFG_TUD_TEST_MODE
diff --git a/src/portable/synopsys/dwc2/dwc2_bcm.h b/src/portable/synopsys/dwc2/dwc2_bcm.h
index 732d96ae0..e5824606a 100644
--- a/src/portable/synopsys/dwc2/dwc2_bcm.h
+++ b/src/portable/synopsys/dwc2/dwc2_bcm.h
@@ -39,7 +39,7 @@
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 }
+ { .reg_base = USB_OTG_GLOBAL_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 16384 }
};
#define dcache_clean(_addr, _size) data_clean(_addr, _size)
diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c
new file mode 100644
index 000000000..f80ae9acb
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_common.c
@@ -0,0 +1,311 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 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"
+
+#define DWC2_COMMON_DEBUG 2
+
+#if defined(TUP_USBIP_DWC2) && (CFG_TUH_ENABLED || CFG_TUD_ENABLED)
+
+#if CFG_TUD_ENABLED
+#include "device/dcd.h"
+#endif
+
+#if CFG_TUH_ENABLED
+#include "host/hcd.h"
+#endif
+
+#include "dwc2_common.h"
+
+//--------------------------------------------------------------------
+//
+//--------------------------------------------------------------------
+static void reset_core(dwc2_regs_t* dwc2) {
+ // reset core
+ dwc2->grstctl |= GRSTCTL_CSRST;
+
+ if ((dwc2->gsnpsid & DWC2_CORE_REV_MASK) < (DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) {
+ // prior v42.0 CSRST is self-clearing
+ while (dwc2->grstctl & GRSTCTL_CSRST) {}
+ } else {
+ // From v4.20a CSRST bit is write only, CSRT_DONE (w1c) is introduced for checking.
+ // CSRST must also be explicitly cleared
+ while (!(dwc2->grstctl & GRSTCTL_CSRST_DONE)) {}
+ dwc2->grstctl = (dwc2->grstctl & ~GRSTCTL_CSRST) | GRSTCTL_CSRST_DONE;
+ }
+
+ while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {} // wait for AHB master IDLE
+}
+
+static void phy_fs_init(dwc2_regs_t* dwc2) {
+ TU_LOG(DWC2_COMMON_DEBUG, "Fullspeed PHY init\r\n");
+
+ uint32_t gusbcfg = dwc2->gusbcfg;
+
+ // Select FS PHY
+ gusbcfg |= GUSBCFG_PHYSEL;
+ dwc2->gusbcfg = gusbcfg;
+
+ // MCU specific PHY init before reset
+ dwc2_phy_init(dwc2, GHWCFG2_HSPHY_NOT_SUPPORTED);
+
+ // 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
+ gusbcfg &= ~GUSBCFG_TRDT_Msk;
+ gusbcfg |= 5u << GUSBCFG_TRDT_Pos;
+ dwc2->gusbcfg = gusbcfg;
+
+ // MCU specific PHY update post reset
+ dwc2_phy_update(dwc2, GHWCFG2_HSPHY_NOT_SUPPORTED);
+}
+
+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 == GHWCFG2_HSPHY_ULPI) {
+ TU_LOG(DWC2_COMMON_DEBUG, "Highspeed ULPI PHY init\r\n");
+
+ // Select ULPI PHY (external)
+ gusbcfg |= GUSBCFG_ULPI_UTMI_SEL;
+
+ // ULPI is always 8-bit interface
+ gusbcfg &= ~GUSBCFG_PHYIF16;
+
+ // ULPI select single data rate
+ gusbcfg &= ~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_COMMON_DEBUG, "Highspeed UTMI+ PHY init\r\n");
+
+ // Select UTMI+ PHY (internal)
+ gusbcfg &= ~GUSBCFG_ULPI_UTMI_SEL;
+
+ // Set 16-bit interface if supported
+ if (dwc2->ghwcfg4_bm.phy_data_width) {
+ gusbcfg |= GUSBCFG_PHYIF16; // 16 bit
+ } else {
+ gusbcfg &= ~GUSBCFG_PHYIF16; // 8 bit
+ }
+ }
+
+ // 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.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);
+}
+
+static bool check_dwc2(dwc2_regs_t* dwc2) {
+#if CFG_TUSB_DEBUG >= DWC2_COMMON_DEBUG
+ // print guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4
+ // Run 'python dwc2_info.py' and check dwc2_info.md for bit-field value and comparison with other ports
+ volatile uint32_t const* p = (volatile uint32_t const*) &dwc2->guid;
+ TU_LOG1("guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4\r\n");
+ for (size_t i = 0; i < 5; i++) {
+ TU_LOG1("0x%08" PRIX32 ", ", p[i]);
+ }
+ TU_LOG1("0x%08" PRIX32 "\r\n", p[5]);
+#endif
+
+ // For some reason: GD32VF103 gsnpsid and all hwcfg register are always zero (skip it)
+ (void)dwc2;
+#if !TU_CHECK_MCU(OPT_MCU_GD32VF103)
+ enum { GSNPSID_ID_MASK = TU_GENMASK(31, 16) };
+ const uint32_t 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;
+}
+
+//--------------------------------------------------------------------
+//
+//--------------------------------------------------------------------
+bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) {
+ (void)dwc2;
+
+#if CFG_TUD_ENABLED
+ if (role == TUSB_ROLE_DEVICE && !TUD_OPT_HIGH_SPEED) {
+ return false;
+ }
+#endif
+#if CFG_TUH_ENABLED
+ if (role == TUSB_ROLE_HOST && !TUH_OPT_HIGH_SPEED) {
+ return false;
+ }
+#endif
+
+ return dwc2->ghwcfg2_bm.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED;
+}
+
+/* dwc2 has several PHYs option
+ * - UTMI+ is internal highspeed PHY, clock can be 30 Mhz (8-bit) or 60 Mhz (16-bit)
+ * - ULPI is external highspeed PHY, clock is 60Mhz with only 8-bit interface
+ * - Dedicated FS PHY is internal with clock 48Mhz.
+ *
+ * In addition, UTMI+/ULPI can be shared to run at fullspeed mode with 48Mhz
+ *
+*/
+bool dwc2_core_init(uint8_t rhport, bool is_highspeed, bool is_dma) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ // Check Synopsys ID register, failed if controller clock/power is not enabled
+ TU_ASSERT(check_dwc2(dwc2));
+
+ // disable global interrupt
+ dwc2->gahbcfg &= ~GAHBCFG_GINT;
+
+ if (is_highspeed) {
+ phy_hs_init(dwc2);
+ } else {
+ phy_fs_init(dwc2);
+ }
+
+ /* 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);
+
+ // Enable PHY clock TODO stop/gate clock when suspended mode
+ dwc2->pcgcctl &= ~(PCGCCTL_STOPPCLK | PCGCCTL_GATEHCLK | PCGCCTL_PWRCLMP | PCGCCTL_RSTPDWNMODULE);
+
+ dfifo_flush_tx(dwc2, 0x10); // all tx fifo
+ dfifo_flush_rx(dwc2);
+
+ // Clear pending and disable all interrupts
+ dwc2->gintsts = 0xFFFFFFFFU;
+ dwc2->gotgint = 0xFFFFFFFFU;
+ dwc2->gintmsk = 0;
+
+ TU_LOG(DWC2_COMMON_DEBUG, "DMA = %u\r\n", is_dma);
+
+ if (is_dma) {
+ // DMA seems to be only settable after a core reset, and not possible to switch on-the-fly
+ dwc2->gahbcfg |= GAHBCFG_DMAEN | GAHBCFG_HBSTLEN_2;
+ } else {
+ dwc2->gintmsk |= GINTSTS_RXFLVL;
+ }
+
+ return true;
+}
+
+// void dwc2_core_handle_common_irq(uint8_t rhport, bool in_isr) {
+// (void) in_isr;
+// dwc2_regs_t * const dwc2 = DWC2_REG(rhport);
+// const uint32_t int_mask = dwc2->gintmsk;
+// const uint32_t int_status = dwc2->gintsts & int_mask;
+//
+// // Device disconnect
+// if (int_status & GINTSTS_DISCINT) {
+// dwc2->gintsts = GINTSTS_DISCINT;
+// }
+//
+// }
+
+//--------------------------------------------------------------------
+// DFIFO
+//--------------------------------------------------------------------
+// Read a single data packet from receive DFIFO
+void dfifo_read_packet(dwc2_regs_t* dwc2, uint8_t* dst, uint16_t len) {
+ const volatile uint32_t* rx_fifo = dwc2->fifo[0];
+
+ // Reading full available 32 bit words from fifo
+ uint16_t word_count = len >> 2;
+ while (word_count--) {
+ tu_unaligned_write32(dst, *rx_fifo);
+ dst += 4;
+ }
+
+ // Read the remaining 1-3 bytes from fifo
+ const uint8_t bytes_rem = len & 0x03;
+ if (bytes_rem != 0) {
+ const uint32_t 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 DFIFO
+void dfifo_write_packet(dwc2_regs_t* dwc2, uint8_t fifo_num, const uint8_t* src, uint16_t len) {
+ volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num];
+
+ // Pushing full available 32 bit words to fifo
+ uint16_t word_count = len >> 2;
+ while (word_count--) {
+ *tx_fifo = tu_unaligned_read32(src);
+ src += 4;
+ }
+
+ // Write the remaining 1-3 bytes into fifo
+ const uint8_t 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;
+ }
+}
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_common.h b/src/portable/synopsys/dwc2/dwc2_common.h
new file mode 100644
index 000000000..18b93894f
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_common.h
@@ -0,0 +1,101 @@
+/*
+* The MIT License (MIT)
+ *
+ * Copyright (c) 2024 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_COMMON_H
+#define TUSB_DWC2_COMMON_H
+
+#include "common/tusb_common.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 defined(TUP_USBIP_DWC2_ESP32)
+ #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
+
+enum {
+ DWC2_CONTROLLER_COUNT = TU_ARRAY_SIZE(_dwc2_controller)
+};
+
+enum {
+ OTG_INT_COMMON = 0 // GINTSTS_DISCINT | GINTSTS_CONIDSTSCHNG
+};
+
+//--------------------------------------------------------------------+
+// Core/Controller
+//--------------------------------------------------------------------+
+TU_ATTR_ALWAYS_INLINE static inline dwc2_regs_t* DWC2_REG(uint8_t rhport) {
+ if (rhport >= DWC2_CONTROLLER_COUNT) {
+ // user mis-configured, ignore and use first controller
+ rhport = 0;
+ }
+ return (dwc2_regs_t*)_dwc2_controller[rhport].reg_base;
+}
+
+bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role);
+bool dwc2_core_init(uint8_t rhport, bool is_highspeed, bool is_dma);
+void dwc2_core_handle_common_irq(uint8_t rhport, bool in_isr);
+
+//--------------------------------------------------------------------+
+// DFIFO
+//--------------------------------------------------------------------+
+TU_ATTR_ALWAYS_INLINE static inline void dfifo_flush_tx(dwc2_regs_t* dwc2, uint8_t fnum) {
+ // flush TX fifo and wait for it cleared
+ dwc2->grstctl = GRSTCTL_TXFFLSH | (fnum << GRSTCTL_TXFNUM_Pos);
+ while (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) {}
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void dfifo_flush_rx(dwc2_regs_t* dwc2) {
+ // flush RX fifo and wait for it cleared
+ dwc2->grstctl = GRSTCTL_RXFFLSH;
+ while (dwc2->grstctl & GRSTCTL_RXFFLSH_Msk) {}
+}
+
+void dfifo_read_packet(dwc2_regs_t* dwc2, uint8_t* dst, uint16_t len);
+void dfifo_write_packet(dwc2_regs_t* dwc2, uint8_t fifo_num, uint8_t const* src, uint16_t len);
+
+//--------------------------------------------------------------------+
+// DMA
+//--------------------------------------------------------------------+
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h
index 932f52f40..3309760ff 100644
--- a/src/portable/synopsys/dwc2/dwc2_esp32.h
+++ b/src/portable/synopsys/dwc2/dwc2_esp32.h
@@ -25,73 +25,134 @@
*/
-#ifndef _DWC2_ESP32_H_
-#define _DWC2_ESP32_H_
+#ifndef TUSB_DWC2_ESP32_H_
+#define TUSB_DWC2_ESP32_H_
#ifdef __cplusplus
extern "C" {
#endif
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
#include "esp_intr_alloc.h"
#include "soc/periph_defs.h"
-//#include "soc/usb_periph.h"
-#include "freertos/task.h"
+#include "soc/usb_wrap_struct.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)
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+#define DWC2_FS_REG_BASE 0x60080000UL
+#define DWC2_EP_MAX 7
-static const dwc2_controller_t _dwc2_controller[] =
-{
- { .reg_base = DWC2_REG_BASE, .irqnum = 0, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1024 }
+static const dwc2_controller_t _dwc2_controller[] = {
+ { .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 }
};
-static intr_handle_t usb_ih;
+#elif TU_CHECK_MCU(OPT_MCU_ESP32P4)
+#define DWC2_FS_REG_BASE 0x50040000UL
+#define DWC2_HS_REG_BASE 0x50000000UL
+#define DWC2_EP_MAX 16
-static void dcd_int_handler_wrap(void* arg)
-{
- (void) arg;
- dcd_int_handler(0);
-}
+// On ESP32 for consistency we associate
+// - Port0 to OTG_FS, and Port1 to OTG_HS
+static const dwc2_controller_t _dwc2_controller[] = {
+{ .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_CH0_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 },
+{ .reg_base = DWC2_HS_REG_BASE, .irqnum = ETS_USB_OTG_INTR_SOURCE, .ep_count = 16, .ep_in_count = 8, .ep_fifo_size = 4096 }
+};
+#endif
-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);
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+static intr_handle_t usb_ih[TU_ARRAY_SIZE(_dwc2_controller)];
+
+static void dwc2_int_handler_wrap(void* arg) {
+ const uint8_t rhport = tu_u16_low((uint16_t)(uintptr_t)arg);
+ const tusb_role_t role = (tusb_role_t) tu_u16_high((uint16_t)(uintptr_t)arg);
+#if CFG_TUD_ENABLED
+ if (role == TUSB_ROLE_DEVICE) {
+ dcd_int_handler(rhport);
+ }
+#endif
+#if CFG_TUH_ENABLED && !CFG_TUH_MAX3421
+ if (role == TUSB_ROLE_HOST) {
+ hcd_int_handler(rhport, true);
+ }
+#endif
}
-TU_ATTR_ALWAYS_INLINE
-static inline void dwc2_dcd_int_disable (uint8_t rhport)
-{
- (void) rhport;
- esp_intr_free(usb_ih);
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_int_set(uint8_t rhport, tusb_role_t role, bool enabled) {
+ if (enabled) {
+ esp_intr_alloc(_dwc2_controller[rhport].irqnum, ESP_INTR_FLAG_LOWMED,
+ dwc2_int_handler_wrap, (void*)(uintptr_t)tu_u16(role, rhport), &usb_ih[rhport]);
+ } else {
+ esp_intr_free(usb_ih[rhport]);
+ }
}
-static inline void dwc2_remote_wakeup_delay(void)
-{
+#define dwc2_dcd_int_enable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, true)
+#define dwc2_dcd_int_disable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, false)
+
+TU_ATTR_ALWAYS_INLINE 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;
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
+ (void)dwc2;
+ (void)hs_phy_type;
+ // maybe usb_utmi_hal_init()
- // 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;
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
+ (void)dwc2;
+ (void)hs_phy_type;
+ // maybe usb_utmi_hal_disable()
+}
+
+//--------------------------------------------------------------------+
+// Data Cache
+//--------------------------------------------------------------------+
+#if CFG_TUD_DWC2_DMA_ENABLE || CFG_TUH_DWC2_DMA_ENABLE
+#if defined(SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE) && SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
+#include "esp_cache.h"
- // nothing to do
+#if CFG_TUD_MEM_DCACHE_LINE_SIZE != CONFIG_CACHE_L1_CACHE_LINE_SIZE || \
+ CFG_TUH_MEM_DCACHE_LINE_SIZE != CONFIG_CACHE_L1_CACHE_LINE_SIZE
+#error "CFG_TUD/TUH_MEM_DCACHE_LINE_SIZE must match CONFIG_CACHE_L1_CACHE_LINE_SIZE"
+#endif
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t round_up_to_cache_line_size(uint32_t size) {
+ if (size & (CONFIG_CACHE_L1_CACHE_LINE_SIZE-1)) {
+ size = (size & ~(CONFIG_CACHE_L1_CACHE_LINE_SIZE-1)) + CONFIG_CACHE_L1_CACHE_LINE_SIZE;
+ }
+ return size;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_clean(const void* addr, uint32_t data_size) {
+ const int flag = ESP_CACHE_MSYNC_FLAG_TYPE_DATA | ESP_CACHE_MSYNC_FLAG_DIR_C2M;
+ data_size = round_up_to_cache_line_size(data_size);
+ return ESP_OK == esp_cache_msync((void*)addr, data_size, flag);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_invalidate(const void* addr, uint32_t data_size) {
+ const int flag = ESP_CACHE_MSYNC_FLAG_TYPE_DATA | ESP_CACHE_MSYNC_FLAG_DIR_M2C;
+ data_size = round_up_to_cache_line_size(data_size);
+ return ESP_OK == esp_cache_msync((void*)addr, data_size, flag);
}
+TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
+ const int flag = ESP_CACHE_MSYNC_FLAG_TYPE_DATA | ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_DIR_M2C;
+ data_size = round_up_to_cache_line_size(data_size);
+ return ESP_OK == esp_cache_msync((void*)addr, data_size, flag);
+}
+
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
-#endif /* _DWC2_ESP32_H_ */
+#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_info.md b/src/portable/synopsys/dwc2/dwc2_info.md
index 8690a0755..dec021f59 100644
--- a/src/portable/synopsys/dwc2/dwc2_info.md
+++ b/src/portable/synopsys/dwc2/dwc2_info.md
@@ -1,55 +1,58 @@
-| | 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 |
+| | BCM2711 (Pi4) | EFM32GG | ESP32-S2/S3 | ESP32-P4 | ST F207/F407/411/429 FS | ST F407/429 HS | ST F412/76x FS | ST F723/L4P5 FS | ST F723 HS | ST F76x HS | ST H743/H750 | ST L476 FS | ST U5A5 HS | XMC4500 | GD32VF103 |
+|:---------------------------|:----------------|:-------------|:--------------|:-------------|:--------------------------|:-----------------|:-----------------|:------------------|:-------------|:-------------|:---------------|:-------------|:-------------|:-------------|:------------|
+| GUID | 0x2708A000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00001200 | 0x00001100 | 0x00002000 | 0x00003000 | 0x00003100 | 0x00002100 | 0x00002300 | 0x00002000 | 0x00005000 | 0x00AEC000 | 0x00001000 |
+| GSNPSID | 0x4F54280A | 0x4F54330A | 0x4F54400A | 0x4F54400A | 0x4F54281A | 0x4F54281A | 0x4F54320A | 0x4F54330A | 0x4F54330A | 0x4F54320A | 0x4F54330A | 0x4F54310A | 0x4F54411A | 0x4F54292A | 0x00000000 |
+| - specs version | 2.80a | 3.30a | 4.00a | 4.00a | 2.81a | 2.81a | 3.20a | 3.30a | 3.30a | 3.20a | 3.30a | 3.10a | 4.11a | 2.92a | 0.00W |
+| GHWCFG1 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 |
+| GHWCFG2 | 0x228DDD50 | 0x228F5910 | 0x224DD930 | 0x215FFFD0 | 0x229DCD20 | 0x229ED590 | 0x229ED520 | 0x229ED520 | 0x229FE1D0 | 0x229FE190 | 0x229FE190 | 0x229ED520 | 0x228FE052 | 0x228F5930 | 0x00000000 |
+| - op_mode | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | noHNP noSRP | HNP SRP | HNP SRP |
+| - arch | DMA internal | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | Slave only | Slave only | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | DMA internal | Slave only |
+| - single_point | hub | hub | n/a | hub | n/a | hub | n/a | n/a | hub | hub | hub | n/a | hub | n/a | hub |
+| - hs_phy_type | UTMI+ | n/a | n/a | UTMI+/ULPI | n/a | ULPI | n/a | n/a | UTMI+/ULPI | ULPI | ULPI | n/a | UTMI+ | n/a | n/a |
+| - fs_phy_type | Dedicated | Dedicated | Dedicated | Shared ULPI | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | n/a | Dedicated | n/a |
+| - num_dev_ep | 7 | 6 | 6 | 15 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
+| - num_host_ch | 7 | 13 | 7 | 15 | 7 | 11 | 11 | 11 | 15 | 15 | 15 | 11 | 15 | 13 | 0 |
+| - period_channel_support | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - enable_dynamic_fifo | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - mul_proc_intrpt | 0 | 0 | 0 | 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 |
+| - nptx_q_depth | 8 | 8 | 4 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
+| - ptx_q_depth | 8 | 8 | 8 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
+| - token_q_depth | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 |
+| - otg_enable_ic_usb | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| GHWCFG3 | 0x0FF000E8 | 0x01F204E8 | 0x00C804B5 | 0x03805EB5 | 0x020001E8 | 0x03F403E8 | 0x0200D1E8 | 0x0200D1E8 | 0x03EED2E8 | 0x03EED2E8 | 0x03B8D2E8 | 0x0200D1E8 | 0x03B882E8 | 0x027A01E5 | 0x00000000 |
+| - xfer_size_width | 8 | 8 | 5 | 5 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 5 | 0 |
+| - packet_size_width | 6 | 6 | 3 | 3 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 0 |
+| - otg_enable | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - i2c_enable | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
+| - vendor_ctrl_itf | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 |
+| - optional_feature_removed | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - synch_reset | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - otg_adp_support | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 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 |
+| - battery_charger_support | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - lpm_mode | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
+| - dfifo_depth | 4080 | 498 | 200 | 896 | 512 | 1012 | 512 | 512 | 1006 | 1006 | 952 | 512 | 952 | 634 | 0 |
+| GHWCFG4 | 0x1FF00020 | 0x1BF08030 | 0xD3F0A030 | 0xDFF1A030 | 0x0FF08030 | 0x17F00030 | 0x17F08030 | 0x17F08030 | 0x23F00030 | 0x23F00030 | 0xE3F00030 | 0x17F08030 | 0xE2103E30 | 0xDBF08030 | 0x00000000 |
+| - num_dev_period_in_ep | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - partial_powerdown | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - ahb_freq_min | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - extended_hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - reserved8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - enhanced_lpm_support1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - service_interval_flow | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - ipg_isoc_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - acg_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - enhanced_lpm_support | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - phy_data_width | 8 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8 bit | 8/16 bit | 8/16 bit | 8 bit | 8 bit | 8 bit | 8/16 bit | 8 bit | 8/16 bit | 8 bit |
+| - ctrl_ep_num | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - iddg_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - vbus_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - a_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - b_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - session_end_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - dedicated_fifos | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - num_dev_in_eps | 7 | 6 | 4 | 7 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
+| - dma_desc_enable | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
+| - dma_desc_dynamic | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
diff --git a/src/portable/synopsys/dwc2/dwc2_info.py b/src/portable/synopsys/dwc2/dwc2_info.py
index 55bec3d23..25edcf22d 100644..100755
--- a/src/portable/synopsys/dwc2/dwc2_info.py
+++ b/src/portable/synopsys/dwc2/dwc2_info.py
@@ -1,38 +1,40 @@
-import click
+#!/usr/bin/env python3
+
import ctypes
+import argparse
+import click
import pandas as pd
# hex value for register: guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4
-dwc2_reg_list = ['guid', 'gsnpsid', 'ghwcfg1', 'ghwcfg2', 'ghwcfg3', 'ghwcfg4']
+# Note: FS is FullSpeed, HS is HighSpeed
+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]
+ 'EFM32GG': [0, 0x4F54330A, 0, 0x228F5910, 0x01F204E8, 0x1BF08030],
+ 'ESP32-S2/S3': [0, 0x4F54400A, 0, 0x224DD930, 0x0C804B5, 0xD3F0A030],
+ 'ESP32-P4': [0, 0x4F54400A, 0, 0x215FFFD0, 0x03805EB5, 0xDFF1A030],
+ 'ST F207/F407/411/429 FS': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x020001E8, 0x0FF08030],
+ 'ST F407/429 HS': [0x1100, 0x4F54281A, 0, 0x229ED590, 0x03F403E8, 0x17F00030],
+ 'ST F412/76x FS': [0x2000, 0x4F54320A, 0, 0x229ED520, 0x0200D1E8, 0x17F08030],
+ 'ST F723/L4P5 FS': [0x3000, 0x4F54330A, 0, 0x229ED520, 0x0200D1E8, 0x17F08030],
+ 'ST F723 HS': [0x3100, 0x4F54330A, 0, 0x229FE1D0, 0x03EED2E8, 0x23F00030],
+ 'ST F76x HS': [0x2100, 0x4F54320A, 0, 0x229FE190, 0x03EED2E8, 0x23F00030],
+ 'ST H743/H750': [0x2300, 0x4F54330A, 0, 0x229FE190, 0x03B8D2E8, 0xE3F00030],
+ 'ST L476 FS': [0x2000, 0x4F54310A, 0, 0x229ED520, 0x0200D1E8, 0x17F08030],
+ 'ST U5A5 HS': [0x5000, 0x4F54411A, 0, 0x228FE052, 0x03B882E8, 0xE2103E30],
+ 'XMC4500': [0xAEC000, 0x4F54292A, 0, 0x228F5930, 0x027A01E5, 0xDBF08030],
+ 'GD32VF103': [0x1000, 0, 0, 0, 0, 0],
}
# Combine dwc2_info with dwc2_reg_list
# dwc2_info = {
# 'BCM2711 (Pi4)': {
-# 'guid': 0x2708A000,
-# 'gsnpsid': 0x4F54280A,
-# 'ghwcfg1': 0,
-# 'ghwcfg2': 0x228DDD50,
-# 'ghwcfg3': 0xFF000E8,
-# 'ghwcfg4': 0x1FF00020
+# '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()}
@@ -41,18 +43,18 @@ class GHWCFG2(ctypes.LittleEndianStructure):
_fields_ = [
("op_mode", ctypes.c_uint32, 3),
("arch", ctypes.c_uint32, 2),
- ("point2point", ctypes.c_uint32, 1),
+ ("single_point", ctypes.c_uint32, 1),
("hs_phy_type", ctypes.c_uint32, 2),
("fs_phy_type", ctypes.c_uint32, 2),
("num_dev_ep", ctypes.c_uint32, 4),
("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),
+ ("mul_proc_intrpt", 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),
+ ("nptx_q_depth", ctypes.c_uint32, 2),
+ ("ptx_q_depth", ctypes.c_uint32, 2),
+ ("token_q_depth", ctypes.c_uint32, 5),
("otg_enable_ic_usb", ctypes.c_uint32, 1)
]
@@ -70,90 +72,129 @@ class GHWCFG3(ctypes.LittleEndianStructure):
("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)
+ ("dfifo_depth", ctypes.c_uint32, 16)
]
class GHWCFG4(ctypes.LittleEndianStructure):
_fields_ = [
("num_dev_period_in_ep", ctypes.c_uint32, 4),
- ("power_optimized", ctypes.c_uint32, 1),
+ ("partial_powerdown", 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),
+ ("extended_hibernation", ctypes.c_uint32, 1),
+ ("reserved8", ctypes.c_uint32, 1),
+ ("enhanced_lpm_support1", ctypes.c_uint32, 1),
+ ("service_interval_flow", ctypes.c_uint32, 1),
+ ("ipg_isoc_support", ctypes.c_uint32, 1),
+ ("acg_support", ctypes.c_uint32, 1),
+ ("enhanced_lpm_support", ctypes.c_uint32, 1),
+ ("phy_data_width", ctypes.c_uint32, 2),
+ ("ctrl_ep_num", ctypes.c_uint32, 4),
+ ("iddg_filter", ctypes.c_uint32, 1),
+ ("vbus_valid_filter", ctypes.c_uint32, 1),
+ ("a_valid_filter", ctypes.c_uint32, 1),
+ ("b_valid_filter", ctypes.c_uint32, 1),
+ ("session_end_filter", 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)
+ ("dma_desc_dynamic", ctypes.c_uint32, 1)
]
+# mapping for specific fields in GHWCFG2
+GHWCFG2_field = {
+ 'op_mode': {
+ 0: "HNP SRP",
+ 1: "SRP",
+ 2: "noHNP noSRP",
+ 3: "SRP Device",
+ 4: "noOTG Device",
+ 5: "SRP Host",
+ 6: "noOTG Host"
+ },
+ 'arch': {
+ 0: "Slave only",
+ 1: "DMA external",
+ 2: "DMA internal"
+ },
+ 'single_point': {
+ 0: "hub",
+ 1: "n/a"
+ },
+ 'hs_phy_type': {
+ 0: "n/a",
+ 1: "UTMI+",
+ 2: "ULPI",
+ 3: "UTMI+/ULPI"
+ },
+ 'fs_phy_type': {
+ 0: "n/a",
+ 1: "Dedicated",
+ 2: "Shared UTMI+",
+ 3: "Shared ULPI"
+ },
+ 'nptx_q_depth': {
+ 0: "2",
+ 1: "4",
+ 2: "8",
+ },
+ 'ptx_q_depth': {
+ 0: "2",
+ 1: "4",
+ 2: "8",
+ 3: "16"
+ },
+}
-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
+# mapping for specific fields in GHWCFG4
+GHWCFG4_field = {
+ 'phy_data_width': {
+ 0: "8 bit",
+ 1: "16 bit",
+ 2: "8/16 bit",
+ 3: "Reserved"
+ },
+ }
- 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 main():
+ """Render dwc2_info to Markdown table"""
+ parser = argparse.ArgumentParser()
+ args = parser.parse_args()
-def render_md():
- """Render dwc2_info to Markdown table"""
# Create an empty list to hold the dictionaries
- dwc2_info_list = []
+ md_table = []
# Iterate over the dwc2_info dictionary and extract fields
for device, reg_values in dwc2_info.items():
- entry_dict = {"Device": device}
+ md_item = {"Device": device}
for r_name, r_value in reg_values.items():
- entry_dict[r_name] = f"0x{r_value:08X}"
+ md_item[r_name] = f"0x{r_value:08X}"
- if r_name == 'gsnpsid':
+ 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():
+ md_item[f' - specs version'] = f"{major:X}.{minor:02X}{patch}"
+ elif r_name 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)
+ class_hdl = globals()[r_name]
+ ghwcfg = class_hdl.from_buffer_copy(r_value.to_bytes(4, byteorder='little'))
+ for field_name, field_type, _ in class_hdl._fields_:
+ field_value = getattr(ghwcfg, field_name)
+ if class_hdl == GHWCFG2 and field_name in GHWCFG2_field:
+ field_value = GHWCFG2_field[field_name].get(field_value, f"Unknown ({field_value})")
+ if class_hdl == GHWCFG4 and field_name in GHWCFG4_field:
+ field_value = GHWCFG4_field[field_name].get(field_value, f"Unknown ({field_value})")
+
+ md_item[f' - {field_name}'] = field_value
- dwc2_info_list.append(entry_dict)
+ md_table.append(md_item)
# Create a Pandas DataFrame from the list of dictionaries
- df = pd.DataFrame(dwc2_info_list).set_index('Device')
+ df = pd.DataFrame(md_table).set_index('Device')
# Transpose the DataFrame to switch rows and columns
df = df.T
@@ -166,4 +207,4 @@ def render_md():
if __name__ == '__main__':
- cli()
+ main()
diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h
index 3237a50f6..c11c1eb05 100644
--- a/src/portable/synopsys/dwc2/dwc2_stm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_stm32.h
@@ -69,6 +69,14 @@ extern "C" {
#define OTG_FS_IRQn OTG_HS_IRQn
#endif
+#elif CFG_TUSB_MCU == OPT_MCU_STM32H7RS
+ #include "stm32h7rsxx.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_STM32F7
#include "stm32f7xx.h"
#define EP_MAX_FS 6
@@ -124,13 +132,19 @@ static const dwc2_controller_t _dwc2_controller[] = {
// 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_int_set(uint8_t rhport, tusb_role_t role, bool enabled) {
+ (void) role;
+ const IRQn_Type irqn = (IRQn_Type) _dwc2_controller[rhport].irqnum;
+ if (enabled) {
+ NVIC_EnableIRQ(irqn);
+ } else {
+ NVIC_DisableIRQ(irqn);
+ }
}
-TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_disable(uint8_t rhport) {
- NVIC_DisableIRQ((IRQn_Type) _dwc2_controller[rhport].irqnum);
-}
+#define dwc2_dcd_int_enable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, true)
+#define dwc2_dcd_int_disable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, false)
+
TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) {
// try to delay for 1 ms
@@ -142,7 +156,7 @@ TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) {
// - 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) {
+ if (hs_phy_type == GHWCFG2_HSPHY_NOT_SUPPORTED) {
// Enable on-chip FS PHY
dwc2->stm32_gccfg |= STM32_GCCFG_PWRDWN;
@@ -175,7 +189,7 @@ static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
#endif
// Enable on-chip HS PHY
- if (hs_phy_type == HS_PHY_TYPE_UTMI || hs_phy_type == HS_PHY_TYPE_UTMI_ULPI) {
+ if (hs_phy_type == GHWCFG2_HSPHY_UTMI || hs_phy_type == GHWCFG2_HSPHY_UTMI_ULPI) {
#ifdef USB_HS_PHYC
// Enable UTMI HS PHY
dwc2->stm32_gccfg |= STM32_GCCFG_PHYHSEN;
@@ -218,7 +232,7 @@ static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
// 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) {
+ if (hs_phy_type == GHWCFG2_HSPHY_NOT_SUPPORTED) {
// Turnaround timeout depends on the AHB clock dictated by STM32 Reference Manual
uint32_t turnaround;
diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h
index cb694b326..812096759 100644
--- a/src/portable/synopsys/dwc2/dwc2_type.h
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -31,8 +31,8 @@
* opensource.org/licenses/BSD-3-Clause
*/
-#ifndef _TUSB_DWC2_TYPES_H_
-#define _TUSB_DWC2_TYPES_H_
+#ifndef TUSB_DWC2_TYPES_H_
+#define TUSB_DWC2_TYPES_H_
#include "stdint.h"
@@ -46,6 +46,7 @@ typedef struct
uintptr_t reg_base;
uint32_t irqnum;
uint8_t ep_count;
+ uint8_t ep_in_count;
uint32_t ep_fifo_size;
}dwc2_controller_t;
@@ -86,220 +87,706 @@ typedef struct
#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 ,
+ GOTGCTL_OTG_VERSION_1_3 = 0,
+ GOTGCTL_OTG_VERSION_2_0 = 1,
};
enum {
- FS_PHY_TYPE_NONE = 0, // not supported
- FS_PHY_TYPE_DEDICATED,
- FS_PHY_TYPE_UTMI,
- FS_PHY_TYPE_ULPI,
+ GHWCFG2_OPMODE_HNP_SRP = 0,
+ GHWCFG2_OPMODE_SRP = 1,
+ GHWCFG2_OPMODE_NON_HNP_NON_SRP = 2,
+ GHWCFG2_OPMODE_SRP_DEVICE = 3,
+ GHWCFFG2_OPMODE_NON_OTG_DEVICE = 4,
+ GHWCFG2_OPMODE_SRP_HOST = 5,
+ GHWCFG2_OPMODE_NON_OTG_HOST = 6,
+};
+enum {
+ GHWCFG2_ARCH_SLAVE_ONLY = 0,
+ GHWCFG2_ARCH_EXTERNAL_DMA = 1,
+ GHWCFG2_ARCH_INTERNAL_DMA = 2,
};
-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;
+enum {
+ GHWCFG2_HSPHY_NOT_SUPPORTED = 0,
+ GHWCFG2_HSPHY_UTMI = 1, // internal PHY (mostly)
+ GHWCFG2_HSPHY_ULPI = 2, // external PHY (mostly)
+ GHWCFG2_HSPHY_UTMI_ULPI = 3, // both
+
+};
+
+enum {
+ GHWCFG2_FSPHY_NOT_SUPPORTED = 0,
+ GHWCFG2_FSPHY_DEDICATED = 1, // have dedicated FS PHY
+ GHWCFG2_FSPHY_UTMI = 2, // shared with UTMI+
+ GHWCFG2_FSPHY_ULPI = 3, // shared with ULPI
+};
+
+enum {
+ GHWCFFG4_PHY_DATA_WIDTH_8 = 0,
+ GHWCFFG4_PHY_DATA_WIDTH_16 = 1,
+ GHWCFFG4_PHY_DATA_WIDTH_8_16 = 2, // software selectable
+};
+
+enum {
+ HPRT_SPEED_HIGH = 0,
+ HPRT_SPEED_FULL = 1,
+ HPRT_SPEED_LOW = 2
+};
+
+enum {
+ GINTSTS_CMODE_DEVICE = 0,
+ GINTSTS_CMODE_HOST = 1,
+};
+
+enum {
+ HCTSIZ_PID_DATA0 = 0, // 00b
+ HCTSIZ_PID_DATA2 = 1, // 01b
+ HCTSIZ_PID_DATA1 = 2, // 10b
+ HCTSIZ_PID_SETUP = 3, // 11b
+};
+enum {
+ HCTSIZ_PID_MDATA = 3,
+};
+enum {
+ GRXSTS_PKTSTS_GLOBAL_OUT_NAK = 1,
+ GRXSTS_PKTSTS_RX_DATA = 2,
+ GRXSTS_PKTSTS_RX_COMPLETE = 3,
+ GRXSTS_PKTSTS_SETUP_DONE = 4,
+ GRXSTS_PKTSTS_HOST_DATATOGGLE_ERR = 5,
+ GRXSTS_PKTSTS_SETUP_RX = 6,
+ GRXSTS_PKTSTS_HOST_CHANNEL_HALTED = 7
+};
+
+// Same as TUSB_XFER_*
+enum {
+ HCCHAR_EPTYPE_CONTROL = 0,
+ HCCHAR_EPTYPE_ISOCHRONOUS = 1,
+ HCCHAR_EPTYPE_BULK = 2,
+ HCCHAR_EPTYPE_INTERRUPT = 3
+};
+
+enum {
+ DCFG_SPEED_HIGH = 0, // Highspeed with 30/60 Mhz
+ DCFG_SPEED_FULL_30_60MHZ = 1, // Fullspeed with UTMI+/ULPI 30/60 Mhz
+ DCFG_SPEED_LOW = 2, // Lowspeed with FS PHY at 6 Mhz
+ DCFG_SPEED_FULL_48MHZ = 3, // Fullspeed with dedicated FS PHY at 48 Mhz
+};
+
+// Same as TUSB_XFER_*
+enum {
+ DEPCTL_EPTYPE_CONTROL = 0,
+ DEPCTL_EPTYPE_ISOCHRONOUS = 1,
+ DEPCTL_EPTYPE_BULK = 2,
+ DEPCTL_EPTYPE_INTERRUPT = 3
+};
+
+//--------------------------------------------------------------------
+// Common Register Bitfield
+//--------------------------------------------------------------------
+typedef struct TU_ATTR_PACKED {
+ uint32_t ses_req_scs : 1; // 0 Session request success
+ uint32_t ses_req : 1; // 1 Session request
+ uint32_t vbval_ov_en : 1; // 2 VBUS valid override enable
+ uint32_t vbval_ov_val : 1; // 3 VBUS valid override value
+ uint32_t aval_ov_en : 1; // 4 A-peripheral session valid override enable
+ uint32_t aval_ov_al : 1; // 5 A-peripheral session valid override value
+ uint32_t bval_ov_en : 1; // 6 B-peripheral session valid override enable
+ uint32_t bval_ov_val : 1; // 7 B-peripheral session valid override value
+ uint32_t hng_scs : 1; // 8 Host negotiation success
+ uint32_t hnp_rq : 1; // 9 HNP (host negotiation protocol) request
+ uint32_t host_set_hnp_en : 1; // 10 Host set HNP enable
+ uint32_t dev_hnp_en : 1; // 11 Device HNP enabled
+ uint32_t embedded_host_en : 1; // 12 Embedded host enable
+ uint32_t rsv13_14 : 2; // 13.14 Reserved
+ uint32_t dbnc_filter_bypass : 1; // 15 Debounce filter bypass
+ uint32_t cid_status : 1; // 16 Connector ID status
+ uint32_t dbnc_done : 1; // 17 Debounce done
+ uint32_t ases_valid : 1; // 18 A-session valid
+ uint32_t bses_valid : 1; // 19 B-session valid
+ uint32_t otg_ver : 1; // 20 OTG version 0: v1.3, 1: v2.0
+ uint32_t current_mode : 1; // 21 Current mode of operation. Only from v3.00a
+ uint32_t mult_val_id_bc : 5; // 22..26 Multi-valued input pin ID battery charger
+ uint32_t chirp_en : 1; // 27 Chirp detection enable
+ uint32_t rsv28_30 : 3; // 28.30: Reserved
+ uint32_t test_mode_corr_eusb2 : 1; // 31 Test mode control for eUSB2 PHY
+} dwc2_gotgctl_t;
+TU_VERIFY_STATIC(sizeof(dwc2_gotgctl_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t rsv0_1 : 2; // 0..1 Reserved
+ uint32_t ses_end_det : 1; // 2 Session end detected
+ uint32_t rsv3_7 : 5; // 3..7 Reserved
+ uint32_t srs_status_change : 1; // 8 Session request success status change
+ uint32_t hns_status_change : 1; // 9 Host negotiation success status change
+ uint32_t rsv10_16 : 7; // 10..16 Reserved
+ uint32_t hng_det : 1; // 17 Host negotiation detected
+ uint32_t adev_timeout_change : 1; // 18 A-device timeout change
+ uint32_t dbnc_done : 1; // 19 Debounce done
+ uint32_t mult_val_lp_change : 1; // 20 Multi-valued input pin change
+ uint32_t rsv21_31 :11; // 21..31 Reserved
+} dwc2_gotgint_t;
+TU_VERIFY_STATIC(sizeof(dwc2_gotgint_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t gintmask : 1; // 0 Global interrupt mask
+ uint32_t hbst_len : 4; // 1..4 Burst length/type
+ uint32_t dma_en : 1; // 5 DMA enable
+ uint32_t rsv6 : 1; // 6 Reserved
+ uint32_t nptxf_empty_lvl : 1; // 7 Non-periodic Tx FIFO empty level
+ uint32_t ptxf_empty_lvl : 1; // 8 Periodic Tx FIFO empty level
+ uint32_t rsv9_20 : 12; // 9.20: Reserved
+ uint32_t remote_mem_support : 1; // 21 Remote memory support
+ uint32_t notify_all_dma_write : 1; // 22 Notify all DMA writes
+ uint32_t ahb_single : 1; // 23 AHB single
+ uint32_t inv_desc_endian : 1; // 24 Inverse descriptor endian
+ uint32_t rsv25_31 : 7; // 25..31 Reserved
+} dwc2_gahbcfg_t;
+TU_VERIFY_STATIC(sizeof(dwc2_gahbcfg_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t timeout_cal : 3; /* 0..2 Timeout calibration.
+ The USB standard timeout value for high-speed operation is 736 to 816 (inclusive) bit times. The USB standard
+ timeout value for full- speed operation is 16 to 18 (inclusive) bit times. The application must program this field
+ based on the speed of enumeration. The number of bit times added per PHY clock are as follows:
+ - High-speed: PHY clock One 30-MHz = 16 bit times, One 60-MHz = 8 bit times
+ - Full-speed: PHY clock One 30-MHz = 0.4 bit times, One 60-MHz = 0.2 bit times, One 48-MHz = 0.25 bit times */
+ uint32_t phy_if16 : 1; // 3 PHY interface. 0: 8 bits, 1: 16 bits
+ uint32_t ulpi_utmi_sel : 1; // 4 ULPI/UTMI select. 0: UTMI+, 1: ULPI
+ uint32_t fs_intf_sel : 1; // 5 Fullspeed serial interface select. 0: 6-pin, 1: 3-pin
+ uint32_t phy_sel : 1; // 6 HS/FS PHY selection. 0: HS UTMI+ or ULPI, 1: FS serial transceiver
+ uint32_t ddr_sel : 1; // 7 ULPI DDR select. 0: Single data rate 8-bit, 1: Double data rate 4-bit
+ uint32_t srp_capable : 1; // 8 SRP-capable
+ uint32_t hnp_capable : 1; // 9 HNP-capable
+ uint32_t turnaround_time : 4; // 10..13 Turnaround time. 9: 8-bit UTMI+, 5: 16-bit UTMI+
+ uint32_t rsv14 : 1; // 14 Reserved
+ uint32_t phy_low_power_clk_sel : 1; /* 15 PHY low-power clock select either 480-MHz or 48-MHz (low-power) PHY mode.
+ In FS/LS modes, the PHY can usually operate on a 48-MHz clock to save power. This bit is valid only for UTMI+ PHYs.
+ - 0: 480 Mhz internal PLL: the UTMI interface operates at either 60 MHz (8 bit) or 30 MHz (16-bit)
+ - 1 48 Mhz external clock: the UTMI interface operates at 48 MHz in FS mode and at either 48 or 6 MHz in LS mode */
+ uint32_t otg_i2c_sel : 1; // 16 OTG I2C interface select. 0: UTMI-FS, 1: I2C for OTG signals
+ uint32_t ulpi_fsls : 1; /* 17 ULPI FS/LS select. 0: ULPI, 1: ULPI FS/LS.
+ valid only when the FS serial transceiver is selected on the ULPI PHY. */
+ uint32_t ulpi_auto_resume : 1; // 18 ULPI Auto-resume
+ uint32_t ulpi_clk_sus_m : 1; // 19 ULPI Clock SuspendM
+ uint32_t ulpi_ext_vbus_drv : 1; // 20 ULPI External VBUS Drive
+ uint32_t ulpi_int_vbus_indicator : 1; // 21 ULPI Internal VBUS Indicator
+ uint32_t term_sel_dl_pulse : 1; // 22 TermSel DLine pulsing
+ uint32_t indicator_complement : 1; // 23 Indicator complement
+ uint32_t indicator_pass_through : 1; // 24 Indicator pass through
+ uint32_t ulpi_if_protect_disable : 1; // 25 ULPI interface protect disable
+ uint32_t ic_usb_capable : 1; // 26 IC_USB Capable
+ uint32_t ic_usb_traf_ctl : 1; // 27 IC_USB Traffic Control
+ uint32_t tx_end_delay : 1; // 28 TX end delay
+ uint32_t force_host_mode : 1; // 29 Force host mode
+ uint32_t force_dev_mode : 1; // 30 Force device mode
+ uint32_t corrupt_tx_pkt : 1; // 31 Corrupt Tx packet. 0: normal, 1: debug
+} dwc2_gusbcfg_t;
+TU_VERIFY_STATIC(sizeof(dwc2_gusbcfg_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t core_soft_rst : 1; // 0 Core Soft Reset
+ uint32_t piufs_soft_rst : 1; // 1 PIU FS Dedicated Controller Soft Reset
+ uint32_t frame_counter_rst : 1; // 2 Frame Counter Reset (host)
+ uint32_t intoken_q_flush : 1; // 3 IN Token Queue Flush
+ uint32_t rx_fifo_flush : 1; // 4 RX FIFO Flush
+ uint32_t tx_fifo_flush : 1; // 5 TX FIFO Flush
+ uint32_t tx_fifo_num : 5; // 6..10 TX FIFO Number
+ uint32_t rsv11_28 :18; // 11..28 Reserved
+ uint32_t core_soft_rst_done : 1; // 29 Core Soft Reset Done, from v4.20a
+ uint32_t dma_req : 1; // 30 DMA Request
+ uint32_t ahb_idle : 1; // 31 AHB Idle
+} dwc2_grstctl_t;
+TU_VERIFY_STATIC(sizeof(dwc2_grstctl_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t ep_ch_num : 4; // 0..3 Endpoint/Channel Number
+ uint32_t byte_count :11; // 4..14 Byte Count
+ uint32_t dpid : 2; // 15..16 Data PID
+ uint32_t packet_status : 4; // 17..20 Packet Status
+ uint32_t frame_number : 4; // 21..24 Frame Number
+ uint32_t rsv25_31 : 7; // 25..31 Reserved
+} dwc2_grxstsp_t;
+TU_VERIFY_STATIC(sizeof(dwc2_grxstsp_t) == 4, "incorrect size");
+
+// Hardware Configuration
+typedef struct TU_ATTR_PACKED {
+ uint32_t op_mode : 3; // 0..2 HNP/SRP Host/Device/OTG mode
+ uint32_t arch : 2; // 3..4 Slave/External/Internal DMA
+ uint32_t single_point : 1; // 5 0: support hub and split | 1: no hub, no split
+ uint32_t hs_phy_type : 2; // 6..7 0: not supported | 1: UTMI+ | 2: ULPI | 3: UTMI+ and ULPI
+ uint32_t fs_phy_type : 2; // 8..9 0: not supported | 1: dedicated | 2: UTMI+ | 3: ULPI
+ uint32_t num_dev_ep : 4; // 10..13 Number of device endpoints (excluding EP0)
+ uint32_t num_host_ch : 4; // 14..17 Number of host channel (excluding control)
+ uint32_t period_channel_support : 1; // 18 Support Periodic OUT Host Channel
+ uint32_t enable_dynamic_fifo : 1; // 19 Dynamic FIFO Sizing Enabled
+ uint32_t mul_proc_intrpt : 1; // 20 Multi-Processor Interrupt enabled (OTG_MULTI_PROC_INTRPT)
+ uint32_t reserved21 : 1; // 21 reserved
+ uint32_t nptx_q_depth : 2; // 22..23 Non-periodic request queue depth: 0 = 2. 1 = 4, 2 = 8
+ uint32_t ptx_q_depth : 2; // 24..25 Host periodic request queue depth: 0 = 2. 1 = 4, 2 = 8
+ uint32_t token_q_depth : 5; // 26..30 Device IN token sequence learning queue depth: 0-30
+ uint32_t otg_enable_ic_usb : 1; // 31 IC_USB mode specified for mode of operation
+} 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
+typedef struct TU_ATTR_PACKED {
+ uint32_t xfer_size_width : 4; // 0..3 Transfer size counter in bits = 11 + n (max 19 bits)
+ uint32_t packet_size_width : 3; // 4..6 Packet size counter in bits = 4 + n (max 10 bits)
+ uint32_t otg_enable : 1; // 7 OTG capable
+ uint32_t i2c_enable : 1; // 8 I2C interface is available
+ uint32_t vendor_ctrl_itf : 1; // 9 Vendor control interface is available
+ uint32_t optional_feature_removed : 1; // 10 remove User ID, GPIO, SOF toggle & counter to save gate count
+ uint32_t synch_reset : 1; // 11 0: async reset | 1: synch reset
+ uint32_t otg_adp_support : 1; // 12 ADP logic is present along with HSOTG controller
+ uint32_t otg_enable_hsic : 1; // 13 1: HSIC-capable with shared UTMI PHY interface | 0: non-HSIC
+ uint32_t battery_charger_support : 1; // s14 upport battery charger
+ uint32_t lpm_mode : 1; // 15 LPM mode
+ uint32_t dfifo_depth : 16; // DFIFO depth - EP_LOC_CNT in terms of 32-bit words
}dwc2_ghwcfg3_t;
-
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
+typedef struct TU_ATTR_PACKED {
+ uint32_t num_dev_period_in_ep : 4; // 0..3 Number of Device Periodic IN Endpoints
+ uint32_t partial_powerdown : 1; // 4 Partial Power Down Enabled
+ uint32_t ahb_freq_min : 1; // 5 1: minimum of AHB frequency is less than 60 MHz
+ uint32_t hibernation : 1; // 6 Hibernation feature is enabled
+ uint32_t extended_hibernation : 1; // 7 Extended Hibernation feature is enabled
+ uint32_t reserved8 : 1; // 8 Reserved
+ uint32_t enhanced_lpm_support1 : 1; // 9 Enhanced LPM Support1
+ uint32_t service_interval_flow : 1; // 10 Service Interval flow is supported
+ uint32_t ipg_isoc_support : 1; // 11 Interpacket GAP ISO OUT worst-case is supported
+ uint32_t acg_support : 1; // 12 Active clock gating is supported
+ uint32_t enhanced_lpm_support : 1; // 13 Enhanced LPM Support
+ uint32_t phy_data_width : 2; // 14..15 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable
+ uint32_t ctrl_ep_num : 4; // 16..19 Number of Device control endpoints in addition to EP0
+ uint32_t iddg_filter : 1; // 20 IDDG Filter Enabled
+ uint32_t vbus_valid_filter : 1; // 21 VBUS Valid Filter Enabled
+ uint32_t a_valid_filter : 1; // 22 A Valid Filter Enabled
+ uint32_t b_valid_filter : 1; // 23 B Valid Filter Enabled
+ uint32_t session_end_filter : 1; // 24 Session End Filter Enabled
+ uint32_t dedicated_fifos : 1; // 25 Dedicated tx fifo for device IN Endpoint
+ uint32_t num_dev_in_eps : 4; // 26..29 Number of Device IN Endpoints including EP0
+ uint32_t dma_desc_enabled : 1; // scatter/gather DMA configuration enabled
+ uint32_t dma_desc_dynamic : 1; // Dynamic scatter/gather DMA
}dwc2_ghwcfg4_t;
-
TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg4_t) == 4, "incorrect size");
+//--------------------------------------------------------------------
+// Host Register Bitfield
+//--------------------------------------------------------------------
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO
+ uint32_t req_queue_available : 8; // 16..23 Number of spaces available in the NPT transmit request queue for both IN and OU
+ // 24..31 is top entry in the request queue that is currently being processed by the MAC
+ uint32_t qtop_terminate : 1; // 24 Last entry for selected channel
+ uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command
+ uint32_t qtop_ch_num : 4; // 27..30 Channel number
+} dwc2_hnptxsts_t;
+TU_VERIFY_STATIC(sizeof(dwc2_hnptxsts_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO
+ uint32_t req_queue_available : 7; // 16..22 Number of spaces available in the PTX transmit request queue
+ uint32_t qtop_terminate : 1; // 23 Last entry for selected channel
+ uint32_t qtop_last_period : 1; // 24 Last entry for selected channel is a periodic entry
+ uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command
+ uint32_t qtop_ch_num : 4; // 27..30 Channel number
+ uint32_t qtop_odd_frame : 1; // 31 Send in odd frame
+} dwc2_hptxsts_t;
+TU_VERIFY_STATIC(sizeof(dwc2_hptxsts_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t conn_status : 1; // 0 Port connect status
+ uint32_t conn_detected : 1; // 1 Port connect detected
+ uint32_t enable : 1; // 2 Port enable status
+ uint32_t enable_change : 1; // 3 Port enable change
+ uint32_t over_current_active : 1; // 4 Port Over-current active
+ uint32_t over_current_change : 1; // 5 Port Over-current change
+ uint32_t resume : 1; // 6 Port resume
+ uint32_t suspend : 1; // 7 Port suspend
+ uint32_t reset : 1; // 8 Port reset
+ uint32_t rsv9 : 1; // 9 Reserved
+ uint32_t line_status : 2; // 10..11 Line status
+ uint32_t power : 1; // 12 Port power
+ uint32_t test_control : 4; // 13..16 Port Test control
+ uint32_t speed : 2; // 17..18 Port speed
+ uint32_t rsv19_31 :13; // 19..31 Reserved
+}dwc2_hprt_t;
+TU_VERIFY_STATIC(sizeof(dwc2_hprt_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t ep_size : 11; // 0..10 Maximum packet size
+ uint32_t ep_num : 4; // 11..14 Endpoint number
+ uint32_t ep_dir : 1; // 15 Endpoint direction
+ uint32_t rsv16 : 1; // 16 Reserved
+ uint32_t low_speed_dev : 1; // 17 Low-speed device
+ uint32_t ep_type : 2; // 18..19 Endpoint type
+ uint32_t err_multi_count : 2; // 20..21 Error (splitEn = 1) / Multi (SplitEn = 0) count
+ uint32_t dev_addr : 7; // 22..28 Device address
+ uint32_t odd_frame : 1; // 29 Odd frame
+ uint32_t disable : 1; // 30 Channel disable
+ uint32_t enable : 1; // 31 Channel enable
+} dwc2_channel_char_t;
+TU_VERIFY_STATIC(sizeof(dwc2_channel_char_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t hub_port : 7; // 0..6 Hub port number
+ uint32_t hub_addr : 7; // 7..13 Hub address
+ uint32_t xact_pos : 2; // 14..15 Transaction position
+ uint32_t split_compl : 1; // 16 Split completion
+ uint32_t rsv17_30 : 14; // 17..30 Reserved
+ uint32_t split_en : 1; // 31 Split enable
+} dwc2_channel_split_t;
+TU_VERIFY_STATIC(sizeof(dwc2_channel_split_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t xfer_size : 19; // 0..18 Transfer size in bytes
+ uint32_t packet_count : 10; // 19..28 Number of packets
+ uint32_t pid : 2; // 29..30 Packet ID
+ uint32_t do_ping : 1; // 31 Do PING
+} dwc2_channel_tsize_t;
+TU_VERIFY_STATIC(sizeof(dwc2_channel_tsize_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t num : 16; // 0..15 Frame number
+ uint32_t remainning : 16; // 16..31 Frame remaining
+} dwc2_hfnum_t;
+TU_VERIFY_STATIC(sizeof(dwc2_hfnum_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
+typedef struct {
+ union {
+ volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics
+ volatile dwc2_channel_char_t hcchar_bm;
+ };
+ union {
+ volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control
+ volatile dwc2_channel_split_t hcsplt_bm;
+ };
+ volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt
+ volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask
+ union {
+ volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size
+ volatile dwc2_channel_tsize_t hctsiz_bm;
+ };
+ volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address
+ uint32_t reserved518; // 518 + 20*ch
+ volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address
} 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;
+//--------------------------------------------------------------------
+// Device Register Bitfield
+//--------------------------------------------------------------------
+typedef struct TU_ATTR_PACKED {
+ uint32_t speed : 2; // 0..1 Speed
+ uint32_t nzsts_out_handshake : 1; // 2 Non-zero-length status OUT handshake
+ uint32_t en_32khz_suspsend : 1; // 3 Enable 32-kHz SUSPEND mode
+ uint32_t address : 7; // 4..10 Device address
+ uint32_t period_frame_interval : 2; // 11..12 Periodic frame interval
+ uint32_t en_out_nak : 1; // 13 Enable Device OUT NAK
+ uint32_t xcvr_delay : 1; // 14 Transceiver delay
+ uint32_t erratic_int_mask : 1; // 15 Erratic interrupt mask
+ uint32_t rsv16 : 1; // 16 Reserved
+ uint32_t ipg_iso_support : 1; // 17 Interpacket gap ISO support
+ uint32_t epin_mismatch_count : 5; // 18..22 EP IN mismatch count
+ uint32_t dma_desc : 1; // 23 Enable scatter/gatter DMA descriptor
+ uint32_t period_schedule_interval : 2; // 24..25 Periodic schedule interval for scatter/gatter DMA
+ uint32_t resume_valid : 6; // 26..31 Resume valid period
+} dwc2_dcfg_t;
+TU_VERIFY_STATIC(sizeof(dwc2_dcfg_t) == 4, "incorrect size");
-// 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 TU_ATTR_PACKED {
+ uint32_t remote_wakeup_signal : 1; // 0 Remote wakeup signal
+ uint32_t soft_disconnet : 1; // 1 Soft disconnect
+ uint32_t gnp_in_nak_status : 1; // 2 Global non-periodic NAK IN status
+ uint32_t gout_nak_status : 1; // 3 Global OUT NAK status
+ uint32_t test_control : 3; // 4..6 Test control
+ uint32_t set_gnp_in_nak : 1; // 7 Set global non-periodic IN NAK
+ uint32_t clear_gnp_in_nak : 1; // 8 Clear global non-periodic IN NAK
+ uint32_t set_gout_nak : 1; // 9 Set global OUT NAK
+ uint32_t clear_gout_nak : 1; // 10 Clear global OUT NAK
+ uint32_t poweron_prog_done : 1; // 11 Power-on programming done
+ uint32_t rsv12 : 1; // 12 Reserved
+ uint32_t global_multi_count : 2; // 13..14 Global multi-count
+ uint32_t ignore_frame_number : 1; // 15 Ignore frame number
+ uint32_t nak_on_babble : 1; // 16 NAK on babble
+ uint32_t en_cont_on_bna : 1; // 17 Enable continue on BNA
+ uint32_t deep_sleep_besl_reject : 1; // 18 Deep sleep BESL reject
+ uint32_t service_interval : 1; // 19 Service interval for ISO IN endpoint
+ uint32_t rsv20_31 :12; // 20..31 Reserved
+} dwc2_dctl_t;
+TU_VERIFY_STATIC(sizeof(dwc2_dctl_t) == 4, "incorrect size");
-typedef struct
-{
- //------------- 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
+typedef struct TU_ATTR_PACKED {
+ uint32_t suspend_status : 1; // 0 Suspend status
+ uint32_t enum_speed : 2; // 1..2 Enumerated speed
+ uint32_t erratic_err : 1; // 3 Erratic error
+ uint32_t rsv4_7 : 4; // 4..7 Reserved
+ uint32_t frame_number : 14; // 8..21 Frame/MicroFrame number
+ uint32_t line_status : 2; // 22..23 Line status
+ uint32_t rsv24_31 : 8; // 24..31 Reserved
+} dwc2_dsts_t;
+TU_VERIFY_STATIC(sizeof(dwc2_dsts_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t xfer_complete : 1; // 0 Transfer complete
+ uint32_t disabled : 1; // 1 Endpoint disabled
+ uint32_t ahb_err : 1; // 2 AHB error
+ uint32_t timeout : 1; // 3 Timeout
+ uint32_t in_rx_txfe : 1; // 4 IN token received when TxFIFO is empty
+ uint32_t in_rx_ep_mismatch : 1; // 5 IN token received with EP mismatch
+ uint32_t in_ep_nak_effective : 1; // 6 IN endpoint NAK effective
+ uint32_t txfifo_empty : 1; // 7 TX FIFO empty
+ uint32_t txfifo_underrun : 1; // 8 Tx FIFO under run
+ uint32_t bna : 1; // 9 Buffer not available
+ uint32_t rsv10 : 1; // 10 Reserved
+ uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status
+ uint32_t babble_err : 1; // 12 Babble error
+ uint32_t nak : 1; // 13 NAK
+ uint32_t nyet : 1; // 14 NYET
+ uint32_t rsv14_31 :17; // 15..31 Reserved
+} dwc2_diepint_t;
+TU_VERIFY_STATIC(sizeof(dwc2_diepint_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t mps : 11; // 0..10 Maximum packet size, EP0 only use 2 bit
+ uint32_t next_ep : 4; // 11..14 Next endpoint number
+ uint32_t active : 1; // 15 Active
+ const uint32_t dpid_iso_odd : 1; // 16 DATA0/DATA1 for bulk/interrupt, odd frame for isochronous
+ const uint32_t nak_status : 1; // 17 NAK status
+ uint32_t type : 2; // 18..19 Endpoint type
+ uint32_t rsv20 : 1; // 20 Reserved
+ uint32_t stall : 1; // 21 Stall
+ uint32_t tx_fifo_num : 4; // 22..25 Tx FIFO number (IN)
+ uint32_t clear_nak : 1; // 26 Clear NAK
+ uint32_t set_nak : 1; // 27 Set NAK
+ uint32_t set_data0_iso_even : 1; // 28 Set DATA0 if bulk/interrupt, even frame for isochronous
+ uint32_t set_data1_iso_odd : 1; // 29 Set DATA1 if bulk/interrupt, odd frame for isochronous
+ uint32_t disable : 1; // 30 Disable
+ uint32_t enable : 1; // 31 Enable
+} dwc2_depctl_t;
+TU_VERIFY_STATIC(sizeof(dwc2_depctl_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t xfer_complete : 1; // 0 Transfer complete
+ uint32_t disabled : 1; // 1 Endpoint disabled
+ uint32_t ahb_err : 1; // 2 AHB error
+ uint32_t setup_phase_done : 1; // 3 Setup phase done
+ uint32_t out_rx_ep_disabled : 1; // 4 OUT token received when endpoint disabled
+ uint32_t status_phase_rx : 1; // 5 Status phase received
+ uint32_t setup_b2b : 1; // 6 Setup packet back-to-back
+ uint32_t rsv7 : 1; // 7 Reserved
+ uint32_t out_packet_err : 1; // 8 OUT packet error
+ uint32_t bna : 1; // 9 Buffer not available
+ uint32_t rsv10 : 1; // 10 Reserved
+ uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status
+ uint32_t babble_err : 1; // 12 Babble error
+ uint32_t nak : 1; // 13 NAK
+ uint32_t nyet : 1; // 14 NYET
+ uint32_t setup_packet_rx : 1; // 15 Setup packet received (Buffer DMA Mode only)
+ uint32_t rsv16_31 :16; // 16..31 Reserved
+} dwc2_doepint_t;
+TU_VERIFY_STATIC(sizeof(dwc2_doepint_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t xfer_size : 19; // 0..18 Transfer size in bytes
+ uint32_t packet_count : 10; // 19..28 Number of packets
+ uint32_t mc_pid : 2; // 29..30 IN: Multi Count, OUT: PID
+} dwc2_ep_tsize_t;
+TU_VERIFY_STATIC(sizeof(dwc2_ep_tsize_t) == 4, "incorrect size");
- //------------- 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
+// Device IN/OUT Endpoint
+typedef struct {
+ union {
+ volatile uint32_t diepctl;
+ volatile uint32_t doepctl;
- //------------- Host Channel -------------//
- dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15
- uint32_t reserved700[64]; // 700..7FF
+ volatile uint32_t ctl;
+ volatile dwc2_depctl_t ctl_bm;
+ };
+ uint32_t rsv04;
+ union {
+ volatile uint32_t intr;
- //------------- 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
+ volatile uint32_t diepint;
+ volatile dwc2_diepint_t diepint_bm;
- //------------- 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
+ volatile uint32_t doepint;
+ volatile dwc2_doepint_t doepint_bm;
+ };
+ uint32_t rsv0c;
+ union {
+ volatile uint32_t dieptsiz;
+ volatile uint32_t doeptsiz;
+ volatile uint32_t tsiz;
+ volatile dwc2_ep_tsize_t tsiz_bm;
+ };
+ union {
+ volatile uint32_t diepdma;
+ volatile uint32_t doepdma;
+ };
+ volatile uint32_t dtxfsts;
+ uint32_t rsv1c;
+}dwc2_dep_t;
- //------------- Power Clock -------------//
- volatile uint32_t pcgctl; // E00 Power and Clock Gating Control
- volatile uint32_t pcgctl1; // E04
- uint32_t reservede08[126]; // E08..FFF
+TU_VERIFY_STATIC(sizeof(dwc2_dep_t) == 0x20, "incorrect size");
- //------------- FIFOs -------------//
- // Word-accessed only using first pointer since it auto shift
- volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO
+//--------------------------------------------------------------------
+// CSR Register Map
+//--------------------------------------------------------------------
+typedef struct {
+ //------------- Core Global -------------//
+ union {
+ volatile uint32_t gotgctl; // 000 OTG Control and Status
+ volatile dwc2_gotgctl_t gotgctl_bm;
+ };
+ union {
+ volatile uint32_t gotgint; // 004 OTG Interrupt
+ volatile dwc2_gotgint_t gotgint_bm;
+ };
+ union {
+ volatile uint32_t gahbcfg; // 008 AHB Configuration
+ volatile dwc2_gahbcfg_t gahbcfg_bm;
+ };
+ union {
+ volatile uint32_t gusbcfg; // 00c USB Configuration
+ volatile dwc2_gusbcfg_t gusbcfg_bm;
+ };
+ union {
+ volatile uint32_t grstctl; // 010 Reset
+ volatile dwc2_grstctl_t grstctl_bm;
+ };
+ volatile uint32_t gintsts; // 014 Interrupt
+ volatile uint32_t gintmsk; // 018 Interrupt Mask
+ volatile uint32_t grxstsr; // 01c Receive Status Debug Read
+ union {
+ volatile uint32_t grxstsp; // 020 Receive Status Read/Pop
+ volatile dwc2_grxstsp_t grxstsp_bm;
+ };
+ volatile uint32_t grxfsiz; // 024 Receive FIFO Size
+ union {
+ volatile uint32_t dieptxf0; // 028 EP0 Tx FIFO Size
+ volatile uint32_t gnptxfsiz; // 028 Non-periodic Transmit FIFO Size
+ };
+ union {
+ volatile uint32_t hnptxsts; // 02c Non-periodic Transmit FIFO/Queue Status
+ volatile dwc2_hnptxsts_t hnptxsts_bm;
+ volatile uint32_t gnptxsts;
+ };
+ volatile uint32_t gi2cctl; // 030 I2C Address
+ volatile uint32_t gpvndctl; // 034 PHY Vendor Control
+ union {
+ volatile uint32_t ggpio; // 038 General Purpose IO
+ volatile uint32_t stm32_gccfg; // 038 STM32 General Core Configuration
+ };
+ volatile uint32_t guid; // 03C User (Application programmable) ID
+ volatile uint32_t gsnpsid; // 040 Synopsys ID + Release version
+ volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep)
+ union {
+ volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2
+ volatile dwc2_ghwcfg2_t ghwcfg2_bm;
+ };
+ union {
+ volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3
+ volatile dwc2_ghwcfg3_t ghwcfg3_bm;
+ };
+ union {
+ volatile uint32_t ghwcfg4; // 050 User Hardware Configuration4
+ volatile dwc2_ghwcfg4_t ghwcfg4_bm;
+ };
+ volatile uint32_t glpmcfg; // 054 Core LPM Configuration
+ volatile uint32_t gpwrdn; // 058 Power Down
+ volatile uint32_t gdfifocfg; // 05C DFIFO Software Configuration
+ volatile uint32_t gadpctl; // 060 ADP Timer, Control and Status
+ uint32_t reserved64[39]; // 064..0FF
+ volatile uint32_t hptxfsiz; // 100 Host Periodic Tx FIFO Size
+ volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size
+ uint32_t reserved140[176]; // 140..3FF
+
+ //------------ Host -------------//
+ volatile uint32_t hcfg; // 400 Host Configuration
+ volatile uint32_t hfir; // 404 Host Frame Interval
+ union {
+ volatile uint32_t hfnum; // 408 Host Frame Number / Frame Remaining
+ volatile dwc2_hfnum_t hfnum_bm;
+ };
+ uint32_t reserved40c; // 40C
+ union {
+ volatile uint32_t hptxsts; // 410 Host Periodic TX FIFO / Queue Status
+ volatile dwc2_hptxsts_t hptxsts_bm;
+ };
+ volatile uint32_t haint; // 414 Host All Channels Interrupt
+ volatile uint32_t haintmsk; // 418 Host All Channels Interrupt Mask
+ volatile uint32_t hflbaddr; // 41C Host Frame List Base Address
+ uint32_t reserved420[8]; // 420..43F
+ union {
+ volatile uint32_t hprt; // 440 Host Port Control and Status
+ volatile dwc2_hprt_t hprt_bm;
+ };
+ uint32_t reserved444[47]; // 444..4FF
+
+ //------------- Host Channel -------------//
+ dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15
+ uint32_t reserved700[64]; // 700..7FF
+
+ //------------- Device -----------//
+ union {
+ volatile uint32_t dcfg; // 800 Device Configuration
+ volatile dwc2_dcfg_t dcfg_bm;
+ };
+ union {
+ volatile uint32_t dctl; // 804 Device Control
+ volatile dwc2_dctl_t dctl_bm;
+ };
+ union {
+ volatile uint32_t dsts; // 808 Device Status (RO)
+ volatile dwc2_dsts_t dsts_bm;
+ };
+ uint32_t reserved80c; // 80C
+ union {
+ volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask
+ volatile dwc2_diepint_t diepmsk_bm;
+ };
+ union {
+ volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask
+ volatile dwc2_doepint_t doepmsk_bm;
+ };
+ volatile uint32_t daint; // 818 Device All Endpoints Interrupt
+ volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask
+ volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1
+ volatile uint32_t dtknqr2; // 824 Device IN token sequence learning queue read2
+ volatile uint32_t dvbusdis; // 828 Device VBUS Discharge Time
+ volatile uint32_t dvbuspulse; // 82C Device VBUS Pulsing Time
+ volatile uint32_t dthrctl; // 830 Device threshold Control
+ volatile uint32_t diepempmsk; // 834 Device IN Endpoint FIFO Empty Interrupt Mask
+
+ // Device Each Endpoint (IN/OUT) Interrupt/Mask for generating dedicated EP interrupt line
+ // require OTG_MULTI_PROC_INTRPT=1
+ volatile uint32_t deachint; // 838 Device Each Endpoint Interrupt
+ volatile uint32_t deachmsk; // 83C Device Each Endpoint Interrupt mask
+ volatile uint32_t diepeachmsk[16]; // 840..87C Device Each IN Endpoint mask
+ volatile uint32_t doepeachmsk[16]; // 880..8BF Device Each OUT Endpoint mask
+ uint32_t reserved8c0[16]; // 8C0..8FF
+
+ //------------- Device Endpoint -------------//
+ union {
+ dwc2_dep_t ep[2][16]; // 0: IN, 1 OUT
+ struct {
+ dwc2_dep_t epin[16]; // 900..AFF IN Endpoints
+ dwc2_dep_t epout[16]; // B00..CFF OUT Endpoints
+ };
+ };
+ uint32_t reservedd00[64]; // D00..DFF
+
+ //------------- Power Clock -------------//
+ volatile uint32_t pcgcctl; // E00 Power and Clock Gating Characteristic Control
+ volatile uint32_t pcgcctl1; // E04 Power and Clock Gating Characteristic Control 1
+ uint32_t reservede08[126]; // E08..FFF
+
+ //------------- 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");
@@ -307,7 +794,7 @@ 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, pcgcctl) == 0x0E00, "incorrect size");
TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
//--------------------------------------------------------------------+
@@ -371,14 +858,16 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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
+#define HCFG_FSLS_PHYCLK_SEL_Pos (0U)
+#define HCFG_FSLS_PHYCLK_SEL_Msk (0x3UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000003
+#define HCFG_FSLS_PHYCLK_SEL HCFG_FSLS_PHYCLK_SEL_Msk // FS/LS PHY clock select
+#define HCFG_FSLS_PHYCLK_SEL_30_60MHZ (0x0UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000000
+#define HCFG_FSLS_PHYCLK_SEL_48MHZ (0x1UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000001
+#define HCFG_FSLS_PHYCLK_SEL_6MHZ (0x2UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000002
+
+#define HCFG_FSLS_ONLY_Pos (2U)
+#define HCFG_FSLS_ONLY_Msk (0x1UL << HCFG_FSLS_ONLY_Pos) // 0x00000004
+#define HCFG_FSLS_ONLY HCFG_FSLS_ONLY_Msk // FS- and LS-only support
/******************** Bit definition for PCGCR register ********************/
#define PCGCR_STPPCLK_Pos (0U)
@@ -493,6 +982,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#define HFIR_FRIVL_Pos (0U)
#define HFIR_FRIVL_Msk (0xFFFFUL << HFIR_FRIVL_Pos) // 0x0000FFFF
#define HFIR_FRIVL HFIR_FRIVL_Msk // Frame interval
+#define HFIR_RELOAD_CTRL_Pos (16U) // available since v2.92a
+#define HFIR_RELOAD_CTRL_Msk (0x1UL << HFIR_RELOAD_CTRL_Pos)
+#define HFIR_RELOAD_CTRL HFIR_RELOAD_CTRL_Msk
/******************** Bit definition for HFNUM register ********************/
#define HFNUM_FRNUM_Pos (0U)
@@ -537,19 +1029,17 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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)
+#define GAHBCFG_TX_FIFO_EPMTY_LVL_Pos (7U)
+#define GAHBCFG_TX_FIFO_EPMTY_LVL_Msk (0x1UL << GAHBCFG_TX_FIFO_EPMTY_LVL_Pos) // 0x00000080
+#define GAHBCFG_TX_FIFO_EPMTY_LVL GAHBCFG_TX_FIFO_EPMTY_LVL_Msk // TxFIFO empty level
+#define GAHBCFG_PTX_FIFO_EPMTY_LVL_Pos (8U)
+#define GAHBCFG_PTX_FIFO_EPMTY_LVL_Msk (0x1UL << GAHBCFG_PTX_FIFO_EPMTY_LVL_Pos) // 0x00000100
+#define GAHBCFG_PTX_FIFO_EPMTY_LVL GAHBCFG_PTX_FIFO_EPMTY_LVL_Msk // Periodic TxFIFO empty level
/******************** 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_TOCAL GUSBCFG_TOCAL_Msk // HS/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)
@@ -633,8 +1123,8 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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_CSRST_DONE_Pos (29)
+#define GRSTCTL_CSRST_DONE (1u << GRSTCTL_CSRST_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
@@ -755,9 +1245,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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_NPTX_FIFO_EMPTY_Pos (5U)
+#define GINTSTS_NPTX_FIFO_EMPTY_Msk (0x1UL << GINTSTS_NPTX_FIFO_EMPTY_Pos) // 0x00000020
+#define GINTSTS_NPTX_FIFO_EMPTY GINTSTS_NPTX_FIFO_EMPTY_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
@@ -806,15 +1296,15 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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_PTX_FIFO_EMPTY_Pos (26U)
+#define GINTSTS_PTX_FIFO_EMPTY_Msk (0x1UL << GINTSTS_PTX_FIFO_EMPTY_Pos) // 0x04000000
+#define GINTSTS_PTX_FIFO_EMPTY GINTSTS_PTX_FIFO_EMPTY_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_CONIDSTSCHNG_Pos (28U)
+#define GINTSTS_CONIDSTSCHNG_Msk (0x1UL << GINTSTS_CONIDSTSCHNG_Pos) // 0x10000000
+#define GINTSTS_CONIDSTSCHNG GINTSTS_CONIDSTSCHNG_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
@@ -898,9 +1388,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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_CONIDSTSCHNGM_Pos (28U)
+#define GINTMSK_CONIDSTSCHNGM_Msk (0x1UL << GINTMSK_CONIDSTSCHNGM_Pos) // 0x10000000
+#define GINTMSK_CONIDSTSCHNGM GINTMSK_CONIDSTSCHNGM_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
@@ -938,17 +1428,6 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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
@@ -957,6 +1436,8 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#define DAINTMSK_OEPM_Msk (0xFFFFUL << DAINTMSK_OEPM_Pos) // 0xFFFF0000
#define DAINTMSK_OEPM DAINTMSK_OEPM_Msk // OUT EP interrupt mask bits
+#define DAINT_SHIFT(_dir) ((_dir == TUSB_DIR_IN) ? 0 : 16)
+
#if 0
/******************** Bit definition for OTG register ********************/
#define CHNUM_Pos (0U)
@@ -1239,6 +1720,12 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#define GLPMCFG_ENBESL_Msk (0x1UL << GLPMCFG_ENBESL_Pos) // 0x10000000
#define GLPMCFG_ENBESL GLPMCFG_ENBESL_Msk // Enable best effort service latency
+// GDFIFOCFG
+#define GDFIFOCFG_EPINFOBASE_MASK (0xffff << 16)
+#define GDFIFOCFG_EPINFOBASE_SHIFT 16
+#define GDFIFOCFG_GDFIFOCFG_MASK (0xffff << 0)
+#define GDFIFOCFG_GDFIFOCFG_SHIFT 0
+
/******************** Bit definition for DIEPEACHMSK1 register ********************/
#define DIEPEACHMSK1_XFRCM_Pos (0U)
#define DIEPEACHMSK1_XFRCM_Msk (0x1UL << DIEPEACHMSK1_XFRCM_Pos) // 0x00000001
@@ -1269,56 +1756,53 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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
+#define HPRT_CONN_STATUS_Pos (0U)
+#define HPRT_CONN_STATUS_Msk (0x1UL << HPRT_CONN_STATUS_Pos) // 0x00000001
+#define HPRT_CONN_STATUS HPRT_CONN_STATUS_Msk // Port connect status
+#define HPRT_CONN_DETECT_Pos (1U)
+#define HPRT_CONN_DETECT_Msk (0x1UL << HPRT_CONN_DETECT_Pos) // 0x00000002
+#define HPRT_CONN_DETECT HPRT_CONN_DETECT_Msk // Port connect detected
+#define HPRT_ENABLE_Pos (2U)
+#define HPRT_ENABLE_Msk (0x1UL << HPRT_ENABLE_Pos) // 0x00000004
+#define HPRT_ENABLE HPRT_ENABLE_Msk // Port enable
+#define HPRT_ENABLE_CHANGE_Pos (3U)
+#define HPRT_ENABLE_CHANGE_Msk (0x1UL << HPRT_ENABLE_CHANGE_Pos) // 0x00000008
+#define HPRT_ENABLE_CHANGE HPRT_ENABLE_CHANGE_Msk // Port enable/disable change
+#define HPRT_OVER_CURRENT_ACTIVE_Pos (4U)
+#define HPRT_OVER_CURRENT_ACTIVE_Msk (0x1UL << HPRT_OVER_CURRENT_ACTIVE_Pos) // 0x00000010
+#define HPRT_OVER_CURRENT_ACTIVE HPRT_OVER_CURRENT_ACTIVE_Msk // Port overcurrent active
+#define HPRT_OVER_CURRENT_CHANGE_Pos (5U)
+#define HPRT_OVER_CURRENT_CHANGE_Msk (0x1UL << HPRT_OVER_CURRENT_CHANGE_Pos) // 0x00000020
+#define HPRT_OVER_CURRENT_CHANGE HPRT_OVER_CURRENT_CHANGE_Msk // Port overcurrent change
+#define HPRT_RESUME_Pos (6U)
+#define HPRT_RESUME_Msk (0x1UL << HPRT_RESUME_Pos) // 0x00000040
+#define HPRT_RESUME HPRT_RESUME_Msk // Port resume
+#define HPRT_SUSPEND_Pos (7U)
+#define HPRT_SUSPEND_Msk (0x1UL << HPRT_SUSPEND_Pos) // 0x00000080
+#define HPRT_SUSPEND HPRT_SUSPEND_Msk // Port suspend
+#define HPRT_RESET_Pos (8U)
+#define HPRT_RESET_Msk (0x1UL << HPRT_RESET_Pos) // 0x00000100
+#define HPRT_RESET HPRT_RESET_Msk // Port reset
+#define HPRT_LINE_STATUS_Pos (10U)
+#define HPRT_LINE_STATUS_Msk (0x3UL << HPRT_LINE_STATUS_Pos) // 0x00000C00
+#define HPRT_LINE_STATUS HPRT_LINE_STATUS_Msk // Port line status
+#define HPRT_LINE_STATUS_0 (0x1UL << HPRT_LINE_STATUS_Pos) // 0x00000400
+#define HPRT_LINE_STATUS_1 (0x2UL << HPRT_LINE_STATUS_Pos) // 0x00000800
+#define HPRT_POWER_Pos (12U)
+#define HPRT_POWER_Msk (0x1UL << HPRT_POWER_Pos) // 0x00001000
+#define HPRT_POWER HPRT_POWER_Msk // Port power
+#define HPRT_TEST_CONTROL_Pos (13U)
+#define HPRT_TEST_CONTROL_Msk (0xFUL << HPRT_TEST_CONTROL_Pos) // 0x0001E000
+#define HPRT_TEST_CONTROL HPRT_TEST_CONTROL_Msk // Port test control
+#define HPRT_TEST_CONTROL_0 (0x1UL << HPRT_TEST_CONTROL_Pos) // 0x00002000
+#define HPRT_TEST_CONTROL_1 (0x2UL << HPRT_TEST_CONTROL_Pos) // 0x00004000
+#define HPRT_TEST_CONTROL_2 (0x4UL << HPRT_TEST_CONTROL_Pos) // 0x00008000
+#define HPRT_TEST_CONTROL_3 (0x8UL << HPRT_TEST_CONTROL_Pos) // 0x00010000
+#define HPRT_SPEED_Pos (17U)
+#define HPRT_SPEED_Msk (0x3UL << HPRT_SPEED_Pos) // 0x00060000
+#define HPRT_SPEED HPRT_SPEED_Msk // Port speed
+#define HPRT_SPEED_0 (0x1UL << HPRT_SPEED_Pos) // 0x00020000
+#define HPRT_SPEED_1 (0x2UL << HPRT_SPEED_Pos) // 0x00040000
/******************** Bit definition for DOEPEACHMSK1 register ********************/
#define DOEPEACHMSK1_XFRCM_Pos (0U)
@@ -1500,15 +1984,15 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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_XFER_COMPLETE_Pos (0U)
+#define HCINT_XFER_COMPLETE_Msk (0x1UL << HCINT_XFER_COMPLETE_Pos) // 0x00000001
+#define HCINT_XFER_COMPLETE HCINT_XFER_COMPLETE_Msk // Transfer completed
+#define HCINT_HALTED_Pos (1U)
+#define HCINT_HALTED_Msk (0x1UL << HCINT_HALTED_Pos) // 0x00000002
+#define HCINT_HALTED HCINT_HALTED_Msk // Channel halted
+#define HCINT_AHB_ERR_Pos (2U)
+#define HCINT_AHB_ERR_Msk (0x1UL << HCINT_AHB_ERR_Pos) // 0x00000004
+#define HCINT_AHB_ERR HCINT_AHB_ERR_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
@@ -1521,18 +2005,27 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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
+#define HCINT_XACT_ERR_Pos (7U)
+#define HCINT_XACT_ERR_Msk (0x1UL << HCINT_XACT_ERR_Pos) // 0x00000080
+#define HCINT_XACT_ERR HCINT_XACT_ERR_Msk // Transaction error
+#define HCINT_BABBLE_ERR_Pos (8U)
+#define HCINT_BABBLE_ERR_Msk (0x1UL << HCINT_BABBLE_ERR_Pos) // 0x00000100
+#define HCINT_BABBLE_ERR HCINT_BABBLE_ERR_Msk // Babble error
+#define HCINT_FARME_OVERRUN_Pos (9U)
+#define HCINT_FARME_OVERRUN_Msk (0x1UL << HCINT_FARME_OVERRUN_Pos) // 0x00000200
+#define HCINT_FARME_OVERRUN HCINT_FARME_OVERRUN_Msk // Frame overrun
+#define HCINT_DATATOGGLE_ERR_Pos (10U)
+#define HCINT_DATATOGGLE_ERR_Msk (0x1UL << HCINT_DATATOGGLE_ERR_Pos) // 0x00000400
+#define HCINT_DATATOGGLE_ERR HCINT_DATATOGGLE_ERR_Msk // Data toggle error
+#define HCINT_BUFFER_NA_Pos (11U)
+#define HCINT_BUFFER_NA_Msk (0x1UL << HCINT_BUFFER_NA_Pos) // 0x00000800
+#define HCINT_BUFFER_NA HCINT_BUFFER_NA_Msk // Buffer not available interrupt
+#define HCINT_XCS_XACT_ERR_Pos (12U)
+#define HCINT_XCS_XACT_ERR_Msk (0x1UL << HCINT_XCS_XACT_ERR_Pos) // 0x00001000
+#define HCINT_XCS_XACT_ERR HCINT_XCS_XACT_ERR_Msk // Excessive transaction error
+#define HCINT_DESC_ROLLOVER_Pos (13U)
+#define HCINT_DESC_ROLLOVER_Msk (0x1UL << HCINT_DESC_ROLLOVER_Pos) // 0x00002000
+#define HCINT_DESC_ROLLOVER HCINT_DESC_ROLLOVER_Msk // Descriptor rollover
/******************** Bit definition for DIEPINT register ********************/
#define DIEPINT_XFRC_Pos (0U)
@@ -1575,41 +2068,6 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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)
@@ -1631,11 +2089,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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
+#define HCTSIZ_PID_Pos (29U)
+#define HCTSIZ_PID_Msk (0x3UL << HCTSIZ_PID_Pos) // 0x60000000
+#define HCTSIZ_PID HCTSIZ_PID_Msk // Data PID
/******************** Bit definition for DIEPDMA register ********************/
#define DIEPDMA_DMAADDR_Pos (0U)
@@ -1660,6 +2116,45 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#define DIEPTXF_INEPTXFD_Msk (0xFFFFUL << DIEPTXF_INEPTXFD_Pos) // 0xFFFF0000
#define DIEPTXF_INEPTXFD DIEPTXF_INEPTXFD_Msk // IN endpoint TxFIFO depth
+
+/******************** Bit definition for Common EPCTL register ********************/
+#define EPCTL_MPSIZ_Pos (0U)
+#define EPCTL_MPSIZ_Msk (0x7FFUL << EPCTL_MPSIZ_Pos) // 0x000007FF
+#define EPCTL_MPSIZ EPCTL_MPSIZ_Msk // Maximum packet size //Bit 1
+#define EPCTL_USBAEP_Pos (15U)
+#define EPCTL_USBAEP_Msk (0x1UL << EPCTL_USBAEP_Pos) // 0x00008000
+#define EPCTL_USBAEP EPCTL_USBAEP_Msk // USB active endpoint
+#define EPCTL_NAKSTS_Pos (17U)
+#define EPCTL_NAKSTS_Msk (0x1UL << EPCTL_NAKSTS_Pos) // 0x00020000
+#define EPCTL_NAKSTS EPCTL_NAKSTS_Msk // NAK status
+#define EPCTL_EPTYP_Pos (18U)
+#define EPCTL_EPTYP_Msk (0x3UL << EPCTL_EPTYP_Pos) // 0x000C0000
+#define EPCTL_EPTYP EPCTL_EPTYP_Msk // Endpoint type
+#define EPCTL_EPTYP_0 (0x1UL << EPCTL_EPTYP_Pos) // 0x00040000
+#define EPCTL_EPTYP_1 (0x2UL << EPCTL_EPTYP_Pos) // 0x00080000
+#define EPCTL_SNPM EPCTL_SNPM_Msk // Snoop mode
+#define EPCTL_STALL_Pos (21U)
+#define EPCTL_STALL_Msk (0x1UL << EPCTL_STALL_Pos) // 0x00200000
+#define EPCTL_STALL EPCTL_STALL_Msk // STALL handshake
+#define EPCTL_CNAK_Pos (26U)
+#define EPCTL_CNAK_Msk (0x1UL << EPCTL_CNAK_Pos) // 0x04000000
+#define EPCTL_CNAK EPCTL_CNAK_Msk // Clear NAK
+#define EPCTL_SNAK_Pos (27U)
+#define EPCTL_SNAK_Msk (0x1UL << EPCTL_SNAK_Pos) // 0x08000000
+#define EPCTL_SNAK EPCTL_SNAK_Msk // Set NAK
+#define EPCTL_SD0PID_SEVNFRM_Pos (28U)
+#define EPCTL_SD0PID_SEVNFRM_Msk (0x1UL << EPCTL_SD0PID_SEVNFRM_Pos) // 0x10000000
+#define EPCTL_SD0PID_SEVNFRM EPCTL_SD0PID_SEVNFRM_Msk // Set DATA0 PID
+#define EPCTL_SODDFRM_Pos (29U)
+#define EPCTL_SODDFRM_Msk (0x1UL << EPCTL_SODDFRM_Pos) // 0x20000000
+#define EPCTL_SODDFRM EPCTL_SODDFRM_Msk // Set odd frame
+#define EPCTL_EPDIS_Pos (30U)
+#define EPCTL_EPDIS_Msk (0x1UL << EPCTL_EPDIS_Pos) // 0x40000000
+#define EPCTL_EPDIS EPCTL_EPDIS_Msk // Endpoint disable
+#define EPCTL_EPENA_Pos (31U)
+#define EPCTL_EPENA_Msk (0x1UL << EPCTL_EPENA_Pos) // 0x80000000
+#define EPCTL_EPENA EPCTL_EPENA_Msk // Endpoint enable
+
/******************** Bit definition for DOEPCTL register ********************/
#define DOEPCTL_MPSIZ_Pos (0U)
#define DOEPCTL_MPSIZ_Msk (0x7FFUL << DOEPCTL_MPSIZ_Pos) // 0x000007FF
@@ -1710,15 +2205,19 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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_SETUP_Pos (3U)
+#define DOEPINT_SETUP_Msk (0x1UL << DOEPINT_SETUP_Pos) // 0x00000008
+#define DOEPINT_SETUP DOEPINT_SETUP_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_STSPHSRX_Pos (5U)
+#define DOEPINT_STSPHSRX_Msk (0x1UL << DOEPINT_STSPHSRX_Pos) // 0x00000020
+#define DOEPINT_STSPHSRX DOEPINT_STSPHSRX_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
@@ -1731,6 +2230,7 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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
@@ -1750,32 +2250,32 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#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 PCGCCTL_IF_DEV_MODE TU_BIT(31)
+#define PCGCCTL_P2HD_PRT_SPD_MASK (0x3ul << 29)
+#define PCGCCTL_P2HD_PRT_SPD_SHIFT 29
+#define PCGCCTL_P2HD_DEV_ENUM_SPD_MASK (0x3ul << 27)
+#define PCGCCTL_P2HD_DEV_ENUM_SPD_SHIFT 27
+#define PCGCCTL_MAC_DEV_ADDR_MASK (0x7ful << 20)
+#define PCGCCTL_MAC_DEV_ADDR_SHIFT 20
+#define PCGCCTL_MAX_TERMSEL TU_BIT(19)
+#define PCGCCTL_MAX_XCVRSELECT_MASK (0x3ul << 17)
+#define PCGCCTL_MAX_XCVRSELECT_SHIFT 17
+#define PCGCCTL_PORT_POWER TU_BIT(16)
+#define PCGCCTL_PRT_CLK_SEL_MASK (0x3ul << 14)
+#define PCGCCTL_PRT_CLK_SEL_SHIFT 14
+#define PCGCCTL_ESS_REG_RESTORED TU_BIT(13)
+#define PCGCCTL_EXTND_HIBER_SWITCH TU_BIT(12)
+#define PCGCCTL_EXTND_HIBER_PWRCLMP TU_BIT(11)
+#define PCGCCTL_ENBL_EXTND_HIBER TU_BIT(10)
+#define PCGCCTL_RESTOREMODE TU_BIT(9)
+#define PCGCCTL_RESETAFTSUSP TU_BIT(8)
+#define PCGCCTL_DEEP_SLEEP TU_BIT(7)
+#define PCGCCTL_PHY_IN_SLEEP TU_BIT(6)
+#define PCGCCTL_ENBL_SLEEP_GATING TU_BIT(5)
+#define PCGCCTL_RSTPDWNMODULE TU_BIT(3)
+#define PCGCCTL_PWRCLMP TU_BIT(2)
+#define PCGCCTL_GATEHCLK TU_BIT(1)
+#define PCGCCTL_STOPPCLK TU_BIT(0)
#define PCGCTL1_TIMER (0x3ul << 1)
#define PCGCTL1_GATEEN TU_BIT(0)
diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c
new file mode 100644
index 000000000..7cbef05b7
--- /dev/null
+++ b/src/portable/synopsys/dwc2/hcd_dwc2.c
@@ -0,0 +1,1366 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 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(TUP_USBIP_DWC2) && !CFG_TUH_MAX3421
+
+#if !(CFG_TUH_DWC2_SLAVE_ENABLE || CFG_TUH_DWC2_DMA_ENABLE)
+#error DWC2 require either CFG_TUH_DWC2_SLAVE_ENABLE or CFG_TUH_DWC2_DMA_ENABLE to be enabled
+#endif
+
+// Debug level for DWC2
+#define DWC2_DEBUG 2
+
+#include "host/hcd.h"
+#include "dwc2_common.h"
+
+// Max number of endpoints application can open, can be larger than DWC2_CHANNEL_COUNT_MAX
+#ifndef CFG_TUH_DWC2_ENDPOINT_MAX
+#define CFG_TUH_DWC2_ENDPOINT_MAX 16
+#endif
+
+#define DWC2_CHANNEL_COUNT_MAX 16 // absolute max channel count
+#define DWC2_CHANNEL_COUNT(_dwc2) tu_min8((_dwc2)->ghwcfg2_bm.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX)
+
+TU_VERIFY_STATIC(CFG_TUH_DWC2_ENDPOINT_MAX <= 255, "currently only use 8-bit for index");
+
+enum {
+ HPRT_W1_MASK = HPRT_CONN_DETECT | HPRT_ENABLE | HPRT_ENABLE_CHANGE | HPRT_OVER_CURRENT_CHANGE | HPRT_SUSPEND
+};
+
+enum {
+ HCD_XFER_ERROR_MAX = 3
+};
+
+enum {
+ HCD_XFER_PERIOD_SPLIT_NYET_MAX = 3
+};
+
+//--------------------------------------------------------------------
+//
+//--------------------------------------------------------------------
+
+// Host driver struct for each opened endpoint
+typedef struct {
+ union {
+ uint32_t hcchar;
+ dwc2_channel_char_t hcchar_bm;
+ };
+ union {
+ uint32_t hcsplt;
+ dwc2_channel_split_t hcsplt_bm;
+ };
+
+ struct TU_ATTR_PACKED {
+ uint32_t uframe_interval : 18; // micro-frame interval
+ uint32_t speed : 2;
+ uint32_t next_pid : 2;
+ uint32_t do_ping : 1;
+ // uint32_t : 9;
+ };
+
+ uint32_t uframe_countdown; // micro-frame count down to transfer for periodic, only need 18-bit
+
+ uint8_t* buffer;
+ uint16_t buflen;
+} hcd_endpoint_t;
+
+// Additional info for each channel when it is active
+typedef struct {
+ volatile bool allocated;
+ uint8_t ep_id;
+ struct TU_ATTR_PACKED {
+ uint8_t err_count : 3;
+ uint8_t period_split_nyet_count : 3;
+ uint8_t halted_nyet : 1;
+ uint8_t halted_sof_schedule : 1;
+ };
+ uint8_t result;
+
+ uint16_t xferred_bytes; // bytes that accumulate transferred though USB bus for the whole hcd_edpt_xfer(), which can
+ // be composed of multiple channel_xfer_start() (retry with NAK/NYET)
+ uint16_t fifo_bytes; // bytes written/read from/to FIFO (may not be transferred on USB bus).
+} hcd_xfer_t;
+
+typedef struct {
+ hcd_xfer_t xfer[DWC2_CHANNEL_COUNT_MAX];
+ hcd_endpoint_t edpt[CFG_TUH_DWC2_ENDPOINT_MAX];
+} hcd_data_t;
+
+hcd_data_t _hcd_data;
+
+//--------------------------------------------------------------------
+//
+//--------------------------------------------------------------------
+TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc2) {
+ tusb_speed_t speed;
+ switch(dwc2->hprt_bm.speed) {
+ case HPRT_SPEED_HIGH: speed = TUSB_SPEED_HIGH; break;
+ case HPRT_SPEED_FULL: speed = TUSB_SPEED_FULL; break;
+ case HPRT_SPEED_LOW : speed = TUSB_SPEED_LOW ; break;
+ default:
+ speed = TUSB_SPEED_INVALID;
+ TU_BREAKPOINT();
+ break;
+ }
+ return speed;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool dma_host_enabled(const dwc2_regs_t* dwc2) {
+ (void) dwc2;
+ // Internal DMA only
+ return CFG_TUH_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA;
+}
+
+#if CFG_TUH_MEM_DCACHE_ENABLE
+bool hcd_dcache_clean(const void* addr, uint32_t data_size) {
+ TU_VERIFY(addr && data_size);
+ return dwc2_dcache_clean(addr, data_size);
+}
+
+bool hcd_dcache_invalidate(const void* addr, uint32_t data_size) {
+ TU_VERIFY(addr && data_size);
+ return dwc2_dcache_invalidate(addr, data_size);
+}
+
+bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
+ TU_VERIFY(addr && data_size);
+ return dwc2_dcache_clean_invalidate(addr, data_size);
+}
+#endif
+
+// Allocate a channel for new transfer
+TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) {
+ const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
+ for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ if (!xfer->allocated) {
+ tu_memclr(xfer, sizeof(hcd_xfer_t));
+ xfer->allocated = true;
+ return ch_id;
+ }
+ }
+ return TUSB_INDEX_INVALID_8;
+}
+
+// Check if is periodic (interrupt/isochronous)
+TU_ATTR_ALWAYS_INLINE static inline bool edpt_is_periodic(uint8_t ep_type) {
+ return ep_type == HCCHAR_EPTYPE_INTERRUPT || ep_type == HCCHAR_EPTYPE_ISOCHRONOUS;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint8_t req_queue_avail(const dwc2_regs_t* dwc2, bool is_period) {
+ if (is_period) {
+ return dwc2->hptxsts_bm.req_queue_available;
+ } else {
+ return dwc2->hnptxsts_bm.req_queue_available;
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void channel_dealloc(dwc2_regs_t* dwc2, uint8_t ch_id) {
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ xfer->allocated = false;
+ dwc2->haintmsk &= ~TU_BIT(ch_id);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) {
+ // disable also require request queue
+ TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type)));
+ channel->hcintmsk |= HCINT_HALTED;
+ channel->hcchar |= HCCHAR_CHDIS | HCCHAR_CHENA; // must set both CHDIS and CHENA
+ return true;
+}
+
+// attempt to send IN token to receive data
+TU_ATTR_ALWAYS_INLINE static inline bool channel_send_in_token(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) {
+ TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type)));
+ channel->hcchar |= HCCHAR_CHENA;
+ return true;
+}
+
+// Find currently enabled channel. Note: EP0 is bidirectional
+TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_find_enabled(dwc2_regs_t* dwc2, uint8_t dev_addr, uint8_t ep_num, uint8_t ep_dir) {
+ const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
+ for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
+ if (_hcd_data.xfer[ch_id].allocated) {
+ const dwc2_channel_char_t hcchar_bm = dwc2->channel[ch_id].hcchar_bm;
+ if (hcchar_bm.dev_addr == dev_addr && hcchar_bm.ep_num == ep_num && (ep_num == 0 || hcchar_bm.ep_dir == ep_dir)) {
+ return ch_id;
+ }
+ }
+ }
+ return TUSB_INDEX_INVALID_8;
+}
+
+
+// Allocate a new endpoint
+TU_ATTR_ALWAYS_INLINE static inline uint8_t edpt_alloc(void) {
+ for (uint32_t i = 0; i < CFG_TUH_DWC2_ENDPOINT_MAX; i++) {
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[i];
+ if (edpt->hcchar_bm.enable == 0) {
+ tu_memclr(edpt, sizeof(hcd_endpoint_t));
+ edpt->hcchar_bm.enable = 1;
+ return i;
+ }
+ }
+ return TUSB_INDEX_INVALID_8;
+}
+
+// Find a endpoint that is opened previously with hcd_edpt_open()
+// Note: EP0 is bidirectional
+TU_ATTR_ALWAYS_INLINE static inline uint8_t edpt_find_opened(uint8_t dev_addr, uint8_t ep_num, uint8_t ep_dir) {
+ for (uint8_t i = 0; i < (uint8_t)CFG_TUH_DWC2_ENDPOINT_MAX; i++) {
+ const dwc2_channel_char_t* hcchar_bm = &_hcd_data.edpt[i].hcchar_bm;
+ if (hcchar_bm->enable && hcchar_bm->dev_addr == dev_addr &&
+ hcchar_bm->ep_num == ep_num && (ep_num == 0 || hcchar_bm->ep_dir == ep_dir)) {
+ return i;
+ }
+ }
+ return TUSB_INDEX_INVALID_8;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t cal_packet_count(uint16_t len, uint16_t ep_size) {
+ if (len == 0) {
+ return 1;
+ } else {
+ return tu_div_ceil(len, ep_size);
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint8_t cal_next_pid(uint8_t pid, uint8_t packet_count) {
+ if (packet_count & 0x01) {
+ return pid ^ 0x02; // toggle DATA0 and DATA1
+ } else {
+ return pid;
+ }
+}
+
+//--------------------------------------------------------------------
+//
+//--------------------------------------------------------------------
+
+/* USB Data FIFO Layout
+
+ The FIFO is split up into
+ - EPInfo: for storing DMA metadata (check dcd_dwc2.c for more details)
+ - 1 RX FIFO: for receiving data
+ - 1 TX FIFO for non-periodic (NPTX)
+ - 1 TX FIFO for periodic (PTX)
+
+ We allocated TX FIFO from top to bottom (using top pointer), this to allow the RX FIFO to grow dynamically which is
+ possible since the free space is located between the RX and TX FIFOs.
+
+ ----------------- ep_fifo_size
+ | HCDMAn |
+ |--------------|-- gdfifocfg.EPINFOBASE (max is ghwcfg3.dfifo_depth)
+ | Non-Periodic |
+ | TX FIFO |
+ |--------------|--- GNPTXFSIZ.addr (fixed size)
+ | Periodic |
+ | TX FIFO |
+ |--------------|--- HPTXFSIZ.addr (expandable downward)
+ | FREE |
+ | |
+ |--------------|-- GRXFSIZ (expandable upward)
+ | RX FIFO |
+ ---------------- 0
+*/
+
+/* Programming Guide 2.1.2 FIFO RAM allocation
+ * RX
+ * - Largest-EPsize/4 + 2 (status info). recommended x2 if high bandwidth or multiple ISO are used.
+ * - 2 for transfer complete and channel halted status
+ * - 1 for each Control/Bulk out endpoint to Handle NAK/NYET (i.e max is number of host channel)
+ *
+ * TX non-periodic (NPTX)
+ * - At least largest-EPsize/4, recommended x2
+ *
+ * TX periodic (PTX)
+ * - At least largest-EPsize*MulCount/4 (MulCount up to 3 for high-bandwidth ISO/interrupt)
+*/
+static void dfifo_host_init(uint8_t rhport) {
+ const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per channel
+ const bool is_dma = dma_host_enabled(dwc2);
+ uint16_t dfifo_top = dwc2_controller->ep_fifo_size/4;
+ if (is_dma) {
+ dfifo_top -= dwc2->ghwcfg2_bm.num_host_ch;
+ }
+
+ // fixed allocation for now, improve later:
+ // - ptx_largest is limited to 256 for FS since most FS core only has 1024 bytes total
+ bool is_highspeed = dwc2_core_is_highspeed(dwc2, TUSB_ROLE_HOST);
+ uint32_t nptx_largest = is_highspeed ? TUSB_EPSIZE_BULK_HS/4 : TUSB_EPSIZE_BULK_FS/4;
+ uint32_t ptx_largest = is_highspeed ? TUSB_EPSIZE_ISO_HS_MAX/4 : 256/4;
+
+ uint16_t nptxfsiz = 2 * nptx_largest;
+ uint16_t rxfsiz = 2 * (ptx_largest + 2) + dwc2->ghwcfg2_bm.num_host_ch;
+ TU_ASSERT(dfifo_top >= (nptxfsiz + rxfsiz),);
+ uint16_t ptxfsiz = dfifo_top - (nptxfsiz + rxfsiz);
+
+ dwc2->gdfifocfg = (dfifo_top << GDFIFOCFG_EPINFOBASE_SHIFT) | dfifo_top;
+
+ dfifo_top -= rxfsiz;
+ dwc2->grxfsiz = rxfsiz;
+
+ dfifo_top -= nptxfsiz;
+ dwc2->gnptxfsiz = tu_u32_from_u16(nptxfsiz, dfifo_top);
+
+ dfifo_top -= ptxfsiz;
+ dwc2->hptxfsiz = tu_u32_from_u16(ptxfsiz, dfifo_top);
+}
+
+//--------------------------------------------------------------------+
+// 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 true;
+}
+
+// Initialize controller to host mode
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ tu_memclr(&_hcd_data, sizeof(_hcd_data));
+
+ // Core Initialization
+ const bool is_highspeed = dwc2_core_is_highspeed(dwc2, TUSB_ROLE_HOST);
+ const bool is_dma = dma_host_enabled(dwc2);
+ TU_ASSERT(dwc2_core_init(rhport, is_highspeed, is_dma));
+
+ //------------- 3.1 Host Initialization -------------//
+
+ // work at max supported speed
+ dwc2->hcfg &= ~HCFG_FSLS_ONLY;
+
+ // Enable HFIR reload
+ if (dwc2->gsnpsid >= DWC2_CORE_REV_2_92a) {
+ dwc2->hfir |= HFIR_RELOAD_CTRL;
+ }
+
+ // force host mode and wait for mode switch
+ dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FDMOD) | GUSBCFG_FHMOD;
+ while ((dwc2->gintsts & GINTSTS_CMOD) != GINTSTS_CMODE_HOST) {}
+
+ // configure fixed-allocated fifo scheme
+ dfifo_host_init(rhport);
+
+ dwc2->hprt = HPRT_W1_MASK; // clear all write-1-clear bits
+ dwc2->hprt = HPRT_POWER; // turn on VBUS
+
+ // Enable required interrupts
+ dwc2->gintmsk |= GINTSTS_OTGINT | GINTSTS_CONIDSTSCHNG | GINTSTS_HPRTINT | GINTSTS_HCINT;
+
+ // NPTX can hold at least 2 packet, change interrupt level to half-empty
+ uint32_t gahbcfg = dwc2->gahbcfg & ~GAHBCFG_TX_FIFO_EPMTY_LVL;
+ gahbcfg |= GAHBCFG_GINT; // Enable global interrupt
+ dwc2->gahbcfg = gahbcfg;
+
+ return true;
+}
+
+// Enable USB interrupt
+void hcd_int_enable (uint8_t rhport) {
+ dwc2_int_set(rhport, TUSB_ROLE_HOST, true);
+}
+
+// Disable USB interrupt
+void hcd_int_disable(uint8_t rhport) {
+ dwc2_int_set(rhport, TUSB_ROLE_HOST, false);
+}
+
+// Get frame number (1ms)
+uint32_t hcd_frame_number(uint8_t rhport) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ return dwc2->hfnum & HFNUM_FRNUM_Msk;
+}
+
+//--------------------------------------------------------------------+
+// Port API
+//--------------------------------------------------------------------+
+
+// Get the current connect status of roothub port
+bool hcd_port_connect_status(uint8_t rhport) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ return dwc2->hprt & HPRT_CONN_STATUS;
+}
+
+// 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) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK;
+ hprt |= HPRT_RESET;
+ dwc2->hprt = hprt;
+}
+
+// Complete bus reset sequence, may be required by some controllers
+void hcd_port_reset_end(uint8_t rhport) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK; // skip w1c bits
+ hprt &= ~HPRT_RESET;
+ dwc2->hprt = hprt;
+}
+
+// Get port link speed
+tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ const tusb_speed_t speed = hprt_speed_get(dwc2);
+ return speed;
+}
+
+// HCD closes all opened endpoints belong to this device
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
+ (void) rhport;
+ for (uint8_t i = 0; i < (uint8_t) CFG_TUH_DWC2_ENDPOINT_MAX; i++) {
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[i];
+ if (edpt->hcchar_bm.enable && edpt->hcchar_bm.dev_addr == dev_addr) {
+ tu_memclr(edpt, sizeof(hcd_endpoint_t));
+ }
+ }
+}
+
+//--------------------------------------------------------------------+
+// Endpoints API
+//--------------------------------------------------------------------+
+
+// Open an endpoint
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* desc_ep) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ const tusb_speed_t rh_speed = hprt_speed_get(dwc2);
+
+ hcd_devtree_info_t devtree_info;
+ hcd_devtree_get_info(dev_addr, &devtree_info);
+
+ // find a free endpoint
+ const uint8_t ep_id = edpt_alloc();
+ TU_ASSERT(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
+
+ dwc2_channel_char_t* hcchar_bm = &edpt->hcchar_bm;
+ hcchar_bm->ep_size = tu_edpt_packet_size(desc_ep);
+ hcchar_bm->ep_num = tu_edpt_number(desc_ep->bEndpointAddress);
+ hcchar_bm->ep_dir = tu_edpt_dir(desc_ep->bEndpointAddress);
+ hcchar_bm->low_speed_dev = (devtree_info.speed == TUSB_SPEED_LOW) ? 1 : 0;
+ hcchar_bm->ep_type = desc_ep->bmAttributes.xfer; // ep_type matches TUSB_XFER_*
+ hcchar_bm->err_multi_count = 0;
+ hcchar_bm->dev_addr = dev_addr;
+ hcchar_bm->odd_frame = 0;
+ hcchar_bm->disable = 0;
+ hcchar_bm->enable = 1;
+
+ dwc2_channel_split_t* hcsplt_bm = &edpt->hcsplt_bm;
+ hcsplt_bm->hub_port = devtree_info.hub_port;
+ hcsplt_bm->hub_addr = devtree_info.hub_addr;
+ hcsplt_bm->xact_pos = 0;
+ hcsplt_bm->split_compl = 0;
+ hcsplt_bm->split_en = (rh_speed == TUSB_SPEED_HIGH && devtree_info.speed != TUSB_SPEED_HIGH) ? 1 : 0;
+
+ edpt->speed = devtree_info.speed;
+ edpt->next_pid = HCTSIZ_PID_DATA0;
+ if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
+ edpt->uframe_interval = 1 << (desc_ep->bInterval - 1);
+ if (devtree_info.speed == TUSB_SPEED_FULL) {
+ edpt->uframe_interval <<= 3;
+ }
+ } else if (desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT) {
+ if (devtree_info.speed == TUSB_SPEED_HIGH) {
+ edpt->uframe_interval = 1 << (desc_ep->bInterval - 1);
+ } else {
+ edpt->uframe_interval = desc_ep->bInterval << 3;
+ }
+ }
+
+ return true;
+}
+
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
+// clean up channel after part of transfer is done but the whole urb is not complete
+static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) {
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+
+ edpt->next_pid = channel->hctsiz_bm.pid; // save PID
+
+ /* Since hctsiz.xfersize field reflects the number of bytes transferred via the AHB, not the USB)
+ * For IN: we can use hctsiz.xfersize as remaining bytes.
+ * For OUT: Must use the hctsiz.pktcnt field to determine how much data has been transferred. This field reflects the
+ * number of packets that have been transferred via the USB. This is always an integral number of packets if the
+ * transfer was halted before its normal completion.
+ */
+ const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
+ const uint16_t total_packets = cal_packet_count(edpt->buflen, channel->hcchar_bm.ep_size);
+ const uint16_t actual_bytes = (total_packets - remain_packets) * channel->hcchar_bm.ep_size;
+
+ xfer->fifo_bytes = 0;
+ xfer->xferred_bytes += actual_bytes;
+ edpt->buffer += actual_bytes;
+ edpt->buflen -= actual_bytes;
+}
+
+static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) {
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+ dwc2_channel_char_t* hcchar_bm = &edpt->hcchar_bm;
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ bool const is_period = edpt_is_periodic(hcchar_bm->ep_type);
+
+ // clear previous state
+ xfer->fifo_bytes = 0;
+
+ // hchar: restore but don't enable yet
+ if (is_period) {
+ hcchar_bm->odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
+ }
+ channel->hcchar = (edpt->hcchar & ~HCCHAR_CHENA);
+
+ // hctsiz: zero length packet still count as 1
+ const uint16_t packet_count = cal_packet_count(edpt->buflen, hcchar_bm->ep_size);
+ uint32_t hctsiz = (edpt->next_pid << HCTSIZ_PID_Pos) | (packet_count << HCTSIZ_PKTCNT_Pos) | edpt->buflen;
+ if (edpt->do_ping && edpt->speed == TUSB_SPEED_HIGH &&
+ edpt->next_pid != HCTSIZ_PID_SETUP && hcchar_bm->ep_dir == TUSB_DIR_OUT) {
+ hctsiz |= HCTSIZ_DOPING;
+ }
+ channel->hctsiz = hctsiz;
+ edpt->do_ping = 0;
+
+ // pre-calculate next PID based on packet count, adjusted in transfer complete interrupt if short packet
+ if (hcchar_bm->ep_num == 0) {
+ edpt->next_pid = HCTSIZ_PID_DATA1; // control data and status stage always start with DATA1
+ } else {
+ edpt->next_pid = cal_next_pid(edpt->next_pid, packet_count);
+ }
+
+ channel->hcsplt = edpt->hcsplt;
+ channel->hcint = 0xFFFFFFFFU; // clear all channel interrupts
+
+ if (dma_host_enabled(dwc2)) {
+ uint32_t hcintmsk = HCINT_HALTED;
+ channel->hcintmsk = hcintmsk;
+ dwc2->haintmsk |= TU_BIT(ch_id);
+
+ channel->hcdma = (uint32_t) edpt->buffer;
+
+ if (hcchar_bm->ep_dir == TUSB_DIR_IN) {
+ channel_send_in_token(dwc2, channel);
+ } else {
+ hcd_dcache_clean(edpt->buffer, edpt->buflen);
+ channel->hcchar |= HCCHAR_CHENA;
+ }
+ } else {
+ uint32_t hcintmsk = HCINT_NAK | HCINT_XACT_ERR | HCINT_STALL | HCINT_XFER_COMPLETE | HCINT_DATATOGGLE_ERR;
+ if (hcchar_bm->ep_dir == TUSB_DIR_IN) {
+ hcintmsk |= HCINT_BABBLE_ERR | HCINT_DATATOGGLE_ERR | HCINT_ACK;
+ } else {
+ hcintmsk |= HCINT_NYET;
+ if (edpt->hcsplt_bm.split_en) {
+ hcintmsk |= HCINT_ACK;
+ }
+ }
+ channel->hcintmsk = hcintmsk;
+ dwc2->haintmsk |= TU_BIT(ch_id);
+
+ // enable channel for slave mode:
+ // - OUT: it will enable corresponding FIFO channel
+ // - IN : it will write an IN request to the Non-periodic Request Queue, this will have dwc2 trying to send
+ // IN Token. If we got NAK, we have to re-enable the channel again in the interrupt. Due to the way usbh stack only
+ // call hcd_edpt_xfer() once, we will need to manage de-allocate/re-allocate IN channel dynamically.
+ if (hcchar_bm->ep_dir == TUSB_DIR_IN) {
+ channel_send_in_token(dwc2, channel);
+ } else {
+ channel->hcchar |= HCCHAR_CHENA;
+ if (edpt->buflen > 0) {
+ // To prevent conflict with other channel, we will enable periodic/non-periodic FIFO empty interrupt accordingly
+ // And write packet in the interrupt handler
+ dwc2->gintmsk |= (is_period ? GINTSTS_PTX_FIFO_EMPTY : GINTSTS_NPTX_FIFO_EMPTY);
+ }
+ }
+ }
+
+ return true;
+}
+
+// kick-off transfer with an endpoint
+static bool edpt_xfer_kickoff(dwc2_regs_t* dwc2, uint8_t ep_id) {
+ uint8_t ch_id = channel_alloc(dwc2);
+ TU_ASSERT(ch_id < 16); // all channel are in used
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ xfer->ep_id = ep_id;
+ xfer->result = XFER_RESULT_INVALID;
+
+ return channel_xfer_start(dwc2, ch_id);
+}
+
+// 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) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const uint8_t ep_dir = tu_edpt_dir(ep_addr);
+
+ uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir);
+ TU_ASSERT(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
+
+ edpt->buffer = buffer;
+ edpt->buflen = buflen;
+
+ if (ep_num == 0) {
+ // update ep_dir since control endpoint can switch direction
+ edpt->hcchar_bm.ep_dir = ep_dir;
+ }
+
+ return edpt_xfer_kickoff(dwc2, ep_id);
+}
+
+// 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) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const uint8_t ep_dir = tu_edpt_dir(ep_addr);
+ const uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir);
+ TU_VERIFY(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
+
+ // hcd_int_disable(rhport);
+
+ // Find enabled channeled and disable it, channel will be de-allocated in the interrupt handler
+ const uint8_t ch_id = channel_find_enabled(dwc2, dev_addr, ep_num, ep_dir);
+ if (ch_id < 16) {
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ channel_disable(dwc2, channel);
+ }
+
+ // hcd_int_enable(rhport);
+
+ return true;
+}
+
+// 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, const uint8_t setup_packet[8]) {
+ uint8_t ep_id = edpt_find_opened(dev_addr, 0, TUSB_DIR_OUT);
+ TU_ASSERT(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); // no opened endpoint
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
+ edpt->next_pid = HCTSIZ_PID_SETUP;
+
+ return hcd_edpt_xfer(rhport, dev_addr, 0, (uint8_t*)(uintptr_t) setup_packet, 8);
+}
+
+// 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;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const uint8_t ep_dir = tu_edpt_dir(ep_addr);
+ const uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir);
+ TU_VERIFY(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
+
+ edpt->next_pid = HCTSIZ_PID_DATA0;
+
+ return true;
+}
+
+//--------------------------------------------------------------------
+// HCD Event Handler
+//--------------------------------------------------------------------
+static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcint) {
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+
+ if (edpt_is_periodic(channel->hcchar_bm.ep_type)){
+ // retry immediately for periodic split NYET if we haven't reach max retry
+ if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) {
+ xfer->period_split_nyet_count++;
+ xfer->halted_nyet = 0;
+ if (xfer->period_split_nyet_count < HCD_XFER_PERIOD_SPLIT_NYET_MAX) {
+ channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
+ channel_send_in_token(dwc2, channel);
+ return;
+ } else {
+ // too many NYET, de-allocate channel with below code
+ xfer->period_split_nyet_count = 0;
+ }
+ }
+
+ // for periodic, de-allocate channel, enable SOF set frame counter for later transfer
+ edpt->next_pid = channel->hctsiz_bm.pid; // save PID
+ edpt->uframe_countdown = edpt->uframe_interval;
+ dwc2->gintmsk |= GINTSTS_SOF;
+
+ if (hcint & HCINT_HALTED) {
+ // already halted, de-allocate channel (called from DMA isr)
+ channel_dealloc(dwc2, ch_id);
+ } else {
+ // disable channel first if not halted (called slave isr)
+ xfer->halted_sof_schedule = 1;
+ channel_disable(dwc2, channel);
+ }
+ } else {
+ // for control/bulk: retry immediately
+ channel_send_in_token(dwc2, channel);
+ }
+}
+
+#if CFG_TUSB_DEBUG
+TU_ATTR_ALWAYS_INLINE static inline void print_hcint(uint32_t hcint) {
+ const char* str[] = {
+ "XFRC", "HALTED", "AHBERR", "STALL",
+ "NAK", "ACK", "NYET", "XERR",
+ "BBLERR", "FRMOR", "DTERR", "BNA",
+ "XCSERR", "DESC_LST"
+ };
+
+ for(uint32_t i=0; i<14; i++) {
+ if (hcint & TU_BIT(i)) {
+ TU_LOG1("%s ", str[i]);
+ }
+ }
+ TU_LOG1("\r\n");
+}
+#endif
+
+#if CFG_TUH_DWC2_SLAVE_ENABLE
+static void handle_rxflvl_irq(uint8_t rhport) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ // Pop control word off FIFO
+ const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm;
+ const uint8_t ch_id = grxstsp_bm.ep_ch_num;
+
+ switch (grxstsp_bm.packet_status) {
+ case GRXSTS_PKTSTS_RX_DATA: {
+ // In packet received, pop this entry --> ACK interrupt
+ const uint16_t byte_count = grxstsp_bm.byte_count;
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,);
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+
+ if (byte_count) {
+ dfifo_read_packet(dwc2, edpt->buffer + xfer->xferred_bytes, byte_count);
+ xfer->xferred_bytes += byte_count;
+ xfer->fifo_bytes = byte_count;
+ }
+ break;
+ }
+
+ case GRXSTS_PKTSTS_RX_COMPLETE:
+ // In transfer complete: After this entry is popped from the rx FIFO, dwc2 asserts a Transfer Completed
+ // interrupt --> handle_channel_irq()
+ break;
+
+ case GRXSTS_PKTSTS_HOST_DATATOGGLE_ERR:
+ TU_ASSERT(0, ); // maybe try to change DToggle
+ break;
+
+ case GRXSTS_PKTSTS_HOST_CHANNEL_HALTED:
+ // triggered when channel.hcchar_bm.disable is set
+ // TODO handle later
+ break;
+
+ default: break; // ignore other status
+ }
+}
+
+// return true if there is still pending data and need more ISR
+static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) {
+ // Use period txsts for both p/np to get request queue space available (1-bit difference, it is small enough)
+ volatile dwc2_hptxsts_t* txsts_bm = (volatile dwc2_hptxsts_t*) (is_periodic ? &dwc2->hptxsts : &dwc2->hnptxsts);
+
+ const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
+ for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ // skip writing to FIFO if channel is expecting halted.
+ if (!(channel->hcintmsk & HCINT_HALTED) && (channel->hcchar_bm.ep_dir == TUSB_DIR_OUT)) {
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+
+ const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
+ for (uint16_t i = 0; i < remain_packets; i++) {
+ const uint16_t remain_bytes = edpt->buflen - xfer->fifo_bytes;
+ const uint16_t xact_bytes = tu_min16(remain_bytes, channel->hcchar_bm.ep_size);
+
+ // skip if there is not enough space in FIFO and RequestQueue.
+ // Packet's last word written to FIFO will trigger a request queue
+ if ((xact_bytes > (txsts_bm->fifo_available << 2)) || (txsts_bm->req_queue_available == 0)) {
+ return true;
+ }
+
+ dfifo_write_packet(dwc2, ch_id, edpt->buffer + xfer->fifo_bytes, xact_bytes);
+ xfer->fifo_bytes += xact_bytes;
+ }
+ }
+ }
+
+ return false; // no channel has pending data
+}
+
+static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcint) {
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+ bool is_done = false;
+
+ // if (channel->hcsplt_bm.split_en) {
+ // if (edpt->hcchar_bm.ep_num == 1) {
+ // TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, channel->hcchar_bm.ep_num, hcint);
+ // print_hcint(hcint);
+ // }
+
+ if (hcint & HCINT_XFER_COMPLETE) {
+ if (edpt->hcchar_bm.ep_num != 0) {
+ edpt->next_pid = channel->hctsiz_bm.pid; // save pid (already toggled)
+ }
+
+ const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
+ if (channel->hcsplt_bm.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) {
+ // Split can only complete 1 transaction (up to 1 packet) at a time, schedule more
+ channel->hcsplt_bm.split_compl = 0;
+ } else {
+ xfer->result = XFER_RESULT_SUCCESS;
+ }
+
+ channel_disable(dwc2, channel);
+ } else if (hcint & (HCINT_XACT_ERR | HCINT_BABBLE_ERR | HCINT_STALL)) {
+ if (hcint & HCINT_STALL) {
+ xfer->result = XFER_RESULT_STALLED;
+ } else if (hcint & HCINT_BABBLE_ERR) {
+ xfer->result = XFER_RESULT_FAILED;
+ } else if (hcint & HCINT_XACT_ERR) {
+ xfer->err_count++;
+ channel->hcintmsk |= HCINT_ACK;
+ }
+
+ channel_disable(dwc2, channel);
+ } else if (hcint & HCINT_NYET) {
+ // restart complete split
+ channel->hcsplt_bm.split_compl = 1;
+ xfer->halted_nyet = 1;
+ channel_disable(dwc2, channel);
+ } else if (hcint & HCINT_NAK) {
+ // NAK received, re-enable channel if request queue is available
+ if (channel->hcsplt_bm.split_en) {
+ channel->hcsplt_bm.split_compl = 0; // restart with start-split
+ }
+
+ channel_disable(dwc2, channel);
+ } else if (hcint & HCINT_ACK) {
+ xfer->err_count = 0;
+
+ if (channel->hcsplt_bm.split_en) {
+ if (!channel->hcsplt_bm.split_compl) {
+ // start split is ACK --> do complete split
+ channel->hcintmsk |= HCINT_NYET;
+ channel->hcsplt_bm.split_compl = 1;
+ channel_send_in_token(dwc2, channel);
+ } else {
+ // do nothing for complete split with DATA, this will trigger XferComplete and handled there
+ }
+ } else {
+ // ACK with data
+ const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
+ if (remain_packets) {
+ // still more packet to receive, also reset to start split
+ channel->hcsplt_bm.split_compl = 0;
+ channel_send_in_token(dwc2, channel);
+ }
+ }
+ } else if (hcint & HCINT_HALTED) {
+ channel->hcintmsk &= ~HCINT_HALTED;
+ if (xfer->halted_sof_schedule) {
+ // de-allocate channel but does not complete xfer, we schedule it in the SOF interrupt
+ channel_dealloc(dwc2, ch_id);
+ } else if (xfer->result != XFER_RESULT_INVALID) {
+ is_done = true;
+ } else if (xfer->err_count == HCD_XFER_ERROR_MAX) {
+ xfer->result = XFER_RESULT_FAILED;
+ is_done = true;
+ } else {
+ // got here due to NAK or NYET
+ channel_xfer_in_retry(dwc2, ch_id, hcint);
+ }
+ } else if (hcint & HCINT_DATATOGGLE_ERR) {
+ xfer->err_count = 0;
+ TU_ASSERT(false);
+ }
+ return is_done;
+}
+
+static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcint) {
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+ bool is_done = false;
+
+ if (hcint & HCINT_XFER_COMPLETE) {
+ is_done = true;
+ xfer->result = XFER_RESULT_SUCCESS;
+ channel->hcintmsk &= ~HCINT_ACK;
+ } else if (hcint & HCINT_STALL) {
+ xfer->result = XFER_RESULT_STALLED;
+ channel_disable(dwc2, channel);
+ } else if (hcint & HCINT_NYET) {
+ xfer->err_count = 0;
+ if (channel->hcsplt_bm.split_en) {
+ // retry complete split
+ channel->hcsplt_bm.split_compl = 1;
+ channel->hcchar |= HCCHAR_CHENA;
+ } else {
+ edpt->do_ping = 1;
+ channel_xfer_out_wrapup(dwc2, ch_id);
+ channel_disable(dwc2, channel);
+ }
+ } else if (hcint & (HCINT_NAK | HCINT_XACT_ERR)) {
+ // clean up transfer so far, disable and start again later
+ channel_xfer_out_wrapup(dwc2, ch_id);
+ channel_disable(dwc2, channel);
+ if (hcint & HCINT_XACT_ERR) {
+ xfer->err_count++;
+ channel->hcintmsk |= HCINT_ACK;
+ } else {
+ // NAK disable channel to flush all posted request and try again
+ edpt->do_ping = 1;
+ xfer->err_count = 0;
+ }
+ } else if (hcint & HCINT_HALTED) {
+ channel->hcintmsk &= ~HCINT_HALTED;
+ if (xfer->result != XFER_RESULT_INVALID) {
+ is_done = true;
+ } else if (xfer->err_count == HCD_XFER_ERROR_MAX) {
+ xfer->result = XFER_RESULT_FAILED;
+ is_done = true;
+ } else {
+ // Got here due to NAK or NYET
+ TU_ASSERT(channel_xfer_start(dwc2, ch_id));
+ }
+ } else if (hcint & HCINT_ACK) {
+ xfer->err_count = 0;
+ channel->hcintmsk &= ~HCINT_ACK;
+ if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) {
+ // start split is ACK --> do complete split
+ channel->hcsplt_bm.split_compl = 1;
+ channel->hcchar |= HCCHAR_CHENA;
+ }
+ }
+
+ if (is_done) {
+ xfer->xferred_bytes += xfer->fifo_bytes;
+ xfer->fifo_bytes = 0;
+ }
+
+ return is_done;
+}
+#endif
+
+#if CFG_TUH_DWC2_DMA_ENABLE
+static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcint) {
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+
+ bool is_done = false;
+
+ // TU_LOG1("in hcint = %02lX\r\n", hcint);
+
+ if (hcint & HCINT_HALTED) {
+ if (hcint & (HCINT_XFER_COMPLETE | HCINT_STALL | HCINT_BABBLE_ERR)) {
+ const uint16_t remain_bytes = (uint16_t) channel->hctsiz_bm.xfer_size;
+ const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
+ const uint16_t actual_len = edpt->buflen - remain_bytes;
+ xfer->xferred_bytes += actual_len;
+
+ is_done = true;
+
+ if (hcint & HCINT_STALL) {
+ xfer->result = XFER_RESULT_STALLED;
+ } else if (hcint & HCINT_BABBLE_ERR) {
+ xfer->result = XFER_RESULT_FAILED;
+ } else if (channel->hcsplt_bm.split_en && remain_packets && actual_len == edpt->hcchar_bm.ep_size) {
+ // Split can only complete 1 transaction (up to 1 packet) at a time, schedule more
+ is_done = false;
+ edpt->buffer += actual_len;
+ edpt->buflen -= actual_len;
+
+ channel->hcsplt_bm.split_compl = 0;
+ channel_xfer_in_retry(dwc2, ch_id, hcint);
+ } else {
+ xfer->result = XFER_RESULT_SUCCESS;
+ }
+
+ xfer->err_count = 0;
+ channel->hcintmsk &= ~HCINT_ACK;
+ } else if (hcint & HCINT_XACT_ERR) {
+ xfer->err_count++;
+ if (xfer->err_count >= HCD_XFER_ERROR_MAX) {
+ is_done = true;
+ xfer->result = XFER_RESULT_FAILED;
+ } else {
+ channel->hcintmsk |= HCINT_ACK | HCINT_NAK | HCINT_DATATOGGLE_ERR;
+ channel->hcsplt_bm.split_compl = 0;
+ channel_xfer_in_retry(dwc2, ch_id, hcint);
+ }
+ } else if (hcint & HCINT_NYET) {
+ // Must handle nyet before nak or ack. Could get a nyet at the same time as either of those on a BULK/CONTROL
+ // OUT that started with a PING. The nyet takes precedence.
+ if (channel->hcsplt_bm.split_en) {
+ // split not yet mean hub has no data, retry complete split
+ channel->hcsplt_bm.split_compl = 1;
+ channel_xfer_in_retry(dwc2, ch_id, hcint);
+ }
+ } else if (hcint & HCINT_ACK) {
+ xfer->err_count = 0;
+ channel->hcintmsk &= ~HCINT_ACK;
+ if (channel->hcsplt_bm.split_en) {
+ // start split is ACK --> do complete split
+ // TODO: for ISO must use xact_pos to plan complete split based on microframe (up to 187.5 bytes/uframe)
+ channel->hcsplt_bm.split_compl = 1;
+ if (edpt_is_periodic(channel->hcchar_bm.ep_type)) {
+ channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
+ }
+ channel_send_in_token(dwc2, channel);
+ }
+ } else if (hcint & (HCINT_NAK | HCINT_DATATOGGLE_ERR)) {
+ xfer->err_count = 0;
+ channel->hcintmsk &= ~(HCINT_NAK | HCINT_DATATOGGLE_ERR);
+ channel->hcsplt_bm.split_compl = 0; // restart with start-split
+ channel_xfer_in_retry(dwc2, ch_id, hcint);
+ } else if (hcint & HCINT_FARME_OVERRUN) {
+ // retry start-split in next binterval
+ channel_xfer_in_retry(dwc2, ch_id, hcint);
+ }
+ }
+
+ return is_done;
+}
+
+static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcint) {
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+
+ bool is_done = false;
+
+ // TU_LOG1("out hcint = %02lX\r\n", hcint);
+
+ if (hcint & HCINT_HALTED) {
+ if (hcint & (HCINT_XFER_COMPLETE | HCINT_STALL)) {
+ is_done = true;
+ xfer->err_count = 0;
+ if (hcint & HCINT_XFER_COMPLETE) {
+ xfer->result = XFER_RESULT_SUCCESS;
+ xfer->xferred_bytes += edpt->buflen;
+ } else {
+ xfer->result = XFER_RESULT_STALLED;
+ channel_xfer_out_wrapup(dwc2, ch_id);
+ }
+ channel->hcintmsk &= ~HCINT_ACK;
+ } else if (hcint & HCINT_XACT_ERR) {
+ if (hcint & (HCINT_NAK | HCINT_NYET | HCINT_ACK)) {
+ xfer->err_count = 0;
+ // clean up transfer so far and start again
+ channel_xfer_out_wrapup(dwc2, ch_id);
+ channel_xfer_start(dwc2, ch_id);
+ } else {
+ xfer->err_count++;
+ if (xfer->err_count >= HCD_XFER_ERROR_MAX) {
+ xfer->result = XFER_RESULT_FAILED;
+ is_done = true;
+ } else {
+ // clean up transfer so far and start again
+ channel_xfer_out_wrapup(dwc2, ch_id);
+ channel_xfer_start(dwc2, ch_id);
+ }
+ }
+ } else if (hcint & HCINT_NYET) {
+ if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl) {
+ // split not yet mean hub has no data, retry complete split
+ channel->hcsplt_bm.split_compl = 1;
+ channel->hcchar |= HCCHAR_CHENA;
+ }
+ } else if (hcint & HCINT_ACK) {
+ xfer->err_count = 0;
+ if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) {
+ // start split is ACK --> do complete split
+ channel->hcsplt_bm.split_compl = 1;
+ channel->hcchar |= HCCHAR_CHENA;
+ }
+ }
+ } else if (hcint & HCINT_ACK) {
+ xfer->err_count = 0;
+ channel->hcintmsk &= ~HCINT_ACK;
+ }
+
+ return is_done;
+}
+#endif
+
+static void handle_channel_irq(uint8_t rhport, bool in_isr) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ const bool is_dma = dma_host_enabled(dwc2);
+ const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
+
+ for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
+ if (tu_bit_test(dwc2->haint, ch_id)) {
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,);
+ dwc2_channel_char_t hcchar_bm = channel->hcchar_bm;
+
+ const uint32_t hcint = channel->hcint;
+ channel->hcint = hcint; // clear interrupt
+
+ bool is_done = false;
+ if (is_dma) {
+ #if CFG_TUH_DWC2_DMA_ENABLE
+ if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
+ is_done = handle_channel_out_dma(dwc2, ch_id, hcint);
+ } else {
+ is_done = handle_channel_in_dma(dwc2, ch_id, hcint);
+ if (is_done && (channel->hcdma > xfer->xferred_bytes)) {
+ // hcdma is increased by word --> need to align4
+ hcd_dcache_invalidate((void*) tu_align4(channel->hcdma - xfer->xferred_bytes), xfer->xferred_bytes);
+ }
+ }
+ #endif
+ } else {
+ #if CFG_TUH_DWC2_SLAVE_ENABLE
+ if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
+ is_done = handle_channel_out_slave(dwc2, ch_id, hcint);
+ } else {
+ is_done = handle_channel_in_slave(dwc2, ch_id, hcint);
+ }
+ #endif
+ }
+
+ if (is_done) {
+ const uint8_t ep_addr = tu_edpt_addr(hcchar_bm.ep_num, hcchar_bm.ep_dir);
+ hcd_event_xfer_complete(hcchar_bm.dev_addr, ep_addr, xfer->xferred_bytes, xfer->result, in_isr);
+ channel_dealloc(dwc2, ch_id);
+ }
+ }
+ }
+}
+
+// SOF is enabled for scheduled periodic transfer
+static bool handle_sof_irq(uint8_t rhport, bool in_isr) {
+ (void) in_isr;
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ dwc2->gintsts = GINTSTS_SOF; // Clear the SOF interrupt flag
+
+ bool more_isr = false;
+
+ // If highspeed then SOF is 125us, else 1ms
+ const uint32_t ucount = (hprt_speed_get(dwc2) == TUSB_SPEED_HIGH ? 1 : 8);
+
+ for(uint8_t ep_id = 0; ep_id < CFG_TUH_DWC2_ENDPOINT_MAX; ep_id++) {
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
+ if (edpt->hcchar_bm.enable && edpt_is_periodic(edpt->hcchar_bm.ep_type) && edpt->uframe_countdown > 0) {
+ edpt->uframe_countdown -= tu_min32(ucount, edpt->uframe_countdown);
+ if (edpt->uframe_countdown == 0) {
+ if (!edpt_xfer_kickoff(dwc2, ep_id)) {
+ edpt->uframe_countdown = ucount; // failed to start, try again next frame
+ }
+ }
+
+ more_isr = true;
+ }
+ }
+
+ return more_isr;
+}
+
+// Config HCFG FS/LS clock and HFIR for SOF interval according to link speed (value is in PHY clock unit)
+static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
+ uint32_t hcfg = dwc2->hcfg & ~HCFG_FSLS_PHYCLK_SEL;
+
+ const dwc2_gusbcfg_t gusbcfg_bm = dwc2->gusbcfg_bm;
+ uint32_t phy_clock;
+
+ if (gusbcfg_bm.phy_sel) {
+ phy_clock = 48; // dedicated FS is 48Mhz
+ if (speed == TUSB_SPEED_LOW) {
+ hcfg |= HCFG_FSLS_PHYCLK_SEL_6MHZ;
+ } else {
+ hcfg |= HCFG_FSLS_PHYCLK_SEL_48MHZ;
+ }
+ } else {
+ if (gusbcfg_bm.ulpi_utmi_sel) {
+ phy_clock = 60; // ULPI 8-bit is 60Mhz
+ } else {
+ // UTMI+ 16-bit is 30Mhz, 8-bit is 60Mhz
+ phy_clock = gusbcfg_bm.phy_if16 ? 30 : 60;
+
+ // Enable UTMI+ low power mode 48Mhz external clock if not highspeed
+ if (speed == TUSB_SPEED_HIGH) {
+ dwc2->gusbcfg &= ~GUSBCFG_PHYLPCS;
+ } else {
+ dwc2->gusbcfg |= GUSBCFG_PHYLPCS;
+ // may need to reset port
+ }
+ }
+ hcfg |= HCFG_FSLS_PHYCLK_SEL_30_60MHZ;
+ }
+
+ dwc2->hcfg = hcfg;
+
+ uint32_t hfir = dwc2->hfir & ~HFIR_FRIVL_Msk;
+ if (speed == TUSB_SPEED_HIGH) {
+ hfir |= 125*phy_clock;
+ } else {
+ hfir |= 1000*phy_clock;
+ }
+
+ dwc2->hfir = hfir;
+}
+
+/* Handle Host Port interrupt, possible source are:
+ - Connection Detection
+ - Enable Change
+ - Over Current Change
+*/
+static void handle_hprt_irq(uint8_t rhport, bool in_isr) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK;
+ const dwc2_hprt_t hprt_bm = dwc2->hprt_bm;
+
+ if (dwc2->hprt & HPRT_CONN_DETECT) {
+ // Port Connect Detect
+ hprt |= HPRT_CONN_DETECT;
+
+ if (hprt_bm.conn_status) {
+ hcd_event_device_attach(rhport, in_isr);
+ } else {
+ hcd_event_device_remove(rhport, in_isr);
+ }
+ }
+
+ if (dwc2->hprt & HPRT_ENABLE_CHANGE) {
+ // Port enable change
+ hprt |= HPRT_ENABLE_CHANGE;
+
+ if (hprt_bm.enable) {
+ // Port enable
+ const tusb_speed_t speed = hprt_speed_get(dwc2);
+ port0_enable(dwc2, speed);
+ } else {
+ // TU_ASSERT(false, );
+ }
+ }
+
+ dwc2->hprt = hprt; // clear interrupt
+}
+
+/* Interrupt Hierarchy
+ HCINTn HPRT
+ | |
+ HAINT.CHn |
+ | |
+ GINTSTS : HCInt | PrtInt | NPTxFEmp | PTxFEmpp | RXFLVL | SOF
+*/
+void hcd_int_handler(uint8_t rhport, bool in_isr) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ const uint32_t gintmsk = dwc2->gintmsk;
+ const uint32_t gintsts = dwc2->gintsts & gintmsk;
+
+ // TU_LOG1_HEX(gintsts);
+
+ if (gintsts & GINTSTS_CONIDSTSCHNG) {
+ // Connector ID status change
+ dwc2->gintsts = GINTSTS_CONIDSTSCHNG;
+
+ //if (dwc2->gotgctl)
+ // dwc2->hprt = HPRT_POWER; // power on port to turn on VBUS
+ //dwc2->gintmsk |= GINTMSK_PRTIM;
+ // TODO wait for SRP if OTG
+ }
+
+ if (gintsts & GINTSTS_SOF) {
+ const bool more_sof = handle_sof_irq(rhport, in_isr);
+ if (!more_sof) {
+ dwc2->gintmsk &= ~GINTSTS_SOF;
+ }
+ }
+
+ if (gintsts & GINTSTS_HPRTINT) {
+ // Host port interrupt: source is cleared in HPRT register
+ // TU_LOG1_HEX(dwc2->hprt);
+ handle_hprt_irq(rhport, in_isr);
+ }
+
+ if (gintsts & GINTSTS_HCINT) {
+ // Host Channel interrupt: source is cleared in HCINT register
+ // must be handled after TX FIFO empty
+ handle_channel_irq(rhport, in_isr);
+ }
+
+#if CFG_TUH_DWC2_SLAVE_ENABLE
+ // RxFIFO non-empty interrupt handling
+ if (gintsts & GINTSTS_RXFLVL) {
+ // RXFLVL bit is read-only
+ dwc2->gintmsk &= ~GINTSTS_RXFLVL; // disable RXFLVL interrupt while reading
+
+ do {
+ handle_rxflvl_irq(rhport); // read all packets
+ } while(dwc2->gintsts & GINTSTS_RXFLVL);
+
+ dwc2->gintmsk |= GINTSTS_RXFLVL;
+ }
+
+ if (gintsts & GINTSTS_NPTX_FIFO_EMPTY) {
+ // NPTX FIFO empty interrupt, this is read-only and cleared by hardware when FIFO is written
+ const bool more_nptxfe = handle_txfifo_empty(dwc2, false);
+ if (!more_nptxfe) {
+ // no more pending packet, disable interrupt
+ dwc2->gintmsk &= ~GINTSTS_NPTX_FIFO_EMPTY;
+ }
+ }
+
+ if (gintsts & GINTSTS_PTX_FIFO_EMPTY) {
+ // PTX FIFO empty interrupt, this is read-only and cleared by hardware when FIFO is written
+ const bool more_ptxfe = handle_txfifo_empty(dwc2, true);
+ if (!more_ptxfe) {
+ // no more pending packet, disable interrupt
+ dwc2->gintmsk &= ~GINTSTS_PTX_FIFO_EMPTY;
+ }
+ }
+#endif
+}
+
+#endif
diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c
index 12d610bd6..3738ac0cb 100644
--- a/src/portable/template/dcd_template.c
+++ b/src/portable/template/dcd_template.c
@@ -40,54 +40,45 @@
*------------------------------------------------------------------*/
// Initialize controller to device mode
-void dcd_init (uint8_t rhport)
-{
- (void) rhport;
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rhport; (void) rh_init;
+ return true;
}
// Enable device interrupt
-void dcd_int_enable (uint8_t rhport)
-{
+void dcd_int_enable (uint8_t rhport) {
(void) rhport;
}
// Disable device interrupt
-void dcd_int_disable (uint8_t rhport)
-{
+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)
-{
+void dcd_set_address (uint8_t rhport, uint8_t dev_addr) {
(void) rhport;
(void) dev_addr;
}
// Wake up host
-void dcd_remote_wakeup (uint8_t rhport)
-{
+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 dcd_connect(uint8_t rhport) {
(void) rhport;
}
// Disconnect by disabling internal pull-up resistor on D+/D-
-void dcd_disconnect(uint8_t rhport)
-{
+void dcd_disconnect(uint8_t rhport) {
(void) rhport;
}
-void dcd_sof_enable(uint8_t rhport, bool en)
-{
+void dcd_sof_enable(uint8_t rhport, bool en) {
(void) rhport;
(void) en;
-
- // TODO implement later
}
//--------------------------------------------------------------------+
@@ -95,21 +86,34 @@ void dcd_sof_enable(uint8_t rhport, bool en)
//--------------------------------------------------------------------+
// Configure endpoint's registers according to descriptor
-bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
-{
+bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) {
(void) rhport;
(void) ep_desc;
return false;
}
-void dcd_edpt_close_all (uint8_t rhport)
-{
+// Allocate packet buffer used by ISO endpoints
+// Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering
+bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
+ (void) rhport;
+ (void) ep_addr;
+ (void) largest_packet_size;
+ return false;
+}
+
+// Configure and enable an ISO endpoint according to descriptor
+bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) {
+ (void) rhport;
+ (void) desc_ep;
+ 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)
-{
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) {
(void) rhport;
(void) ep_addr;
(void) buffer;
@@ -118,8 +122,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
}
// 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)
-{
+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;
@@ -128,19 +131,15 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
}
// Stall endpoint
-void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
-{
+void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) {
(void) rhport;
(void) ep_addr;
}
// clear stall, data toggle is also reset to DATA0
-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;
(void) ep_addr;
}
-
-
#endif
diff --git a/src/portable/template/hcd_template.c b/src/portable/template/hcd_template.c
index fd870c91e..22ea22e63 100644
--- a/src/portable/template/hcd_template.c
+++ b/src/portable/template/hcd_template.c
@@ -36,24 +36,19 @@
// 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;
-
+ (void) rhport; (void) cfg_id; (void) cfg_param;
return false;
}
// Initialize controller to host mode
-bool hcd_init(uint8_t rhport) {
- (void) rhport;
-
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rhport; (void) rh_init;
return false;
}
// Interrupt Handler
void hcd_int_handler(uint8_t rhport, bool in_isr) {
- (void) rhport;
- (void) in_isr;
+ (void) rhport; (void) in_isr;
}
// Enable USB interrupt
@@ -69,7 +64,6 @@ void hcd_int_disable(uint8_t rhport) {
// Get frame number (1ms)
uint32_t hcd_frame_number(uint8_t rhport) {
(void) rhport;
-
return 0;
}
@@ -80,7 +74,6 @@ uint32_t hcd_frame_number(uint8_t rhport) {
// Get the current connect status of roothub port
bool hcd_port_connect_status(uint8_t rhport) {
(void) rhport;
-
return false;
}
@@ -98,14 +91,12 @@ void hcd_port_reset_end(uint8_t rhport) {
// Get port link speed
tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
(void) rhport;
-
return TUSB_SPEED_FULL;
}
// 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;
+ (void) rhport; (void) dev_addr;
}
//--------------------------------------------------------------------+
@@ -114,53 +105,42 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
// 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) rhport; (void) dev_addr; (void) ep_desc;
// NOTE: ep_desc is allocated on the stack when called from usbh_edpt_control_open()
// You need to copy the data into a local variable who maintains the state of the endpoint and transfer.
// Check _hcd_data in hcd_dwc2.c for example.
- (void) ep_desc;
return false;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
// 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;
-
+ (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;
-
+ (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;
-
+ (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;
-
+ (void) rhport; (void) dev_addr; (void) ep_addr;
return false;
}
diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
index 8005f5f7b..3752ae251 100644
--- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
+++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
@@ -130,9 +130,8 @@ static void enable_functional_reset(const bool enable)
/*------------------------------------------------------------------*/
/* Controller API
*------------------------------------------------------------------*/
-void dcd_init (uint8_t rhport)
-{
- (void) rhport;
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rhport; (void) rh_init;
USBKEYPID = USBKEY;
@@ -164,6 +163,8 @@ void dcd_init (uint8_t rhport)
}
USBKEYPID = 0;
+
+ return true;
}
// There is no "USB peripheral interrupt disable" bit on MSP430, so we have
@@ -332,6 +333,11 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
return true;
}
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport; (void) ep_addr;
+ // TODO implement dcd_edpt_close()
+}
+
void dcd_edpt_close_all (uint8_t rhport)
{
(void) rhport;
@@ -694,7 +700,11 @@ static void handle_bus_power_event(void *param) {
// A successful lock is indicated by all PLL-related interrupt flags being cleared.
if(!USBPLLIR) {
- dcd_init(0); // Re-initialize the USB module.
+ const tusb_rhport_init_t rhport_init = {
+ .role = TUSB_ROLE_DEVICE,
+ .speed = TUSB_SPEED_FULL
+ };
+ dcd_init(0, &rhport_init); // Re-initialize the USB module.
}
} else { // Event caused by removal of bus power.
USBPWRCTL |= VBONIE; // Enable bus-power-applied interrupt.
diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c
index 58628a8bb..a03c94558 100644
--- a/src/portable/valentyusb/eptri/dcd_eptri.c
+++ b/src/portable/valentyusb/eptri/dcd_eptri.c
@@ -336,9 +336,9 @@ static void dcd_reset(void)
}
// Initializes the USB peripheral for device mode and enables it.
-void dcd_init(uint8_t rhport)
-{
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
usb_pullup_out_write(0);
@@ -352,6 +352,8 @@ void dcd_init(uint8_t rhport)
// Turn on the external pullup
usb_pullup_out_write(1);
+
+ return true;
}
// Enables or disables the USB device interrupt(s). May be used to
@@ -436,6 +438,11 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport; (void) ep_addr;
+ // TODO implement dcd_edpt_close()
+}
+
void dcd_edpt_close_all (uint8_t rhport)
{
(void) rhport;
diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c
index 9ed370b40..c248ba14e 100644
--- a/src/portable/wch/dcd_ch32_usbfs.c
+++ b/src/portable/wch/dcd_ch32_usbfs.c
@@ -123,7 +123,8 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) {
}
/* public functions */
-void dcd_init(uint8_t rhport) {
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
// init registers
USBOTG_FS->BASE_CTRL = USBFS_CTRL_SYS_CTRL | USBFS_CTRL_INT_BUSY | USBFS_CTRL_DMA_EN;
USBOTG_FS->UDEV_CTRL = USBFS_UDEV_CTRL_PD_DIS | USBFS_UDEV_CTRL_PORT_EN;
@@ -153,6 +154,8 @@ void dcd_init(uint8_t rhport) {
EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0];
dcd_connect(rhport);
+
+ return true;
}
void dcd_int_handler(uint8_t rhport) {
@@ -189,7 +192,8 @@ void dcd_int_handler(uint8_t rhport) {
data.xfer[0][TUSB_DIR_OUT].max_size = 64;
data.xfer[0][TUSB_DIR_IN].max_size = 64;
- dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true);
+ //dcd_event_bus_reset(rhport, (USBOTG_FS->BASE_CTRL & USBFS_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true);
+ dcd_event_bus_reset(rhport, (USBOTG_FS->UDEV_CTRL & USBFS_UDEV_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true);
USBOTG_FS->DEV_ADDR = 0x00;
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c
index 622f9c508..f8bf3c889 100644
--- a/src/portable/wch/dcd_ch32_usbhs.c
+++ b/src/portable/wch/dcd_ch32_usbhs.c
@@ -131,8 +131,9 @@ static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t* xfer
ep_set_response_and_toggle(ep_num, ep_dir, USBHS_EP_R_RES_ACK);
}
-void dcd_init(uint8_t rhport) {
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
+ (void) rh_init;
memset(&xfer_status, 0, sizeof(xfer_status));
@@ -170,6 +171,8 @@ void dcd_init(uint8_t rhport) {
USBHSD->DEV_AD = 0;
USBHSD->CONTROL |= USBHS_DEV_PU_EN;
+
+ return true;
}
void dcd_int_enable(uint8_t rhport) {