summaryrefslogtreecommitdiff
path: root/src/portable
diff options
context:
space:
mode:
Diffstat (limited to 'src/portable')
-rw-r--r--src/portable/analog/max3421/hcd_max3421.c264
-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/dcd_ci_hs.c21
-rw-r--r--src/portable/chipidea/ci_hs/hcd_ci_hs.c7
-rw-r--r--src/portable/dialog/da146xx/dcd_da146xx.c9
-rw-r--r--src/portable/espressif/esp32sx/dcd_esp32sx.c9
-rw-r--r--src/portable/mentor/musb/dcd_musb.c766
-rw-r--r--src/portable/mentor/musb/hcd_musb.c18
-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/dcd_pic.c5
-rw-r--r--src/portable/microchip/pic32mz/dcd_pic32mz.c5
-rw-r--r--src/portable/microchip/samd/dcd_samd.c17
-rw-r--r--src/portable/microchip/samg/dcd_samg.c12
-rw-r--r--src/portable/microchip/samx7x/dcd_samx7x.c5
-rw-r--r--src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c16
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c44
-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.c7
-rw-r--r--src/portable/nxp/lpc17_40/dcd_lpc17_40.c11
-rw-r--r--src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c17
-rw-r--r--src/portable/ohci/ohci.c4
-rw-r--r--src/portable/raspberrypi/pio_usb/dcd_pio_usb.c7
-rw-r--r--src/portable/raspberrypi/pio_usb/hcd_pio_usb.c3
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c4
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c4
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c13
-rw-r--r--src/portable/renesas/rusb2/dcd_rusb2.c46
-rw-r--r--src/portable/renesas/rusb2/hcd_rusb2.c4
-rw-r--r--src/portable/sony/cxd56/dcd_cxd56.c6
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c1299
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h551
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_ch32.h206
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_stm32.h356
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_type.h307
-rw-r--r--src/portable/sunxi/dcd_sunxi_musb.c21
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c846
-rw-r--r--src/portable/synopsys/dwc2/dwc2_bcm.h2
-rw-r--r--src/portable/synopsys/dwc2/dwc2_esp32.h72
-rw-r--r--src/portable/synopsys/dwc2/dwc2_info.md113
-rwxr-xr-x[-rw-r--r--]src/portable/synopsys/dwc2/dwc2_info.py193
-rw-r--r--src/portable/synopsys/dwc2/dwc2_stm32.h6
-rw-r--r--src/portable/synopsys/dwc2/dwc2_type.h592
-rw-r--r--src/portable/template/dcd_template.c65
-rw-r--r--src/portable/template/hcd_template.c4
-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/ch32_usbfs_reg.h175
-rw-r--r--src/portable/wch/ch32_usbhs_reg.h82
-rw-r--r--src/portable/wch/dcd_ch32_usbfs.c347
-rw-r--r--src/portable/wch/dcd_ch32_usbhs.c562
57 files changed, 4812 insertions, 5460 deletions
diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c
index 39afb7505..c5e924266 100644
--- a/src/portable/analog/max3421/hcd_max3421.c
+++ b/src/portable/analog/max3421/hcd_max3421.c
@@ -168,13 +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_ATTEMPT_1 = 2, // pending 1st attempt
+ EP_STATE_ABORTING = 2,
+ EP_STATE_ATTEMPT_1 = 3, // Number of attempts to transfer in a frame. Incremented after each NAK
EP_STATE_ATTEMPT_MAX = 15
};
@@ -182,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;
};
@@ -218,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
@@ -316,33 +329,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
@@ -376,6 +365,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
//--------------------------------------------------------------------+
@@ -416,7 +446,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) &&
@@ -459,12 +489,13 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
tuh_configure_param_t const* cfg = (tuh_configure_param_t const*) cfg_param;
_tuh_cfg = cfg->max3421;
+ _tuh_cfg.max_nak = tu_min8(_tuh_cfg.max_nak, EP_STATE_ATTEMPT_MAX-EP_STATE_ATTEMPT_1);
return true;
}
// 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);
@@ -479,13 +510,16 @@ bool hcd_init(uint8_t rhport) {
_hcd_data.spi_mutex = osal_mutex_create(&_hcd_data.spi_mutexdef);
#endif
+ // NOTE: driver does not seem to work without nRST pin signal
+
// full duplex, interrupt negative edge
reg_write(rhport, PINCTL_ADDR, _tuh_cfg.pinctl | PINCTL_FDUPSPI, false);
// v1 is 0x01, v2 is 0x12, v3 is 0x13
+ // 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_ASSERT(revision == 0x01 || revision == 0x12 || revision == 0x13, false);
TU_LOG2_HEX(revision);
+ TU_ASSERT(revision == 0x01 || revision == 0x12 || revision == 0x13, false);
// reset
reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false);
@@ -611,22 +645,45 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
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);
}
@@ -644,7 +701,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);
}
@@ -658,7 +715,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;
@@ -676,7 +733,6 @@ static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool
bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) {
uint8_t const ep_num = tu_edpt_number(ep_addr);
uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr);
-
max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir);
TU_VERIFY(ep);
@@ -700,14 +756,19 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf
return true;
}
-// Abort a queued transfer. Note: it can only abort transfer that has not been started
-// Return true if a queued transfer is aborted, false if there is no transfer to abort
-bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
- (void) rhport;
- (void) dev_addr;
- (void) ep_addr;
+bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr);
+ max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir);
+ TU_VERIFY(ep);
- return false;
+ if (EP_STATE_ATTEMPT_1 <= ep->state && ep->state < EP_STATE_ATTEMPT_MAX) {
+ hcd_int_disable(rhport);
+ ep->state = EP_STATE_ABORTING;
+ 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
@@ -815,46 +876,41 @@ 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, );
xfer_result_t xfer_result;
switch(hresult) {
- case HRSL_SUCCESS:
- xfer_result = XFER_RESULT_SUCCESS;
- break;
-
- case HRSL_STALL:
- xfer_result = XFER_RESULT_STALLED;
- break;
-
case HRSL_NAK:
- if (ep_num == 0) {
- // control endpoint -> retry immediately
- hxfr_write(rhport, _hcd_data.hxfr, in_isr);
+ if (ep->state == EP_STATE_ABORTING) {
+ ep->state = EP_STATE_IDLE;
} else {
- if (ep->state < EP_STATE_ATTEMPT_MAX) {
+ if (ep_num == 0) {
+ // control endpoint -> retry immediately and return
+ hxfr_write(rhport, _hcd_data.hxfr, in_isr);
+ return;
+ }
+ if (EP_STATE_ATTEMPT_1 <= ep->state && ep->state < EP_STATE_ATTEMPT_MAX) {
ep->state++;
}
+ }
- max3421_ep_t * next_ep = find_next_pending_ep(ep);
- if (ep == next_ep) {
- // this endpoint is only one pending -> retry immediately
- hxfr_write(rhport, _hcd_data.hxfr, in_isr);
- } else if (next_ep) {
- // switch to next pending endpoint TODO could have issue with double buffered if not clear previously out data
- xact_generic(rhport, next_ep, true, in_isr);
- } else {
- // no more pending in this frame -> clear busy
- atomic_flag_clear(&_hcd_data.busy);
- }
+ max3421_ep_t * next_ep = find_next_pending_ep(ep);
+ if (ep == next_ep) {
+ // this endpoint is only one pending -> retry immediately
+ hxfr_write(rhport, _hcd_data.hxfr, in_isr);
+ } else if (next_ep) {
+ // switch to next pending endpoint
+ xact_generic(rhport, next_ep, true, in_isr);
+ } else {
+ // no more pending in this frame -> clear busy
+ atomic_flag_clear(&_hcd_data.busy);
}
return;
@@ -862,6 +918,14 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
// occurred when initialized without any pending transfer. Skip for now
return;
+ case HRSL_SUCCESS:
+ xfer_result = XFER_RESULT_SUCCESS;
+ break;
+
+ case HRSL_STALL:
+ xfer_result = XFER_RESULT_STALLED;
+ break;
+
default:
TU_LOG3("HRSL: %02X\r\n", hrsl);
xfer_result = XFER_RESULT_FAILED;
@@ -885,11 +949,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) {
@@ -906,8 +974,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
}
}
}
@@ -940,9 +1007,8 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
if (hirq & HIRQ_FRAME_IRQ) {
_hcd_data.frame_count++;
+ // reset all endpoints nak counter, retry with 1st pending ep.
max3421_ep_t* ep_retry = NULL;
-
- // reset all endpoints attempt counter
for (size_t i = 0; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i];
if (ep->packet_size && ep->state > EP_STATE_ATTEMPT_1) {
@@ -968,16 +1034,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;
}
@@ -1002,7 +1068,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
// clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing
hirq &= (uint8_t) ~HIRQ_SNDBAV_IRQ;
- if ( hirq ) {
+ if (hirq) {
hirq_write(rhport, hirq, in_isr);
}
}
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/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
index f9ec666e5..430a0aad1 100644
--- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
@@ -234,13 +234,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 +268,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)
@@ -309,10 +311,12 @@ void dcd_disconnect(uint8_t rhport)
void dcd_sof_enable(uint8_t rhport, bool en)
{
- (void) rhport;
- (void) en;
-
- // TODO implement later
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ if (en) {
+ dcd_reg->USBINTR |= INTR_SOF;
+ } else {
+ dcd_reg->USBINTR &= ~INTR_SOF;
+ }
}
//--------------------------------------------------------------------+
@@ -679,7 +683,8 @@ void dcd_int_handler(uint8_t rhport)
if (int_status & INTR_SOF)
{
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ const uint32_t frame = dcd_reg->FRINDEX;
+ dcd_event_sof(rhport, frame, true);
}
}
diff --git a/src/portable/chipidea/ci_hs/hcd_ci_hs.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
index 462cbd301..14f8acb45 100644
--- a/src/portable/chipidea/ci_hs/hcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
@@ -70,7 +70,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 +83,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..887f59588 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)
diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c
index bfc0baa56..1b6aae026 100644
--- a/src/portable/espressif/esp32sx/dcd_esp32sx.c
+++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c
@@ -31,7 +31,8 @@
#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && CFG_TUD_ENABLED)
// Espressif
-#include "xtensa_api.h"
+#include "xtensa/xtensa_api.h"
+
#include "esp_intr_alloc.h"
#include "esp_log.h"
#include "soc/dport_reg.h"
@@ -171,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
@@ -206,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..1c0740193 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;
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/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c
index ccc27c3c9..d40c4794a 100644
--- a/src/portable/microchip/pic/dcd_pic.c
+++ b/src/portable/microchip/pic/dcd_pic.c
@@ -470,8 +470,8 @@ 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);
@@ -502,6 +502,7 @@ void dcd_init(uint8_t rhport)
U1IE = _U1IE_URSTIE_MASK;
dcd_connect(rhport);
+ return true;
}
void dcd_int_enable(uint8_t 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 976d3dfd0..0c96f6ac4 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
@@ -183,9 +185,12 @@ void dcd_connect(uint8_t rhport)
void dcd_sof_enable(uint8_t rhport, bool en)
{
(void) rhport;
- (void) en;
- // TODO implement later
+ if (en) {
+ USB->DEVICE.INTENSET.bit.SOF = 1;
+ } else {
+ USB->DEVICE.INTENCLR.bit.SOF = 1;
+ }
}
/*------------------------------------------------------------------*/
@@ -374,7 +379,9 @@ void dcd_int_handler (uint8_t rhport)
if ( int_status & USB_DEVICE_INTFLAG_SOF )
{
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF;
- dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+ const uint32_t frame = USB->DEVICE.FNUM.bit.FNUM;
+ dcd_event_sof(0, frame, true);
+ //dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
}
// SAMD doesn't distinguish between Suspend and Disconnect state.
diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c
index e3fa51e31..c88b31514 100644
--- a/src/portable/microchip/samg/dcd_samg.c
+++ b/src/portable/microchip/samg/dcd_samg.c
@@ -155,10 +155,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 +280,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 c3d0c7297..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)
@@ -283,7 +284,18 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
/* Response with status first before changing device address */
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
}
+
+#ifdef __GNUC__ // caused by extra declaration of SystemCoreClock in freeRTOSConfig.h
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
extern u32 SystemCoreClock;
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
void dcd_remote_wakeup(uint8_t rhport)
{
(void) rhport;
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 2fe721d6b..3f53ee26e 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -120,6 +120,9 @@ static struct {
// nRF can only carry one DMA at a time, this is used to guard the access to EasyDMA
atomic_flag dma_running;
+
+ // Track whether sof has been manually enabled
+ bool sof_enabled;
} _dcd;
/*------------------------------------------------------------------*/
@@ -147,7 +150,7 @@ static void start_dma(volatile uint32_t* reg_startep) {
static void edpt_dma_start(volatile uint32_t* reg_startep) {
if (atomic_flag_test_and_set(&_dcd.dma_running)) {
- usbd_defer_func((osal_task_func_t)(uintptr_t ) edpt_dma_start, (void*) (uintptr_t) reg_startep, true);
+ usbd_defer_func((osal_task_func_t)(uintptr_t ) edpt_dma_start, (void*) (uintptr_t) reg_startep, is_in_isr());
} else {
start_dma(reg_startep);
}
@@ -227,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) {
@@ -283,9 +288,13 @@ void dcd_connect(uint8_t rhport) {
void dcd_sof_enable(uint8_t rhport, bool en) {
(void) rhport;
- (void) en;
-
- // TODO implement later
+ if (en) {
+ _dcd.sof_enabled = true;
+ NRF_USBD->INTENSET = USBD_INTENSET_SOF_Msk;
+ } else {
+ _dcd.sof_enabled = false;
+ NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
+ }
}
//--------------------------------------------------------------------+
@@ -434,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) {
@@ -607,13 +616,16 @@ void dcd_int_handler(uint8_t rhport) {
}
}
- if (!iso_enabled) {
- // ISO endpoint is not used, SOF is only enabled one-time for remote wakeup
- // so we disable it now
- NRF_USBD->INTENCLR = USBD_INTENSET_SOF_Msk;
+ if (!iso_enabled && !_dcd.sof_enabled) {
+ // SOF interrupt not manually enabled and ISO endpoint is not used,
+ // SOF is only enabled one-time for remote wakeup so we disable it now
+
+ NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
}
- dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+ const uint32_t frame = NRF_USBD->FRAMECNTR;
+ dcd_event_sof(0, frame, true);
+ //dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
}
if (int_status & USBD_INTEN_USBEVENT_Msk) {
@@ -897,9 +909,9 @@ void tusb_hal_nrf_power_event(uint32_t event) {
USB_EVT_READY = 2
};
-#if CFG_TUSB_DEBUG >= 2
+#if CFG_TUSB_DEBUG >= 3
const char* const power_evt_str[] = {"Detected", "Removed", "Ready"};
- TU_LOG(2, "Power USB event: %s\r\n", power_evt_str[event]);
+ TU_LOG(3, "Power USB event: %s\r\n", power_evt_str[event]);
#endif
switch (event) {
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 dc71117b3..8398b09bf 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)
@@ -540,7 +542,7 @@ void dcd_int_handler(uint8_t rhport)
}
if (is & USB_ISTAT_SLEEP_MASK) {
- // TU_LOG2("Suspend: "); TU_LOG2_HEX(is);
+ // TU_LOG3("Suspend: "); TU_LOG2_HEX(is);
// Note Host usually has extra delay after bus reset (without SOF), which could falsely
// detected as Sleep event. Though usbd has debouncing logic so we are good
diff --git a/src/portable/nxp/khci/hcd_khci.c b/src/portable/nxp/khci/hcd_khci.c
index 57684b259..f5ca73c18 100644
--- a/src/portable/nxp/khci/hcd_khci.c
+++ b/src/portable/nxp/khci/hcd_khci.c
@@ -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);
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/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
index 022904a3a..7d5cfb5b0 100644
--- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
+++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
@@ -42,7 +42,18 @@
#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX)
// LPCOpen
+ #ifdef __GNUC__
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
+ #pragma GCC diagnostic ignored "-Wstrict-prototypes"
+ #endif
+
#include "chip.h"
+
+ #ifdef __GNUC__
+ #pragma GCC diagnostic pop
+ #endif
+
#else
// SDK
#include "fsl_device_registers.h"
@@ -278,8 +289,8 @@ 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;
@@ -292,6 +303,8 @@ void dcd_init(uint8_t rhport)
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)
diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c
index c59d4755e..ce35eab70 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));
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..6422afff1 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);
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index bc0deee32..2e177d5cb 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -369,7 +369,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());
@@ -405,6 +406,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) {
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index 222dbbbf0..2c0a3fd49 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);
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index 1ca711c77..43f48da39 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -53,6 +53,14 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode(void) {
//--------------------------------------------------------------------+
// Implementation
//--------------------------------------------------------------------+
+// Provide own byte by byte memcpy as not all copies are aligned
+static void unaligned_memcpy(void *dst, const void *src, size_t n) {
+ uint8_t *dst_byte = (uint8_t*)dst;
+ const uint8_t *src_byte = (const uint8_t*)src;
+ while (n--) {
+ *dst_byte++ = *src_byte++;
+ }
+}
void rp2040_usb_init(void) {
// Reset usb controller
@@ -67,7 +75,6 @@ void rp2040_usb_init(void) {
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
#endif
- memset(usb_hw, 0, sizeof(*usb_hw));
memset(usb_dpram, 0, sizeof(*usb_dpram));
#ifdef __GNUC__
#pragma GCC diagnostic pop
@@ -125,7 +132,7 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep,
if (!ep->rx) {
// Copy data from user buffer to hw buffer
- memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen);
+ unaligned_memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen);
ep->user_buf += buflen;
// Mark as full
@@ -230,7 +237,7 @@ static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint* ep, uin
// we have received AFTER we have copied it to the user buffer at the appropriate offset
assert(buf_ctrl & USB_BUF_CTRL_FULL);
- memcpy(ep->user_buf, ep->hw_data_buf + buf_id * 64, xferred_bytes);
+ unaligned_memcpy(ep->user_buf, ep->hw_data_buf + buf_id * 64, xferred_bytes);
ep->xferred_len = (uint16_t) (ep->xferred_len + xferred_bytes);
ep->user_buf += xferred_bytes;
}
diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c
index 50400d1f5..ecd28973c 100644
--- a/src/portable/renesas/rusb2/dcd_rusb2.c
+++ b/src/portable/renesas/rusb2/dcd_rusb2.c
@@ -29,10 +29,6 @@
#if CFG_TUD_ENABLED && defined(TUP_USBIP_RUSB2)
-// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
-// We disable SOF for now until needed later on
-#define USE_SOF 0
-
#include "device/dcd.h"
#include "rusb2_type.h"
@@ -74,6 +70,8 @@ typedef struct
{
pipe_state_t pipe[PIPE_COUNT];
uint8_t ep[2][16]; /* a lookup table for a pipe index from an endpoint address */
+ // Track whether sof has been manually enabled
+ bool sof_enabled;
} dcd_data_t;
static dcd_data_t _dcd;
@@ -659,11 +657,15 @@ 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;
+
#ifdef RUSB2_SUPPORT_HIGHSPEED
if ( rusb2_is_highspeed_rhport(rhport) ) {
rusb->SYSCFG_b.HSE = 1;
@@ -708,7 +710,7 @@ void dcd_init(uint8_t rhport)
rusb->INTSTS0 = 0;
rusb->INTENB0 = RUSB2_INTSTS0_VBINT_Msk | RUSB2_INTSTS0_BRDY_Msk | RUSB2_INTSTS0_BEMP_Msk |
- RUSB2_INTSTS0_DVST_Msk | RUSB2_INTSTS0_CTRT_Msk | (USE_SOF ? RUSB2_INTSTS0_SOFR_Msk : 0) |
+ RUSB2_INTSTS0_DVST_Msk | RUSB2_INTSTS0_CTRT_Msk | (_dcd.sof_enabled ? RUSB2_INTSTS0_SOFR_Msk : 0) |
RUSB2_INTSTS0_RESM_Msk;
rusb->BEMPENB = 1;
rusb->BRDYENB = 1;
@@ -717,6 +719,8 @@ void dcd_init(uint8_t rhport)
if (rusb->INTSTS0_b.VBSTS) {
dcd_connect(rhport);
}
+
+ return true;
}
void dcd_int_enable(uint8_t rhport) {
@@ -756,10 +760,9 @@ void dcd_disconnect(uint8_t rhport)
void dcd_sof_enable(uint8_t rhport, bool en)
{
- (void) rhport;
- (void) en;
-
- // TODO implement later
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ _dcd.sof_enabled = en;
+ rusb->INTENB0_b.SOFE = en ? 1: 0;
}
//--------------------------------------------------------------------+
@@ -949,18 +952,19 @@ void dcd_int_handler(uint8_t rhport)
// Resumed
if ( is0 & RUSB2_INTSTS0_RESM_Msk ) {
dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
-#if (0 == USE_SOF)
- rusb->INTENB0_b.SOFE = 0;
-#endif
+ if (!_dcd.sof_enabled) {
+ rusb->INTENB0_b.SOFE = 0;
+ }
}
// SOF received
if ( (is0 & RUSB2_INTSTS0_SOFR_Msk) && rusb->INTENB0_b.SOFE ) {
// USBD will exit suspended mode when SOF event is received
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
-#if (0 == USE_SOF)
- rusb->INTENB0_b.SOFE = 0;
-#endif
+ const uint32_t frame = rusb->FRMNUM_b.FRNM;
+ dcd_event_sof(rhport, frame, true);
+ if (!_dcd.sof_enabled) {
+ rusb->INTENB0_b.SOFE = 0;
+ }
}
// Device state changes
@@ -979,9 +983,9 @@ void dcd_int_handler(uint8_t rhport)
case RUSB2_INTSTS0_DVSQ_STATE_SUSP2:
case RUSB2_INTSTS0_DVSQ_STATE_SUSP3:
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
-#if (0 == USE_SOF)
- rusb->INTENB0_b.SOFE = 1;
-#endif
+ if (!_dcd.sof_enabled) {
+ rusb->INTENB0_b.SOFE = 1;
+ }
default: break;
}
diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c
index f140da690..4c81b05be 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);
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 a26c66892..d921429e2 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -4,7 +4,6 @@
* Copyright (c) 2019 Nathan Conrad
*
* Portions:
- * Copyright (c) 2016 STMicroelectronics
* Copyright (c) 2019 Ha Thach (tinyusb.org)
* Copyright (c) 2022 Simon Küppers (skuep)
* Copyright (c) 2022 HiFiPhile
@@ -37,14 +36,20 @@
* It also should work with minimal changes for any ST MCU with an "USB A"/"PCD"/"HCD" peripheral. This
* covers:
*
- * F04x, F072, F078, 070x6/B 1024 byte buffer
+ * F04x, F072, F078, F070x6/B 1024 byte buffer
* 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
+ * G0 2048 byte buffer; 32-bit bus; host mode
+ * G4 1024 byte buffer
+ * H5 2048 byte buffer; 32-bit bus; host mode
* L0x2, L0x3 1024 byte buffer
* L1 512 byte buffer
* L4x2, L4x3 1024 byte buffer
- * G0 2048 byte buffer
+ * L5 1024 byte buffer
+ * U0 1024 byte buffer; 32-bit bus
+ * U535, U545 2048 byte buffer; 32-bit bus; host mode
+ * WB35, WB55 1024 byte buffer
*
* To use this driver, you must:
* - If you are using a device with crystal-less USB, set up the clock recovery system (CRS)
@@ -102,43 +107,20 @@
#include "tusb_option.h"
-#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV)
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) && \
+ !(defined(TUP_USBIP_FSDEV_CH32) && CFG_TUD_WCH_USBIP_FSDEV == 0)
#include "device/dcd.h"
-#ifdef TUP_USBIP_FSDEV_STM32
-// Undefine to reduce the dependence on HAL
-#undef USE_HAL_DRIVER
-#include "portable/st/stm32_fsdev/dcd_stm32_fsdev.h"
-#endif
-
-/*****************************************************
- * Configuration
- *****************************************************/
-
-// HW supports max of 8 bidirectional endpoints, but this can be reduced to save RAM
-// (8u here would mean 8 IN and 8 OUT)
-#ifndef MAX_EP_COUNT
-#define MAX_EP_COUNT 8U
-#endif
-
-// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it
-// Both of these MUST be a multiple of 2, and are in byte units.
-#ifndef DCD_STM32_BTABLE_BASE
-#define DCD_STM32_BTABLE_BASE 0U
-#endif
-
-#ifndef DCD_STM32_BTABLE_SIZE
-#define DCD_STM32_BTABLE_SIZE (FSDEV_PMA_SIZE - DCD_STM32_BTABLE_BASE)
+#if defined(TUP_USBIP_FSDEV_STM32)
+ #include "fsdev_stm32.h"
+#elif defined(TUP_USBIP_FSDEV_CH32)
+ #include "fsdev_ch32.h"
+#else
+ #error "Unknown USB IP"
#endif
-/***************************************************
- * Checks, structs, defines, function definitions, etc.
- */
-
-TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware");
-TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_SIZE)) <= (FSDEV_PMA_SIZE), "BTABLE does not fit in PMA RAM");
-TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes");
+#include "fsdev_type.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
@@ -162,12 +144,8 @@ typedef struct {
bool allocated[2];
} ep_alloc_t;
-static xfer_ctl_t xfer_status[MAX_EP_COUNT][2];
-
-static ep_alloc_t ep_alloc_status[STFSDEV_EP_COUNT];
-
-static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6];
-
+static xfer_ctl_t xfer_status[CFG_TUD_ENDPPOINT_MAX][2];
+static ep_alloc_t ep_alloc_status[FSDEV_EP_COUNT];
static uint8_t remoteWakeCountdown; // When wake is requested
//--------------------------------------------------------------------+
@@ -175,253 +153,93 @@ static uint8_t remoteWakeCountdown; // When wake is requested
//--------------------------------------------------------------------+
// into the stack.
-static void dcd_handle_bus_reset(void);
+static void handle_bus_reset(uint8_t rhport);
static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix);
-static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr);
-static void dcd_ep_ctr_handler(void);
+static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir);
// PMA allocation/access
static uint16_t ep_buf_ptr; ///< Points to first free memory location
-static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf);
+static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf);
static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type);
-static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes);
-static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes);
+static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes);
+static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes);
static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes);
static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes);
+static void edpt0_open(uint8_t rhport);
+
+TU_ATTR_ALWAYS_INLINE static inline void edpt0_prepare_setup(void) {
+ btable_set_rx_bufsize(0, BTABLE_BUF_RX, 8);
+}
+
//--------------------------------------------------------------------+
// Inline helper
//--------------------------------------------------------------------+
-TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint32_t ep_addr)
-{
- uint8_t epnum = tu_edpt_number(ep_addr);
- uint8_t dir = tu_edpt_dir(ep_addr);
- // Fix -Werror=null-dereference
- TU_ASSERT(epnum < MAX_EP_COUNT, &xfer_status[0][0]);
-
+TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint8_t epnum, uint8_t dir) {
return &xfer_status[epnum][dir];
}
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
-
-void dcd_init(uint8_t rhport)
-{
- /* Clocks should already be enabled */
- /* Use __HAL_RCC_USB_CLK_ENABLE(); to enable the clocks before calling this function */
-
- /* The RM mentions to use a special ordering of PDWN and FRES, but this isn't done in HAL.
- * Here, the RM is followed. */
-
- for (uint32_t i = 0; i < 200; i++) { // should be a few us
+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");
}
+
// Perform USB peripheral reset
- USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN;
- for (uint32_t i = 0; i < 200; i++) { // should be a few us
+ FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN;
+ for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
- USB->CNTR &= ~USB_CNTR_PDWN;
+ FSDEV_REG->CNTR &= ~USB_CNTR_PDWN;
// Wait startup time, for F042 and F070, this is <= 1 us.
- for (uint32_t i = 0; i < 200; i++) { // should be a few us
+ for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
- USB->CNTR = 0; // Enable USB
+ FSDEV_REG->CNTR = 0; // Enable USB
-#if !defined(STM32G0) && !defined(STM32H5) // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address
- USB->BTABLE = DCD_STM32_BTABLE_BASE;
+#if !defined(FSDEV_BUS_32BIT)
+ // BTABLE register does not exist any more on 32-bit bus devices
+ FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE;
#endif
- USB->ISTR = 0; // Clear pending interrupts
+
+ FSDEV_REG->ISTR = 0; // Clear pending interrupts
// Reset endpoints to disabled
- for (uint32_t i = 0; i < STFSDEV_EP_COUNT; i++) {
+ for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) {
// This doesn't clear all bits since some bits are "toggle", but does set the type to DISABLED.
- pcd_set_endpoint(USB, i, 0u);
+ ep_write(i, 0u, false);
}
- USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
- dcd_handle_bus_reset();
+ FSDEV_REG->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM |
+ USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_PMAOVRM;
+ handle_bus_reset(rhport);
// Enable pull-up if supported
- if (dcd_connect) {
- dcd_connect(rhport);
- }
-}
-
-// Define only on MCU with internal pull-up. BSP can define on MCU without internal PU.
-#if defined(USB_BCDR_DPPU)
-
-// Disable internal D+ PU
-void dcd_disconnect(uint8_t rhport)
-{
- (void)rhport;
- USB->BCDR &= ~(USB_BCDR_DPPU);
-}
-
-// Enable internal D+ PU
-void dcd_connect(uint8_t rhport)
-{
- (void)rhport;
- USB->BCDR |= USB_BCDR_DPPU;
-}
+ dcd_connect(rhport);
-#elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151
-// Disable internal D+ PU
-void dcd_disconnect(uint8_t rhport)
-{
- (void)rhport;
- SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU);
-}
-
-// Enable internal D+ PU
-void dcd_connect(uint8_t rhport)
-{
- (void)rhport;
- SYSCFG->PMC |= SYSCFG_PMC_USB_PU;
+ return true;
}
-#endif
-void dcd_sof_enable(uint8_t rhport, bool en)
-{
+void dcd_sof_enable(uint8_t rhport, bool en) {
(void)rhport;
- (void)en;
if (en) {
- USB->CNTR |= USB_CNTR_SOFM;
+ FSDEV_REG->CNTR |= USB_CNTR_SOFM;
} else {
- USB->CNTR &= ~USB_CNTR_SOFM;
+ FSDEV_REG->CNTR &= ~USB_CNTR_SOFM;
}
}
-// Enable device interrupt
-void dcd_int_enable(uint8_t rhport)
-{
- (void)rhport;
- // Member here forces write to RAM before allowing ISR to execute
- __DSB();
- __ISB();
-#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4
- NVIC_EnableIRQ(USB_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
- NVIC_EnableIRQ(USB_LP_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F3
-// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
-// shared USB/CAN IRQs to separate CAN and USB IRQs.
-// This dynamically checks if this remap is active to enable the right IRQs.
-#ifdef SYSCFG_CFGR1_USB_IT_RMP
- if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) {
- NVIC_EnableIRQ(USB_HP_IRQn);
- NVIC_EnableIRQ(USB_LP_IRQn);
- NVIC_EnableIRQ(USBWakeUp_RMP_IRQn);
- } else
-#endif
- {
- NVIC_EnableIRQ(USB_HP_CAN_TX_IRQn);
- NVIC_EnableIRQ(USB_LP_CAN_RX0_IRQn);
- NVIC_EnableIRQ(USBWakeUp_IRQn);
- }
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
- NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
- NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
- NVIC_EnableIRQ(USBWakeUp_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
- NVIC_EnableIRQ(USB_HP_IRQn);
- NVIC_EnableIRQ(USB_LP_IRQn);
- NVIC_EnableIRQ(USBWakeUp_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
-#ifdef STM32G0B0xx
- NVIC_EnableIRQ(USB_IRQn);
-#else
- NVIC_EnableIRQ(USB_UCPD1_2_IRQn);
-#endif
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
- NVIC_EnableIRQ(USB_DRD_FS_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
- NVIC_EnableIRQ(USB_HP_IRQn);
- NVIC_EnableIRQ(USB_LP_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
- NVIC_EnableIRQ(USB_FS_IRQn);
-
-#else
-#error Unknown arch in USB driver
-#endif
-}
-
-// Disable device interrupt
-void dcd_int_disable(uint8_t rhport)
-{
- (void)rhport;
-
-#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4
- NVIC_DisableIRQ(USB_IRQn);
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
- NVIC_DisableIRQ(USB_LP_IRQn);
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F3
-// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
-// shared USB/CAN IRQs to separate CAN and USB IRQs.
-// This dynamically checks if this remap is active to disable the right IRQs.
-#ifdef SYSCFG_CFGR1_USB_IT_RMP
- if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) {
- NVIC_DisableIRQ(USB_HP_IRQn);
- NVIC_DisableIRQ(USB_LP_IRQn);
- NVIC_DisableIRQ(USBWakeUp_RMP_IRQn);
- } else
-#endif
- {
- NVIC_DisableIRQ(USB_HP_CAN_TX_IRQn);
- NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn);
- NVIC_DisableIRQ(USBWakeUp_IRQn);
- }
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
- NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
- NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
- NVIC_DisableIRQ(USBWakeUp_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
- NVIC_DisableIRQ(USB_HP_IRQn);
- NVIC_DisableIRQ(USB_LP_IRQn);
- NVIC_DisableIRQ(USBWakeUp_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
-#ifdef STM32G0B0xx
- NVIC_DisableIRQ(USB_IRQn);
-#else
- NVIC_DisableIRQ(USB_UCPD1_2_IRQn);
-#endif
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
- NVIC_DisableIRQ(USB_DRD_FS_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
- NVIC_DisableIRQ(USB_HP_IRQn);
- NVIC_DisableIRQ(USB_LP_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
- NVIC_DisableIRQ(USB_FS_IRQn);
-
-#else
-#error Unknown arch in USB driver
-#endif
-
- // CMSIS has a membar after disabling interrupts
-}
-
// 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 dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
(void)dev_addr;
// Respond with status
@@ -431,37 +249,17 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
// do it at dcd_edpt0_status_complete()
}
-void dcd_remote_wakeup(uint8_t rhport)
-{
+void dcd_remote_wakeup(uint8_t rhport) {
(void)rhport;
- USB->CNTR |= USB_CNTR_RESUME;
+ FSDEV_REG->CNTR |= USB_CNTR_RESUME;
remoteWakeCountdown = 4u; // required to be 1 to 15 ms, ESOF should trigger every 1ms.
}
-static const tusb_desc_endpoint_t ep0OUT_desc = {
- .bLength = sizeof(tusb_desc_endpoint_t),
- .bDescriptorType = TUSB_DESC_ENDPOINT,
- .bEndpointAddress = 0x00,
- .bmAttributes = {.xfer = TUSB_XFER_CONTROL},
- .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
- .bInterval = 0
-};
-
-static const tusb_desc_endpoint_t ep0IN_desc = {
- .bLength = sizeof(tusb_desc_endpoint_t),
- .bDescriptorType = TUSB_DESC_ENDPOINT,
- .bEndpointAddress = 0x80,
- .bmAttributes = {.xfer = TUSB_XFER_CONTROL},
- .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
- .bInterval = 0
-};
+static void handle_bus_reset(uint8_t rhport) {
+ FSDEV_REG->DADDR = 0u; // disable USB Function
-static void dcd_handle_bus_reset(void)
-{
- USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag
-
- for (uint32_t i = 0; i < STFSDEV_EP_COUNT; i++) {
+ for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) {
// Clear EP allocation status
ep_alloc_status[i].ep_num = 0xFF;
ep_alloc_status[i].ep_type = 0xFF;
@@ -470,35 +268,21 @@ static void dcd_handle_bus_reset(void)
}
// Reset PMA allocation
- ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * MAX_EP_COUNT;
+ ep_buf_ptr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT;
- dcd_edpt_open(0, &ep0OUT_desc);
- dcd_edpt_open(0, &ep0IN_desc);
+ edpt0_open(rhport); // open control endpoint (both IN & OUT)
- USB->DADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero.
+ FSDEV_REG->DADDR = USB_DADDR_EF; // Enable USB Function
}
// Handle CTR interrupt for the TX/IN direction
-//
-// Upon call, (wIstr & USB_ISTR_DIR) == 0U
-static void dcd_ep_ctr_tx_handler(uint32_t wIstr)
-{
- uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
- uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
- uint8_t ep_addr = (wEPRegVal & USB_EPADDR_FIELD) | TUSB_DIR_IN_MASK;
+static void handle_ctr_tx(uint32_t ep_id) {
+ uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
- // Verify the CTR_TX bit is set. This was in the ST Micro code,
- // but I'm not sure it's actually necessary?
- if ((wEPRegVal & USB_EP_CTR_TX) == 0U) {
- return;
- }
+ uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD;
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_IN);
- /* clear int flag */
- pcd_clear_tx_ep_ctr(USB, EPindex);
-
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
-
- if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) {
+ if (ep_is_iso(ep_reg)) {
// Ignore spurious interrupts that we don't schedule
// host can send IN token while there is no data to send, since ISO does not have NAK
// this will result to zero length packet --> trigger interrupt (which cannot be masked)
@@ -506,190 +290,106 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr)
return;
}
xfer->iso_in_sending = false;
-
- if (wEPRegVal & USB_EP_DTOG_TX) {
- pcd_set_ep_tx_dbuf0_cnt(USB, EPindex, 0);
- } else {
- pcd_set_ep_tx_dbuf1_cnt(USB, EPindex, 0);
- }
+ uint8_t buf_id = (ep_reg & USB_EP_DTOG_TX) ? 0 : 1;
+ btable_set_count(ep_id, buf_id, 0);
}
- if ((xfer->total_len != xfer->queued_len)) {
- dcd_transmit_packet(xfer, EPindex);
+ if (xfer->total_len != xfer->queued_len) {
+ dcd_transmit_packet(xfer, ep_id);
} else {
- dcd_event_xfer_complete(0, ep_addr, xfer->total_len, XFER_RESULT_SUCCESS, true);
+ dcd_event_xfer_complete(0, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len, XFER_RESULT_SUCCESS, true);
}
}
-// Handle CTR interrupt for the RX/OUT direction
-// Upon call, (wIstr & USB_ISTR_DIR) == 0U
-static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
-{
-#ifdef FSDEV_BUS_32BIT
- /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf
- * From STM32H503 errata 2.15.1: Buffer description table update completes after CTR interrupt triggers
- * Description:
- * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses
- * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct.
- * Workaround:
- * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay
- * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode
- * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code
- * also takes time, so we'll wait 60 cycles (count = 20).
- * - Since Low Speed mode is not supported/popular, we will ignore it for now.
- *
- * Note: this errata also seems to apply to G0, U5, H5 etc.
- */
- volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver
- while (cycle_count > 0U) {
- cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
- }
-#endif
+static void handle_ctr_setup(uint32_t ep_id) {
+ uint16_t rx_count = btable_get_count(ep_id, BTABLE_BUF_RX);
+ uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX);
+ uint8_t setup_packet[8] TU_ATTR_ALIGNED(4);
- uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
- uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
- uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD;
+ dcd_read_packet_memory(setup_packet, rx_addr, rx_count);
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
+ // Clear CTR RX if another setup packet arrived before this, it will be discarded
+ ep_write_clear_ctr(ep_id, TUSB_DIR_OUT);
- // Verify the CTR_RX bit is set. This was in the ST Micro code,
- // but I'm not sure it's actually necessary?
- if ((wEPRegVal & USB_EP_CTR_RX) == 0U) {
- return;
- }
-
- if ((ep_addr == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) {
- /* Setup packet */
- uint32_t count = pcd_get_ep_rx_cnt(USB, EPindex);
- // Setup packet should always be 8 bytes. If not, ignore it, and try again.
- if (count == 8) {
- // Must reset EP to NAK (in case it had been stalling) (though, maybe too late here)
- pcd_set_ep_rx_status(USB, 0u, USB_EP_RX_NAK);
- pcd_set_ep_tx_status(USB, 0u, USB_EP_TX_NAK);
-#ifdef FSDEV_BUS_32BIT
- dcd_event_setup_received(0, (uint8_t *)(USB_PMAADDR + pcd_get_ep_rx_address(USB, EPindex)), true);
-#else
- // The setup_received function uses memcpy, so this must first copy the setup data into
- // user memory, to allow for the 32-bit access that memcpy performs.
- uint8_t userMemBuf[8];
- dcd_read_packet_memory(userMemBuf, pcd_get_ep_rx_address(USB, EPindex), 8);
- dcd_event_setup_received(0, (uint8_t *)userMemBuf, true);
-#endif
- }
+ // Setup packet should always be 8 bytes. If not, we probably missed the packet
+ if (rx_count == 8) {
+ dcd_event_setup_received(0, (uint8_t*) setup_packet, true);
+ // Hardware should reset EP0 RX/TX to NAK and both toggle to 1
} else {
- // Clear RX CTR interrupt flag
- if (ep_addr != 0u) {
- pcd_clear_rx_ep_ctr(USB, EPindex);
- }
-
- uint32_t count;
- uint16_t addr;
- /* Read from correct register when ISOCHRONOUS (double buffered) */
- if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) {
- if (wEPRegVal & USB_EP_DTOG_RX) {
- count = pcd_get_ep_dbuf0_cnt(USB, EPindex);
- addr = pcd_get_ep_dbuf0_address(USB, EPindex);
- } else {
- count = pcd_get_ep_dbuf1_cnt(USB, EPindex);
- addr = pcd_get_ep_dbuf1_address(USB, EPindex);
- }
- } else {
- count = pcd_get_ep_rx_cnt(USB, EPindex);
- addr = pcd_get_ep_rx_address(USB, EPindex);
- }
-
- TU_ASSERT(count <= xfer->max_packet_size, /**/);
-
- if (count != 0U) {
- if (xfer->ff) {
- dcd_read_packet_memory_ff(xfer->ff, addr, count);
- } else {
- dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), addr, count);
- }
+ // Missed setup packet !!!
+ TU_BREAKPOINT();
+ edpt0_prepare_setup();
+ }
+}
- xfer->queued_len = (uint16_t)(xfer->queued_len + count);
- }
+// Handle CTR interrupt for the RX/OUT direction
+static void handle_ctr_rx(uint32_t ep_id) {
+ uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
+ uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD;
+ bool const is_iso = ep_is_iso(ep_reg);
+ xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT);
- if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) {
- // all bytes received or short packet
- dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true);
- } else {
- /* Set endpoint active again for receiving more data.
- * Note that isochronous endpoints stay active always */
- if ((wEPRegVal & USB_EP_TYPE_MASK) != USB_EP_ISOCHRONOUS) {
- uint16_t remaining = xfer->total_len - xfer->queued_len;
- uint16_t cnt = tu_min16(remaining, xfer->max_packet_size);
- pcd_set_ep_rx_cnt(USB, EPindex, cnt);
- }
- pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID);
- }
+ uint8_t buf_id;
+ if (is_iso) {
+ buf_id = (ep_reg & USB_EP_DTOG_RX) ? 0 : 1; // ISO are double buffered
+ } else {
+ buf_id = BTABLE_BUF_RX;
}
+ uint16_t const rx_count = btable_get_count(ep_id, buf_id);
+ uint16_t pma_addr = (uint16_t) btable_get_addr(ep_id, buf_id);
- // For EP0, prepare to receive another SETUP packet.
- // Clear CTR last so that a new packet does not overwrite the packing being read.
- // (Based on the docs, it seems SETUP will always be accepted after CTR is cleared)
- if (ep_addr == 0u) {
- // Always be prepared for a status packet...
- pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE);
- pcd_clear_rx_ep_ctr(USB, EPindex);
+ if (xfer->ff) {
+ dcd_read_packet_memory_ff(xfer->ff, pma_addr, rx_count);
+ } else {
+ dcd_read_packet_memory(xfer->buffer + xfer->queued_len, pma_addr, rx_count);
}
-}
+ xfer->queued_len += rx_count;
-static void dcd_ep_ctr_handler(void)
-{
- uint32_t wIstr;
+ if ((rx_count < xfer->max_packet_size) || (xfer->queued_len >= xfer->total_len)) {
+ // all bytes received or short packet
- /* stay in loop while pending interrupts */
- while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) {
- if ((wIstr & USB_ISTR_DIR) == 0U) {
- /* TX/IN */
- dcd_ep_ctr_tx_handler(wIstr);
- } else {
- /* RX/OUT*/
- dcd_ep_ctr_rx_handler(wIstr);
+ // For ch32v203: reset rx bufsize to mps to prevent race condition to cause PMAOVR (occurs with msc write10)
+ btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, xfer->max_packet_size);
+
+ dcd_event_xfer_complete(0, ep_num, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+
+ // ch32 seems to unconditionally accept ZLP on EP0 OUT, which can incorrectly use queued_len of previous
+ // transfer. So reset total_len and queued_len to 0.
+ xfer->total_len = xfer->queued_len = 0;
+ } else {
+ // Set endpoint active again for receiving more data. Note that isochronous endpoints stay active always
+ if (!is_iso) {
+ uint16_t const cnt = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
+ btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, cnt);
}
+ ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(TUSB_DIR_OUT); // will change RX Status, reserved other toggle bits
+ ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_VALID);
+ ep_write(ep_id, ep_reg, false);
}
}
-void dcd_int_handler(uint8_t rhport)
-{
-
- (void)rhport;
-
- uint32_t int_status = USB->ISTR;
- // const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP
- // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF;
- // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ )
-
- // The ST driver loops here on the CTR bit, but that loop has been moved into the
- // dcd_ep_ctr_handler(), so less need to loop here. The other interrupts shouldn't
- // be triggered repeatedly.
+void dcd_int_handler(uint8_t rhport) {
+ uint32_t int_status = FSDEV_REG->ISTR;
/* Put SOF flag at the beginning of ISR in case to get least amount of jitter if it is used for timing purposes */
if (int_status & USB_ISTR_SOF) {
- USB->ISTR = (fsdev_bus_t)~USB_ISTR_SOF;
- dcd_event_sof(0, USB->FNR & USB_FNR_FN, true);
+ FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_SOF;
+ dcd_event_sof(0, FSDEV_REG->FNR & USB_FNR_FN, true);
}
if (int_status & USB_ISTR_RESET) {
// USBRST is start of reset.
- USB->ISTR = (fsdev_bus_t)~USB_ISTR_RESET;
- dcd_handle_bus_reset();
+ FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_RESET;
+ handle_bus_reset(rhport);
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
return; // Don't do the rest of the things here; perhaps they've been cleared?
}
- if (int_status & USB_ISTR_CTR) {
- /* servicing of the endpoint correct transfer interrupt */
- /* clear of the CTR flag into the sub */
- dcd_ep_ctr_handler();
- }
-
if (int_status & USB_ISTR_WKUP) {
- USB->CNTR &= ~USB_CNTR_LPMODE;
- USB->CNTR &= ~USB_CNTR_FSUSP;
+ FSDEV_REG->CNTR &= ~USB_CNTR_LPMODE;
+ FSDEV_REG->CNTR &= ~USB_CNTR_FSUSP;
- USB->ISTR = (fsdev_bus_t)~USB_ISTR_WKUP;
+ FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_WKUP;
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
}
@@ -698,22 +398,70 @@ void dcd_int_handler(uint8_t rhport)
* these events cannot be differentiated, so we only trigger suspend. */
/* Force low-power mode in the macrocell */
- USB->CNTR |= USB_CNTR_FSUSP;
- USB->CNTR |= USB_CNTR_LPMODE;
+ FSDEV_REG->CNTR |= USB_CNTR_FSUSP;
+ FSDEV_REG->CNTR |= USB_CNTR_LPMODE;
/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
- USB->ISTR = (fsdev_bus_t)~USB_ISTR_SUSP;
+ FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_SUSP;
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
}
if (int_status & USB_ISTR_ESOF) {
if (remoteWakeCountdown == 1u) {
- USB->CNTR &= ~USB_CNTR_RESUME;
+ FSDEV_REG->CNTR &= ~USB_CNTR_RESUME;
}
if (remoteWakeCountdown > 0u) {
remoteWakeCountdown--;
}
- USB->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF;
+ FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF;
+ }
+
+ // loop to handle all pending CTR interrupts
+ while (FSDEV_REG->ISTR & USB_ISTR_CTR) {
+ // skip DIR bit, and use CTR TX/RX instead, since there is chance we have both TX/RX completed in one interrupt
+ uint32_t const ep_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID;
+ uint32_t const ep_reg = ep_read(ep_id);
+
+ if (ep_reg & USB_EP_CTR_RX) {
+ #ifdef FSDEV_BUS_32BIT
+ /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf
+ * https://www.st.com/resource/en/errata_sheet/es0587-stm32u535xx-and-stm32u545xx-device-errata-stmicroelectronics.pdf
+ * From H503/U535 errata: Buffer description table update completes after CTR interrupt triggers
+ * Description:
+ * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses
+ * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct.
+ * Workaround:
+ * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay
+ * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode
+ * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code
+ * also takes time, so we'll wait 60 cycles (count = 20).
+ * - Since Low Speed mode is not supported/popular, we will ignore it for now.
+ *
+ * Note: this errata may also apply to G0, U5, H5 etc.
+ */
+ volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver
+ while (cycle_count > 0U) {
+ cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
+ }
+ #endif
+
+ if (ep_reg & USB_EP_SETUP) {
+ handle_ctr_setup(ep_id); // CTR will be clear after copied setup packet
+ } else {
+ ep_write_clear_ctr(ep_id, TUSB_DIR_OUT);
+ handle_ctr_rx(ep_id);
+ }
+ }
+
+ if (ep_reg & USB_EP_CTR_TX) {
+ ep_write_clear_ctr(ep_id, TUSB_DIR_IN);
+ handle_ctr_tx(ep_id);
+ }
+ }
+
+ if (int_status & USB_ISTR_PMAOVR) {
+ TU_BREAKPOINT();
+ FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_PMAOVR;
}
}
@@ -723,19 +471,17 @@ void dcd_int_handler(uint8_t rhport)
// Invoked when a control transfer's status stage is complete.
// May help DCD to prepare for next control transfer, this API is optional.
-void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request)
-{
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) {
(void)rhport;
if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
request->bRequest == TUSB_REQ_SET_ADDRESS) {
uint8_t const dev_addr = (uint8_t)request->wValue;
-
- // Setting new address after the whole request is complete
- USB->DADDR &= ~USB_DADDR_ADD;
- USB->DADDR |= dev_addr; // leave the enable bit set
+ FSDEV_REG->DADDR = (USB_DADDR_EF | dev_addr);
}
+
+ edpt0_prepare_setup();
}
/***
@@ -743,21 +489,19 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *req
* In case of double buffering, high 16bit is the address of 2nd buffer
* During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually.
*/
-static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf)
+static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf)
{
- // Ensure allocated buffer is aligned
-#ifdef FSDEV_BUS_32BIT
- length = (length + 3) & ~0x03;
-#else
- length = (length + 1) & ~0x01;
-#endif
+ uint8_t blsize, num_block;
+ uint16_t aligned_len = pma_align_buffer_size(len, &blsize, &num_block);
+ (void) blsize;
+ (void) num_block;
uint32_t addr = ep_buf_ptr;
- ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer
+ ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer
if (dbuf) {
addr |= ((uint32_t)ep_buf_ptr) << 16;
- ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer
+ ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer
}
// Verify packet buffer is not overflowed
@@ -774,7 +518,7 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
- for (uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) {
+ for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) {
// Check if already allocated
if (ep_alloc_status[i].allocated[dir] &&
ep_alloc_status[i].ep_type == ep_type &&
@@ -804,34 +548,53 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
TU_ASSERT(0);
}
-// The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers,
-// so I'm using the #define from HAL here, instead.
+void edpt0_open(uint8_t rhport) {
+ (void) rhport;
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
-{
+ dcd_ep_alloc(0x0, TUSB_XFER_CONTROL);
+ dcd_ep_alloc(0x80, TUSB_XFER_CONTROL);
+
+ xfer_status[0][0].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
+ xfer_status[0][0].ep_idx = 0;
+
+ xfer_status[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
+ xfer_status[0][1].ep_idx = 0;
+
+ uint16_t pma_addr0 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false);
+ uint16_t pma_addr1 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false);
+
+ btable_set_addr(0, BTABLE_BUF_RX, pma_addr0);
+ btable_set_addr(0, BTABLE_BUF_TX, pma_addr1);
+
+ uint32_t ep_reg = ep_read(0) & ~USB_EPREG_MASK; // only get toggle bits
+ ep_reg |= USB_EP_CONTROL;
+ ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_NAK);
+ ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_NAK);
+ // no need to explicitly set DTOG bits since we aren't masked DTOG bit
+
+ edpt0_prepare_setup(); // prepare for setup packet
+ ep_write(0, ep_reg, false);
+}
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
(void)rhport;
- uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress;
- uint8_t const ep_idx = dcd_ep_alloc(ep_addr, p_endpoint_desc->bmAttributes.xfer);
- uint8_t const dir = tu_edpt_dir(ep_addr);
- const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc);
- const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size);
- uint16_t pma_addr;
- uint32_t wType;
+ uint8_t const ep_addr = desc_ep->bEndpointAddress;
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+ const uint16_t packet_size = tu_edpt_packet_size(desc_ep);
+ uint8_t const ep_idx = dcd_ep_alloc(ep_addr, desc_ep->bmAttributes.xfer);
+ TU_ASSERT(ep_idx < FSDEV_EP_COUNT);
- TU_ASSERT(ep_idx < STFSDEV_EP_COUNT);
- TU_ASSERT(buffer_size <= 64);
+ uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK;
+ ep_reg |= tu_edpt_number(ep_addr) | USB_EP_CTR_TX | USB_EP_CTR_RX;
// Set type
- switch (p_endpoint_desc->bmAttributes.xfer) {
- case TUSB_XFER_CONTROL:
- wType = USB_EP_CONTROL;
- break;
+ switch (desc_ep->bmAttributes.xfer) {
case TUSB_XFER_BULK:
- wType = USB_EP_CONTROL;
+ ep_reg |= USB_EP_BULK;
break;
-
case TUSB_XFER_INTERRUPT:
- wType = USB_EP_INTERRUPT;
+ ep_reg |= USB_EP_INTERRUPT;
break;
default:
@@ -839,35 +602,35 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
TU_ASSERT(false);
}
- pcd_set_eptype(USB, ep_idx, wType);
- pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr));
-
/* Create a packet memory buffer area. */
- pma_addr = dcd_pma_alloc(buffer_size, false);
+ uint16_t pma_addr = dcd_pma_alloc(packet_size, false);
+ btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+ xfer->max_packet_size = packet_size;
+ xfer->ep_idx = ep_idx;
+
+ ep_change_status(&ep_reg, dir, EP_STAT_NAK);
+ ep_change_dtog(&ep_reg, dir, 0);
+
+ // reserve other direction toggle bits
if (dir == TUSB_DIR_IN) {
- pcd_set_ep_tx_address(USB, ep_idx, pma_addr);
- pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK);
- pcd_clear_tx_dtog(USB, ep_idx);
+ ep_reg &= ~(USB_EPRX_STAT | USB_EP_DTOG_RX);
} else {
- pcd_set_ep_rx_address(USB, ep_idx, pma_addr);
- pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK);
- pcd_clear_rx_dtog(USB, ep_idx);
+ ep_reg &= ~(USB_EPTX_STAT | USB_EP_DTOG_TX);
}
- xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size;
- xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx;
+ ep_write(ep_idx, ep_reg, true);
return true;
}
-void dcd_edpt_close_all(uint8_t rhport)
-{
- (void)rhport;
+void dcd_edpt_close_all(uint8_t rhport) {
+ dcd_int_disable(rhport);
- for (uint32_t i = 1; i < STFSDEV_EP_COUNT; i++) {
+ for (uint32_t i = 1; i < FSDEV_EP_COUNT; i++) {
// Reset endpoint
- pcd_set_endpoint(USB, i, 0);
+ ep_write(i, 0, false);
// Clear EP allocation status
ep_alloc_status[i].ep_num = 0xFF;
ep_alloc_status[i].ep_type = 0xFF;
@@ -875,508 +638,340 @@ void dcd_edpt_close_all(uint8_t rhport)
ep_alloc_status[i].allocated[1] = false;
}
+ dcd_int_enable(rhport);
+
// Reset PMA allocation
- ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * MAX_EP_COUNT + 2 * CFG_TUD_ENDPOINT0_SIZE;
+ ep_buf_ptr = FSDEV_BTABLE_BASE + 8 * CFG_TUD_ENDPPOINT_MAX + 2 * CFG_TUD_ENDPOINT0_SIZE;
}
-/**
- * Close an endpoint.
- *
- * This function may be called with interrupts enabled or disabled.
- *
- * This also clears transfers in progress, should there be any.
- */
-void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
-{
+bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
(void)rhport;
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
- uint8_t const ep_idx = xfer->ep_idx;
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if (dir == TUSB_DIR_IN) {
- pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS);
- } else {
- pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS);
- }
-}
-
-bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size)
-{
- (void)rhport;
-
uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS);
- const uint16_t buffer_size = pcd_aligned_buffer_size(largest_packet_size);
/* Create a packet memory buffer area. Enable double buffering for devices with 2048 bytes PMA,
for smaller devices double buffering occupy too much space. */
#if FSDEV_PMA_SIZE > 1024u
- uint32_t pma_addr = dcd_pma_alloc(buffer_size, true);
+ uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true);
uint16_t pma_addr2 = pma_addr >> 16;
#else
- uint32_t pma_addr = dcd_pma_alloc(buffer_size, true);
+ uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, false);
uint16_t pma_addr2 = pma_addr;
#endif
- pcd_set_ep_tx_address(USB, ep_idx, pma_addr);
- pcd_set_ep_rx_address(USB, ep_idx, pma_addr2);
- pcd_set_eptype(USB, ep_idx, USB_EP_ISOCHRONOUS);
+ btable_set_addr(ep_idx, 0, pma_addr);
+ btable_set_addr(ep_idx, 1, pma_addr2);
- xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx;
+ xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir);
+ xfer->ep_idx = ep_idx;
return true;
}
-bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
-{
+bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
(void)rhport;
- uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress;
- uint8_t const ep_idx = xfer_ctl_ptr(ep_addr)->ep_idx;
- uint8_t const dir = tu_edpt_dir(ep_addr);
- const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc);
-
- pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS);
- pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS);
+ uint8_t const ep_addr = desc_ep->bEndpointAddress;
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir);
- pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr));
+ uint8_t const ep_idx = xfer->ep_idx;
- pcd_clear_tx_dtog(USB, ep_idx);
- pcd_clear_rx_dtog(USB, ep_idx);
+ xfer->max_packet_size = tu_edpt_packet_size(desc_ep);
- if (dir == TUSB_DIR_IN) {
- pcd_rx_dtog(USB, ep_idx);
- } else {
- pcd_tx_dtog(USB, ep_idx);
- }
+ uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK;
+ ep_reg |= tu_edpt_number(ep_addr) | USB_EP_ISOCHRONOUS | USB_EP_CTR_TX | USB_EP_CTR_RX;
+ ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_DISABLED);
+ ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_DISABLED);
+ ep_change_dtog(&ep_reg, dir, 0);
+ ep_change_dtog(&ep_reg, (tusb_dir_t)(1 - dir), 1);
- xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size;
+ ep_write(ep_idx, ep_reg, true);
return true;
}
// Currently, single-buffered, and only 64 bytes at a time (max)
+static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) {
+ uint16_t len = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
+ uint32_t ep_reg = ep_read(ep_ix) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR
-static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix)
-{
- uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len);
- if (len > xfer->max_packet_size) {
- len = xfer->max_packet_size;
- }
-
- uint16_t ep_reg = pcd_get_endpoint(USB, ep_ix);
- bool const is_iso = (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS;
- uint16_t addr_ptr;
+ bool const is_iso = ep_is_iso(ep_reg);
+ uint8_t buf_id;
if (is_iso) {
- if (ep_reg & USB_EP_DTOG_TX) {
- addr_ptr = pcd_get_ep_dbuf1_address(USB, ep_ix);
- pcd_set_ep_tx_dbuf1_cnt(USB, ep_ix, len);
- } else {
- addr_ptr = pcd_get_ep_dbuf0_address(USB, ep_ix);
- pcd_set_ep_tx_dbuf0_cnt(USB, ep_ix, len);
- }
+ buf_id = (ep_reg & USB_EP_DTOG_TX) ? 1 : 0;
} else {
- addr_ptr = pcd_get_ep_tx_address(USB, ep_ix);
- pcd_set_ep_tx_cnt(USB, ep_ix, len);
+ buf_id = BTABLE_BUF_TX;
}
+ uint16_t addr_ptr = (uint16_t) btable_get_addr(ep_ix, buf_id);
if (xfer->ff) {
dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len);
} else {
dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len);
}
- xfer->queued_len = (uint16_t)(xfer->queued_len + len);
+ xfer->queued_len += len;
+
+ btable_set_count(ep_ix, buf_id, len);
+ ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_VALID);
- dcd_int_disable(0);
- pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID);
if (is_iso) {
xfer->iso_in_sending = true;
}
- dcd_int_enable(0);
+ ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(TUSB_DIR_IN); // only change TX Status, reserve other toggle bits
+ ep_write(ep_ix, ep_reg, true);
}
-static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr)
-{
- (void)rhport;
+static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) {
+ (void) rhport;
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
uint8_t const ep_idx = xfer->ep_idx;
- uint8_t const dir = tu_edpt_dir(ep_addr);
if (dir == TUSB_DIR_IN) {
dcd_transmit_packet(xfer, ep_idx);
} else {
- // A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid
- // buffer for the control endpoint.
- if (ep_idx == 0 && xfer->buffer == NULL) {
- xfer->buffer = (uint8_t *)_setup_packet;
- }
+ uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR
+ ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir);
- uint32_t cnt = (uint32_t ) tu_min16(xfer->total_len, xfer->max_packet_size);
- uint16_t ep_reg = pcd_get_endpoint(USB, ep_idx);
+ uint16_t cnt = tu_min16(xfer->total_len, xfer->max_packet_size);
- if ((ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) {
- pcd_set_ep_rx_dbuf0_cnt(USB, ep_idx, cnt);
- pcd_set_ep_rx_dbuf1_cnt(USB, ep_idx, cnt);
+ if (ep_is_iso(ep_reg)) {
+ btable_set_rx_bufsize(ep_idx, 0, cnt);
+ btable_set_rx_bufsize(ep_idx, 1, cnt);
} else {
- pcd_set_ep_rx_cnt(USB, ep_idx, cnt);
+ btable_set_rx_bufsize(ep_idx, BTABLE_BUF_RX, cnt);
}
- pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_VALID);
+ ep_change_status(&ep_reg, dir, EP_STAT_VALID);
+ ep_write(ep_idx, ep_reg, true);
}
return true;
}
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
-{
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) {
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
xfer->buffer = buffer;
xfer->ff = NULL;
xfer->total_len = total_bytes;
xfer->queued_len = 0;
- return edpt_xfer(rhport, ep_addr);
+ return edpt_xfer(rhport, ep_num, dir);
}
-bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes)
-{
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes) {
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+
xfer->buffer = NULL;
xfer->ff = ff;
xfer->total_len = total_bytes;
xfer->queued_len = 0;
- return edpt_xfer(rhport, ep_addr);
+ return edpt_xfer(rhport, ep_num, dir);
}
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
-{
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
(void)rhport;
-
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
uint8_t const ep_idx = xfer->ep_idx;
- uint8_t const dir = tu_edpt_dir(ep_addr);
- if (dir == TUSB_DIR_IN) {
- pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_STALL);
- } else {
- pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_STALL);
- }
+ uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits
+ ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir);
+ ep_change_status(&ep_reg, dir, EP_STAT_STALL);
+
+ ep_write(ep_idx, ep_reg, true);
}
-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;
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
uint8_t const ep_idx = xfer->ep_idx;
- uint8_t const dir = tu_edpt_dir(ep_addr);
- if (dir == TUSB_DIR_IN) { // IN
- if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) {
- pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK);
- }
+ uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits
+ ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir) | EP_DTOG_MASK(dir);
- /* Reset to DATA0 if clearing stall condition. */
- pcd_clear_tx_dtog(USB, ep_idx);
- } else { // OUT
- if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) {
- pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK);
- }
- /* Reset to DATA0 if clearing stall condition. */
- pcd_clear_rx_dtog(USB, ep_idx);
+ if (!ep_is_iso(ep_reg)) {
+ ep_change_status(&ep_reg, dir, EP_STAT_NAK);
}
+ ep_change_dtog(&ep_reg, dir, 0); // Reset to DATA0
+ ep_write(ep_idx, ep_reg, true);
}
-#ifdef FSDEV_BUS_32BIT
-static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes)
-{
- const uint8_t *srcVal = src;
- volatile uint32_t *dst32 = (volatile uint32_t *)(USB_PMAADDR + dst);
+//--------------------------------------------------------------------+
+// PMA read/write
+//--------------------------------------------------------------------+
- for (uint32_t n = wNBytes / 4; n > 0; --n) {
- *dst32++ = tu_unaligned_read32(srcVal);
- srcVal += 4;
- }
+// Write to packet memory area (PMA) from user memory
+// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT
+// - Uses unaligned for RAM (since M0 cannot access unaligned address)
+static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes) {
+ if (nbytes == 0) return true;
+ uint32_t n_write = nbytes / FSDEV_BUS_SIZE;
- wNBytes = wNBytes & 0x03;
- if (wNBytes) {
- uint32_t wrVal = *srcVal;
- wNBytes--;
+ fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(dst);
+ const uint8_t *src8 = src;
- if (wNBytes) {
- wrVal |= *++srcVal << 8;
- wNBytes--;
+ while (n_write--) {
+ pma_buf->value = fsdevbus_unaligned_read(src8);
+ src8 += FSDEV_BUS_SIZE;
+ pma_buf++;
+ }
- if (wNBytes) {
- wrVal |= *++srcVal << 16;
- }
+ // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit
+ uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1);
+ if (odd) {
+ fsdev_bus_t temp = 0;
+ for(uint16_t i = 0; i < odd; i++) {
+ temp |= *src8++ << (i * 8);
}
-
- *dst32 = wrVal;
+ pma_buf->value = temp;
}
return true;
}
-#else
-// Packet buffer access can only be 8- or 16-bit.
-/**
- * @brief Copy a buffer from user memory area to packet memory area (PMA).
- * This uses byte-access for user memory (so support non-aligned buffers)
- * and 16-bit access for packet memory.
- * @param dst, byte address in PMA; must be 16-bit aligned
- * @param src pointer to user memory area.
- * @param wPMABufAddr address into PMA.
- * @param wNBytes no. of bytes to be copied.
- * @retval None
- */
-static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes)
-{
- uint32_t n = (uint32_t)wNBytes >> 1U;
- uint16_t temp1, temp2;
- const uint8_t *srcVal;
- // The GCC optimizer will combine access to 32-bit sizes if we let it. Force
- // it volatile so that it won't do that.
- __IO uint16_t *pdwVal;
+// Read from packet memory area (PMA) to user memory.
+// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT
+// - Uses unaligned for RAM (since M0 cannot access unaligned address)
+static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes) {
+ if (nbytes == 0) return true;
+ uint32_t n_read = nbytes / FSDEV_BUS_SIZE;
- srcVal = src;
- pdwVal = &pma[FSDEV_PMA_STRIDE * (dst >> 1)];
+ fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(src);
+ uint8_t *dst8 = (uint8_t *)dst;
- while (n--) {
- temp1 = (uint16_t)*srcVal;
- srcVal++;
- temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U));
- *pdwVal = temp2;
- pdwVal += FSDEV_PMA_STRIDE;
- srcVal++;
+ while (n_read--) {
+ fsdevbus_unaligned_write(dst8, (fsdev_bus_t ) pma_buf->value);
+ dst8 += FSDEV_BUS_SIZE;
+ pma_buf++;
}
- if (wNBytes) {
- temp1 = *srcVal;
- *pdwVal = temp1;
+ // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit
+ uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1);
+ if (odd) {
+ fsdev_bus_t temp = pma_buf->value;
+ while (odd--) {
+ *dst8++ = (uint8_t) (temp & 0xfful);
+ temp >>= 8;
+ }
}
return true;
}
-#endif
-/**
- * @brief Copy from FIFO to packet memory area (PMA).
- * Uses byte-access of system memory and 16-bit access of packet memory
- * @param wNBytes no. of bytes to be copied.
- * @retval None
- */
-static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes)
-{
+// Write to PMA from FIFO
+static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) {
+ if (wNBytes == 0) return true;
+
// Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
tu_fifo_buffer_info_t info;
tu_fifo_get_read_info(ff, &info);
- uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin);
- uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap);
+ uint16_t cnt_lin = tu_min16(wNBytes, info.len_lin);
+ uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.len_wrap);
+ uint16_t const cnt_total = cnt_lin + cnt_wrap;
// We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part,
- // last lin byte will be combined with wrapped part
- // To ensure PMA is always access aligned (dst aligned to 16 or 32 bit)
-#ifdef FSDEV_BUS_32BIT
- if ((cnt_lin & 0x03) && cnt_wrap) {
- // Copy first linear part
- dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x03);
- dst += cnt_lin & ~0x03;
+ // last lin byte will be combined with wrapped part To ensure PMA is always access aligned
+ uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1);
+ uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1);
+ uint8_t const *src8 = (uint8_t const*) info.ptr_lin;
- // Copy last linear bytes & first wrapped bytes to buffer
- uint32_t i;
- uint8_t tmp[4];
- for (i = 0; i < (cnt_lin & 0x03); i++) {
- tmp[i] = ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i];
- }
- uint32_t wCnt = cnt_wrap;
- for (; i < 4 && wCnt > 0; i++, wCnt--) {
- tmp[i] = *(uint8_t *)info.ptr_wrap;
- info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1;
- }
-
- // Write unaligned buffer
- dcd_write_packet_memory(dst, &tmp, 4);
- dst += 4;
+ // write even linear part
+ dcd_write_packet_memory(dst, src8, lin_even);
+ dst += lin_even;
+ src8 += lin_even;
- // Copy rest of wrapped byte
- if (wCnt)
- dcd_write_packet_memory(dst, info.ptr_wrap, wCnt);
- }
-#else
- if ((cnt_lin & 0x01) && cnt_wrap) {
- // Copy first linear part
- dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x01);
- dst += cnt_lin & ~0x01;
-
- // Copy last linear byte & first wrapped byte
- uint16_t tmp = ((uint8_t *)info.ptr_lin)[cnt_lin - 1] | ((uint16_t)(((uint8_t *)info.ptr_wrap)[0]) << 8U);
- dcd_write_packet_memory(dst, &tmp, 2);
- dst += 2;
-
- // Copy rest of wrapped byte
- dcd_write_packet_memory(dst, ((uint8_t *)info.ptr_wrap) + 1, cnt_wrap - 1);
- }
-#endif
- else {
- // Copy linear part
- dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin);
- dst += info.len_lin;
-
- if (info.len_wrap) {
- // Copy wrapped byte
- dcd_write_packet_memory(dst, info.ptr_wrap, cnt_wrap);
+ if (lin_odd == 0) {
+ src8 = (uint8_t const*) info.ptr_wrap;
+ } else {
+ // Combine last linear bytes + first wrapped bytes to form fsdev bus width data
+ fsdev_bus_t temp = 0;
+ uint16_t i;
+ for(i = 0; i < lin_odd; i++) {
+ temp |= *src8++ << (i * 8);
}
- }
-
- tu_fifo_advance_read_pointer(ff, cnt_lin + cnt_wrap);
- return true;
-}
-
-#ifdef FSDEV_BUS_32BIT
-static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes)
-{
- uint8_t *dstVal = dst;
- volatile uint32_t *src32 = (volatile uint32_t *)(USB_PMAADDR + src);
+ src8 = (uint8_t const*) info.ptr_wrap;
+ for(; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) {
+ temp |= *src8++ << (i * 8);
+ }
- for (uint32_t n = wNBytes / 4; n > 0; --n) {
- tu_unaligned_write32(dstVal, *src32++);
- dstVal += 4;
+ dcd_write_packet_memory(dst, &temp, FSDEV_BUS_SIZE);
+ dst += FSDEV_BUS_SIZE;
}
- wNBytes = wNBytes & 0x03;
- if (wNBytes) {
- uint32_t rdVal = *src32;
-
- *dstVal = tu_u32_byte0(rdVal);
- wNBytes--;
-
- if (wNBytes) {
- *++dstVal = tu_u32_byte1(rdVal);
- wNBytes--;
-
- if (wNBytes) {
- *++dstVal = tu_u32_byte2(rdVal);
- }
- }
- }
+ // write the rest of the wrapped part
+ dcd_write_packet_memory(dst, src8, cnt_wrap);
+ tu_fifo_advance_read_pointer(ff, cnt_total);
return true;
}
-#else
-/**
- * @brief Copy a buffer from packet memory area (PMA) to user memory area.
- * Uses byte-access of system memory and 16-bit access of packet memory
- * @param wNBytes no. of bytes to be copied.
- * @retval None
- */
-static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes)
-{
- uint32_t n = (uint32_t)wNBytes >> 1U;
- // The GCC optimizer will combine access to 32-bit sizes if we let it. Force
- // it volatile so that it won't do that.
- __IO const uint16_t *pdwVal;
- uint32_t temp;
-
- pdwVal = &pma[FSDEV_PMA_STRIDE * (src >> 1)];
- uint8_t *dstVal = (uint8_t *)dst;
-
- while (n--) {
- temp = *pdwVal;
- pdwVal += FSDEV_PMA_STRIDE;
- *dstVal++ = ((temp >> 0) & 0xFF);
- *dstVal++ = ((temp >> 8) & 0xFF);
- }
- if (wNBytes & 0x01) {
- temp = *pdwVal;
- pdwVal += FSDEV_PMA_STRIDE;
- *dstVal++ = ((temp >> 0) & 0xFF);
- }
- return true;
-}
-#endif
+// Read from PMA to FIFO
+static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) {
+ if (wNBytes == 0) return true;
-/**
- * @brief Copy a buffer from user packet memory area (PMA) to FIFO.
- * Uses byte-access of system memory and 16-bit access of packet memory
- * @param wNBytes no. of bytes to be copied.
- * @retval None
- */
-static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes)
-{
// Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
// Check for first linear part
tu_fifo_buffer_info_t info;
tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO
- uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin);
- uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap);
-
- // We want to read from PMA and write it into the FIFO, if LIN part is ODD and has WRAPPED part,
- // last lin byte will be combined with wrapped part
- // To ensure PMA is always access aligned (src aligned to 16 or 32 bit)
-#ifdef FSDEV_BUS_32BIT
- if ((cnt_lin & 0x03) && cnt_wrap) {
- // Copy first linear part
- dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x03);
- src += cnt_lin & ~0x03;
+ uint16_t cnt_lin = tu_min16(wNBytes, info.len_lin);
+ uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.len_wrap);
+ uint16_t cnt_total = cnt_lin + cnt_wrap;
- // Copy last linear bytes & first wrapped bytes
- uint8_t tmp[4];
- dcd_read_packet_memory(tmp, src, 4);
- src += 4;
-
- uint32_t i;
- for (i = 0; i < (cnt_lin & 0x03); i++) {
- ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i] = tmp[i];
- }
- uint32_t wCnt = cnt_wrap;
- for (; i < 4 && wCnt > 0; i++, wCnt--) {
- *(uint8_t *)info.ptr_wrap = tmp[i];
- info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1;
- }
+ // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part,
+ // last lin byte will be combined with wrapped part To ensure PMA is always access aligned
- // Copy rest of wrapped byte
- if (wCnt)
- dcd_read_packet_memory(info.ptr_wrap, src, wCnt);
- }
-#else
- if ((cnt_lin & 0x01) && cnt_wrap) {
- // Copy first linear part
- dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x01);
- src += cnt_lin & ~0x01;
+ uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1);
+ uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1);
+ uint8_t *dst8 = (uint8_t *) info.ptr_lin;
- // Copy last linear byte & first wrapped byte
- uint8_t tmp[2];
- dcd_read_packet_memory(tmp, src, 2);
- src += 2;
+ // read even linear part
+ dcd_read_packet_memory(dst8, src, lin_even);
+ dst8 += lin_even;
+ src += lin_even;
- ((uint8_t *)info.ptr_lin)[cnt_lin - 1] = tmp[0];
- ((uint8_t *)info.ptr_wrap)[0] = tmp[1];
+ if (lin_odd == 0) {
+ dst8 = (uint8_t *) info.ptr_wrap;
+ } else {
+ // Combine last linear bytes + first wrapped bytes to form fsdev bus width data
+ fsdev_bus_t temp;
+ dcd_read_packet_memory(&temp, src, FSDEV_BUS_SIZE);
+ src += FSDEV_BUS_SIZE;
- // Copy rest of wrapped byte
- dcd_read_packet_memory(((uint8_t *)info.ptr_wrap) + 1, src, cnt_wrap - 1);
- }
-#endif
- else {
- // Copy linear part
- dcd_read_packet_memory(info.ptr_lin, src, cnt_lin);
- src += cnt_lin;
+ uint16_t i;
+ for (i = 0; i < lin_odd; i++) {
+ *dst8++ = (uint8_t) (temp & 0xfful);
+ temp >>= 8;
+ }
- if (info.len_wrap) {
- // Copy wrapped byte
- dcd_read_packet_memory(info.ptr_wrap, src, cnt_wrap);
+ dst8 = (uint8_t *) info.ptr_wrap;
+ for (; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) {
+ *dst8++ = (uint8_t) (temp & 0xfful);
+ temp >>= 8;
}
}
- tu_fifo_advance_write_pointer(ff, cnt_lin + cnt_wrap);
+ // read the rest of the wrapped part
+ dcd_read_packet_memory(dst8, src, cnt_wrap);
+ tu_fifo_advance_write_pointer(ff, cnt_total);
return true;
}
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h
deleted file mode 100644
index 7992f34a1..000000000
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * Copyright(c) 2016 STMicroelectronics
- * Copyright(c) N Conrad
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of STMicroelectronics nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-// This file contains source copied from ST's HAL, and thus should have their copyright statement.
-
-// FSDEV_PMA_SIZE is PMA buffer size in bytes.
-// On 512-byte devices, access with a stride of two words (use every other 16-bit address)
-// On 1024-byte devices, access with a stride of one word (use every 16-bit address)
-
-#ifndef PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_
-#define PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_
-
-#if CFG_TUSB_MCU == OPT_MCU_STM32F0
- #include "stm32f0xx.h"
- #define FSDEV_PMA_SIZE (1024u)
- // F0x2 models are crystal-less
- // All have internal D+ pull-up
- // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support
- // PMA dedicated to USB (no sharing with CAN)
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
- #include "stm32f1xx.h"
- #define FSDEV_PMA_SIZE (512u)
- // NO internal Pull-ups
- // *B, and *C: 2 x 16 bits/word
-
- // F1 names this differently from the rest
- #define USB_CNTR_LPMODE USB_CNTR_LP_MODE
-
-#elif defined(STM32F302xB) || defined(STM32F302xC) || \
- defined(STM32F303xB) || defined(STM32F303xC) || \
- defined(STM32F373xC)
- #include "stm32f3xx.h"
- #define FSDEV_PMA_SIZE (512u)
- // NO internal Pull-ups
- // *B, and *C: 1 x 16 bits/word
- // PMA dedicated to USB (no sharing with CAN)
-
-#elif defined(STM32F302x6) || defined(STM32F302x8) || \
- defined(STM32F302xD) || defined(STM32F302xE) || \
- defined(STM32F303xD) || defined(STM32F303xE)
- #include "stm32f3xx.h"
- #define FSDEV_PMA_SIZE (1024u)
- // NO internal Pull-ups
- // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support
- // When CAN clock is enabled, USB can use first 768 bytes ONLY.
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L0
- #include "stm32l0xx.h"
- #define FSDEV_PMA_SIZE (1024u)
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
- #include "stm32l1xx.h"
- #define FSDEV_PMA_SIZE (512u)
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
- #include "stm32g4xx.h"
- #define FSDEV_PMA_SIZE (1024u)
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
- #include "stm32g0xx.h"
- #define FSDEV_BUS_32BIT
- #define FSDEV_PMA_SIZE (2048u)
- #undef USB_PMAADDR
- #define USB_PMAADDR USB_DRD_PMAADDR
- #define USB_TypeDef USB_DRD_TypeDef
- #define EP0R CHEP0R
- #define USB_EP_CTR_RX USB_EP_VTRX
- #define USB_EP_CTR_TX USB_EP_VTTX
- #define USB_EP_T_FIELD USB_CHEP_UTYPE
- #define USB_EPREG_MASK USB_CHEP_REG_MASK
- #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
- #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
- #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
- #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
- #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
- #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
- #define USB_EPRX_STAT USB_CH_RX_VALID
- #define USB_EPKIND_MASK USB_EP_KIND_MASK
- #define USB USB_DRD_FS
- #define USB_CNTR_FRES USB_CNTR_USBRST
- #define USB_CNTR_RESUME USB_CNTR_L2RES
- #define USB_ISTR_EP_ID USB_ISTR_IDN
- #define USB_EPADDR_FIELD USB_CHEP_ADDR
- #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
- #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
- #include "stm32h5xx.h"
- #define FSDEV_BUS_32BIT
-
- #if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE)
- #define USB_DRD_BASE USB_DRD_FS_BASE
- #endif
-
- #define FSDEV_PMA_SIZE (2048u)
- #undef USB_PMAADDR
- #define USB_PMAADDR USB_DRD_PMAADDR
- #define USB_TypeDef USB_DRD_TypeDef
- #define EP0R CHEP0R
- #define USB_EP_CTR_RX USB_EP_VTRX
- #define USB_EP_CTR_TX USB_EP_VTTX
- #define USB_EP_T_FIELD USB_CHEP_UTYPE
- #define USB_EPREG_MASK USB_CHEP_REG_MASK
- #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
- #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
- #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
- #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
- #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
- #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
- #define USB_EPRX_STAT USB_CH_RX_VALID
- #define USB_EPKIND_MASK USB_EP_KIND_MASK
- #define USB USB_DRD_FS
- #define USB_CNTR_FRES USB_CNTR_USBRST
- #define USB_CNTR_RESUME USB_CNTR_L2RES
- #define USB_ISTR_EP_ID USB_ISTR_IDN
- #define USB_EPADDR_FIELD USB_CHEP_ADDR
- #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
- #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
- #include "stm32wbxx.h"
- #define FSDEV_PMA_SIZE (1024u)
- /* ST provided header has incorrect value */
- #undef USB_PMAADDR
- #define USB_PMAADDR USB1_PMAADDR
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
- #include "stm32l4xx.h"
- #define FSDEV_PMA_SIZE (1024u)
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
- #include "stm32l5xx.h"
- #define FSDEV_PMA_SIZE (1024u)
-
- #ifndef USB_PMAADDR
- #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
- #endif
-
-#else
- #error You are using an untested or unimplemented STM32 variant. Please update the driver.
- // This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4
-#endif
-
-// For purposes of accessing the packet
-#if ((FSDEV_PMA_SIZE) == 512u)
- #define FSDEV_PMA_STRIDE (2u)
-#elif ((FSDEV_PMA_SIZE) == 1024u)
- #define FSDEV_PMA_STRIDE (1u)
-#endif
-
-// The fsdev_bus_t type can be used for both register and PMA access necessities
-// For type-safety create a new macro for the volatile address of PMAADDR
-// The compiler should warn us if we cast it to a non-volatile type?
-#ifdef FSDEV_BUS_32BIT
-typedef uint32_t fsdev_bus_t;
-static __IO uint32_t * const pma32 = (__IO uint32_t*)USB_PMAADDR;
-
-#else
-typedef uint16_t fsdev_bus_t;
-// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden)
-static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR;
-
-TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) {
- size_t total_word_offset = (((USBx)->BTABLE)>>1) + x;
- total_word_offset *= FSDEV_PMA_STRIDE;
- return &(pma[total_word_offset]);
-}
-
-TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
- return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u);
-}
-
-TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
- return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u);
-}
-#endif
-
-/* Aligned buffer size according to hardware */
-TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) {
- /* The STM32 full speed USB peripheral supports only a limited set of
- * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */
- uint16_t blocksize = (size > 62) ? 32 : 2;
-
- // Round up while dividing requested size by blocksize
- uint16_t numblocks = (size + blocksize - 1) / blocksize ;
-
- return numblocks * blocksize;
-}
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) {
-#ifdef FSDEV_BUS_32BIT
- (void) USBx;
- __O uint32_t *reg = (__O uint32_t *)(USB_DRD_BASE + bEpIdx*4);
- *reg = wRegValue;
-#else
- __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpIdx*2u);
- *reg = (uint16_t)wRegValue;
-#endif
-}
-
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) {
-#ifdef FSDEV_BUS_32BIT
- (void) USBx;
- __I uint32_t *reg = (__I uint32_t *)(USB_DRD_BASE + bEpIdx*4);
-#else
- __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpIdx*2u);
-#endif
- return *reg;
-}
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- regVal &= (uint32_t)USB_EP_T_MASK;
- regVal |= wType;
- regVal |= USB_EP_CTR_RX | USB_EP_CTR_TX; // These clear on write0, so must set high
- pcd_set_endpoint(USBx, bEpIdx, regVal);
-}
-
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- regVal &= USB_EP_T_FIELD;
- return regVal;
-}
-
-/**
- * @brief Clears bit CTR_RX / CTR_TX in the endpoint register.
- * @param USBx USB peripheral instance register address.
- * @param bEpIdx Endpoint Number.
- * @retval None
- */
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- regVal &= USB_EPREG_MASK;
- regVal &= ~USB_EP_CTR_RX;
- regVal |= USB_EP_CTR_TX; // preserve CTR_TX (clears on writing 0)
- pcd_set_endpoint(USBx, bEpIdx, regVal);
-}
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- regVal &= USB_EPREG_MASK;
- regVal &= ~USB_EP_CTR_TX;
- regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0)
- pcd_set_endpoint(USBx, bEpIdx,regVal);
-}
-
-/**
- * @brief gets counter of the tx buffer.
- * @param USBx USB peripheral instance register address.
- * @param bEpIdx Endpoint Number.
- * @retval Counter value
- */
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) {
-#ifdef FSDEV_BUS_32BIT
- (void) USBx;
- return (pma32[2*bEpIdx] & 0x03FF0000) >> 16;
-#else
- __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpIdx);
- return *regPtr & 0x3ffU;
-#endif
-}
-
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) {
-#ifdef FSDEV_BUS_32BIT
- (void) USBx;
- return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16;
-#else
- __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx);
- return *regPtr & 0x3ffU;
-#endif
-}
-
-#define pcd_get_ep_dbuf0_cnt pcd_get_ep_tx_cnt
-#define pcd_get_ep_dbuf1_cnt pcd_get_ep_rx_cnt
-
-/**
- * @brief Sets address in an endpoint register.
- * @param USBx USB peripheral instance register address.
- * @param bEpIdx Endpoint Number.
- * @param bAddr Address.
- * @retval None
- */
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- regVal &= USB_EPREG_MASK;
- regVal |= bAddr;
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
- pcd_set_endpoint(USBx, bEpIdx,regVal);
-}
-
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx) {
-#ifdef FSDEV_BUS_32BIT
- (void) USBx;
- return pma32[2*bEpIdx] & 0x0000FFFFu ;
-#else
- return *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u);
-#endif
-}
-
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx) {
-#ifdef FSDEV_BUS_32BIT
- (void) USBx;
- return pma32[2*bEpIdx + 1] & 0x0000FFFFu;
-#else
- return *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u);
-#endif
-}
-
-#define pcd_get_ep_dbuf0_address pcd_get_ep_tx_address
-#define pcd_get_ep_dbuf1_address pcd_get_ep_rx_address
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) {
-#ifdef FSDEV_BUS_32BIT
- (void) USBx;
- pma32[2*bEpIdx] = (pma32[2*bEpIdx] & 0xFFFF0000u) | (addr & 0x0000FFFCu);
-#else
- *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u) = addr;
-#endif
-}
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) {
-#ifdef FSDEV_BUS_32BIT
- (void) USBx;
- pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & 0xFFFF0000u) | (addr & 0x0000FFFCu);
-#else
- *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u) = addr;
-#endif
-}
-
-#define pcd_set_ep_dbuf0_address pcd_set_ep_tx_address
-#define pcd_set_ep_dbuf1_address pcd_set_ep_rx_address
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
-#ifdef FSDEV_BUS_32BIT
- (void) USBx;
- pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16);
-#else
- __IO uint16_t * reg = pcd_ep_tx_cnt_ptr(USBx, bEpIdx);
- *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU);
-#endif
-}
-
-#define pcd_set_ep_tx_dbuf0_cnt pcd_set_ep_tx_cnt
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_dbuf1_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
-#ifdef FSDEV_BUS_32BIT
- (void) USBx;
- pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16);
-#else
- __IO uint16_t * reg = pcd_ep_rx_cnt_ptr(USBx, bEpIdx);
- *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU);
-#endif
-}
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx,
- uint32_t blocksize, uint32_t numblocks) {
- /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */
-#ifdef FSDEV_BUS_32BIT
- (void) USBx;
- pma32[rxtx_idx] = (pma32[rxtx_idx] & 0x0000FFFFu) | (blocksize << 31) | ((numblocks - blocksize) << 26);
-#else
- __IO uint16_t *pdwReg = pcd_btable_word_ptr(USBx, rxtx_idx*2u + 1u);
- *pdwReg = (blocksize << 15) | ((numblocks - blocksize) << 10);
-#endif
-}
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t wCount) {
- wCount = pcd_aligned_buffer_size(wCount);
-
- /* We assume that the buffer size is already aligned to hardware requirements. */
- uint16_t blocksize = (wCount > 62) ? 1 : 0;
- uint16_t numblocks = wCount / (blocksize ? 32 : 2);
-
- /* There should be no remainder in the above calculation */
- TU_ASSERT((wCount - (numblocks * (blocksize ? 32 : 2))) == 0, /**/);
-
- /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */
- pcd_set_ep_blsize_num_blocks(USBx, rxtx_idx, blocksize, numblocks);
-}
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_dbuf0_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
- pcd_set_ep_bufsize(USBx, 2*bEpIdx, wCount);
-}
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
- pcd_set_ep_bufsize(USBx, 2*bEpIdx + 1, wCount);
-}
-
-#define pcd_set_ep_rx_dbuf1_cnt pcd_set_ep_rx_cnt
-
-/**
- * @brief sets the status for tx transfer (bits STAT_TX[1:0]).
- * @param USBx USB peripheral instance register address.
- * @param bEpIdx Endpoint Number.
- * @param wState new state
- * @retval None
- */
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- regVal &= USB_EPTX_DTOGMASK;
-
- /* toggle first bit ? */
- if((USB_EPTX_DTOG1 & (wState))!= 0U)
- {
- regVal ^= USB_EPTX_DTOG1;
- }
- /* toggle second bit ? */
- if((USB_EPTX_DTOG2 & ((uint32_t)(wState)))!= 0U)
- {
- regVal ^= USB_EPTX_DTOG2;
- }
-
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
- pcd_set_endpoint(USBx, bEpIdx, regVal);
-}
-
-/**
- * @brief sets the status for rx transfer (bits STAT_TX[1:0])
- * @param USBx USB peripheral instance register address.
- * @param bEpIdx Endpoint Number.
- * @param wState new state
- * @retval None
- */
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- regVal &= USB_EPRX_DTOGMASK;
-
- /* toggle first bit ? */
- if((USB_EPRX_DTOG1 & wState)!= 0U) {
- regVal ^= USB_EPRX_DTOG1;
- }
- /* toggle second bit ? */
- if((USB_EPRX_DTOG2 & wState)!= 0U) {
- regVal ^= USB_EPRX_DTOG2;
- }
-
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
- pcd_set_endpoint(USBx, bEpIdx, regVal);
-}
-
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- return (regVal & USB_EPRX_STAT) >> (12u);
-}
-
-
-/**
- * @brief Toggles DTOG_RX / DTOG_TX bit in the endpoint register.
- * @param USBx USB peripheral instance register address.
- * @param bEpIdx Endpoint Number.
- * @retval None
- */
-TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- regVal &= USB_EPREG_MASK;
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX;
- pcd_set_endpoint(USBx, bEpIdx, regVal);
-}
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- regVal &= USB_EPREG_MASK;
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX;
- pcd_set_endpoint(USBx, bEpIdx, regVal);
-}
-
-/**
- * @brief Clears DTOG_RX / DTOG_TX bit in the endpoint register.
- * @param USBx USB peripheral instance register address.
- * @param bEpIdx Endpoint Number.
- * @retval None
- */
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- if((regVal & USB_EP_DTOG_RX) != 0) {
- pcd_rx_dtog(USBx,bEpIdx);
- }
-}
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- if((regVal & USB_EP_DTOG_TX) != 0) {
- pcd_tx_dtog(USBx,bEpIdx);
- }
-}
-
-/**
- * @brief set & clear EP_KIND bit.
- * @param USBx USB peripheral instance register address.
- * @param bEpIdx Endpoint Number.
- * @retval None
- */
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- regVal |= USB_EP_KIND;
- regVal &= USB_EPREG_MASK;
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
- pcd_set_endpoint(USBx, bEpIdx, regVal);
-}
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) {
- uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- regVal &= USB_EPKIND_MASK;
- regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
- pcd_set_endpoint(USBx, bEpIdx, regVal);
-}
-
-// This checks if the device has "LPM"
-#if defined(USB_ISTR_L1REQ)
-#define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ)
-#else
-#define USB_ISTR_L1REQ_FORCED ((uint16_t)0x0000U)
-#endif
-
-#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \
- USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED )
-
-// Number of endpoints in hardware
-// TODO should use TUP_DCD_ENDPOINT_MAX
-#define STFSDEV_EP_COUNT (8u)
-
-#endif /* PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ */
diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h
new file mode 100644
index 000000000..518197c47
--- /dev/null
+++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h
@@ -0,0 +1,206 @@
+/*
+* The MIT License (MIT)
+ *
+ * Copyright (c) 2024, hathach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+/** <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
+ * All rights reserved.</center></h2>
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef TUSB_FSDEV_CH32_H
+#define TUSB_FSDEV_CH32_H
+
+#include "common/tusb_compiler.h"
+
+// https://github.com/openwch/ch32v307/pull/90
+// https://github.com/openwch/ch32v20x/pull/12
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_CH32F20X
+ #include <ch32f20x.h>
+#elif CFG_TUSB_MCU == OPT_MCU_CH32V20X
+ #include <ch32v20x.h>
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+#define FSDEV_PMA_SIZE (512u)
+#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL)
+#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL)
+
+/**************************** ISTR interrupt events *************************/
+#define USB_ISTR_CTR ((uint16_t)0x8000U) /*!< Correct TRansfer (clear-only bit) */
+#define USB_ISTR_PMAOVR ((uint16_t)0x4000U) /*!< DMA OVeR/underrun (clear-only bit) */
+#define USB_ISTR_ERR ((uint16_t)0x2000U) /*!< ERRor (clear-only bit) */
+#define USB_ISTR_WKUP ((uint16_t)0x1000U) /*!< WaKe UP (clear-only bit) */
+#define USB_ISTR_SUSP ((uint16_t)0x0800U) /*!< SUSPend (clear-only bit) */
+#define USB_ISTR_RESET ((uint16_t)0x0400U) /*!< RESET (clear-only bit) */
+#define USB_ISTR_SOF ((uint16_t)0x0200U) /*!< Start Of Frame (clear-only bit) */
+#define USB_ISTR_ESOF ((uint16_t)0x0100U) /*!< Expected Start Of Frame (clear-only bit) */
+#define USB_ISTR_DIR ((uint16_t)0x0010U) /*!< DIRection of transaction (read-only bit) */
+#define USB_ISTR_EP_ID ((uint16_t)0x000FU) /*!< EndPoint IDentifier (read-only bit) */
+
+/* Legacy defines */
+#define USB_ISTR_PMAOVRM USB_ISTR_PMAOVR
+
+#define USB_CLR_CTR (~USB_ISTR_CTR) /*!< clear Correct TRansfer bit */
+#define USB_CLR_PMAOVR (~USB_ISTR_PMAOVR) /*!< clear DMA OVeR/underrun bit*/
+#define USB_CLR_ERR (~USB_ISTR_ERR) /*!< clear ERRor bit */
+#define USB_CLR_WKUP (~USB_ISTR_WKUP) /*!< clear WaKe UP bit */
+#define USB_CLR_SUSP (~USB_ISTR_SUSP) /*!< clear SUSPend bit */
+#define USB_CLR_RESET (~USB_ISTR_RESET) /*!< clear RESET bit */
+#define USB_CLR_SOF (~USB_ISTR_SOF) /*!< clear Start Of Frame bit */
+#define USB_CLR_ESOF (~USB_ISTR_ESOF) /*!< clear Expected Start Of Frame bit */
+
+/* Legacy defines */
+#define USB_CLR_PMAOVRM USB_CLR_PMAOVR
+
+/************************* CNTR control register bits definitions ***********/
+#define USB_CNTR_CTRM ((uint16_t)0x8000U) /*!< Correct TRansfer Mask */
+#define USB_CNTR_PMAOVR ((uint16_t)0x4000U) /*!< DMA OVeR/underrun Mask */
+#define USB_CNTR_ERRM ((uint16_t)0x2000U) /*!< ERRor Mask */
+#define USB_CNTR_WKUPM ((uint16_t)0x1000U) /*!< WaKe UP Mask */
+#define USB_CNTR_SUSPM ((uint16_t)0x0800U) /*!< SUSPend Mask */
+#define USB_CNTR_RESETM ((uint16_t)0x0400U) /*!< RESET Mask */
+#define USB_CNTR_SOFM ((uint16_t)0x0200U) /*!< Start Of Frame Mask */
+#define USB_CNTR_ESOFM ((uint16_t)0x0100U) /*!< Expected Start Of Frame Mask */
+#define USB_CNTR_RESUME ((uint16_t)0x0010U) /*!< RESUME request */
+#define USB_CNTR_FSUSP ((uint16_t)0x0008U) /*!< Force SUSPend */
+#define USB_CNTR_LPMODE ((uint16_t)0x0004U) /*!< Low-power MODE */
+#define USB_CNTR_PDWN ((uint16_t)0x0002U) /*!< Power DoWN */
+#define USB_CNTR_FRES ((uint16_t)0x0001U) /*!< Force USB RESet */
+
+/* Legacy defines */
+#define USB_CNTR_PMAOVRM USB_CNTR_PMAOVR
+#define USB_CNTR_LP_MODE USB_CNTR_LPMODE
+
+/******************** FNR Frame Number Register bit definitions ************/
+#define USB_FNR_RXDP ((uint16_t)0x8000U) /*!< status of D+ data line */
+#define USB_FNR_RXDM ((uint16_t)0x4000U) /*!< status of D- data line */
+#define USB_FNR_LCK ((uint16_t)0x2000U) /*!< LoCKed */
+#define USB_FNR_LSOF ((uint16_t)0x1800U) /*!< Lost SOF */
+#define USB_FNR_FN ((uint16_t)0x07FFU) /*!< Frame Number */
+
+/******************** DADDR Device ADDRess bit definitions ****************/
+#define USB_DADDR_EF ((uint8_t)0x80U) /*!< USB device address Enable Function */
+#define USB_DADDR_ADD ((uint8_t)0x7FU) /*!< USB device address */
+
+/****************************** Endpoint register *************************/
+#define USB_EP0R USB_BASE /*!< endpoint 0 register address */
+#define USB_EP1R (USB_BASE + 0x04U) /*!< endpoint 1 register address */
+#define USB_EP2R (USB_BASE + 0x08U) /*!< endpoint 2 register address */
+#define USB_EP3R (USB_BASE + 0x0CU) /*!< endpoint 3 register address */
+#define USB_EP4R (USB_BASE + 0x10U) /*!< endpoint 4 register address */
+#define USB_EP5R (USB_BASE + 0x14U) /*!< endpoint 5 register address */
+#define USB_EP6R (USB_BASE + 0x18U) /*!< endpoint 6 register address */
+#define USB_EP7R (USB_BASE + 0x1CU) /*!< endpoint 7 register address */
+/* bit positions */
+#define USB_EP_CTR_RX ((uint16_t)0x8000U) /*!< EndPoint Correct TRansfer RX */
+#define USB_EP_DTOG_RX ((uint16_t)0x4000U) /*!< EndPoint Data TOGGLE RX */
+#define USB_EPRX_STAT ((uint16_t)0x3000U) /*!< EndPoint RX STATus bit field */
+#define USB_EP_SETUP ((uint16_t)0x0800U) /*!< EndPoint SETUP */
+#define USB_EP_T_FIELD ((uint16_t)0x0600U) /*!< EndPoint TYPE */
+#define USB_EP_KIND ((uint16_t)0x0100U) /*!< EndPoint KIND */
+#define USB_EP_CTR_TX ((uint16_t)0x0080U) /*!< EndPoint Correct TRansfer TX */
+#define USB_EP_DTOG_TX ((uint16_t)0x0040U) /*!< EndPoint Data TOGGLE TX */
+#define USB_EPTX_STAT ((uint16_t)0x0030U) /*!< EndPoint TX STATus bit field */
+#define USB_EPADDR_FIELD ((uint16_t)0x000FU) /*!< EndPoint ADDRess FIELD */
+
+/* EndPoint REGister MASK (no toggle fields) */
+#define USB_EPREG_MASK (USB_EP_CTR_RX|USB_EP_SETUP|USB_EP_T_FIELD|USB_EP_KIND|USB_EP_CTR_TX|USB_EPADDR_FIELD)
+ /*!< EP_TYPE[1:0] EndPoint TYPE */
+#define USB_EP_TYPE_MASK ((uint16_t)0x0600U) /*!< EndPoint TYPE Mask */
+#define USB_EP_BULK ((uint16_t)0x0000U) /*!< EndPoint BULK */
+#define USB_EP_CONTROL ((uint16_t)0x0200U) /*!< EndPoint CONTROL */
+#define USB_EP_ISOCHRONOUS ((uint16_t)0x0400U) /*!< EndPoint ISOCHRONOUS */
+#define USB_EP_INTERRUPT ((uint16_t)0x0600U) /*!< EndPoint INTERRUPT */
+#define USB_EP_T_MASK ((uint16_t) ~USB_EP_T_FIELD & USB_EPREG_MASK)
+
+#define USB_EPKIND_MASK ((uint16_t) ~USB_EP_KIND & USB_EPREG_MASK) /*!< EP_KIND EndPoint KIND */
+ /*!< STAT_TX[1:0] STATus for TX transfer */
+#define USB_EP_TX_DIS ((uint16_t)0x0000U) /*!< EndPoint TX DISabled */
+#define USB_EP_TX_STALL ((uint16_t)0x0010U) /*!< EndPoint TX STALLed */
+#define USB_EP_TX_NAK ((uint16_t)0x0020U) /*!< EndPoint TX NAKed */
+#define USB_EP_TX_VALID ((uint16_t)0x0030U) /*!< EndPoint TX VALID */
+#define USB_EPTX_DTOG1 ((uint16_t)0x0010U) /*!< EndPoint TX Data TOGgle bit1 */
+#define USB_EPTX_DTOG2 ((uint16_t)0x0020U) /*!< EndPoint TX Data TOGgle bit2 */
+#define USB_EPTX_DTOGMASK (USB_EPTX_STAT|USB_EPREG_MASK)
+ /*!< STAT_RX[1:0] STATus for RX transfer */
+#define USB_EP_RX_DIS ((uint16_t)0x0000U) /*!< EndPoint RX DISabled */
+#define USB_EP_RX_STALL ((uint16_t)0x1000U) /*!< EndPoint RX STALLed */
+#define USB_EP_RX_NAK ((uint16_t)0x2000U) /*!< EndPoint RX NAKed */
+#define USB_EP_RX_VALID ((uint16_t)0x3000U) /*!< EndPoint RX VALID */
+#define USB_EPRX_DTOG1 ((uint16_t)0x1000U) /*!< EndPoint RX Data TOGgle bit1 */
+#define USB_EPRX_DTOG2 ((uint16_t)0x2000U) /*!< EndPoint RX Data TOGgle bit1 */
+#define USB_EPRX_DTOGMASK (USB_EPRX_STAT|USB_EPREG_MASK)
+
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+#if CFG_TUSB_MCU == OPT_MCU_CH32V20X
+static const IRQn_Type fsdev_irq[] = {
+ USB_HP_CAN1_TX_IRQn,
+ USB_LP_CAN1_RX0_IRQn,
+ USBWakeUp_IRQn
+};
+enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) };
+#else
+ #error "Unsupported MCU"
+#endif
+
+void dcd_int_enable(uint8_t rhport) {
+ (void)rhport;
+ for(uint8_t i=0; i < FSDEV_IRQ_NUM; i++) {
+ NVIC_EnableIRQ(fsdev_irq[i]);
+ }
+}
+
+void dcd_int_disable(uint8_t rhport) {
+ (void)rhport;
+ for(uint8_t i=0; i < FSDEV_IRQ_NUM; i++) {
+ NVIC_DisableIRQ(fsdev_irq[i]);
+ }
+}
+
+void dcd_disconnect(uint8_t rhport) {
+ (void) rhport;
+ EXTEN->EXTEN_CTR &= ~EXTEN_USBD_PU_EN;
+}
+
+void dcd_connect(uint8_t rhport) {
+ (void) rhport;
+ EXTEN->EXTEN_CTR |= EXTEN_USBD_PU_EN;
+}
+
+#endif
diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h
new file mode 100644
index 000000000..03ea4c67e
--- /dev/null
+++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h
@@ -0,0 +1,356 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright(c) N Conrad
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef TUSB_FSDEV_STM32_H
+#define TUSB_FSDEV_STM32_H
+
+#if CFG_TUSB_MCU == OPT_MCU_STM32F0
+ #include "stm32f0xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_REG_BASE USB_BASE
+ // F0x2 models are crystal-less
+ // All have internal D+ pull-up
+ // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support
+ // PMA dedicated to USB (no sharing with CAN)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
+ #include "stm32f1xx.h"
+ #define FSDEV_PMA_SIZE (512u)
+ // NO internal Pull-ups
+ // *B, and *C: 2 x 16 bits/word
+
+ // F1 names this differently from the rest
+ #define USB_CNTR_LPMODE USB_CNTR_LP_MODE
+
+#elif defined(STM32F302xB) || defined(STM32F302xC) || \
+ defined(STM32F303xB) || defined(STM32F303xC) || \
+ defined(STM32F373xC)
+ #include "stm32f3xx.h"
+ #define FSDEV_PMA_SIZE (512u)
+ // NO internal Pull-ups
+ // *B, and *C: 1 x 16 bits/word
+ // PMA dedicated to USB (no sharing with CAN)
+
+#elif defined(STM32F302x6) || defined(STM32F302x8) || \
+ defined(STM32F302xD) || defined(STM32F302xE) || \
+ defined(STM32F303xD) || defined(STM32F303xE)
+ #include "stm32f3xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+ // NO internal Pull-ups
+ // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support
+ // When CAN clock is enabled, USB can use first 768 bytes ONLY.
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L0
+ #include "stm32l0xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
+ #include "stm32l1xx.h"
+ #define FSDEV_PMA_SIZE (512u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
+ #include "stm32g4xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
+ #include "stm32g0xx.h"
+ #define FSDEV_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
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
+ #include "stm32h5xx.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
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ #include "stm32wbxx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+ /* ST provided header has incorrect value of USB_PMAADDR */
+ #define FSDEV_PMA_BASE USB1_PMAADDR
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
+ #include "stm32l4xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
+ #include "stm32l5xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+
+ #ifndef USB_PMAADDR
+ #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
+ #endif
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
+ #include "stm32u5xx.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
+
+#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
+#endif
+
+//--------------------------------------------------------------------+
+// Register and PMA Base Address
+//--------------------------------------------------------------------+
+#ifndef FSDEV_REG_BASE
+#if defined(USB_BASE)
+ #define FSDEV_REG_BASE USB_BASE
+#elif defined(USB_DRD_BASE)
+ #define FSDEV_REG_BASE USB_DRD_BASE
+#elif defined(USB_DRD_FS_BASE)
+ #define FSDEV_REG_BASE USB_DRD_FS_BASE
+#else
+ #error "FSDEV_REG_BASE not defined"
+#endif
+#endif
+
+#ifndef FSDEV_PMA_BASE
+#if defined(USB_PMAADDR)
+ #define FSDEV_PMA_BASE USB_PMAADDR
+#elif defined(USB_DRD_PMAADDR)
+ #define FSDEV_PMA_BASE USB_DRD_PMAADDR
+#else
+ #error "FSDEV_PMA_BASE not defined"
+#endif
+#endif
+
+// This checks if the device has "LPM"
+#if defined(USB_ISTR_L1REQ)
+#define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ)
+#else
+#define USB_ISTR_L1REQ_FORCED ((uint16_t)0x0000U)
+#endif
+
+#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \
+ USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED )
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+#if TU_CHECK_MCU(OPT_MCU_STM32L1) && !defined(USBWakeUp_IRQn)
+ #define USBWakeUp_IRQn USB_FS_WKUP_IRQn
+#endif
+
+static const IRQn_Type fsdev_irq[] = {
+ #if TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32L0, OPT_MCU_STM32L4)
+ USB_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32F1
+ USB_HP_CAN1_TX_IRQn,
+ USB_LP_CAN1_RX0_IRQn,
+ USBWakeUp_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32F3
+ // USB remap handles dcd functions
+ USB_HP_CAN_TX_IRQn,
+ USB_LP_CAN_RX0_IRQn,
+ USBWakeUp_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32G0
+ #ifdef STM32G0B0xx
+ USB_IRQn,
+ #else
+ USB_UCPD1_2_IRQn,
+ #endif
+ #elif TU_CHECK_MCU(OPT_MCU_STM32G4, OPT_MCU_STM32L1)
+ USB_HP_IRQn,
+ USB_LP_IRQn,
+ USBWakeUp_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32H5
+ USB_DRD_FS_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32L5
+ USB_FS_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ USB_HP_IRQn,
+ 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
+};
+enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) };
+
+void dcd_int_enable(uint8_t rhport) {
+ (void)rhport;
+
+ // forces write to RAM before allowing ISR to execute
+ __DSB(); __ISB();
+
+ #if CFG_TUSB_MCU == OPT_MCU_STM32F3 && defined(SYSCFG_CFGR1_USB_IT_RMP)
+ // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
+ // shared USB/CAN IRQs to separate CAN and USB IRQs.
+ // This dynamically checks if this remap is active to enable the right IRQs.
+ if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) {
+ NVIC_EnableIRQ(USB_HP_IRQn);
+ NVIC_EnableIRQ(USB_LP_IRQn);
+ NVIC_EnableIRQ(USBWakeUp_RMP_IRQn);
+ } else
+ #endif
+ {
+ for (uint8_t i = 0; i < FSDEV_IRQ_NUM; i++) {
+ NVIC_EnableIRQ(fsdev_irq[i]);
+ }
+ }
+}
+
+void dcd_int_disable(uint8_t rhport) {
+ (void)rhport;
+
+ #if CFG_TUSB_MCU == OPT_MCU_STM32F3 && defined(SYSCFG_CFGR1_USB_IT_RMP)
+ // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
+ // shared USB/CAN IRQs to separate CAN and USB IRQs.
+ // This dynamically checks if this remap is active to enable the right IRQs.
+ if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) {
+ NVIC_DisableIRQ(USB_HP_IRQn);
+ NVIC_DisableIRQ(USB_LP_IRQn);
+ NVIC_DisableIRQ(USBWakeUp_RMP_IRQn);
+ } else
+ #endif
+ {
+ for (uint8_t i = 0; i < FSDEV_IRQ_NUM; i++) {
+ NVIC_DisableIRQ(fsdev_irq[i]);
+ }
+ }
+
+ // CMSIS has a membar after disabling interrupts
+}
+
+// Define only on MCU with internal pull-up. BSP can define on MCU without internal PU.
+#if defined(USB_BCDR_DPPU)
+
+void dcd_disconnect(uint8_t rhport) {
+ (void)rhport;
+ USB->BCDR &= ~(USB_BCDR_DPPU);
+}
+
+void dcd_connect(uint8_t rhport) {
+ (void)rhport;
+ USB->BCDR |= USB_BCDR_DPPU;
+}
+
+#elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151
+
+void dcd_disconnect(uint8_t rhport) {
+ (void)rhport;
+ SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU);
+}
+
+void dcd_connect(uint8_t rhport) {
+ (void)rhport;
+ SYSCFG->PMC |= SYSCFG_PMC_USB_PU;
+}
+#endif
+
+
+#endif /* TUSB_FSDEV_STM32_H */
diff --git a/src/portable/st/stm32_fsdev/fsdev_type.h b/src/portable/st/stm32_fsdev/fsdev_type.h
new file mode 100644
index 000000000..cf36576bb
--- /dev/null
+++ b/src/portable/st/stm32_fsdev/fsdev_type.h
@@ -0,0 +1,307 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright(c) N Conrad
+ * Copyright(c) 2024, hathach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef TUSB_FSDEV_TYPE_H
+#define TUSB_FSDEV_TYPE_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "stdint.h"
+
+// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it
+// Both of these MUST be a multiple of 2, and are in byte units.
+#ifndef FSDEV_BTABLE_BASE
+#define FSDEV_BTABLE_BASE 0U
+#endif
+
+TU_VERIFY_STATIC(FSDEV_BTABLE_BASE % 8 == 0, "BTABLE base must be aligned to 8 bytes");
+
+// FSDEV_PMA_SIZE is PMA buffer size in bytes.
+// - 512-byte devices, access with a stride of two words (use every other 16-bit address)
+// - 1024-byte devices, access with a stride of one word (use every 16-bit address)
+// - 2048-byte devices, access with 32-bit address
+
+// For purposes of accessing the packet
+#if FSDEV_PMA_SIZE == 512
+ // 1x16 bit / word access scheme
+ #define FSDEV_PMA_STRIDE 2
+ #define pma_access_scheme TU_ATTR_ALIGNED(4)
+#elif FSDEV_PMA_SIZE == 1024
+ // 2x16 bit / word access scheme
+ #define FSDEV_PMA_STRIDE 1
+ #define pma_access_scheme
+#elif FSDEV_PMA_SIZE == 2048
+ // 32 bit access scheme
+ #define FSDEV_BUS_32BIT
+ #define FSDEV_PMA_STRIDE 1
+ #define pma_access_scheme
+#endif
+
+// The fsdev_bus_t type can be used for both register and PMA access necessities
+#ifdef FSDEV_BUS_32BIT
+ typedef uint32_t fsdev_bus_t;
+ #define fsdevbus_unaligned_read(_addr) tu_unaligned_read32(_addr)
+ #define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write32(_addr, _value)
+#else
+ typedef uint16_t fsdev_bus_t;
+ #define fsdevbus_unaligned_read(_addr) tu_unaligned_read16(_addr)
+ #define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write16(_addr, _value)
+#endif
+
+enum {
+ FSDEV_BUS_SIZE = sizeof(fsdev_bus_t),
+};
+
+//--------------------------------------------------------------------+
+// BTable Typedef
+//--------------------------------------------------------------------+
+enum {
+ BTABLE_BUF_TX = 0,
+ BTABLE_BUF_RX = 1
+};
+
+// hardware limit endpoint
+#define FSDEV_EP_COUNT 8
+
+// Buffer Table is located in Packet Memory Area (PMA) and therefore its address access is forced to either
+// 16-bit or 32-bit depending on FSDEV_BUS_32BIT.
+// 0: TX (IN), 1: RX (OUT)
+typedef union {
+ // data is strictly 16-bit access (address could be 32-bit aligned)
+ struct {
+ volatile pma_access_scheme uint16_t addr;
+ volatile pma_access_scheme uint16_t count;
+ } ep16[FSDEV_EP_COUNT][2];
+
+ // strictly 32-bit access
+ struct {
+ volatile uint32_t count_addr;
+ } ep32[FSDEV_EP_COUNT][2];
+} fsdev_btable_t;
+
+TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT*8*FSDEV_PMA_STRIDE, "size is not correct");
+TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT*8 <= FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM");
+
+#define FSDEV_BTABLE ((volatile fsdev_btable_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(FSDEV_BTABLE_BASE)))
+
+typedef struct {
+ volatile pma_access_scheme fsdev_bus_t value;
+} fsdev_pma_buf_t;
+
+#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(_addr)))
+
+//--------------------------------------------------------------------+
+// Registers Typedef
+//--------------------------------------------------------------------+
+
+// volatile 32-bit aligned
+#define _va32 volatile TU_ATTR_ALIGNED(4)
+
+typedef struct {
+ struct {
+ _va32 fsdev_bus_t reg;
+ }ep[FSDEV_EP_COUNT];
+
+ _va32 uint32_t RESERVED7[8]; // Reserved
+ _va32 fsdev_bus_t CNTR; // 40: Control register
+ _va32 fsdev_bus_t ISTR; // 44: Interrupt status register
+ _va32 fsdev_bus_t FNR; // 48: Frame number register
+ _va32 fsdev_bus_t DADDR; // 4C: Device address register
+ _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only)
+ _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only)
+ _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only)
+} fsdev_regs_t;
+
+TU_VERIFY_STATIC(offsetof(fsdev_regs_t, CNTR) == 0x40, "Wrong offset");
+TU_VERIFY_STATIC(sizeof(fsdev_regs_t) == 0x5C, "Size is not correct");
+
+#define FSDEV_REG ((fsdev_regs_t*) FSDEV_REG_BASE)
+
+
+#ifndef USB_EPTX_STAT
+#define USB_EPTX_STAT 0x0030U
+#endif
+
+#ifndef USB_EPRX_STAT
+#define USB_EPRX_STAT 0x3000U
+#endif
+
+#ifndef USB_EPTX_STAT_Pos
+#define USB_EPTX_STAT_Pos 4u
+#endif
+
+#ifndef USB_EP_DTOG_TX_Pos
+#define USB_EP_DTOG_TX_Pos 6u
+#endif
+
+#ifndef USB_EP_CTR_TX_Pos
+#define USB_EP_CTR_TX_Pos 7u
+#endif
+
+typedef enum {
+ EP_STAT_DISABLED = 0,
+ EP_STAT_STALL = 1,
+ EP_STAT_NAK = 2,
+ EP_STAT_VALID = 3
+}ep_stat_t;
+
+#define EP_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8)))
+#define EP_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8)))
+
+//--------------------------------------------------------------------+
+// Endpoint Helper
+// - CTR is write 0 to clear
+// - DTOG and STAT are write 1 to toggle
+//--------------------------------------------------------------------+
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_read(uint32_t ep_id) {
+ return FSDEV_REG->ep[ep_id].reg;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void ep_write(uint32_t ep_id, uint32_t value, bool need_exclusive) {
+ if (need_exclusive) {
+ dcd_int_disable(0);
+ }
+
+ FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t) value;
+
+ if (need_exclusive) {
+ dcd_int_enable(0);
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void ep_write_clear_ctr(uint32_t ep_id, tusb_dir_t dir) {
+ uint32_t reg = FSDEV_REG->ep[ep_id].reg;
+ reg |= USB_EP_CTR_TX | USB_EP_CTR_RX;
+ reg &= USB_EPREG_MASK;
+ reg &= ~(1 << (USB_EP_CTR_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8)));
+ ep_write(ep_id, reg, false);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void ep_change_status(uint32_t* reg, tusb_dir_t dir, ep_stat_t state) {
+ *reg ^= (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 0 : 8)));
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void ep_change_dtog(uint32_t* reg, tusb_dir_t dir, uint8_t state) {
+ *reg ^= (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8)));
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool ep_is_iso(uint32_t reg) {
+ return (reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS;
+}
+
+//--------------------------------------------------------------------+
+// BTable Helper
+//--------------------------------------------------------------------+
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_addr(uint32_t ep_id, uint8_t buf_id) {
+#ifdef FSDEV_BUS_32BIT
+ return FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr & 0x0000FFFFu;
+#else
+ return FSDEV_BTABLE->ep16[ep_id][buf_id].addr;
+#endif
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void btable_set_addr(uint32_t ep_id, uint8_t buf_id, uint16_t addr) {
+#ifdef FSDEV_BUS_32BIT
+ uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
+ count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu);
+ FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
+#else
+ FSDEV_BTABLE->ep16[ep_id][buf_id].addr = addr;
+#endif
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t btable_get_count(uint32_t ep_id, uint8_t buf_id) {
+ uint16_t count;
+#ifdef FSDEV_BUS_32BIT
+ count = (FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr >> 16);
+#else
+ count = FSDEV_BTABLE->ep16[ep_id][buf_id].count;
+#endif
+ return count & 0x3FFU;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_t buf_id, uint16_t byte_count) {
+#ifdef FSDEV_BUS_32BIT
+ uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
+ count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16);
+ FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
+#else
+ uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count;
+ cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU);
+ FSDEV_BTABLE->ep16[ep_id][buf_id].count = cnt;
+#endif
+}
+
+/* Aligned buffer size according to hardware */
+TU_ATTR_ALWAYS_INLINE static inline uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block) {
+ /* The STM32 full speed USB peripheral supports only a limited set of
+ * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */
+ uint16_t block_in_bytes;
+ if (size > 62) {
+ block_in_bytes = 32;
+ *blsize = 1;
+ *num_block = tu_div_ceil(size, 32);
+ } else {
+ block_in_bytes = 2;
+ *blsize = 0;
+ *num_block = tu_div_ceil(size, 2);
+ }
+
+ return (*num_block) * block_in_bytes;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount) {
+ uint8_t blsize, num_block;
+ (void) pma_align_buffer_size(wCount, &blsize, &num_block);
+
+ /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */
+ uint16_t bl_nb = (blsize << 15) | ((num_block - blsize) << 10);
+ if (bl_nb == 0) {
+ // zlp but 0 is invalid value, set blsize to 1 (32 bytes)
+ // Note: lower value can cause PMAOVR on setup with ch32v203
+ bl_nb = 1 << 15;
+ }
+
+#ifdef FSDEV_BUS_32BIT
+ uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
+ count_addr = (bl_nb << 16) | (count_addr & 0x0000FFFFu);
+ FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
+#else
+ FSDEV_BTABLE->ep16[ep_id][buf_id].count = bl_nb;
+#endif
+
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c
index 6cc1975a8..21f13b279 100644
--- a/src/portable/sunxi/dcd_sunxi_musb.c
+++ b/src/portable/sunxi/dcd_sunxi_musb.c
@@ -35,7 +35,9 @@
#include <f1c100s-irq.h>
#include <device/dcd.h>
#include "musb_def.h"
-#include "bsp/board.h"
+
+//#include "bsp/board_api.h"
+extern uint32_t board_millis(void); // TODO remove
typedef uint32_t u32;
typedef uint16_t u16;
@@ -58,7 +60,7 @@ typedef struct TU_ATTR_PACKED
typedef struct
{
- tusb_control_request_t setup_packet;
+ CFG_TUD_MEM_ALIGN tusb_control_request_t setup_packet;
uint16_t remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */
int8_t status_out;
pipe_state_t pipe0;
@@ -350,7 +352,7 @@ static void USBC_INT_DisableRxEp(u8 ep_index)
* INTERNAL FUNCTION DECLARATION
*------------------------------------------------------------------*/
-static dcd_data_t _dcd;
+CFG_TUD_MEM_ALIGN static dcd_data_t _dcd;
static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
{
@@ -560,7 +562,7 @@ static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigne
static void process_setup_packet(uint8_t rhport)
{
- uint32_t *p = (uint32_t*)&_dcd.setup_packet;
+ uint32_t *p = (uint32_t*)(uintptr_t) &_dcd.setup_packet;
p[0] = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
p[1] = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
@@ -594,7 +596,7 @@ static bool handle_xfer_in(uint_fast8_t ep_addr)
if (len) {
volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff((tu_fifo_t *)buf, addr, len, TUSB_DIR_IN);
+ pipe_read_write_packet_ff((tu_fifo_t *)(uintptr_t) buf, addr, len, TUSB_DIR_IN);
} else {
pipe_write_packet(buf, addr, len);
pipe->buf = buf + len;
@@ -622,7 +624,7 @@ static bool handle_xfer_out(uint_fast8_t ep_addr)
if (len) {
volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff((tu_fifo_t *)buf, addr, len, TUSB_DIR_OUT);
+ pipe_read_write_packet_ff((tu_fifo_t *)(uintptr_t )buf, addr, len, TUSB_DIR_OUT);
} else {
pipe_read_packet(buf, addr, len);
pipe->buf = buf + len;
@@ -865,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();
@@ -893,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 692096fc8..f30ec5ee3 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -31,6 +31,9 @@
#if CFG_TUD_ENABLED && defined(TUP_USBIP_DWC2)
+// Debug level for DWC2
+#define DWC2_DEBUG 2
+
#include "device/dcd.h"
#include "dwc2_type.h"
@@ -43,7 +46,7 @@
#if defined(TUP_USBIP_DWC2_STM32)
#include "dwc2_stm32.h"
-#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+#elif defined(TUP_USBIP_DWC2_ESP32)
#include "dwc2_esp32.h"
#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
#include "dwc2_gd32.h"
@@ -57,29 +60,26 @@
#error "Unsupported MCUs"
#endif
-//--------------------------------------------------------------------+
-// MACRO TYPEDEF CONSTANT ENUM
-//--------------------------------------------------------------------+
+enum {
+ DWC2_CONTROLLER_COUNT = TU_ARRAY_SIZE(_dwc2_controller)
+};
// DWC2 registers
-#define DWC2_REG(_port) ((dwc2_regs_t*) _dwc2_controller[_port].reg_base)
-
-// Debug level for DWC2
-#define DWC2_DEBUG 2
+//#define DWC2_REG(_port) ((dwc2_regs_t*) _dwc2_controller[_port].reg_base)
-#ifndef dcache_clean
-#define dcache_clean(_addr, _size)
-#endif
-
-#ifndef dcache_invalidate
-#define dcache_invalidate(_addr, _size)
-#endif
+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;
+}
-#ifndef dcache_clean_invalidate
-#define dcache_clean_invalidate(_addr, _size)
-#endif
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
-static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2];
+static CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2];
typedef struct {
uint8_t* buffer;
@@ -93,99 +93,230 @@ 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
+static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type
+static uint16_t _dfifo_top; // top free location in FIFO RAM
-// 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)
+// Number of IN endpoints active
+static uint8_t _allocated_ep_in_count;
// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by
static bool _sof_en;
-// Calculate the RX FIFO size according to minimum recommendations from reference manual
-// RxFIFO = (5 * number of control endpoints + 8) +
-// ((largest USB packet used / 4) + 1 for status information) +
-// (2 * number of OUT endpoints) + 1 for Global NAK
-// with number of control endpoints = 1 we have
-// RxFIFO = 15 + (largest USB packet used / 4) + 2 * number of OUT endpoints
-// we double the largest USB packet size to be able to hold up to 2 packets
-static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) {
- return 15 + 2 * (max_ep_size / 4) + 2 * ep_count;
+//--------------------------------------------------------------------
+// DMA
+//--------------------------------------------------------------------
+
+TU_ATTR_ALWAYS_INLINE static inline bool dma_enabled(const dwc2_regs_t* dwc2) {
+ #if !CFG_TUD_DWC2_DMA
+ (void) dwc2;
+ return false;
+ #else
+ // Internal DMA only
+ return (dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA);
+ #endif
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t dma_cal_epfifo_base(uint8_t rhport) {
+ // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per endpoint direction
+ const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
+ return dwc2_controller->ep_fifo_size/4 - 2*dwc2_controller->ep_count;
+}
+
+static void dma_setup_prepare(uint8_t rhport) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ 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)_setup_packet;
+ dwc2->epout[0].doepctl |= DOEPCTL_EPENA | DOEPCTL_USBAEP;
}
-TU_ATTR_ALWAYS_INLINE static inline void fifo_flush_tx(dwc2_regs_t* dwc2, uint8_t epnum) {
+//--------------------------------------------------------------------+
+// Data FIFO
+//--------------------------------------------------------------------+
+
+TU_ATTR_ALWAYS_INLINE static inline void dfifo_flush_tx(dwc2_regs_t* dwc2, uint8_t epnum) {
// flush TX fifo and wait for it cleared
dwc2->grstctl = GRSTCTL_TXFFLSH | (epnum << GRSTCTL_TXFNUM_Pos);
while (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) {}
}
-TU_ATTR_ALWAYS_INLINE static inline void fifo_flush_rx(dwc2_regs_t* dwc2) {
+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) {}
}
-static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) {
+/* USB Data FIFO Layout
+
+ 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
+ | EPInfo |
+ | for DMA |
+ |-------------|-- gdfifocfg.EPINFOBASE (max is ghwcfg3.dfifo_depth)
+ | IN FIFO 0 |
+ | control |
+ |-------------|
+ | 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_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);
- uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
+ const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
+ uint8_t const ep_count = dwc2_controller->ep_count;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
TU_ASSERT(epnum < ep_count);
uint16_t fifo_size = tu_div_ceil(packet_size, 4);
-
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO 0 |
- // --------------- (320 or 1024) - 16
- // | IN FIFO 1 |
- // --------------- (320 or 1024) - 16 - x
- // | . . . . |
- // --------------- (320 or 1024) - 16 - x - y - ... - z
- // | IN FIFO MAX |
- // ---------------
- // | FREE |
- // --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
- // --------------- 0
- //
- // In FIFO is allocated by following rules:
- // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
if (dir == TUSB_DIR_OUT) {
// Calculate required size of RX FIFO
- uint16_t const sz = calc_grxfsiz(4 * fifo_size, ep_count);
+ uint16_t const new_sz = calc_grxfsiz(4 * fifo_size, ep_count);
- // If size_rx needs to be extended check if possible and if so enlarge it
- if (dwc2->grxfsiz < sz) {
- TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size / 4);
-
- // Enlarge RX FIFO
- dwc2->grxfsiz = sz;
+ // If size_rx needs to be extended check if there is enough free space
+ if (dwc2->grxfsiz < new_sz) {
+ TU_ASSERT(new_sz <= _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.
+ // Check IN endpoints concurrently active limit
+ if(_dwc2_controller->ep_in_count) {
+ TU_ASSERT(_allocated_ep_in_count < _dwc2_controller->ep_in_count);
+ _allocated_ep_in_count++;
+ }
+
+ // If The TXFELVL is configured as half empty, the fifo must be twice the max_size.
if ((dwc2->gahbcfg & GAHBCFG_TXFELVL) == 0) {
fifo_size *= 2;
}
// Check if free space is available
- TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size / 4);
- _allocated_fifo_words_tx += fifo_size;
- TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %" PRIu32, fifo_size * 4,
- _dwc2_controller[rhport].ep_fifo_size - _allocated_fifo_words_tx * 4);
+ TU_ASSERT(_dfifo_top >= fifo_size + dwc2->grxfsiz);
+ _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) | _dfifo_top;
+ } else {
+ // DIEPTXF starts at FIFO #1.
+ dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | _dfifo_top;
+ }
}
return true;
}
+static void dfifo_init(uint8_t rhport) {
+ const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ dwc2->grxfsiz = calc_grxfsiz(CFG_TUD_ENDPOINT0_SIZE, dwc2_controller->ep_count);
+
+ if(dma_enabled(dwc2)) {
+ // DMA use last DFIFO to store metadata
+ _dfifo_top = dma_cal_epfifo_base(rhport);
+ }else {
+ _dfifo_top = dwc2_controller->ep_fifo_size / 4;
+ }
+
+ // Allocate FIFO for EP0 IN
+ dfifo_alloc(rhport, 0x80, CFG_TUD_ENDPOINT0_SIZE);
+}
+
+// Read a single data packet from receive FIFO
+static void dfifo_read_packet(uint8_t rhport, uint8_t* dst, uint16_t len) {
+ (void) rhport;
+
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ volatile const uint32_t* rx_fifo = dwc2->fifo[0];
+
+ // Reading full available 32 bit words from fifo
+ uint16_t full_words = len >> 2;
+ while (full_words--) {
+ tu_unaligned_write32(dst, *rx_fifo);
+ dst += 4;
+ }
+
+ // Read the remaining 1-3 bytes from fifo
+ uint8_t const bytes_rem = len & 0x03;
+ if (bytes_rem != 0) {
+ uint32_t const tmp = *rx_fifo;
+ dst[0] = tu_u32_byte0(tmp);
+ if (bytes_rem > 1) dst[1] = tu_u32_byte1(tmp);
+ if (bytes_rem > 2) dst[2] = tu_u32_byte2(tmp);
+ }
+}
+
+// Write a single data packet to EPIN FIFO
+static void dfifo_write_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const* src, uint16_t len) {
+ (void) rhport;
+
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num];
+
+ // Pushing full available 32 bit words to fifo
+ uint16_t full_words = len >> 2;
+ while (full_words--) {
+ *tx_fifo = tu_unaligned_read32(src);
+ src += 4;
+ }
+
+ // Write the remaining 1-3 bytes into fifo
+ uint8_t const bytes_rem = len & 0x03;
+ if (bytes_rem) {
+ uint32_t tmp_word = src[0];
+ if (bytes_rem > 1) tmp_word |= (src[1] << 8);
+ if (bytes_rem > 2) tmp_word |= (src[2] << 16);
+
+ *tx_fifo = tmp_word;
+ }
+}
+
+//--------------------------------------------------------------------
+// Endpoint
+//--------------------------------------------------------------------
+
static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
@@ -196,53 +327,49 @@ static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoin
xfer->interval = p_endpoint_desc->bInterval;
// USBAEP, EPTYP, SD0PID_SEVNFRM, MPSIZ are the same for IN and OUT endpoints.
- uint32_t const dxepctl = (1 << DOEPCTL_USBAEP_Pos) |
- (p_endpoint_desc->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) |
- (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) |
- (xfer->max_size << DOEPCTL_MPSIZ_Pos);
-
- if (dir == TUSB_DIR_OUT) {
- dwc2->epout[epnum].doepctl = dxepctl;
- dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum);
- } else {
- dwc2->epin[epnum].diepctl = dxepctl | (epnum << DIEPCTL_TXFNUM_Pos);
- dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum));
+ uint32_t epctl = (1 << DOEPCTL_USBAEP_Pos) |
+ (p_endpoint_desc->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) |
+ (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) |
+ (xfer->max_size << DOEPCTL_MPSIZ_Pos);
+ if (dir == TUSB_DIR_IN) {
+ epctl |= (epnum << DIEPCTL_TXFNUM_Pos);
}
+
+ dwc2_dep_t* dep = &dwc2->ep[1 - dir][epnum];
+ dep->ctl = epctl;
+ 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[1 - dir][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 +378,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;
@@ -271,9 +398,7 @@ static void bus_reset(uint8_t rhport) {
tu_memclr(xfer_status, sizeof(xfer_status));
_sof_en = false;
-
- // clear device address
- dwc2->dcfg &= ~DCFG_DAD_Msk;
+ _allocated_ep_in_count = 1;
// 1. NAK for all OUT endpoints
for (uint8_t n = 0; n < ep_count; n++) {
@@ -287,79 +412,32 @@ static void bus_reset(uint8_t rhport) {
}
}
- fifo_flush_tx(dwc2, 0x10); // all tx fifo
- fifo_flush_rx(dwc2);
+ dfifo_flush_tx(dwc2, 0x10); // all tx fifo
+ dfifo_flush_rx(dwc2);
- // 3. Set up interrupt mask
+ // 3. 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;
- // "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);
+ // 4. Set up DFIFO
+ dfifo_init(rhport);
- // 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);
+ // 5. Reset device address
+ dwc2->dcfg &= ~DCFG_DAD_Msk;
- // Fixed control EP0 size to 64 bytes
+ // Fixed both control EP0 size to 64 bytes
dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos);
+ dwc2->epout[0].doepctl &= ~(0x03 << DOEPCTL_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);
+ if(dma_enabled(dwc2)) {
+ dma_setup_prepare(rhport);
+ } else {
+ dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
+ }
dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT;
}
@@ -369,68 +447,73 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c
(void) rhport;
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir);
// EP0 is limited to one packet each xfer
// We use multiple transaction of xfer->max_size length to get a whole transfer done
if (epnum == 0) {
- xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir);
total_bytes = tu_min16(ep0_pending[dir], xfer->max_size);
ep0_pending[dir] -= total_bytes;
}
// IN and OUT endpoint xfers are interrupt-driven, we just schedule them here.
- if (dir == TUSB_DIR_IN) {
- dwc2_epin_t* epin = dwc2->epin;
+ const uint8_t is_epout = 1 - dir;
+ dwc2_dep_t* dep = &dwc2->ep[is_epout][epnum];
+ if (dir == TUSB_DIR_IN) {
// A full IN transfer (multiple packets, possibly) triggers XFRC.
- epin[epnum].dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) |
+ dep->dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) |
((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk);
- epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK;
+ if(dma_enabled(dwc2)) {
+ dep->diepdma = (uintptr_t)xfer->buffer;
- // 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);
+ // For ISO endpoint set correct odd/even bit for next frame.
+ if ((dep->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));
+ dep->diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk);
+ }
+
+ dep->diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK;
+ } else {
+ dep->diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK;
+
+ // For ISO endpoint set correct odd/even bit for next frame.
+ if ((dep->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));
+ dep->diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk);
+ }
+ // Enable fifo empty interrupt only if there are something to put in the fifo.
+ if (total_bytes != 0) {
+ dwc2->diepempmsk |= (1 << epnum);
+ }
}
} else {
- dwc2_epout_t* epout = dwc2->epout;
-
// A full OUT transfer (multiple packets, possibly) triggers XFRC.
- epout[epnum].doeptsiz &= ~(DOEPTSIZ_PKTCNT_Msk | DOEPTSIZ_XFRSIZ);
- epout[epnum].doeptsiz |= (num_packets << DOEPTSIZ_PKTCNT_Pos) |
+ dep->doeptsiz &= ~(DOEPTSIZ_PKTCNT_Msk | DOEPTSIZ_XFRSIZ);
+ dep->doeptsiz |= (num_packets << DOEPTSIZ_PKTCNT_Pos) |
((total_bytes << DOEPTSIZ_XFRSIZ_Pos) & DOEPTSIZ_XFRSIZ_Msk);
- epout[epnum].doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK;
- if ((epout[epnum].doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 &&
+ if ((dep->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);
+ dep->doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk);
+ }
+
+ if(dma_enabled(dwc2)) {
+ dep->doepdma = (uintptr_t)xfer->buffer;
}
+
+ dep->doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK;
}
}
/*------------------------------------------------------------------*/
/* 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
@@ -449,13 +532,10 @@ static void reset_core(dwc2_regs_t* dwc2) {
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
+#if !TUD_OPT_HIGH_SPEED
return false;
#else
- return dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE;
+ return dwc2->ghwcfg2_bm.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED;
#endif
}
@@ -466,7 +546,7 @@ static void phy_fs_init(dwc2_regs_t* dwc2) {
dwc2->gusbcfg |= GUSBCFG_PHYSEL;
// MCU specific PHY init before reset
- dwc2_phy_init(dwc2, HS_PHY_TYPE_NONE);
+ dwc2_phy_init(dwc2, GHWCFG2_HSPHY_NOT_SUPPORTED);
// Reset core after selecting PHY
reset_core(dwc2);
@@ -477,7 +557,7 @@ static void phy_fs_init(dwc2_regs_t* dwc2) {
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);
+ dwc2_phy_update(dwc2, GHWCFG2_HSPHY_NOT_SUPPORTED);
// set max speed
dwc2->dcfg = (dwc2->dcfg & ~DCFG_DSPD_Msk) | (DCFG_DSPD_FS << DCFG_DSPD_Pos);
@@ -489,7 +569,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
// De-select FS PHY
gusbcfg &= ~GUSBCFG_PHYSEL;
- if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) {
+ if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) {
TU_LOG(DWC2_DEBUG, "Highspeed ULPI PHY init\r\n");
// Select ULPI
@@ -510,7 +590,9 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
gusbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
// Set 16-bit interface if supported
- if (dwc2->ghwcfg4_bm.utmi_phy_data_width) gusbcfg |= GUSBCFG_PHYIF16;
+ if (dwc2->ghwcfg4_bm.phy_data_width) {
+ gusbcfg |= GUSBCFG_PHYIF16;
+ }
}
// Apply config
@@ -526,7 +608,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
// - 9 if using 8-bit PHY interface
// - 5 if using 16-bit PHY interface
gusbcfg &= ~GUSBCFG_TRDT_Msk;
- gusbcfg |= (dwc2->ghwcfg4_bm.utmi_phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos;
+ gusbcfg |= (dwc2->ghwcfg4_bm.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos;
dwc2->gusbcfg = gusbcfg;
// MCU specific PHY update post reset
@@ -539,17 +621,26 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
// 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;
+ if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) {
+ dcfg |= DCFG_XCVRDLY;
+ }
dwc2->dcfg = dcfg;
}
static bool check_dwc2(dwc2_regs_t* dwc2) {
#if CFG_TUSB_DEBUG >= DWC2_DEBUG
- print_dwc2_info(dwc2);
+ // 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 reasons: GD32VF103 snpsid and all hwcfg register are always zero (skip it)
+ // For some reason: 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;
@@ -559,18 +650,17 @@ static bool check_dwc2(dwc2_regs_t* dwc2) {
return 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;
// 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;
+ TU_ASSERT(check_dwc2(dwc2));
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 {
@@ -600,8 +690,8 @@ void dcd_init(uint8_t rhport) {
// (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);
+ dfifo_flush_tx(dwc2, 0x10); // all tx fifo
+ dfifo_flush_rx(dwc2);
// Clear all interrupts
uint32_t int_mask = dwc2->gintsts;
@@ -610,12 +700,21 @@ void dcd_init(uint8_t rhport) {
dwc2->gotgint |= int_mask;
// Required as part of core initialization.
- dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_RXFLVLM |
- GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM;
+ dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM;
// Configure TX FIFO empty level for interrupt. Default is complete empty
dwc2->gahbcfg |= GAHBCFG_TXFELVL;
+ if (dma_enabled(dwc2)) {
+ const uint16_t epinfo_base = dma_cal_epfifo_base(rhport);
+ dwc2->gdfifocfg = (epinfo_base << GDFIFOCFG_EPINFOBASE_SHIFT) | epinfo_base;
+
+ // DMA seems to be only settable after a core reset
+ dwc2->gahbcfg |= GAHBCFG_DMAEN | GAHBCFG_HBSTLEN_2;
+ }else {
+ dwc2->gintmsk |= GINTMSK_RXFLVLM;
+ }
+
// Enable global interrupt
dwc2->gahbcfg |= GAHBCFG_GINT;
@@ -628,6 +727,8 @@ void dcd_init(uint8_t rhport) {
// TU_LOG_HEX(DWC2_DEBUG, dwc2->gahbcfg);
dcd_connect(rhport);
+
+ return true;
}
void dcd_int_enable(uint8_t rhport) {
@@ -667,12 +768,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;
}
@@ -696,7 +819,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 +829,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;
+ _allocated_ep_in_count = 1;
+
// 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_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;
}
@@ -795,7 +911,9 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t
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++;
+ 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);
@@ -809,100 +927,38 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
edpt_disable(rhport, ep_addr, true);
+ if((tu_edpt_number(ep_addr) == 0) && dma_enabled(DWC2_REG(rhport))) {
+ 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[1 - dir][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;
}
-/*------------------------------------------------------------------*/
-
-// Read a single data packet from receive FIFO
-static void read_fifo_packet(uint8_t rhport, uint8_t* dst, uint16_t len) {
- (void) rhport;
-
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
- volatile const uint32_t* rx_fifo = dwc2->fifo[0];
-
- // Reading full available 32 bit words from fifo
- uint16_t full_words = len >> 2;
- while (full_words--) {
- tu_unaligned_write32(dst, *rx_fifo);
- dst += 4;
- }
-
- // Read the remaining 1-3 bytes from fifo
- uint8_t const bytes_rem = len & 0x03;
- if (bytes_rem != 0) {
- uint32_t const tmp = *rx_fifo;
- dst[0] = tu_u32_byte0(tmp);
- if (bytes_rem > 1) dst[1] = tu_u32_byte1(tmp);
- if (bytes_rem > 2) dst[2] = tu_u32_byte2(tmp);
- }
-}
-
-// Write a single data packet to EPIN FIFO
-static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const* src, uint16_t len) {
- (void) rhport;
-
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
- volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num];
-
- // Pushing full available 32 bit words to fifo
- uint16_t full_words = len >> 2;
- while (full_words--) {
- *tx_fifo = tu_unaligned_read32(src);
- src += 4;
- }
-
- // Write the remaining 1-3 bytes into fifo
- uint8_t const bytes_rem = len & 0x03;
- if (bytes_rem) {
- uint32_t tmp_word = src[0];
- if (bytes_rem > 1) tmp_word |= (src[1] << 8);
- if (bytes_rem > 2) tmp_word |= (src[2] << 16);
-
- *tx_fifo = tmp_word;
- }
-}
+//--------------------------------------------------------------------
+// Interrupt Handler
+//--------------------------------------------------------------------
+// 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];
// 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;
-
+ uint32_t const grxstsp = dwc2->grxstsp;
+ uint8_t const pktsts = (grxstsp & GRXSTSP_PKTSTS_Msk) >> GRXSTSP_PKTSTS_Pos;
+ uint8_t const epnum = (grxstsp & GRXSTSP_EPNUM_Msk) >> GRXSTSP_EPNUM_Pos;
+ uint16_t const bcnt = (grxstsp & GRXSTSP_BCNT_Msk) >> GRXSTSP_BCNT_Pos;
dwc2_epout_t* epout = &dwc2->epout[epnum];
-//#if CFG_TUSB_DEBUG >= DWC2_DEBUG
-// const char * pktsts_str[] =
-// {
-// "ASSERT", "Global NAK (ISR)", "Out Data Received", "Out Transfer Complete (ISR)",
-// "Setup Complete (ISR)", "ASSERT", "Setup Data Received"
-// };
-// TU_LOG_LOCATION();
-// TU_LOG(DWC2_DEBUG, " EP %02X, Byte Count %u, %s\r\n", epnum, bcnt, pktsts_str[pktsts]);
-// TU_LOG(DWC2_DEBUG, " daint = %08lX, doepint = %04X\r\n", (unsigned long) dwc2->daint, (unsigned int) epout->doepint);
-//#endif
-
switch (pktsts) {
// Global OUT NAK: do nothing
case GRXSTS_PKTSTS_GLOBALOUTNAK:
@@ -910,15 +966,14 @@ static void handle_rxflvl_irq(uint8_t rhport) {
case GRXSTS_PKTSTS_SETUPRX:
// Setup packet received
-
- // We can receive up to three setup packets in succession, but
- // only the last one is valid.
+ // We can receive up to three setup packets in succession, but only the last one is valid.
_setup_packet[0] = (*rx_fifo);
_setup_packet[1] = (*rx_fifo);
break;
case GRXSTS_PKTSTS_SETUPDONE:
- // Setup packet done (Interrupt)
+ // 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;
@@ -932,7 +987,7 @@ static void handle_rxflvl_irq(uint8_t rhport) {
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);
+ dfifo_read_packet(rhport, xfer->buffer, bcnt);
// Increment pointer to xfer data
xfer->buffer += bcnt;
@@ -946,34 +1001,16 @@ static void handle_rxflvl_irq(uint8_t rhport) {
ep0_pending[TUSB_DIR_OUT] = 0;
}
}
- }
break;
+ }
- // Out packet done (Interrupt)
case GRXSTS_PKTSTS_OUTDONE:
- // Occurred on STM32L47 with dwc2 version 3.10a but not found on other version like 2.80a or 3.30a
- // May (or not) be 3.10a specific feature/bug or depending on MCU configuration
- // XFRC complete is additionally generated when
- // - setup packet is received
- // - complete the data stage of control write is complete
- if ((epnum == 0) && (bcnt == 0) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) {
- uint32_t doepint = epout->doepint;
-
- if (doepint & (DOEPINT_STPKTRX | DOEPINT_OTEPSPR)) {
- // skip this "no-data" transfer complete event
- // Note: STPKTRX will be clear later by setup received handler
- uint32_t clear_flags = DOEPINT_XFRC;
-
- if (doepint & DOEPINT_OTEPSPR) clear_flags |= DOEPINT_OTEPSPR;
-
- epout->doepint = clear_flags;
-
- // TU_LOG(DWC2_DEBUG, " FIX extra transfer complete on setup/data compete\r\n");
- }
- }
+ /* 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;
- default: // Invalid
+ default:
TU_BREAKPOINT();
break;
}
@@ -985,37 +1022,68 @@ static void handle_epout_irq(uint8_t rhport) {
// 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];
+ for (uint8_t epnum = 0; epnum < ep_count; epnum++) {
+ if (dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + epnum)) {
+ dwc2_epout_t* epout = &dwc2->epout[epnum];
+ const uint32_t doepint = epout->doepint;
+ TU_ASSERT((epout->doepint & DOEPINT_AHBERR) == 0, );
+
+ // Setup and/or STPKTRX/STSPHSRX (from 3.00a) can be set along with XFRC, and also set independently.
+ if (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a) {
+ if (doepint & DOEPINT_STSPHSRX) {
+ // Status phase received for control write: In token received from Host
+ epout->doepint = DOEPINT_STSPHSRX;
+ }
- uint32_t const doepint = epout->doepint;
+ if (doepint & DOEPINT_STPKTRX) {
+ // New setup packet received, but wait for Setup done, since we can receive up to 3 setup consecutively
+ epout->doepint = DOEPINT_STPKTRX;
+ }
+ }
- // SETUP packet Setup Phase done.
- if (doepint & DOEPINT_STUP) {
- uint32_t clear_flag = DOEPINT_STUP;
+ if (doepint & DOEPINT_SETUP) {
+ epout->doepint = DOEPINT_SETUP;
- // STPKTRX is only available for version from 3_00a
- if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) {
- clear_flag |= DOEPINT_STPKTRX;
+ if(dma_enabled(dwc2)) {
+ dma_setup_prepare(rhport);
}
- epout->doepint = clear_flag;
dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true);
}
// OUT XFER complete
- if (epout->doepint & DOEPINT_XFRC) {
+ if (doepint & DOEPINT_XFRC) {
epout->doepint = DOEPINT_XFRC;
- xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
+ // only handle data skip if it is setup or status related
+ // Normal OUT transfer complete
+ if (!(doepint & (DOEPINT_SETUP | DOEPINT_STPKTRX | DOEPINT_STSPHSRX))) {
+ xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, 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);
+ if(dma_enabled(dwc2)) {
+ if ((epnum == 0) && 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, 1, ep0_pending[TUSB_DIR_OUT]);
+ } else {
+ // Fix packet length
+ uint16_t remain = (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos;
+ xfer->total_len -= remain;
+ // this is ZLP, so prepare EP0 for next setup
+ if(epnum == 0 && xfer->total_len == 0) {
+ dma_setup_prepare(rhport);
+ }
+
+ dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true);
+ }
+ } else {
+ // EP0 can only handle one packet
+ if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) {
+ // Schedule another packet to be received.
+ edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]);
+ } else {
+ dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true);
+ }
+ }
}
}
}
@@ -1042,6 +1110,9 @@ static void handle_epin_irq(uint8_t rhport) {
// Schedule another packet to be transmitted.
edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]);
} else {
+ if((n == 0) && dma_enabled(dwc2)) {
+ dma_setup_prepare(rhport);
+ }
dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
}
}
@@ -1071,7 +1142,7 @@ static void handle_epin_irq(uint8_t rhport) {
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);
+ dfifo_write_packet(rhport, n, xfer->buffer, packet_size);
// Increment pointer to xfer data
xfer->buffer += packet_size;
@@ -1087,6 +1158,29 @@ static void handle_epin_irq(uint8_t rhport) {
}
}
+/* Interrupt Hierarchy
+
+ DxEPMSK.XferComplMsk DxEPINTn.XferCompl
+ | |
+ +---------- AND --------+
+ |
+ DAINT.xEPnInt DAINTMSK.xEPnMsk
+ | |
+ +---------- AND --------+
+ |
+ GINTSTS.xEPInt GINTMSK.xEPIntMsk
+ | |
+ +---------- AND --------+
+ |
+ GAHBCFG.GblIntrMsk
+ |
+ IRQn
+
+ 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);
@@ -1164,13 +1258,10 @@ void dcd_int_handler(uint8_t rhport) {
// RxFIFO non-empty interrupt handling.
if (int_status & 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;
@@ -1195,4 +1286,13 @@ void dcd_int_handler(uint8_t rhport) {
// }
}
+#if CFG_TUD_TEST_MODE
+void dcd_enter_test_mode(uint8_t rhport, tusb_feature_test_mode_t test_selector) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ // Enable the test mode
+ dwc2->dctl = (dwc2->dctl & ~DCTL_TCTL_Msk) | (((uint8_t) test_selector) << DCTL_TCTL_Pos);
+}
+#endif
+
#endif
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_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h
index c50dd66b8..4cdbcdb7a 100644
--- a/src/portable/synopsys/dwc2/dwc2_esp32.h
+++ b/src/portable/synopsys/dwc2/dwc2_esp32.h
@@ -32,60 +32,64 @@
extern "C" {
#endif
+#include "freertos/task.h"
+
#include "esp_intr_alloc.h"
#include "soc/periph_defs.h"
-//#include "soc/usb_periph.h"
+#include "soc/usb_wrap_struct.h"
+
+#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_FS_REG_BASE, .irqnum = ETS_USB_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 }
+};
-#define DWC2_REG_BASE 0x60080000UL
-#define DWC2_EP_MAX 6 // USB_OUT_EP_NUM. TODO ESP32Sx only has 5 tx fifo (5 endpoint IN)
+#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 const dwc2_controller_t _dwc2_controller[] =
-{
- { .reg_base = DWC2_REG_BASE, .irqnum = 0, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1024 }
+// 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
-static intr_handle_t usb_ih;
+static intr_handle_t usb_ih[TU_ARRAY_SIZE(_dwc2_controller)];
-static void dcd_int_handler_wrap(void* arg)
-{
- (void) arg;
- dcd_int_handler(0);
+static void dcd_int_handler_wrap(void* arg) {
+ const uint8_t rhport = (uint8_t)(uintptr_t) arg;
+ dcd_int_handler(rhport);
}
-TU_ATTR_ALWAYS_INLINE
-static inline void dwc2_dcd_int_enable (uint8_t rhport)
-{
- (void) rhport;
- esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, dcd_int_handler_wrap, NULL, &usb_ih);
+TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_enable(uint8_t rhport) {
+ esp_intr_alloc(_dwc2_controller[rhport].irqnum, ESP_INTR_FLAG_LOWMED,
+ dcd_int_handler_wrap, (void*)(uintptr_t) rhport, &usb_ih[rhport]);
}
-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_dcd_int_disable(uint8_t rhport) {
+ esp_intr_free(usb_ih[rhport]);
}
-static inline void dwc2_remote_wakeup_delay(void)
-{
+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;
// 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;
// nothing to do
}
@@ -93,4 +97,4 @@ static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
}
#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..cfd0c81a8 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/767 FS | ST F723/L4P5 FS | ST F723 HS | ST F769 | ST H743/H750 | ST L476 FS | ST U5A5 HS | GD32VF103 | XMC4500 |
+|:---------------------------|:----------------|:-------------|:--------------|:-------------|:--------------------------|:-----------------|:-----------------|:------------------|:-------------|:-------------|:---------------|:-------------|:-------------|:------------|:-------------|
+| GUID | 0x2708A000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00001200 | 0x00001100 | 0x00002000 | 0x00003000 | 0x00003100 | 0x00002100 | 0x00002300 | 0x00002000 | 0x00005000 | 0x00001000 | 0x00AEC000 |
+| GSNPSID | 0x4F54280A | 0x4F54330A | 0x4F54400A | 0x4F54400A | 0x4F54281A | 0x4F54281A | 0x4F54320A | 0x4F54330A | 0x4F54330A | 0x4F54320A | 0x4F54330A | 0x4F54310A | 0x4F54411A | 0x00000000 | 0x4F54292A |
+| - 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 | 0.00W | 2.92a |
+| 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 | 0x00000000 | 0x228F5930 |
+| - op_mode | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | noHNP noSRP | HNP SRP | HNP SRP |
+| - arch | DMA internal | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | Slave only | Slave only | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | Slave only | DMA internal |
+| - p2p (hub support) | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 |
+| - hs_phy_type | UTMI+ | n/a | n/a | UTMI+/ULPI | n/a | ULPI | n/a | n/a | UTMI+/ULPI | ULPI | ULPI | n/a | UTMI+ | n/a | n/a |
+| - fs_phy_type | Dedicated | Dedicated | Dedicated | Shared ULPI | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | n/a | n/a | Dedicated |
+| - num_dev_ep | 7 | 6 | 6 | 15 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 0 | 6 |
+| - num_host_ch | 7 | 13 | 7 | 15 | 7 | 11 | 11 | 11 | 15 | 15 | 15 | 11 | 15 | 0 | 13 |
+| - period_channel_support | 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 | 0 | 1 |
+| - 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 | 2 | 2 | 1 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 0 | 2 |
+| - ptx_q_depth | 2 | 2 | 2 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 0 | 2 |
+| - token_q_depth | 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 |
+| GHWCFG3 | 0x0FF000E8 | 0x01F204E8 | 0x00C804B5 | 0x03805EB5 | 0x020001E8 | 0x03F403E8 | 0x0200D1E8 | 0x0200D1E8 | 0x03EED2E8 | 0x03EED2E8 | 0x03B8D2E8 | 0x0200D1E8 | 0x03B882E8 | 0x00000000 | 0x027A01E5 |
+| - xfer_size_width | 8 | 8 | 5 | 5 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 | 5 |
+| - packet_size_width | 6 | 6 | 3 | 3 | 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 | 0 | 1 |
+| - i2c_enable | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 |
+| - 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 | 0 | 634 |
+| GHWCFG4 | 0x1FF00020 | 0x1BF08030 | 0xD3F0A030 | 0xDFF1A030 | 0x0FF08030 | 0x17F00030 | 0x17F08030 | 0x17F08030 | 0x23F00030 | 0x23F00030 | 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 |
+| - partial_powerdown | 0 | 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 | 0 | 1 |
+| - 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 bit | 8/16 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 | 0 | 1 |
+| - vbus_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
+| - a_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
+| - b_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
+| - session_end_filter | 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 | 0 | 1 |
+| - num_dev_in_eps | 7 | 6 | 4 | 7 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 0 | 6 |
+| - dma_desc_enable | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
+| - dma_desc_dynamic | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
diff --git a/src/portable/synopsys/dwc2/dwc2_info.py b/src/portable/synopsys/dwc2/dwc2_info.py
index 55bec3d23..d1793a005 100644..100755
--- a/src/portable/synopsys/dwc2/dwc2_info.py
+++ b/src/portable/synopsys/dwc2/dwc2_info.py
@@ -1,38 +1,41 @@
-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/767 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 F769': [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],
+ 'GD32VF103': [0x1000, 0, 0, 0, 0, 0],
+ 'XMC4500': [0xAEC000, 0x4F54292A, 0, 0x228F5930, 0x027A01E5, 0xDBF08030]
+
}
# 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 +44,18 @@ class GHWCFG2(ctypes.LittleEndianStructure):
_fields_ = [
("op_mode", ctypes.c_uint32, 3),
("arch", ctypes.c_uint32, 2),
- ("point2point", ctypes.c_uint32, 1),
+ ("p2p (hub support)", 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 +73,114 @@ 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"
+ },
+ '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"
+ }
+}
-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 +193,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..395b6d870 100644
--- a/src/portable/synopsys/dwc2/dwc2_stm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_stm32.h
@@ -142,7 +142,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 +175,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 +218,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 c15771237..cf05bbfec 100644
--- a/src/portable/synopsys/dwc2/dwc2_type.h
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -1,17 +1,34 @@
-/**
- * @author MCD Application Team
- * Ha Thach (tinyusb.org)
- *
- * @attention
- *
- * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024, hathach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+/** <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
- *
*/
#ifndef _TUSB_DWC2_TYPES_H_
@@ -29,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;
@@ -69,86 +87,222 @@ 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 ,
+ 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,
+};
+
+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 {
- FS_PHY_TYPE_NONE = 0, // not supported
- FS_PHY_TYPE_DEDICATED,
- FS_PHY_TYPE_UTMI,
- FS_PHY_TYPE_ULPI,
+ 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
};
-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 {
+ GHWCFFG4_PHY_DATA_WIDTH_8 = 0,
+ GHWCFFG4_PHY_DATA_WIDTH_16 = 1,
+ GHWCFFG4_PHY_DATA_WIDTH_8_16 = 2, // software selectable
+};
+
+//--------------------------------------------------------------------
+// Register bitfield definitions
+//--------------------------------------------------------------------
+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 0: device, 1: host
+ 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_if : 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 op_mode : 3; // 0..2 HNP/SRP Host/Device/OTG mode
+ uint32_t arch : 2; // 3..4 Slave/External/Internal DMA
+ uint32_t point2point : 1; // 5 0: support hub and split | 1: no hub, no split
+ uint32_t 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 Channel
-typedef struct
-{
+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
@@ -160,8 +314,7 @@ typedef struct
} dwc2_channel_t;
// Endpoint IN
-typedef struct
-{
+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
@@ -173,8 +326,7 @@ typedef struct
} dwc2_epin_t;
// Endpoint OUT
-typedef struct
-{
+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
@@ -184,105 +336,141 @@ typedef struct
uint32_t reserved18[2]; // B18..B1C
} dwc2_epout_t;
-typedef struct
-{
- //------------- Core Global -------------//
- volatile uint32_t gotgctl; // 000 OTG Control and Status
- volatile uint32_t gotgint; // 004 OTG Interrupt
- volatile uint32_t gahbcfg; // 008 AHB Configuration
- volatile uint32_t gusbcfg; // 00c USB Configuration
- volatile uint32_t grstctl; // 010 Reset
- volatile uint32_t gintsts; // 014 Interrupt
- volatile uint32_t gintmsk; // 018 Interrupt Mask
- volatile uint32_t grxstsr; // 01c Receive Status Debug Read
- volatile uint32_t grxstsp; // 020 Receive Status Read/Pop
- volatile uint32_t grxfsiz; // 024 Receive FIFO Size
-union {
- volatile uint32_t dieptxf0; // 028 EP0 Tx FIFO Size
- volatile uint32_t gnptxfsiz; // 028 Non-periodic Transmit FIFO Size
-};
- volatile uint32_t gnptxsts; // 02c Non-periodic Transmit FIFO/Queue Status
- volatile uint32_t gi2cctl; // 030 I2C Address
- volatile uint32_t gpvndctl; // 034 PHY Vendor Control
-union {
- volatile uint32_t ggpio; // 038 General Purpose IO
- volatile uint32_t stm32_gccfg; // 038 STM32 General Core Configuration
-};
- volatile uint32_t guid; // 03C User (Application programmable) ID
- volatile uint32_t gsnpsid; // 040 Synopsys ID + Release version
- volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep)
-union {
- volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2
- dwc2_ghwcfg2_t ghwcfg2_bm;
-};
-union {
- volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3
- dwc2_ghwcfg3_t ghwcfg3_bm;
-};
-union {
- volatile uint32_t ghwcfg4; // 050 User Hardware Configuration4
- dwc2_ghwcfg4_t ghwcfg4_bm;
-};
- volatile uint32_t glpmcfg; // 054 Core LPM Configuration
- volatile uint32_t gpwrdn; // 058 Power Down
- volatile uint32_t gdfifocfg; // 05C DFIFO Software Configuration
- volatile uint32_t gadpctl; // 060 ADP Timer, Control and Status
- uint32_t reserved64[39]; // 064..0FF
- volatile uint32_t hptxfsiz; // 100 Host Periodic Tx FIFO Size
- volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size
- uint32_t reserved140[176]; // 140..3FF
+typedef struct {
+ union {
+ volatile uint32_t diepctl;
+ volatile uint32_t doepctl;
+ volatile uint32_t ctl;
+ };
+ uint32_t rsv04;
+ union {
+ volatile uint32_t diepint;
+ volatile uint32_t doepint;
+ };
+ uint32_t rsv0c;
+ union {
+ volatile uint32_t dieptsiz;
+ volatile uint32_t doeptsiz;
+ };
+ union {
+ volatile uint32_t diepdma;
+ volatile uint32_t doepdma;
+ };
+ volatile uint32_t dtxfsts;
+ uint32_t rsv1c;
+}dwc2_dep_t;
- //------------- 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
+TU_VERIFY_STATIC(sizeof(dwc2_dep_t) == 0x20, "incorrect size");
- //------------- Host Channel -------------//
- dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15
- uint32_t reserved700[64]; // 700..7FF
+//--------------------------------------------------------------------
+// CSR Register Map
+//--------------------------------------------------------------------
+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
+ 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
- //------------- 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
+ //------------ 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 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
+ //------------- Host Channel -------------//
+ dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15
+ uint32_t reserved700[64]; // 700..7FF
- //------------- Power Clock -------------//
- volatile uint32_t pcgctl; // E00 Power and Clock Gating Control
- volatile uint32_t pcgctl1; // E04
- uint32_t reservede08[126]; // E08..FFF
+ //------------- 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
- //------------- FIFOs -------------//
- // Word-accessed only using first pointer since it auto shift
- volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO
+ // 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_epin_t epin[16]; // 900..AFF IN Endpoints
+ dwc2_epout_t epout[16]; // B00..CFF OUT Endpoints
+ };
+ };
+ uint32_t reservedd00[64]; // D00..DFF
+
+ //------------- Power Clock -------------//
+ volatile uint32_t pcgctl; // E00 Power and Clock Gating Control
+ volatile uint32_t pcgctl1; // E04
+ uint32_t reservede08[126]; // E08..FFF
+
+ //------------- FIFOs -------------//
+ // Word-accessed only using first pointer since it auto shift
+ volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO
} dwc2_regs_t;
TU_VERIFY_STATIC(offsetof(dwc2_regs_t, hcfg ) == 0x0400, "incorrect size");
@@ -940,6 +1128,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)
@@ -1222,6 +1412,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
@@ -1643,6 +1839,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
@@ -1693,15 +1928,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
@@ -1714,6 +1953,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
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 b073d6057..d8bca196f 100644
--- a/src/portable/template/hcd_template.c
+++ b/src/portable/template/hcd_template.c
@@ -44,9 +44,9 @@ 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) {
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
(void) rhport;
-
+ (void) rh_init;
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/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h
new file mode 100644
index 000000000..68be64f5e
--- /dev/null
+++ b/src/portable/wch/ch32_usbfs_reg.h
@@ -0,0 +1,175 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 Matthew Tran
+ * Copyright (c) 2024 hathach
+ *
+ * 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 USB_CH32_USBFS_REG_H
+#define USB_CH32_USBFS_REG_H
+
+// https://github.com/openwch/ch32v307/pull/90
+// https://github.com/openwch/ch32v20x/pull/12
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_CH32F20X
+ #include <ch32f20x.h>
+#elif CFG_TUSB_MCU == OPT_MCU_CH32V103
+ #include <ch32v10x.h>
+ typedef struct
+ {
+ __IO uint8_t BASE_CTRL;
+ __IO uint8_t UDEV_CTRL;
+ __IO uint8_t INT_EN;
+ __IO uint8_t DEV_ADDR;
+ __IO uint8_t Reserve0;
+ __IO uint8_t MIS_ST;
+ __IO uint8_t INT_FG;
+ __IO uint8_t INT_ST;
+ __IO uint32_t RX_LEN;
+ __IO uint8_t UEP4_1_MOD;
+ __IO uint8_t UEP2_3_MOD;
+ __IO uint8_t UEP5_6_MOD;
+ __IO uint8_t UEP7_MOD;
+ __IO uint32_t UEP0_DMA;
+ __IO uint32_t UEP1_DMA;
+ __IO uint32_t UEP2_DMA;
+ __IO uint32_t UEP3_DMA;
+ __IO uint32_t UEP4_DMA;
+ __IO uint32_t UEP5_DMA;
+ __IO uint32_t UEP6_DMA;
+ __IO uint32_t UEP7_DMA;
+ __IO uint16_t UEP0_TX_LEN;
+ __IO uint8_t UEP0_TX_CTRL;
+ __IO uint8_t UEP0_RX_CTRL;
+ __IO uint16_t UEP1_TX_LEN;
+ __IO uint8_t UEP1_TX_CTRL;
+ __IO uint8_t UEP1_RX_CTRL;
+ __IO uint16_t UEP2_TX_LEN;
+ __IO uint8_t UEP2_TX_CTRL;
+ __IO uint8_t UEP2_RX_CTRL;
+ __IO uint16_t UEP3_TX_LEN;
+ __IO uint8_t UEP3_TX_CTRL;
+ __IO uint8_t UEP3_RX_CTRL;
+ __IO uint16_t UEP4_TX_LEN;
+ __IO uint8_t UEP4_TX_CTRL;
+ __IO uint8_t UEP4_RX_CTRL;
+ __IO uint16_t UEP5_TX_LEN;
+ __IO uint8_t UEP5_TX_CTRL;
+ __IO uint8_t UEP5_RX_CTRL;
+ __IO uint16_t UEP6_TX_LEN;
+ __IO uint8_t UEP6_TX_CTRL;
+ __IO uint8_t UEP6_RX_CTRL;
+ __IO uint16_t UEP7_TX_LEN;
+ __IO uint8_t UEP7_TX_CTRL;
+ __IO uint8_t UEP7_RX_CTRL;
+ __IO uint32_t Reserve1;
+ __IO uint32_t OTG_CR;
+ __IO uint32_t OTG_SR;
+ } USBOTG_FS_TypeDef;
+
+ #define USBOTG_FS ((USBOTG_FS_TypeDef *) 0x40023400)
+#elif CFG_TUSB_MCU == OPT_MCU_CH32V20X
+ #include <ch32v20x.h>
+#elif CFG_TUSB_MCU == OPT_MCU_CH32V307
+ #include <ch32v30x.h>
+ #define USBHD_IRQn OTG_FS_IRQn
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+// CTRL
+#define USBFS_CTRL_DMA_EN (1 << 0)
+#define USBFS_CTRL_CLR_ALL (1 << 1)
+#define USBFS_CTRL_RESET_SIE (1 << 2)
+#define USBFS_CTRL_INT_BUSY (1 << 3)
+#define USBFS_CTRL_SYS_CTRL (1 << 4)
+#define USBFS_CTRL_DEV_PUEN (1 << 5)
+#define USBFS_CTRL_LOW_SPEED (1 << 6)
+#define USBFS_CTRL_HOST_MODE (1 << 7)
+
+// INT_EN
+#define USBFS_INT_EN_BUS_RST (1 << 0)
+#define USBFS_INT_EN_DETECT (1 << 0)
+#define USBFS_INT_EN_TRANSFER (1 << 1)
+#define USBFS_INT_EN_SUSPEND (1 << 2)
+#define USBFS_INT_EN_HST_SOF (1 << 3)
+#define USBFS_INT_EN_FIFO_OV (1 << 4)
+#define USBFS_INT_EN_DEV_NAK (1 << 6)
+#define USBFS_INT_EN_DEV_SOF (1 << 7)
+
+// INT_FG
+#define USBFS_INT_FG_BUS_RST (1 << 0)
+#define USBFS_INT_FG_DETECT (1 << 0)
+#define USBFS_INT_FG_TRANSFER (1 << 1)
+#define USBFS_INT_FG_SUSPEND (1 << 2)
+#define USBFS_INT_FG_HST_SOF (1 << 3)
+#define USBFS_INT_FG_FIFO_OV (1 << 4)
+#define USBFS_INT_FG_SIE_FREE (1 << 5)
+#define USBFS_INT_FG_TOG_OK (1 << 6)
+#define USBFS_INT_FG_IS_NAK (1 << 7)
+
+// INT_ST
+#define USBFS_INT_ST_MASK_UIS_ENDP(x) (((x) >> 0) & 0x0F)
+#define USBFS_INT_ST_MASK_UIS_TOKEN(x) (((x) >> 4) & 0x03)
+
+// UDEV_CTRL
+#define USBFS_UDEV_CTRL_PORT_EN (1 << 0)
+#define USBFS_UDEV_CTRL_GP_BIT (1 << 1)
+#define USBFS_UDEV_CTRL_LOW_SPEED (1 << 2)
+#define USBFS_UDEV_CTRL_DM_PIN (1 << 4)
+#define USBFS_UDEV_CTRL_DP_PIN (1 << 5)
+#define USBFS_UDEV_CTRL_PD_DIS (1 << 7)
+
+// TX_CTRL
+#define USBFS_EP_T_RES_MASK (3 << 0)
+#define USBFS_EP_T_TOG (1 << 2)
+#define USBFS_EP_T_AUTO_TOG (1 << 3)
+
+#define USBFS_EP_T_RES_ACK (0 << 0)
+#define USBFS_EP_T_RES_NYET (1 << 0)
+#define USBFS_EP_T_RES_NAK (2 << 0)
+#define USBFS_EP_T_RES_STALL (3 << 0)
+
+// RX_CTRL
+#define USBFS_EP_R_RES_MASK (3 << 0)
+#define USBFS_EP_R_TOG (1 << 2)
+#define USBFS_EP_R_AUTO_TOG (1 << 3)
+
+#define USBFS_EP_R_RES_ACK (0 << 0)
+#define USBFS_EP_R_RES_NYET (1 << 0)
+#define USBFS_EP_R_RES_NAK (2 << 0)
+#define USBFS_EP_R_RES_STALL (3 << 0)
+
+// token PID
+#define PID_OUT 0
+#define PID_SOF 1
+#define PID_IN 2
+#define PID_SETUP 3
+
+#endif // USB_CH32_USBFS_REG_H
diff --git a/src/portable/wch/ch32_usbhs_reg.h b/src/portable/wch/ch32_usbhs_reg.h
index 9b956231f..87300b497 100644
--- a/src/portable/wch/ch32_usbhs_reg.h
+++ b/src/portable/wch/ch32_usbhs_reg.h
@@ -1,12 +1,51 @@
-#ifndef _USB_CH32_USBHS_REG_H
-#define _USB_CH32_USBHS_REG_H
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 Matthew Tran
+ * Copyright (c) 2024 hathach
+ *
+ * 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.
+ */
-#if (CFG_TUSB_MCU == OPT_MCU_CH32V307)
-#include <ch32v30x.h>
-#elif (CFG_TUSB_MCU == OPT_MCU_CH32F20X)
-#include <ch32f20x.h>
+#ifndef USB_CH32_USBHS_REG_H
+#define USB_CH32_USBHS_REG_H
+
+// https://github.com/openwch/ch32v307/pull/90
+// https://github.com/openwch/ch32v20x/pull/12
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_CH32V307
+ #include <ch32v30x.h>
+#elif CFG_TUSB_MCU == OPT_MCU_CH32F20X
+ #include <ch32f20x.h>
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
#endif
+
/******************* GLOBAL ******************/
// USB CONTROL
@@ -36,8 +75,13 @@
// USB DEV AD
#define USBHS_DEV_AD_OFFSET 0x03
+
// USB FRAME_NO
#define USBHS_FRAME_NO_OFFSET 0x04
+#define USBHS_FRAME_NO_NUM_MASK (0x7FF)
+#define USBHS_FRAME_NO_MICROFRAME_SHIFT (11)
+#define USBHS_FRAME_NO_MICROFRAME_MASK (0x7 << USBHS_FRAME_NO_MICROFRAME_SHIFT)
+
// USB SUSPEND
#define USBHS_SUSPEND_OFFSET 0x06
#define USBHS_DEV_REMOTE_WAKEUP (1 << 2)
@@ -47,7 +91,10 @@
// USB SPEED TYPE
#define USBHS_SPEED_TYPE_OFFSET 0x08
-#define USBSPEED_MASK (0x03)
+#define USBHS_SPEED_TYPE_MASK 0x03
+#define USBHS_SPEED_TYPE_FULL 0
+#define USBHS_SPEED_TYPE_HIGH 1
+#define USBHS_SPEED_TYPE_LOW 2
// USB_MIS_ST
#define USBHS_MIS_ST_OFFSET 0x09
@@ -72,12 +119,16 @@
#define USBHS_ISO_ACT_FLAG (1 << 6)
// INT_ST
-#define USBHS_INT_ST_OFFSET 0x0B
-#define USBHS_DEV_UIS_IS_NAK (1 << 7)
-#define USBHS_DEV_UIS_TOG_OK (1 << 6)
-#define MASK_UIS_TOKEN (3 << 4)
-#define MASK_UIS_ENDP (0x0F)
-#define MASK_UIS_H_RES (0x0F)
+#define USBHS_INT_ST_OFFSET 0x0B
+#define USBHS_DEV_UIS_IS_NAK (1 << 7)
+#define USBHS_DEV_UIS_TOG_OK (1 << 6)
+#define MASK_UIS_TOKEN (3 << 4)
+#define USBHS_TOKEN_PID_OUT (0 << 4)
+#define USBHS_TOKEN_PID_SOF (1 << 4)
+#define USBHS_TOKEN_PID_IN (2 << 4)
+#define USBHS_TOKEN_PID_SETUP (3 << 4)
+#define MASK_UIS_ENDP (0x0F)
+#define MASK_UIS_H_RES (0x0F)
#define USBHS_TOGGLE_OK (0x40)
#define USBHS_HOST_RES (0x0f)
@@ -340,10 +391,5 @@
#define USBHS_UH_T_TOG_AUTO (1 << 5)
#define USBHS_UH_T_DATA_NO (1 << 6)
-// 00: OUT, 01:SOF, 10:IN, 11:SETUP
-#define PID_OUT 0
-#define PID_SOF 1
-#define PID_IN 2
-#define PID_SETUP 3
#endif
diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c
new file mode 100644
index 000000000..4e8e25a00
--- /dev/null
+++ b/src/portable/wch/dcd_ch32_usbfs.c
@@ -0,0 +1,347 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 Matthew Tran
+ * Copyright (c) 2024 hathach
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBFS) && CFG_TUD_WCH_USBIP_USBFS
+
+#include "device/dcd.h"
+#include "ch32_usbfs_reg.h"
+
+/* private defines */
+#define EP_MAX (8)
+
+#define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep])
+#define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep])
+#define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep])
+#define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep])
+
+/* private data */
+struct usb_xfer {
+ bool valid;
+ uint8_t* buffer;
+ size_t len;
+ size_t processed_len;
+ size_t max_size;
+};
+
+static struct {
+ bool ep0_tog;
+ bool isochronous[EP_MAX];
+ struct usb_xfer xfer[EP_MAX][2];
+ TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX][2][64];
+ TU_ATTR_ALIGNED(4) struct {
+ // OUT transfers >64 bytes will overwrite queued IN data!
+ uint8_t out[64];
+ uint8_t in[1023];
+ uint8_t pad;
+ } ep3_buffer;
+} data;
+
+/* private helpers */
+static void update_in(uint8_t rhport, uint8_t ep, bool force) {
+ struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_IN];
+ if (xfer->valid) {
+ if (force || xfer->len) {
+ size_t len = TU_MIN(xfer->max_size, xfer->len);
+ if (ep == 0) {
+ memcpy(data.buffer[ep][TUSB_DIR_OUT], xfer->buffer, len); // ep0 uses same chunk
+ } else if (ep == 3) {
+ memcpy(data.ep3_buffer.in, xfer->buffer, len);
+ } else {
+ memcpy(data.buffer[ep][TUSB_DIR_IN], xfer->buffer, len);
+ }
+ xfer->buffer += len;
+ xfer->len -= len;
+ xfer->processed_len += len;
+
+ EP_TX_LEN(ep) = len;
+ if (ep == 0) {
+ EP_TX_CTRL(0) = USBFS_EP_T_RES_ACK | (data.ep0_tog ? USBFS_EP_T_TOG : 0);
+ data.ep0_tog = !data.ep0_tog;
+ } else if (data.isochronous[ep]) {
+ EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NYET;
+ } else {
+ EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_ACK;
+ }
+ } else {
+ xfer->valid = false;
+ EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK;
+ dcd_event_xfer_complete(
+ rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len,
+ XFER_RESULT_SUCCESS, true);
+ }
+ }
+}
+
+static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) {
+ struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_OUT];
+ if (xfer->valid) {
+ size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len));
+ if (ep == 3) {
+ memcpy(xfer->buffer, data.ep3_buffer.out, len);
+ } else {
+ memcpy(xfer->buffer, data.buffer[ep][TUSB_DIR_OUT], len);
+ }
+ xfer->buffer += len;
+ xfer->len -= len;
+ xfer->processed_len += len;
+
+ if (xfer->len == 0 || len < xfer->max_size) {
+ xfer->valid = false;
+ dcd_event_xfer_complete(rhport, ep, xfer->processed_len, XFER_RESULT_SUCCESS, true);
+ }
+
+ if (ep == 0) {
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+ }
+ }
+}
+
+/* public functions */
+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;
+ USBOTG_FS->DEV_ADDR = 0x00;
+
+ USBOTG_FS->INT_FG = 0xFF;
+ USBOTG_FS->INT_EN = USBFS_INT_EN_BUS_RST | USBFS_INT_EN_TRANSFER | USBFS_INT_EN_SUSPEND;
+
+ // setup endpoint 0
+ EP_DMA(0) = (uint32_t) &data.buffer[0][0];
+ EP_TX_LEN(0) = 0;
+ EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+
+ // enable other endpoints but NAK everything
+ USBOTG_FS->UEP4_1_MOD = 0xCC;
+ USBOTG_FS->UEP2_3_MOD = 0xCC;
+ USBOTG_FS->UEP5_6_MOD = 0xCC;
+ USBOTG_FS->UEP7_MOD = 0x0C;
+
+ for (uint8_t ep = 1; ep < EP_MAX; ep++) {
+ EP_DMA(ep) = (uint32_t) &data.buffer[ep][0];
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK;
+ EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK;
+ }
+ EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0];
+
+ dcd_connect(rhport);
+
+ return true;
+}
+
+void dcd_int_handler(uint8_t rhport) {
+ (void) rhport;
+ uint8_t status = USBOTG_FS->INT_FG;
+ if (status & USBFS_INT_FG_TRANSFER) {
+ uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST);
+ uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST);
+
+ switch (token) {
+ case PID_OUT: {
+ uint16_t rx_len = USBOTG_FS->RX_LEN;
+ update_out(rhport, ep, rx_len);
+ break;
+ }
+
+ case PID_IN:
+ update_in(rhport, ep, false);
+ break;
+
+ case PID_SETUP:
+ // setup clears stall
+ EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+
+ data.ep0_tog = true;
+ dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true);
+ break;
+ }
+
+ USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER;
+ } else if (status & USBFS_INT_FG_BUS_RST) {
+ data.ep0_tog = true;
+ 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);
+
+ USBOTG_FS->DEV_ADDR = 0x00;
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+
+ USBOTG_FS->INT_FG = USBFS_INT_FG_BUS_RST;
+ } else if (status & USBFS_INT_FG_SUSPEND) {
+ dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND};
+ dcd_event_handler(&event, true);
+ USBOTG_FS->INT_FG = USBFS_INT_FG_SUSPEND;
+ }
+}
+
+void dcd_int_enable(uint8_t rhport) {
+ (void) rhport;
+ NVIC_EnableIRQ(USBHD_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport) {
+ (void) rhport;
+ NVIC_DisableIRQ(USBHD_IRQn);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
+ (void) dev_addr;
+ dcd_edpt_xfer(rhport, 0x80, NULL, 0); // zlp status response
+}
+
+void dcd_remote_wakeup(uint8_t rhport) {
+ (void) rhport;
+ // TODO optional
+}
+
+void dcd_connect(uint8_t rhport) {
+ (void) rhport;
+ USBOTG_FS->BASE_CTRL |= USBFS_CTRL_DEV_PUEN;
+}
+
+void dcd_disconnect(uint8_t rhport) {
+ (void) rhport;
+ USBOTG_FS->BASE_CTRL &= ~USBFS_CTRL_DEV_PUEN;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en) {
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
+ (void) rhport;
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
+ request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ USBOTG_FS->DEV_ADDR = (uint8_t) request->wValue;
+ }
+ EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+}
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) {
+ (void) rhport;
+ uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress);
+ uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress);
+ TU_ASSERT(ep < EP_MAX);
+
+ data.isochronous[ep] = desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS;
+ data.xfer[ep][dir].max_size = tu_edpt_packet_size(desc_ep);
+
+ if (ep != 0) {
+ if (dir == TUSB_DIR_OUT) {
+ if (data.isochronous[ep]) {
+ EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET;
+ } else {
+ EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_ACK;
+ }
+ } else {
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK;
+ }
+ }
+ return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport) {
+ (void) rhport;
+ // TODO optional
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
+ (void) ep_addr;
+ // TODO optional
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
+ (void) rhport;
+ uint8_t ep = tu_edpt_number(ep_addr);
+ uint8_t dir = tu_edpt_dir(ep_addr);
+
+ struct usb_xfer* xfer = &data.xfer[ep][dir];
+ dcd_int_disable(rhport);
+ xfer->valid = true;
+ xfer->buffer = buffer;
+ xfer->len = total_bytes;
+ xfer->processed_len = 0;
+ dcd_int_enable(rhport);
+
+ if (dir == TUSB_DIR_IN) {
+ update_in(rhport, ep, true);
+ }
+ return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
+ uint8_t ep = tu_edpt_number(ep_addr);
+ uint8_t dir = tu_edpt_dir(ep_addr);
+ if (ep == 0) {
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_STALL;
+ } else {
+ EP_TX_LEN(0) = 0;
+ EP_TX_CTRL(0) = USBFS_EP_T_RES_STALL;
+ }
+ } else {
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_STALL;
+ } else {
+ EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~USBFS_EP_T_RES_MASK) | USBFS_EP_T_RES_STALL;
+ }
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
+ uint8_t ep = tu_edpt_number(ep_addr);
+ uint8_t dir = tu_edpt_dir(ep_addr);
+ if (ep == 0) {
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+ }
+ } else {
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~(USBFS_EP_R_RES_MASK | USBFS_EP_R_TOG)) | USBFS_EP_R_RES_ACK;
+ } else {
+ EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK | USBFS_EP_T_TOG)) | USBFS_EP_T_RES_NAK;
+ }
+ }
+}
+
+#endif
diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c
index 1f1c0b876..f8bf3c889 100644
--- a/src/portable/wch/dcd_ch32_usbhs.c
+++ b/src/portable/wch/dcd_ch32_usbhs.c
@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2022 Greg Davill
+ * Copyright (c) 2023 Denis Krasutski
*
* 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,366 +27,397 @@
#include "tusb_option.h"
-#if CFG_TUD_ENABLED && ((CFG_TUSB_MCU == OPT_MCU_CH32V307) || (CFG_TUSB_MCU == OPT_MCU_CH32F20X))
-#include "device/dcd.h"
-
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBHS) && CFG_TUD_WCH_USBIP_USBHS
#include "ch32_usbhs_reg.h"
+#include "device/dcd.h"
// Max number of bi-directional endpoints including EP0
-#define EP_MAX 16
+#define EP_MAX 16
typedef struct {
- uint8_t *buffer;
- // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
- uint16_t total_len;
- uint16_t queued_len;
- uint16_t max_size;
- bool short_packet;
+ uint8_t* buffer;
+ uint16_t total_len;
+ uint16_t queued_len;
+ uint16_t max_size;
+ bool is_last_packet;
+ bool is_iso;
} xfer_ctl_t;
+typedef enum {
+ EP_RESPONSE_ACK,
+ EP_RESPONSE_NAK,
+} ep_response_list_t;
+
#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
static xfer_ctl_t xfer_status[EP_MAX][2];
-#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep)*2)
-#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep)*4)
-#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep)*4)
-#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep)*2)
+#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2)
+#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4)
+#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4)
+#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2)
#define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1))
#define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1))
/* Endpoint Buffer */
-TU_ATTR_ALIGNED(4) uint8_t EP0_DatabufHD[64]; // ep0(64)
+TU_ATTR_ALIGNED(4) static uint8_t ep0_buffer[CFG_TUD_ENDPOINT0_SIZE];
-volatile uint8_t USBHS_Dev_Endp0_Tog = 0x01;
+static void ep_set_response_and_toggle(uint8_t ep_num, tusb_dir_t ep_dir, ep_response_list_t response_type) {
+ if (ep_dir == TUSB_DIR_IN) {
+ uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_T_RES_ACK : USBHS_EP_T_RES_NAK;
+ if (ep_num == 0) {
+ if (response_type == EP_RESPONSE_ACK) {
+ if (EP_TX_LEN(ep_num) == 0) {
+ EP_TX_CTRL(ep_num) |= USBHS_EP_T_TOG_1;
+ } else {
+ EP_TX_CTRL(ep_num) ^= USBHS_EP_T_TOG_1;
+ }
+ }
+ }
+ if (xfer_status[ep_num][TUSB_DIR_IN].is_iso == true) {
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG;
+ } else {
+ EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | response;
+ }
+ } else {
+ uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_R_RES_ACK : USBHS_EP_R_RES_NAK;
+ if (ep_num == 0) {
+ if (response_type == EP_RESPONSE_ACK) {
+ if (xfer_status[ep_num][TUSB_DIR_OUT].queued_len == 0) {
+ EP_RX_CTRL(ep_num) |= USBHS_EP_R_TOG_1;
+ }
+ } else {
+ EP_RX_CTRL(ep_num) ^= USBHS_EP_R_TOG_1;
+ }
+ }
+ EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | response;
+ }
+}
-void dcd_init(uint8_t rhport) {
- (void)rhport;
+static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t* xfer) {
+ if (ep_dir == TUSB_DIR_IN) {
+ uint16_t remaining = xfer->total_len - xfer->queued_len;
+ uint16_t next_tx_size = TU_MIN(remaining, xfer->max_size);
- memset(&xfer_status, 0, sizeof(xfer_status));
+ if (ep_num == 0) {
+ memcpy(ep0_buffer, &xfer->buffer[xfer->queued_len], next_tx_size);
+ } else {
+ EP_TX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len];
+ }
- USBHSD->HOST_CTRL = 0x00;
- USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM;
+ EP_TX_LEN(ep_num) = next_tx_size;
+ xfer->queued_len += next_tx_size;
+ if (xfer->queued_len == xfer->total_len) {
+ xfer->is_last_packet = true;
+ }
+ if (xfer->is_iso == true) {
+ /* Enable EP to generate ISA_ACT interrupt */
+ USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num);
+ }
+ } else { /* TUSB_DIR_OUT */
+ uint16_t left_to_receive = xfer->total_len - xfer->queued_len;
+ uint16_t max_possible_rx_size = TU_MIN(xfer->max_size, left_to_receive);
- USBHSD->CONTROL = 0;
+ if (max_possible_rx_size == left_to_receive) {
+ xfer->is_last_packet = true;
+ }
+
+ if (ep_num > 0) {
+ EP_RX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len];
+ EP_RX_MAX_LEN(ep_num) = max_possible_rx_size;
+ }
+ }
+ ep_set_response_and_toggle(ep_num, ep_dir, USBHS_EP_R_RES_ACK);
+}
+
+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));
+
+ USBHSD->HOST_CTRL = 0x00;
+ USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM;
+
+ USBHSD->CONTROL = 0;
#if TUD_OPT_HIGH_SPEED
- USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
+ USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
#else
- #error OPT_MODE_FULL_SPEED not currently supported on CH32
- USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED;
+ #error OPT_MODE_FULL_SPEED not currently supported on CH32
+ USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED;
#endif
- USBHSD->INT_EN = 0;
- USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_DETECT_EN | USBHS_SUSPEND_EN;
-
- /* ALL endpoint enable */
- USBHSD->ENDP_CONFIG = 0xffffffff;
+ USBHSD->INT_EN = 0;
+ USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN | USBHS_ISO_ACT_EN;
- USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
- USBHSD->ENDP_TYPE = 0x00;
- USBHSD->BUF_MODE = 0x00;
+ USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
+ USBHSD->ENDP_TYPE = 0x00;
+ USBHSD->BUF_MODE = 0x00;
- USBHSD->UEP0_MAX_LEN = 64;
+ for (int ep = 0; ep < EP_MAX; ep++) {
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
+ EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
- USBHSD->UEP0_DMA = (uint32_t)EP0_DatabufHD;
+ EP_RX_MAX_LEN(ep) = 0;
+ }
- USBHSD->UEP0_TX_LEN = 0;
- USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_NAK;
- USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
+ USBHSD->UEP0_DMA = (uint32_t) ep0_buffer;
+ USBHSD->UEP0_MAX_LEN = CFG_TUD_ENDPOINT0_SIZE;
+ xfer_status[0][TUSB_DIR_OUT].max_size = CFG_TUD_ENDPOINT0_SIZE;
+ xfer_status[0][TUSB_DIR_IN].max_size = CFG_TUD_ENDPOINT0_SIZE;
- for (int ep = 1; ep < EP_MAX; ep++) {
- EP_TX_LEN(ep) = 0;
- EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
- EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ USBHSD->DEV_AD = 0;
+ USBHSD->CONTROL |= USBHS_DEV_PU_EN;
- EP_RX_MAX_LEN(ep) = 512;
- }
-
- USBHSD->DEV_AD = 0;
- USBHSD->CONTROL |= USBHS_DEV_PU_EN;
+ return true;
}
void dcd_int_enable(uint8_t rhport) {
- (void)rhport;
-
- NVIC_EnableIRQ(USBHS_IRQn);
+ (void) rhport;
+ NVIC_EnableIRQ(USBHS_IRQn);
}
void dcd_int_disable(uint8_t rhport) {
- (void)rhport;
-
- NVIC_DisableIRQ(USBHS_IRQn);
+ (void) rhport;
+ NVIC_DisableIRQ(USBHS_IRQn);
}
void dcd_edpt_close_all(uint8_t rhport) {
- (void)rhport;
+ (void) rhport;
+
+ for (size_t ep = 1; ep < EP_MAX; ep++) {
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
+ EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+
+ EP_RX_MAX_LEN(ep) = 0;
+ }
+
+ USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
- (void)dev_addr;
+ (void) dev_addr;
- // Response with zlp status
- dcd_edpt_xfer(rhport, 0x80, NULL, 0);
+ // Response with zlp status
+ dcd_edpt_xfer(rhport, 0x80, NULL, 0);
}
-void dcd_remote_wakeup(uint8_t rhport)
-{
+void dcd_remote_wakeup(uint8_t rhport) {
(void) rhport;
}
-void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) {
- (void)rhport;
-
- if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
- request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
- request->bRequest == TUSB_REQ_SET_ADDRESS) {
- USBHSD->DEV_AD = (uint8_t)request->wValue;
- }
-
- EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK;
- EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK;
+void dcd_sof_enable(uint8_t rhport, bool en) {
+ (void) rhport;
+ if (en) {
+ USBHSD->INT_EN |= USBHS_SOF_ACT_EN;
+ } else {
+ USBHSD->INT_EN &= ~(USBHS_SOF_ACT_EN);
+ }
}
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt) {
- (void)rhport;
-
- uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
-
- TU_ASSERT(epnum < EP_MAX);
-
- xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
- xfer->max_size = tu_edpt_packet_size(desc_edpt);
-
- if (epnum != 0) {
- if (tu_edpt_dir(desc_edpt->bEndpointAddress) == TUSB_DIR_OUT) {
- EP_RX_CTRL(epnum) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_ACK;
- } else {
- EP_TX_LEN(epnum) = 0;
- EP_TX_CTRL(epnum) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
- }
- }
-
- return true;
-}
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
+ (void) rhport;
-int usbd_ep_close(const uint8_t ep) {
- (void)ep;
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
+ request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ USBHSD->DEV_AD = (uint8_t) request->wValue;
+ }
- return 0;
+ EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ EP_RX_CTRL(0) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0;
}
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
- (void)rhport;
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
+ (void) rhport;
- if (epnum == 0) {
- if (dir == TUSB_DIR_OUT) {
- USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_STALL;
- } else {
- USBHSD->UEP0_TX_LEN = 0;
- USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_STALL;
- }
- } else {
- if (dir == TUSB_DIR_OUT) {
- EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_STALL;
+ uint8_t const ep_num = tu_edpt_number(desc_edpt->bEndpointAddress);
+ tusb_dir_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
- } else {
- EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~USBHS_EP_T_RES_MASK) | USBHS_EP_T_RES_STALL;
- }
- }
-}
+ TU_ASSERT(ep_num < EP_MAX);
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
- (void)rhport;
+ if (ep_num == 0) {
+ return true;
+ }
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir);
+ xfer->max_size = tu_edpt_packet_size(desc_edpt);
- if (epnum == 0) {
- if (dir == TUSB_DIR_OUT) {
- USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
- } else {
- }
+ xfer->is_iso = (desc_edpt->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS);
+ if (dir == TUSB_DIR_OUT) {
+ USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << ep_num);
+ EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ if (xfer->is_iso == true) {
+ USBHSD->ENDP_TYPE |= (USBHS_EP0_R_TYP << ep_num);
+ }
+ EP_RX_MAX_LEN(ep_num) = xfer->max_size;
+ } else {
+ if (xfer->is_iso == true) {
+ USBHSD->ENDP_TYPE |= (USBHS_EP0_T_TYP << ep_num);
} else {
- if (dir == TUSB_DIR_OUT) {
- EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~(USBHS_EP_R_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_ACK;
-
- } else {
- EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_NAK;
- }
+ /* Enable all types except Isochronous to avoid ISO_ACT interrupt generation */
+ USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num);
}
-}
-
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) {
- (void)rhport;
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ EP_TX_LEN(ep_num) = 0;
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ }
- xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = buffer;
- // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
- xfer->total_len = total_bytes;
- xfer->queued_len = 0;
- xfer->short_packet = false;
-
- // uint16_t num_packets = (total_bytes / xfer->max_size);
- uint16_t short_packet_size = total_bytes % (xfer->max_size + 1);
+ return true;
+}
- // Zero-size packet is special case.
- if (short_packet_size == 0 || (total_bytes == 0)) {
- xfer->short_packet = true;
- }
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
- if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
- if (!total_bytes) {
- xfer->short_packet = true;
- if (epnum == 0) {
- USBHSD->UEP0_TX_LEN = 0;
- USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
- USBHS_Dev_Endp0_Tog ^= 1;
- } else {
- EP_TX_LEN(epnum) = 0;
- EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
- }
- } else {
- if (epnum == 0) {
- xfer->queued_len += short_packet_size;
- memcpy(&EP0_DatabufHD[0], buffer, short_packet_size);
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- USBHSD->UEP0_TX_LEN = short_packet_size;
- USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
- USBHS_Dev_Endp0_Tog ^= 1;
- } else {
- xfer->queued_len += short_packet_size;
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ EP_RX_MAX_LEN(ep_num) = 0;
+ USBHSD->ENDP_TYPE &= ~(USBHS_EP0_R_TYP << ep_num);
+ USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_R_EN << ep_num);
+ } else { // TUSB_DIR_IN
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ EP_TX_LEN(ep_num) = 0;
+ USBHSD->ENDP_TYPE &= ~(USBHS_EP0_T_TYP << ep_num);
+ USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num);
+ }
+}
- EP_TX_DMA_ADDR(epnum) = (uint32_t)buffer;
- USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << epnum);
- EP_TX_LEN(epnum) = short_packet_size;
- EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
- }
- }
- } else { /* TUSB_DIR_OUT */
- if (epnum == 0) {
- uint32_t read_count = USBHSD->RX_LEN;
- read_count = TU_MIN(read_count, total_bytes);
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
- if ((total_bytes == 8)) {
- read_count = 8;
- memcpy(buffer, &EP0_DatabufHD[0], 8);
- } else {
- memcpy(buffer, &EP0_DatabufHD[0], read_count);
- }
- } else {
- EP_RX_DMA_ADDR(epnum) = (uint32_t)xfer->buffer;
- USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << epnum);
- }
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- // usbd_ep_read(ep_addr, buffer, total_bytes, &ret_bytes);
- }
- return true;
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_STALL;
+ } else {
+ EP_TX_LEN(0) = 0;
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_STALL;
+ }
}
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
-static void receive_packet(xfer_ctl_t *xfer, uint16_t xfer_size) {
- // xfer->queued_len = xfer->total_len - remaining;
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- uint16_t remaining = xfer->total_len - xfer->queued_len;
- uint16_t to_recv_size;
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ } else {
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_R_RES_NAK;
+ }
+}
- if (remaining <= xfer->max_size) {
- // Avoid buffer overflow.
- to_recv_size = (xfer_size > remaining) ? remaining : xfer_size;
- } else {
- // Room for full packet, choose recv_size based on what the microcontroller
- // claims.
- to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
- }
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
+ (void) rhport;
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- if (to_recv_size) {
- }
+ xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir);
+ xfer->buffer = buffer;
+ xfer->total_len = total_bytes;
+ xfer->queued_len = 0;
+ xfer->is_last_packet = false;
- xfer->queued_len += xfer_size;
+ xfer_data_packet(ep_num, dir, xfer);
- // Per USB spec, a short OUT packet (including length 0) is always
- // indicative of the end of a transfer (at least for ctl, bulk, int).
- xfer->short_packet = (xfer_size < xfer->max_size);
+ return true;
}
void dcd_int_handler(uint8_t rhport) {
- (void)rhport;
-
- uint32_t end_num, rx_token;
- uint8_t intflag = 0;
-
- intflag = USBHSD->INT_FG;
-
- if (intflag & USBHS_TRANSFER_FLAG) {
-
- end_num = (USBHSD->INT_ST) & MASK_UIS_ENDP;
- rx_token = (((USBHSD->INT_ST) & MASK_UIS_TOKEN) >> 4) & 0x03;
-
- uint8_t endp = end_num | (rx_token == PID_IN ? TUSB_DIR_IN_MASK : 0);
-
- xfer_ctl_t *xfer = XFER_CTL_BASE(end_num, tu_edpt_dir(endp));
-
- if (rx_token == PID_OUT) {
- uint16_t rx_len = USBHSD->RX_LEN;
-
- receive_packet(xfer, rx_len);
+ (void) rhport;
- if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
- xfer->short_packet = false;
+ uint8_t int_flag = USBHSD->INT_FG;
+ uint8_t int_status = USBHSD->INT_ST;
- dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true);
- }
+ if (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)) {
+ uint8_t const token = int_status & MASK_UIS_TOKEN;
- if (end_num == 0) {
- USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
- }
+ if (token == USBHS_TOKEN_PID_SOF) {
+ uint32_t frame_count = USBHSD->FRAME_NO & USBHS_FRAME_NO_NUM_MASK;
+ dcd_event_sof(rhport, frame_count, true);
+ }else {
+ uint8_t const ep_num = int_status & MASK_UIS_ENDP;
+ tusb_dir_t const ep_dir = (token == USBHS_TOKEN_PID_IN) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+ uint8_t const ep_addr = tu_edpt_addr(ep_num, ep_dir);
+ xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, ep_dir);
- } else if (rx_token == PID_IN) {
- if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
- xfer->short_packet = false;
- xfer->total_len = 0;
- dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+ if (token == USBHS_TOKEN_PID_OUT) {
+ uint16_t rx_len = USBHSD->RX_LEN;
- EP_TX_CTRL(end_num) = (EP_TX_CTRL(end_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK;
+ if (ep_num == 0) {
+ memcpy(&xfer->buffer[xfer->queued_len], ep0_buffer, rx_len);
+ }
- if (end_num == 0) {
- }
- } else {
- dcd_edpt_xfer(0, endp, xfer->buffer + xfer->queued_len, xfer->total_len - xfer->queued_len);
- }
+ xfer->queued_len += rx_len;
+ if (rx_len < xfer->max_size) {
+ xfer->is_last_packet = true;
+ }
+ } else if (token == USBHS_TOKEN_PID_IN) {
+ if (xfer->is_iso && xfer->is_last_packet) {
+ /* Disable EP to avoid ISO_ACT interrupt generation */
+ USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num);
+ } else {
+ // Do nothing, no need to update xfer->is_last_packet, it is already updated in xfer_data_packet
}
+ }
- USBHSD->INT_FG = USBHS_TRANSFER_FLAG; /* Clear flag */
- } else if (intflag & USBHS_SETUP_FLAG) {
- USBHS_Dev_Endp0_Tog = 1;
- dcd_event_setup_received(0, EP0_DatabufHD, true);
+ if (xfer->is_last_packet == true) {
+ ep_set_response_and_toggle(ep_num, ep_dir, EP_RESPONSE_NAK);
+ dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+ } else {
+ /* prepare next part of packet to xref */
+ xfer_data_packet(ep_num, ep_dir, xfer);
+ }
+ }
- USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */
- } else if (intflag & USBHS_DETECT_FLAG) {
- USBHS_Dev_Endp0_Tog = 1;
+ USBHSD->INT_FG = (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)); /* Clear flag */
+ } else if (int_flag & USBHS_SETUP_FLAG) {
+ ep_set_response_and_toggle(0, TUSB_DIR_IN, EP_RESPONSE_NAK);
+ ep_set_response_and_toggle(0, TUSB_DIR_OUT, EP_RESPONSE_NAK);
+ dcd_event_setup_received(0, ep0_buffer, true);
- xfer_status[0][TUSB_DIR_OUT].max_size = 64;
- xfer_status[0][TUSB_DIR_IN].max_size = 64;
+ USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */
+ } else if (int_flag & USBHS_BUS_RST_FLAG) {
+ // TODO CH32 does not detect actual speed at this time (should be known at end of reset)
+ // This interrupt probably triggered at start of bus reset
+// tusb_speed_t actual_speed;
+// switch(USBHSD->SPEED_TYPE & USBHS_SPEED_TYPE_MASK){
+// case USBHS_SPEED_TYPE_HIGH:
+// actual_speed = TUSB_SPEED_HIGH;
+// break;
+// case USBHS_SPEED_TYPE_FULL:
+// actual_speed = TUSB_SPEED_FULL;
+// break;
+// case USBHS_SPEED_TYPE_LOW:
+// actual_speed = TUSB_SPEED_LOW;
+// break;
+// default:
+// TU_ASSERT(0,);
+// break;
+// }
+// dcd_event_bus_reset(0, actual_speed, true);
- dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true);
+ dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true);
- USBHSD->DEV_AD = 0;
- USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
+ USBHSD->DEV_AD = 0;
+ EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
+ EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
- USBHSD->INT_FG = USBHS_DETECT_FLAG; /* Clear flag */
- } else if (intflag & USBHS_SUSPEND_FLAG) {
- dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SUSPEND };
- dcd_event_handler(&event, true);
+ USBHSD->INT_FG = USBHS_BUS_RST_FLAG; /* Clear flag */
+ } else if (int_flag & USBHS_SUSPEND_FLAG) {
+ dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND};
+ dcd_event_handler(&event, true);
- USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */
- }
+ USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */
+ }
}
#endif