summaryrefslogtreecommitdiff
path: root/src/portable
diff options
context:
space:
mode:
authorMengsk <[email protected]>2022-11-07 12:47:41 +0100
committerMengsk <[email protected]>2022-11-07 12:47:41 +0100
commit9d3d8fd5b0788b811ad283d10d37dfd1b1005224 (patch)
treef66b39fe968cc1a6e46e3074bbda9b907064bc15 /src/portable
parent1eae139aa94130a63ecc4725852cb69c02566c82 (diff)
parente434a1dc0584e841da1ae4ff525bbe81a0f5514b (diff)
Merge branch 'master' of https://github.com/hathach/tinyusb into bsp_412
Diffstat (limited to 'src/portable')
-rw-r--r--src/portable/bridgetek/ft9xx/dcd_ft9xx.c1117
-rw-r--r--src/portable/broadcom/synopsys/dcd_synopsys.c1267
-rw-r--r--src/portable/broadcom/synopsys/synopsys_common.h1476
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_imxrt.h58
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h45
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_type.h144
-rw-r--r--src/portable/chipidea/ci_hs/dcd_ci_hs.c644
-rw-r--r--src/portable/chipidea/ci_hs/hcd_ci_hs.c94
-rw-r--r--src/portable/dialog/da146xx/dcd_da146xx.c27
-rw-r--r--src/portable/ehci/ehci.c58
-rw-r--r--src/portable/ehci/ehci.h4
-rw-r--r--src/portable/espressif/esp32sx/dcd_esp32sx.c27
-rw-r--r--src/portable/mentor/musb/dcd_musb.c25
-rw-r--r--src/portable/mentor/musb/hcd_musb.c881
-rw-r--r--src/portable/microchip/pic/dcd_pic.c786
-rw-r--r--src/portable/microchip/pic32mz/dcd_pic32mz.c753
-rw-r--r--src/portable/microchip/pic32mz/usbhs_registers.h931
-rw-r--r--src/portable/microchip/samd/dcd_samd.c29
-rw-r--r--src/portable/microchip/samg/dcd_samg.c8
-rw-r--r--src/portable/microchip/samx7x/dcd_samx7x.c10
-rw-r--r--src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c10
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c191
-rw-r--r--src/portable/nuvoton/nuc120/dcd_nuc120.c10
-rw-r--r--src/portable/nuvoton/nuc121/dcd_nuc121.c10
-rw-r--r--src/portable/nuvoton/nuc505/dcd_nuc505.c10
-rw-r--r--src/portable/nxp/khci/dcd_khci.c10
-rw-r--r--src/portable/nxp/khci/hcd_khci.c626
-rw-r--r--src/portable/nxp/lpc17_40/dcd_lpc17_40.c10
-rw-r--r--src/portable/nxp/lpc17_40/hcd_lpc17_40.c2
-rw-r--r--src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c117
-rw-r--r--src/portable/nxp/transdimension/dcd_transdimension.c24
-rw-r--r--src/portable/nxp/transdimension/hcd_transdimension.c10
-rw-r--r--src/portable/ohci/ohci.c15
-rw-r--r--src/portable/ohci/ohci.h9
-rw-r--r--src/portable/raspberrypi/pio_usb/dcd_pio_usb.c210
-rw-r--r--src/portable/raspberrypi/pio_usb/hcd_pio_usb.c225
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c94
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c271
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c32
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h23
-rw-r--r--src/portable/renesas/usba/dcd_usba.c18
-rw-r--r--src/portable/renesas/usba/hcd_usba.c875
-rw-r--r--src/portable/sony/cxd56/dcd_cxd56.c15
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c20
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h7
-rw-r--r--src/portable/st/synopsys/dcd_synopsys.c9
-rw-r--r--src/portable/sunxi/dcd_sunxi_musb.c1219
-rw-r--r--src/portable/sunxi/musb_def.h643
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c134
-rw-r--r--src/portable/synopsys/dwc2/dwc2_bcm.h16
-rw-r--r--src/portable/synopsys/dwc2/dwc2_efm32.h12
-rw-r--r--src/portable/synopsys/dwc2/dwc2_esp32.h8
-rw-r--r--src/portable/synopsys/dwc2/dwc2_gd32.h13
-rw-r--r--src/portable/synopsys/dwc2/dwc2_stm32.h59
-rw-r--r--src/portable/synopsys/dwc2/dwc2_type.h25
-rw-r--r--src/portable/synopsys/dwc2/dwc2_xmc.h15
-rw-r--r--src/portable/template/dcd_template.c8
-rw-r--r--src/portable/ti/msp430x5xx/dcd_msp430x5xx.c23
-rw-r--r--src/portable/valentyusb/eptri/dcd_eptri.c15
59 files changed, 10227 insertions, 3200 deletions
diff --git a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c
new file mode 100644
index 000000000..2445593fe
--- /dev/null
+++ b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c
@@ -0,0 +1,1117 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright 2021 Bridgetek Pte Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/*
+ * Contains code adapted from Bridgetek Pte Ltd via license terms stated
+ * in https://brtchip.com/BRTSourceCodeLicenseAgreement
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && \
+ (CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X)
+
+#include <stdint.h>
+#include <ft900.h>
+#include <registers/ft900_registers.h>
+
+#include "board.h"
+#include "bsp/board.h"
+
+#define USBD_USE_STREAMS
+
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+// Board code will determine the state of VBUS from USB host.
+extern int8_t board_ft90x_vbus(void);
+
+// Static array to store an incoming SETUP request for processing by tinyusb.
+static uint8_t _ft90x_setup_packet[8];
+
+struct ft90x_xfer_state
+{
+ volatile uint8_t valid; // Transfer is pending and total_size, remain_size, and buff_ptr are valid.
+ volatile int16_t total_size; // Total transfer size in bytes for this transfer.
+ volatile int16_t remain_size; // Total remaining in transfer.
+ volatile uint8_t *buff_ptr; // Pointer to buffer to transmit from or receive to.
+
+ uint8_t type; // Endpoint type. Of type USBD_ENDPOINT_TYPE from endpoint descriptor.
+ uint8_t dir; // Endpoint direction. TUSB_DIR_OUT or TUSB_DIR_IN. For control endpoint this is the current direction.
+ uint16_t buff_size; // Actual size of buffer RAM used by endpoint.
+ uint16_t size; // Max packet size for endpoint from endpoint descriptor.
+};
+// Endpoint description array for each endpoint.
+static struct ft90x_xfer_state ep_xfer[USBD_MAX_ENDPOINT_COUNT];
+// USB speed.
+static tusb_speed_t _speed;
+
+// Interrupt handlers.
+void _ft90x_usbd_ISR(void); // Interrupt handler for USB device.
+void ft90x_usbd_pm_ISR(void); // Interrupt handler for USB device for power management (called by board).
+
+// Internal functions forward declarations.
+static uint16_t _ft90x_edpt_xfer_out(uint8_t ep_number, uint8_t *buffer, uint16_t xfer_bytes);
+static uint16_t _ft90x_edpt_xfer_in(uint8_t ep_number, uint8_t *buffer, uint16_t xfer_bytes);
+static void _ft90x_reset_edpts(void);
+static inline void _ft90x_phy_enable(bool en);
+static void _ft90x_usb_speed(void);
+static void _dcd_ft90x_attach(void);
+static void _dcd_ft90x_detach(void) __attribute__((unused));
+static uint16_t _ft90x_dusb_in(uint8_t ep_number, const uint8_t *buffer, uint16_t length);
+static uint16_t _ft90x_dusb_out(uint8_t ep_number, uint8_t *buffer, uint16_t length);
+
+// Internal functions.
+
+// Manage an OUT transfer from the host.
+// This can be up-to the maximum packet size of the endpoint.
+// Continuation of a transfer beyond the maximum packet size is performed
+// by the interrupt handler.
+static uint16_t _ft90x_edpt_xfer_out(uint8_t ep_number, uint8_t *buffer, uint16_t xfer_bytes)
+{
+ //Note: this is called from only the interrupt handler when an OUT transfer is called.
+ uint16_t ep_size = ep_xfer[ep_number].size;
+ (void)ep_size;
+ if (xfer_bytes > ep_size)
+ {
+ xfer_bytes = ep_size;
+ }
+
+ // Wait until the endpoint has finished - it should be complete!
+ //while (!(USBD_EP_SR_REG(ep_number) & MASK_USBD_EPxSR_OPRDY))
+ //;
+
+ // Send the first packet of max packet size
+ xfer_bytes = _ft90x_dusb_out(ep_number, (uint8_t *)buffer, xfer_bytes);
+ if (ep_number == USBD_EP_0)
+ {
+ // Set flags to indicate data ready.
+ USBD_EP_SR_REG(USBD_EP_0) = (MASK_USBD_EP0SR_OPRDY);
+ }
+ else
+ {
+ USBD_EP_SR_REG(ep_number) = (MASK_USBD_EPxSR_OPRDY);
+ }
+
+ return xfer_bytes;
+}
+
+// Manage an IN transfer to the host.
+// This can be up-to the maximum packet size of the endpoint.
+// Continuation of a transfer beyond the maximum packet size is performed
+// by the interrupt handler.
+static uint16_t _ft90x_edpt_xfer_in(uint8_t ep_number, uint8_t *buffer, uint16_t xfer_bytes)
+{
+ //Note: this may be called from the interrupt handler or from normal code.
+ uint8_t end = 0;
+ uint16_t ep_size = ep_xfer[ep_number].size;
+ (void)ep_size;
+
+ if ((xfer_bytes == 0) || (xfer_bytes < ep_size))
+ {
+ end = 1;
+ }
+ else
+ {
+ xfer_bytes = ep_size;
+ }
+
+ if (ep_number == USBD_EP_0)
+ {
+ // An IN direction SETUP can be interrupted by an OUT packet.
+ // This will result in a STALL generated by the silicon.
+ while (USBD_EP_SR_REG(USBD_EP_0) & MASK_USBD_EP0SR_STALL)
+ {
+ // Clear the STALL and finish the transaction.
+ USBD_EP_SR_REG(USBD_EP_0) = (MASK_USBD_EP0SR_STALL);
+ }
+ }
+ else
+ {
+ uint8_t sr_reg;
+ // If there is data to transmit then wait until the IN buffer
+ // for the endpoint is empty.
+ do
+ {
+ sr_reg = USBD_EP_SR_REG(ep_number);
+ } while (sr_reg & MASK_USBD_EPxSR_INPRDY);
+
+ }
+
+ xfer_bytes = _ft90x_dusb_in(ep_number, (uint8_t *)buffer, xfer_bytes);
+
+ if (ep_number == USBD_EP_0)
+ {
+ if (end)
+ {
+ // Set flags to indicate data ready and transfer complete.
+ USBD_EP_SR_REG(USBD_EP_0) = MASK_USBD_EP0SR_INPRDY | MASK_USBD_EP0SR_DATAEND;
+ }
+ else
+ {
+ // Set flags to indicate data ready.
+ USBD_EP_SR_REG(USBD_EP_0) = (MASK_USBD_EP0SR_INPRDY);
+ }
+ }
+ else
+ {
+ // Set flags to indicate data ready.
+ USBD_EP_SR_REG(ep_number) = (MASK_USBD_EPxSR_INPRDY);
+ }
+
+ return xfer_bytes;
+}
+
+// Reset all non-control endpoints to a default state.
+// Control endpoint is always enabled and ready. All others disabled.
+static void _ft90x_reset_edpts(void)
+{
+ // Disable all endpoints and remove configuration values.
+ for (int i = 1; i < USBD_MAX_ENDPOINT_COUNT; i++)
+ {
+ // Clear settings.
+ tu_memclr(&ep_xfer[i], sizeof(struct ft90x_xfer_state));
+ // Disable hardware.
+ USBD_EP_CR_REG(i) = 0;
+ }
+
+ // Enable interrupts from USB device control.
+ USBD_REG(cmie) = MASK_USBD_CMIE_ALL;
+}
+
+// Enable or disable the USB PHY.
+static inline void _ft90x_phy_enable(bool en)
+{
+ if (en)
+ SYS->PMCFG_L |= MASK_SYS_PMCFG_DEV_PHY_EN;
+ else
+ SYS->PMCFG_L &= ~MASK_SYS_PMCFG_DEV_PHY_EN;
+}
+
+// Safely connect to the USB.
+static void _dcd_ft90x_attach(void)
+{
+ uint8_t reg;
+
+ CRITICAL_SECTION_BEGIN
+ // Disable device responses.
+ USBD_REG(faddr) = 0;
+
+ // Reset USB Device.
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_DEV_RESET_ALL;
+ // Disable device connect/disconnect/host reset detection.
+ SYS->PMCFG_H = MASK_SYS_PMCFG_DEV_DIS_DEV;
+ SYS->PMCFG_H = MASK_SYS_PMCFG_DEV_CONN_DEV;
+ SYS->PMCFG_L = SYS->PMCFG_L & (~MASK_SYS_PMCFG_DEV_DETECT_EN);
+
+ // Enable Chip USB device clock/PM configuration.
+ sys_enable(sys_device_usb_device);
+ CRITICAL_SECTION_END;
+
+ // Wait a short time to get started.
+ delayms(1);
+
+ CRITICAL_SECTION_BEGIN
+ // Turn off the device enable bit.
+#if BOARD_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED
+ USBD_REG(fctrl) = 0;
+#else // BOARD_TUD_MAX_SPEED == OPT_MODE_FULL_SPEED
+ //Set the full speed only bit if required.
+ USBD_REG(fctrl) = MASK_USBD_FCTRL_MODE_FS_ONLY;
+#endif // BOARD_TUD_MAX_SPEED
+
+ // Clear first reset and suspend interrupts.
+ do
+ {
+ reg = USBD_REG(cmif);
+ USBD_REG(cmif) = reg;
+ } while (reg);
+ // Clear any endpoint interrupts.
+ reg = USBD_REG(epif);
+ USBD_REG(epif) = reg;
+
+ // Disable all interrupts from USB device control before attaching interrupt.
+ USBD_REG(cmie) = 0;
+ CRITICAL_SECTION_END;
+
+ // Enable device connect/disconnect/host reset detection.
+ // Set device detect and remote wakeup enable interrupt enables.
+ SYS->PMCFG_L = SYS->PMCFG_L | MASK_SYS_PMCFG_DEV_DETECT_EN;
+
+#if defined(__FT930__)
+ // Setup VBUS detect
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_USB_VBUS_EN;
+#endif
+}
+
+// Gracefully disconnect from the USB.
+static void _dcd_ft90x_detach(void)
+{
+ // Disable device connect/disconnect/host reset detection.
+ SYS->PMCFG_L = SYS->PMCFG_L & (~MASK_SYS_PMCFG_DEV_DETECT_EN);
+
+#if defined(__FT930__)
+ // Disable VBUS detection.
+ SYS->MSC0CFG = SYS->MSC0CFG & (~MASK_SYS_MSC0CFG_USB_VBUS_EN);
+#endif
+ CRITICAL_SECTION_BEGIN
+ // Disable interrupts from USB.
+ USBD_REG(epie) = 0;
+ USBD_REG(cmie) = 0;
+ // Turn off the device enable bit.
+ USBD_REG(fctrl) = 0;
+ CRITICAL_SECTION_END;
+
+ delayms(1);
+
+ // Disable USB PHY
+ dcd_disconnect(BOARD_TUD_RHPORT);
+ delayms(1);
+
+ // Disable Chip USB device clock/PM configuration.
+ sys_disable(sys_device_usb_device);
+
+ // Reset USB Device... Needed for Back voltage D+ to be <400mV
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_DEV_RESET_ALL;
+
+ delayms(1);
+ // Set device detect and remote wakeup enable interrupt enables.
+ SYS->PMCFG_L = SYS->PMCFG_L | MASK_SYS_PMCFG_DEV_DETECT_EN;
+
+#if defined(__FT930__)
+ // Setup VBUS detect
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_USB_VBUS_EN;
+#endif
+}
+
+// Determine the speed of the USB to which we are connected.
+// Set the speed of the PHY accordingly.
+// High speed can be disabled through CFG_TUSB_RHPORT0_MODE or CFG_TUD_MAX_SPEED settings.
+static void _ft90x_usb_speed(void)
+{
+ uint8_t fctrl_val;
+
+ // If USB device function is already enabled then disable it.
+ if (USBD_REG(fctrl) & MASK_USBD_FCTRL_USB_DEV_EN) {
+ USBD_REG(fctrl) = (USBD_REG(fctrl) & (~MASK_USBD_FCTRL_USB_DEV_EN));
+ delayus(200);
+ }
+
+#if BOARD_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED
+
+ /* Detect high or full speed */
+ fctrl_val = MASK_USBD_FCTRL_USB_DEV_EN;
+#if defined(__FT900__)
+ if (!sys_check_ft900_revB())//if 90x series is rev C
+ {
+ fctrl_val |= MASK_USBD_FCTRL_IMP_PERF;
+ }
+#endif
+ USBD_REG(fctrl) = fctrl_val;
+
+#if defined(__FT930__)
+ delayus(200);
+
+ _speed = (SYS->MSC0CFG & MASK_SYS_MSC0CFG_HIGH_SPED_MODE) ?
+ TUSB_SPEED_HIGH : TUSB_SPEED_FULL;
+#else /* __FT930__ */
+ /* Detection by SOF */
+ while (!(USBD_REG(cmif) & MASK_USBD_CMIF_SOFIRQ));
+ USBD_REG(cmif) = MASK_USBD_CMIF_SOFIRQ;
+ delayus(125 + 5);
+ _speed = (USBD_REG(cmif) & MASK_USBD_CMIF_SOFIRQ) ?
+ TUSB_SPEED_HIGH : TUSB_SPEED_FULL;
+ dcd_event_bus_reset(BOARD_TUD_RHPORT, _speed, true);
+
+#endif /* !__FT930__ */
+
+#else // BOARD_TUD_MAX_SPEED == OPT_MODE_FULL_SPEED
+
+ /* User force set to full speed */
+ _speed = TUSB_SPEED_FULL;
+ fctrl_val =
+ MASK_USBD_FCTRL_USB_DEV_EN | MASK_USBD_FCTRL_MODE_FS_ONLY;
+#if defined(__FT900__)
+ if (!sys_check_ft900_revB())//if 90x series is rev C
+ {
+ fctrl_val |= MASK_USBD_FCTRL_IMP_PERF;
+ }
+#endif
+ USBD_REG(fctrl) = fctrl_val;
+ dcd_event_bus_reset(BOARD_TUD_RHPORT, _speed, true);
+ return;
+
+#endif // BOARD_TUD_MAX_SPEED
+}
+
+// Send a buffer to the USB IN FIFO.
+// When the macro USBD_USE_STREAMS is defined this will stream a buffer of data
+// to the FIFO using the most efficient MCU streamout combination.
+// If streaming is disabled then it will send each byte of the buffer in turn
+// to the FIFO. The is no reason to not stream.
+// The total number of bytes sent to the FIFO is returned.
+static uint16_t _ft90x_dusb_in(uint8_t ep_number, const uint8_t *buffer, uint16_t length)
+{
+ uint16_t bytes_read = 0;
+ uint16_t buff_size = length;
+
+#ifdef USBD_USE_STREAMS
+ volatile uint8_t *data_reg;
+
+ data_reg = (volatile uint8_t *)&(USBD->ep[ep_number].epxfifo);
+ if (buff_size)
+ {
+ if (((uint32_t)buffer) % 4 == 0)
+ {
+ uint16_t aligned = buff_size & (~3);
+ uint16_t left = buff_size & 3;
+
+ if (aligned)
+ {
+ __asm__ volatile("streamout.l %0,%1,%2"
+ :
+ : "r"(data_reg), "r"(buffer), "r"(aligned));
+ buffer += aligned;
+ }
+ if (left)
+ {
+ __asm__ volatile("streamout.b %0,%1,%2"
+ :
+ : "r"(data_reg), "r"(buffer), "r"(left));
+ }
+ }
+ else
+ {
+ __asm__ volatile("streamout.b %0,%1,%2"
+ :
+ : "r"(data_reg), "r"(buffer), "r"(buff_size));
+ }
+ bytes_read = buff_size;
+ }
+#else // USBD_USE_STREAMS
+
+ bytes_read = buff_size;
+ while (buff_size--)
+ {
+ USBD_EP_FIFO_REG(ep_number) = *buffer++;
+ };
+
+#endif // USBD_USE_STREAMS
+
+ return bytes_read;
+}
+
+// Receive a buffer from the USB OUT FIFO.
+// When the macro USBD_USE_STREAMS is defined this will stream from the FIFO
+// to a buffer of data using the most efficient MCU streamin combination.
+// If streaming is disabled then it will receive each byte from the FIFO in turn
+// to the buffer. The is no reason to not stream.
+// The total number of bytes received from the FIFO is returned.
+static uint16_t _ft90x_dusb_out(uint8_t ep_number, uint8_t *buffer, uint16_t length)
+{
+#ifdef USBD_USE_STREAMS
+ volatile uint8_t *data_reg;
+#endif // USBD_USE_STREAMS
+ uint16_t bytes_read = 0;
+ uint16_t buff_size = length;
+
+ if (length > 0)
+ {
+ if (ep_number == USBD_EP_0)
+ {
+ buff_size = USBD_EP_CNT_REG(USBD_EP_0);
+ }
+ else
+ {
+ if (USBD_EP_SR_REG(ep_number) & (MASK_USBD_EPxSR_OPRDY))
+ {
+ buff_size = USBD_EP_CNT_REG(ep_number);
+ }
+ }
+ }
+
+ // Only read as many bytes as we have space for.
+ if (buff_size > length)
+ buff_size = length;
+
+#ifdef USBD_USE_STREAMS
+ data_reg = (volatile uint8_t *)&(USBD->ep[ep_number].epxfifo);
+ if (buff_size)
+ {
+ if ((uint32_t)buffer % 4 == 0)
+ {
+ uint16_t aligned = buff_size & (~3);
+ uint16_t left = buff_size & 3;
+
+ if (aligned)
+ {
+ __asm__ volatile("streamin.l %0,%1,%2"
+ :
+ : "r"(buffer), "r"(data_reg), "r"(aligned));
+ buffer += aligned;
+ }
+ if (left)
+ {
+ __asm__ volatile("streamin.b %0,%1,%2"
+ :
+ : "r"(buffer), "r"(data_reg), "r"(left));
+ }
+ }
+ else
+ {
+ __asm__ volatile("streamin.b %0,%1,%2"
+ :
+ : "r"(buffer), "r"(data_reg), "r"(buff_size));
+ }
+ bytes_read = buff_size;
+ }
+#else // USBD_USE_STREAMS
+
+ bytes_read = buff_size;
+ while (buff_size--)
+ {
+ *buffer++ = USBD_EP_FIFO_REG(ep_number);
+ }
+
+#endif // USBD_USE_STREAMS
+
+ return bytes_read;
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+
+// Initialize controller to device mode
+void dcd_init(uint8_t rhport)
+{
+ TU_LOG2("FT90x initialisation\r\n");
+
+ _dcd_ft90x_attach();
+
+ interrupt_attach(interrupt_usb_device, (int8_t)interrupt_usb_device, _ft90x_usbd_ISR);
+
+ dcd_connect(rhport);
+}
+
+// Enable device interrupt
+void dcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ TU_LOG3("FT90x int enable\r\n");
+
+ // Peripheral devices interrupt enable.
+ interrupt_enable_globally();
+}
+
+// Disable device interrupt
+void dcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ TU_LOG3("FT90x int disable\r\n");
+
+ // Peripheral devices interrupt disable.
+ interrupt_disable_globally();
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ (void)dev_addr;
+
+ // Respond with status. There is no checking that the address is in range.
+ dcd_edpt_xfer(rhport, tu_edpt_addr(USBD_EP_0, TUSB_DIR_IN), NULL, 0);
+
+ // Set the update bit for the address register.
+ dev_addr |= 0x80;
+
+ // Modify the address register within a critical section.
+ CRITICAL_SECTION_BEGIN
+ {
+ USBD_REG(faddr) = dev_addr;
+ }
+ CRITICAL_SECTION_END;
+}
+
+// Invoked when a control transfer's status stage is complete.
+// May help DCD to prepare for next control transfer, this API is optional.
+#if 0 // never called
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
+{
+ (void) rhport;
+
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD )
+ {
+ if (request->bRequest == TUSB_REQ_SET_ADDRESS)
+ {
+ }
+ else if (request->bRequest == TUSB_REQ_SET_CONFIGURATION)
+ {
+ }
+ }
+}
+#endif // 0
+
+// Wake up host
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void)rhport;
+
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_DEV_RMWAKEUP;
+
+ // Atleast 2 ms of delay needed for RESUME Data K state.
+ delayms(2);
+
+ SYS->MSC0CFG &= ~MASK_SYS_MSC0CFG_DEV_RMWAKEUP;
+
+ // Enable USB PHY and determine current bus speed.
+ dcd_connect(rhport);
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ (void)rhport;
+ TU_LOG2("FT90x connect\r\n");
+
+ CRITICAL_SECTION_BEGIN
+ // Is device connected?
+ if (board_ft90x_vbus())
+ {
+ // Clear/disable address register.
+ USBD_REG(faddr) = 0;
+ _ft90x_phy_enable(true);
+
+ // Determine bus speed and signal speed to tusb.
+ _ft90x_usb_speed();
+ }
+
+ // Setup the control endpoint only.
+#if CFG_TUD_ENDPOINT0_SIZE == 64
+ USBD_EP_CR_REG(USBD_EP_0) = (USBD_EP0_MAX_SIZE_64 << BIT_USBD_EP0_MAX_SIZE);
+#elif CFG_TUD_ENDPOINT0_SIZE == 32
+ USBD_EP_CR_REG(USBD_EP_0) = (USBD_EP0_MAX_SIZE_32 << BIT_USBD_EP0_MAX_SIZE);
+#elif CFG_TUD_ENDPOINT0_SIZE == 16
+ USBD_EP_CR_REG(USBD_EP_0) = (USBD_EP0_MAX_SIZE_16 << BIT_USBD_EP0_MAX_SIZE);
+#elif CFG_TUD_ENDPOINT0_SIZE == 8
+ USBD_EP_CR_REG(USBD_EP_0) = (USBD_EP0_MAX_SIZE_8 << BIT_USBD_EP0_MAX_SIZE);
+#else
+#error "CFG_TUD_ENDPOINT0_SIZE must be defined with a value of 8, 16, 32 or 64."
+#endif
+ CRITICAL_SECTION_END;
+
+ // Configure the control endpoint.
+ ep_xfer[USBD_EP_0].size = CFG_TUD_ENDPOINT0_SIZE;
+ ep_xfer[USBD_EP_0].type = TUSB_XFER_CONTROL;
+
+ // Enable interrupts on EP0.
+ USBD_REG(epie) = (MASK_USBD_EPIE_EP0IE);
+
+ // Restore default endpoint state.
+ _ft90x_reset_edpts();
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ (void)rhport;
+ TU_LOG2("FT90x disconnect\r\n");
+
+ // Disable the USB PHY.
+ _ft90x_phy_enable(false);
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc)
+{
+ (void)rhport;
+ uint8_t const ep_number = tu_edpt_number(ep_desc->bEndpointAddress);
+ uint8_t const ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress);
+ uint8_t const ep_type = ep_desc->bmAttributes.xfer;
+ uint16_t const ep_size = tu_edpt_packet_size(ep_desc); // Mask size per packet, bits 10..0.
+ uint16_t ep_buff_size;
+ uint8_t ep_reg_size = USBD_EP_MAX_SIZE_8;
+ uint8_t ep_reg_data = 0;
+ int16_t total_ram;
+
+ TU_LOG2("FT90x endpoint open %d %c\r\n", ep_number, ep_dir?'I':'O');
+
+ // Check that the requested endpoint number is allowable.
+ if (ep_number >= USBD_MAX_ENDPOINT_COUNT)
+ {
+ TU_LOG1("FT90x endpoint not valid: requested %d max %d\r\n", ep_number, USBD_MAX_ENDPOINT_COUNT);
+ return false;
+ }
+
+ // Calculate the physical size of the endpoint as a power of 2. This may be more than
+ // the requested size.
+ while (ep_size > (8 * (1 << ep_reg_size)))
+ {
+ ep_reg_size++;
+ }
+ if (ep_reg_size > USBD_EP_MAX_SIZE_1024)
+ {
+ TU_LOG1("FT90x endpoint size not valid: requested %d max 1024\r\n", ep_size);
+ return false;
+ }
+ // Calculate actual amount of buffer RAM used by this endpoint. This may be more than the
+ // requested size.
+ ep_buff_size = 8 << ep_reg_size;
+
+ if (ep_number > 0)
+ {
+ // Set EP cmd parameters...
+ ep_reg_data |= (ep_reg_size << BIT_USBD_EP_MAX_SIZE);
+
+ if (ep_xfer[ep_number].type != USBD_EP_TYPE_DISABLED)
+ {
+ // This could be because an endpoint has been assigned with the same number.
+ // On FT90x, IN and OUT endpoints may not have the same number. e.g. There
+ // cannot been an 0x81 and 0x01 endpoint.
+ TU_LOG1("FT90x endpoint %d already assigned\r\n", ep_number);
+ return false;
+ }
+
+ // Check that there is enough buffer RAM to allocate to this new endpoint.
+ // Available buffer RAM depends on the device revision.
+ // The IN and OUT buffer RAM should be the same size.
+ if (ep_dir == USBD_DIR_IN)
+ total_ram = USBD_RAMTOTAL_IN;
+ else
+ total_ram = USBD_RAMTOTAL_OUT;
+ // Work out how much has been allocated to existing endpoints.
+ // The total RAM allocated shoudl alsyes be a positive number as this
+ // algorithm should not let it go below zero.
+ for (int i = 1; i < USBD_MAX_ENDPOINT_COUNT; i++)
+ {
+ if (ep_xfer[i].type != USBD_EP_TYPE_DISABLED)
+ {
+ if (ep_xfer[i].dir == ep_dir)
+ {
+ total_ram -= ep_xfer[i].buff_size;
+ }
+ }
+ }
+ // The control endpoint is taken into account as well.
+ total_ram -= ep_xfer[0].buff_size;
+ // Make sure we have enough space. The corner case is having zero bytes
+ // free which means that total_ram must be signed as zero bytes free is
+ // allowable.
+ if (total_ram < ep_buff_size)
+ {
+ TU_LOG1("FT90x insufficient buffer RAM for endpoint %d\r\n", ep_number);
+ return false;
+ }
+
+ // Set the type of this endpoint in the control register.
+ if (ep_type == USBD_EP_BULK)
+ ep_reg_data |= (USBD_EP_DIS_BULK << BIT_USBD_EP_CONTROL_DIS);
+ else if (ep_type == USBD_EP_INT)
+ ep_reg_data |= (USBD_EP_DIS_INT << BIT_USBD_EP_CONTROL_DIS);
+ else if (ep_type == USBD_EP_ISOC)
+ ep_reg_data |= (USBD_EP_DIS_ISO << BIT_USBD_EP_CONTROL_DIS);
+ // Set the direction of this endpoint in the control register.
+ if (ep_dir == USBD_DIR_IN)
+ ep_reg_data |= MASK_USBD_EPxCR_DIR;
+ // Do not perform double buffering.
+ //if (<double buffering flag> != USBD_DB_OFF)
+ //ep_reg_data |= MASK_USBD_EPxCR_DB;
+ // Set the control endpoint for this endpoint.
+ USBD_EP_CR_REG(ep_number) = ep_reg_data;
+ TU_LOG2("FT90x endpoint setting %x\r\n", ep_reg_data);
+ }
+ else
+ {
+ // Set the control register for endpoint zero.
+ USBD_EP_CR_REG(USBD_EP_0) = (ep_reg_size << BIT_USBD_EP0_MAX_SIZE);
+ }
+
+ // Store the endpoint characteristics for later reference.
+ ep_xfer[ep_number].dir = ep_dir;
+ ep_xfer[ep_number].type = ep_type;
+ ep_xfer[ep_number].size = ep_size;
+ ep_xfer[ep_number].buff_size = ep_buff_size;
+
+ CRITICAL_SECTION_BEGIN
+ // Clear register transaction continuation and signalling state.
+ ep_xfer[ep_number].valid = 0;
+ ep_xfer[ep_number].buff_ptr = NULL;
+ ep_xfer[ep_number].total_size = 0;
+ ep_xfer[ep_number].remain_size = 0;
+ CRITICAL_SECTION_END
+
+ return true;
+}
+
+// Close all endpoints.
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ (void)rhport;
+ // Reset the endpoint configurations.
+ _ft90x_reset_edpts();
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+ uint8_t ep_number = tu_edpt_number(ep_addr);
+ uint8_t dir = tu_edpt_dir(ep_addr);
+ uint16_t xfer_bytes;
+ bool status = false;
+
+ // We will attempt to transfer the buffer. If it is less than or equal to the endpoint
+ // maximum packet size then the whole buffer will be transferred. If it is larger then
+ // the interrupt handler will transfer the remainder.
+ // ep_xfer is used to tell the interrupt handler what to do.
+ // ep_xfer can be used at interrupt level to continue transfers.
+ CRITICAL_SECTION_BEGIN
+ // Transfer currently in progress.
+ if (ep_xfer[ep_number].valid == 0)
+ {
+ status = true;
+
+ ep_xfer[ep_number].total_size = total_bytes;
+ ep_xfer[ep_number].remain_size = total_bytes;
+ ep_xfer[ep_number].buff_ptr = buffer;
+ ep_xfer[ep_number].valid = 1;
+
+ if (ep_number == USBD_EP_0)
+ {
+ ep_xfer[USBD_EP_0].dir = dir;
+ }
+ else
+ {
+ // Enable the interrupt for this endpoint allowing the interrupt handler to report
+ // continue the transfer and signal completion.
+ USBD_REG(epie) = USBD_REG(epie) | (1 << ep_number);
+ }
+
+ if (dir == TUSB_DIR_IN)
+ {
+ // For IN transfers send the first packet as a starter. Interrupt handler to complete
+ // this if it is larger than one packet.
+ xfer_bytes = _ft90x_edpt_xfer_in(ep_number, buffer, total_bytes);
+
+ ep_xfer[ep_number].buff_ptr += xfer_bytes;
+ ep_xfer[ep_number].remain_size -= xfer_bytes;
+ }
+ }
+ CRITICAL_SECTION_END
+
+ return status;
+}
+
+// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes)
+{
+ (void)rhport;
+ (void)ep_addr;
+ (void)ff;
+ (void)total_bytes;
+ bool status = false;
+ return status;
+}
+
+// Stall endpoint (non-control endpoint)
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t ep_number = tu_edpt_number(ep_addr);
+ (void)rhport;
+
+ CRITICAL_SECTION_BEGIN
+ if (ep_number == USBD_EP_0)
+ {
+ USBD_EP_CR_REG(USBD_EP_0) = USBD_EP_CR_REG(USBD_EP_0) |
+ MASK_USBD_EP0CR_SDSTL;
+ }
+ else
+ {
+ USBD_EP_CR_REG(ep_number) = USBD_EP_CR_REG(ep_number) |
+ MASK_USBD_EPxCR_SDSTL;
+ USBD_EP_SR_REG(ep_number) = MASK_USBD_EPxSR_CLR_TOGGLE |
+ MASK_USBD_EPxSR_FIFO_FLUSH;
+ }
+ CRITICAL_SECTION_END
+}
+
+// Clear stall (non-control endpoint), data toggle is also reset to DATA0
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t ep_number = tu_edpt_number(ep_addr);
+ (void)rhport;
+
+ if (ep_number > USBD_EP_0)
+ {
+ CRITICAL_SECTION_BEGIN
+ USBD_EP_CR_REG(ep_number) = USBD_EP_CR_REG(ep_number) &
+ (~MASK_USBD_EPxCR_SDSTL);
+ USBD_EP_SR_REG(ep_number) = MASK_USBD_EPxSR_CLR_TOGGLE;
+
+ // Allow transfers to restart.
+ ep_xfer[ep_number].valid = 0;
+ ep_xfer[ep_number].remain_size = 0;
+ CRITICAL_SECTION_END
+ }
+}
+
+// Interrupt handling.
+
+void _ft90x_usbd_ISR(void)
+{
+ tud_int_handler(BOARD_TUD_RHPORT); // Resolves to dcd_int_handler().
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+ (void)rhport;
+
+ // Read the Common Interrupt Flag Register.
+ uint8_t cmif = USBD_REG(cmif);
+ // Read the Endpoint Interrupt Flag Register.
+#if defined(__FT930__)
+ // This is 16 bits on FT93x.
+ uint16_t epif = USBD_REG(epif);
+#else
+ // This is 8 bits on FT90x.
+ uint8_t epif = USBD_REG(epif);
+#endif
+
+ if (cmif & MASK_USBD_CMIF_ALL)
+ {
+ // Clear all CMIF bits.
+ USBD_REG(cmif) = MASK_USBD_CMIF_ALL;
+ if (cmif & MASK_USBD_CMIF_PHYIRQ) //Handle PHY interrupt
+ {
+ }
+ if (cmif & MASK_USBD_CMIF_PIDIRQ) //Handle PIDIRQ interrupt
+ {
+ }
+ if (cmif & MASK_USBD_CMIF_CRC16IRQ) //Handle CRC16IRQ interrupt
+ {
+ }
+ if (cmif & MASK_USBD_CMIF_CRC5IRQ) //Handle CRC5 interrupt
+ {
+ }
+ if (cmif & MASK_USBD_CMIF_RSTIRQ) //Handle Reset interrupt
+ {
+ // Reset endpoints to default state.
+ _ft90x_reset_edpts();
+ dcd_event_bus_reset(BOARD_TUD_RHPORT, _speed, true);
+ }
+ if (cmif & MASK_USBD_CMIF_SUSIRQ) //Handle Suspend interrupt
+ {
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_SUSPEND, true);
+ }
+ if (cmif & MASK_USBD_CMIF_RESIRQ) //Handle Resume interrupt
+ {
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_RESUME, true);
+ }
+ if (cmif & MASK_USBD_CMIF_SOFIRQ) //Handle SOF interrupt
+ {
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_SOF, true);
+ }
+ }
+ // Handle endpoint interrupts.
+ if (epif)
+ {
+ uint16_t xfer_bytes;
+
+ // Check for EP0 interrupts pending.
+ if (epif & MASK_USBD_EPIF_EP0IRQ)
+ {
+ // Clear interrupt register.
+ USBD_REG(epif) = MASK_USBD_EPIF_EP0IRQ;
+
+ // Test for an incoming SETUP request on the control endpoint.
+ if (USBD_EP_SR_REG(USBD_EP_0) & MASK_USBD_EP0SR_SETUP)
+ {
+ // If protocol STALL, End the STALL signalling.
+ if (USBD_EP_CR_REG(USBD_EP_0) & MASK_USBD_EP0CR_SDSTL)
+ {
+ // STALL end.
+ USBD_EP_CR_REG(USBD_EP_0) = USBD_EP_CR_REG(USBD_EP_0) &
+ (~MASK_USBD_EP0CR_SDSTL);
+ // Clear STALL send.
+ USBD_EP_SR_REG(USBD_EP_0) = MASK_USBD_EP0SR_STALL;
+ }
+
+ // Host has sent a SETUP packet. Recieve this into the setup packet store.
+ _ft90x_dusb_out(USBD_EP_0, (uint8_t *)_ft90x_setup_packet, sizeof(USB_device_request));
+
+ // Send the packet to tinyusb.
+ dcd_event_setup_received(BOARD_TUD_RHPORT, _ft90x_setup_packet, true);
+
+ // Clear the interrupt that signals a SETUP packet is received.
+ USBD_EP_SR_REG(USBD_EP_0) = (MASK_USBD_EP0SR_SETUP);
+
+ // Allow new transfers on the control endpoint.
+ ep_xfer[USBD_EP_0].valid = 0;
+ return;
+ }
+ else
+ {
+ // Check for a complete or partially complete transfers on EP0.
+ if (ep_xfer[USBD_EP_0].valid)
+ {
+ xfer_bytes = (uint16_t)ep_xfer[USBD_EP_0].total_size;
+
+ // Transfer incoming data from an OUT packet to the buffer supplied.
+ if (ep_xfer[USBD_EP_0].dir == TUSB_DIR_OUT)
+ {
+ xfer_bytes = _ft90x_edpt_xfer_out(USBD_EP_0, (uint8_t *)ep_xfer[USBD_EP_0].buff_ptr, xfer_bytes);
+ }
+ // Now signal completion of data packet.
+ dcd_event_xfer_complete(BOARD_TUD_RHPORT, (ep_xfer[USBD_EP_0].dir ? TUSB_DIR_IN_MASK : 0), xfer_bytes, XFER_RESULT_SUCCESS, true);
+
+ // Allow new transfers on the control endpoint.
+ ep_xfer[USBD_EP_0].valid = 0;
+ }
+ }
+ }
+ else // !(epif & MASK_USBD_EPIF_EP0IRQ)
+ {
+ // Mask out currently disabled endpoints.
+ epif &= USBD_REG(epie);
+
+ // Handle complete and partially complete transfers for each endpoint.
+ for (uint8_t ep_number = 1; ep_number < USBD_MAX_ENDPOINT_COUNT; ep_number++)
+ {
+ if ((epif & MASK_USBD_EPIF_IRQ(ep_number)) == 0)
+ {
+ // No pending interrupt for this endpoint.
+ continue;
+ }
+
+ if (ep_xfer[ep_number].valid)
+ {
+ xfer_bytes = 0;
+ uint8_t ep_dirmask = (ep_xfer[ep_number].dir ? TUSB_DIR_IN_MASK : 0);
+
+ // Clear interrupt register for this endpoint.
+ USBD_REG(epif) = MASK_USBD_EPIF_IRQ(ep_number);
+
+ // Start or continue an OUT transfer.
+ if (ep_xfer[ep_number].dir == TUSB_DIR_OUT)
+ {
+ xfer_bytes = _ft90x_edpt_xfer_out(ep_number,
+ (uint8_t *)ep_xfer[ep_number].buff_ptr,
+ (uint16_t)ep_xfer[ep_number].remain_size);
+
+ ep_xfer[ep_number].buff_ptr += xfer_bytes;
+ ep_xfer[ep_number].remain_size -= xfer_bytes;
+ }
+ // continue an IN transfer
+ else // if (ep_xfer[ep_number].dir == TUSB_DIR_IN)
+ {
+ if (ep_xfer[ep_number].remain_size > 0)
+ {
+ xfer_bytes = _ft90x_edpt_xfer_in(ep_number,
+ (uint8_t *)ep_xfer[ep_number].buff_ptr,
+ (uint16_t)ep_xfer[ep_number].remain_size);
+
+ ep_xfer[ep_number].buff_ptr += xfer_bytes;
+ ep_xfer[ep_number].remain_size -= xfer_bytes;
+ }
+ }
+
+ // When the transfer is complete...
+ if (ep_xfer[ep_number].remain_size == 0)
+ {
+ // Signal tinyUSB.
+ dcd_event_xfer_complete(BOARD_TUD_RHPORT, ep_number | ep_dirmask, ep_xfer[ep_number].total_size, XFER_RESULT_SUCCESS, true);
+
+ // Allow new transfers on this endpoint.
+ ep_xfer[ep_number].valid = 0;
+
+ // Disable the interrupt for this endpoint now it is complete.
+ USBD_REG(epie) = USBD_REG(epie) & (~(1 << ep_number));
+ }
+ }
+ }
+ }
+ }
+}
+
+// Power management interrupt handler.
+// This handles USB device related power management interrupts only.
+void ft90x_usbd_pm_ISR(void)
+{
+ uint16_t pmcfg = SYS->PMCFG_H;
+
+ // Main interrupt handler is responible for
+ if (pmcfg & MASK_SYS_PMCFG_DEV_CONN_DEV)
+ {
+ // Signal connection interrupt
+ SYS->PMCFG_H = MASK_SYS_PMCFG_PM_GPIO_IRQ_PEND;
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_RESUME, true);
+ }
+
+ if (pmcfg & MASK_SYS_PMCFG_DEV_DIS_DEV)
+ {
+ // Signal disconnection interrupt
+ SYS->PMCFG_H = MASK_SYS_PMCFG_PM_GPIO_IRQ_PEND;
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_UNPLUGGED, true);
+ }
+
+ if (pmcfg & MASK_SYS_PMCFG_HOST_RST_DEV)
+ {
+ // Signal Host Reset interrupt
+ SYS->PMCFG_H = MASK_SYS_PMCFG_PM_GPIO_IRQ_PEND;
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_BUS_RESET, true);
+ }
+
+ if (pmcfg & MASK_SYS_PMCFG_HOST_RESUME_DEV)
+ {
+ // Signal Host Resume interrupt
+ SYS->PMCFG_H = MASK_SYS_PMCFG_PM_GPIO_IRQ_PEND;
+ if (!(SYS->MSC0CFG & MASK_SYS_MSC0CFG_DEV_RMWAKEUP))
+ {
+ // If we are driving K-state on Device USB port;
+ // We must maintain the 1ms requirement before resuming the phy
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_RESUME, true);
+ }
+ }
+}
+
+#endif
diff --git a/src/portable/broadcom/synopsys/dcd_synopsys.c b/src/portable/broadcom/synopsys/dcd_synopsys.c
deleted file mode 100644
index 494bb70ee..000000000
--- a/src/portable/broadcom/synopsys/dcd_synopsys.c
+++ /dev/null
@@ -1,1267 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2018 Scott Shawcroft, 2019 William D. Jones for Adafruit Industries
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
- * Copyright (c) 2020 Jan Duempelmann
- * Copyright (c) 2020 Reinhard Panhuber
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-#include "tusb_option.h"
-
-#if TUSB_OPT_DEVICE_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_BCM2711 ) \
-
-
-#include "synopsys_common.h"
-
-#include "broadcom/interrupts.h"
-
-// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
-// We disable SOF for now until needed later on
-#define USE_SOF 0
-
-// EP_MAX : Max number of bi-directional endpoints including EP0
-// EP_FIFO_SIZE : Size of dedicated USB SRAM
-#if CFG_TUSB_MCU == OPT_MCU_BCM2711
-// #include "bcm2711.h"
-#define EP_MAX_FS 8
-#define EP_FIFO_SIZE_FS 4096
-#define EP_MAX_HS 8
-#define EP_FIFO_SIZE_HS 4096
-#else
-#error "Unsupported MCUs"
-#endif
-
-#define EP_MAX 8
-#define EP_FIFO_SIZE 4096
-
-// Info on values here: https://github.com/torvalds/linux/blob/79160a603bdb51916226caf4a6616cc4e1c58a58/Documentation/devicetree/bindings/usb/dwc2.yaml
-
-// From: https://github.com/raspberrypi/linux/blob/rpi-5.10.y/arch/arm/boot/dts/bcm283x.dtsi
-// usb: usb@7e980000 {
-// compatible = "brcm,bcm2835-usb";
-// reg = <0x7e980000 0x10000>;
-// interrupts = <1 9>;
-// #address-cells = <1>;
-// #size-cells = <0>;
-// clocks = <&clk_usb>;
-// clock-names = "otg";
-// phys = <&usbphy>;
-// phy-names = "usb2-phy";
-// };
-
-// From: https://github.com/raspberrypi/linux/blob/rpi-5.10.y/arch/arm/boot/dts/bcm283x-rpi-usb-otg.dtsi
-// SPDX-License-Identifier: GPL-2.0
-// &usb {
-// dr_mode = "otg";
-// g-rx-fifo-size = <256>;
-// g-np-tx-fifo-size = <32>;
-
-// * According to dwc2 the sum of all device EP
-// * fifo sizes shouldn't exceed 3776 bytes.
-
-// g-tx-fifo-size = <256 256 512 512 512 768 768>;
-// };
-
-// From: https://github.com/raspberrypi/linux/blob/rpi-5.10.y/arch/arm/boot/dts/bcm2711-rpi.dtsi
-// &usb {
-// /* Enable the FIQ support */
-// reg = <0x7e980000 0x10000>,
-// <0x7e00b200 0x200>;
-// interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
-// <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
-// status = "disabled";
-// };
-
-// From: https://github.com/raspberrypi/linux/blob/rpi-5.10.y/arch/arm/boot/dts/bcm2711.dtsi
-// &usb {
-// interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
-// };
-
-// From: https://github.com/torvalds/linux/blob/1d597682d3e669ec7021aa33d088ed3d136a5149/drivers/usb/dwc2/params.c
-// static void dwc2_set_bcm_params(struct dwc2_hsotg *hsotg)
-// {
-// struct dwc2_core_params *p = &hsotg->params;
-
-// p->host_rx_fifo_size = 774;
-// p->max_transfer_size = 65535;
-// p->max_packet_count = 511;
-// p->ahbcfg = 0x10;
-// }
-
-#include "device/dcd.h"
-
-TU_VERIFY_STATIC(sizeof(USB_OTG_GlobalTypeDef) == 0x140, "size is incorrect");
-
-//--------------------------------------------------------------------+
-// MACRO TYPEDEF CONSTANT ENUM
-//--------------------------------------------------------------------+
-
-#define RHPORT_REGS_BASE USB_OTG_GLOBAL_BASE
-
-#define GLOBAL_BASE(_port) ((USB_OTG_GlobalTypeDef*) RHPORT_REGS_BASE)
-#define DEVICE_BASE(_port) (USB_OTG_DeviceTypeDef *) (USB_OTG_DEVICE_BASE)
-#define OUT_EP_BASE(_port) (USB_OTG_OUTEndpointTypeDef *) (RHPORT_REGS_BASE + USB_OTG_OUT_ENDPOINT_BASE)
-#define IN_EP_BASE(_port) (USB_OTG_INEndpointTypeDef *) (RHPORT_REGS_BASE + USB_OTG_IN_ENDPOINT_BASE)
-#define FIFO_BASE(_port, _x) ((volatile uint32_t *) (RHPORT_REGS_BASE + USB_OTG_FIFO_BASE + (_x) * USB_OTG_FIFO_SIZE))
-
-enum
-{
- DCD_HIGH_SPEED = 0, // Highspeed mode
- DCD_FULL_SPEED_USE_HS = 1, // Full speed in Highspeed port (probably with internal PHY)
- DCD_FULL_SPEED = 3, // Full speed with internal PHY
-};
-
-static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2];
-
-typedef struct {
- uint8_t * buffer;
- tu_fifo_t * ff;
- uint16_t total_len;
- uint16_t max_size;
- uint8_t interval;
-} xfer_ctl_t;
-
-typedef volatile uint32_t * usb_fifo_t;
-
-xfer_ctl_t xfer_status[EP_MAX][2];
-#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
-
-// EP0 transfers are limited to 1 packet - larger sizes has to be split
-static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type
-
-// TX FIFO RAM allocation so far in words - RX FIFO size is readily available from usb_otg->GRXFSIZ
-static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs)
-static bool _out_ep_closed; // Flag to check if RX FIFO size needs an update (reduce its size)
-
-// Calculate the RX FIFO size according to recommendations from reference manual
-static inline uint16_t calc_rx_ff_size(uint16_t ep_size)
-{
- return 15 + 2*(ep_size/4) + 2*EP_MAX;
-}
-
-static void update_grxfsiz(uint8_t rhport)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
-
- // Determine largest EP size for RX FIFO
- uint16_t max_epsize = 0;
- for (uint8_t epnum = 0; epnum < EP_MAX; epnum++)
- {
- max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size);
- }
-
- // Update size of RX FIFO
- usb_otg->GRXFSIZ = calc_rx_ff_size(max_epsize);
-}
-
-// Setup the control endpoint 0.
-static void bus_reset(uint8_t rhport)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- tu_memclr(xfer_status, sizeof(xfer_status));
- _out_ep_closed = false;
-
- // clear device address
- dev->DCFG &= ~USB_OTG_DCFG_DAD_Msk;
-
- // 1. NAK for all OUT endpoints
- for(uint8_t n = 0; n < EP_MAX; n++) {
- out_ep[n].DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
- }
-
- // 2. Un-mask interrupt bits
- dev->DAINTMSK = (1 << USB_OTG_DAINTMSK_OEPM_Pos) | (1 << USB_OTG_DAINTMSK_IEPM_Pos);
- dev->DOEPMSK = USB_OTG_DOEPMSK_STUPM | USB_OTG_DOEPMSK_XFRCM;
- dev->DIEPMSK = USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM;
-
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // The FIFO is split up in a lower part where the RX FIFO is located and an upper part where the TX FIFOs start.
- // We do this to allow the RX FIFO to grow dynamically which is possible since the free space is located
- // between the RX and TX FIFOs. This is required by ISO OUT EPs which need a bigger FIFO than the standard
- // configuration done below.
- //
- // Dynamically FIFO sizes are of interest only for ISO EPs since all others are usually not opened and closed.
- // All EPs other than ISO are opened as soon as the driver starts up i.e. when the host sends a
- // configure interface command. Hence, all IN EPs other the ISO will be located at the top. IN ISO EPs are usually
- // opened when the host sends an additional command: setInterface. At this point in time
- // the ISO EP will be located next to the free space and can change its size. In case more IN EPs change its size
- // an additional memory
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO 0 |
- // --------------- (320 or 1024) - 16
- // | IN FIFO 1 |
- // --------------- (320 or 1024) - 16 - x
- // | . . . . |
- // --------------- (320 or 1024) - 16 - x - y - ... - z
- // | IN FIFO MAX |
- // ---------------
- // | FREE |
- // --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
- // --------------- 0
- //
- // According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits):
- // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN
- //
- // - All EP OUT shared a unique OUT FIFO which uses
- // - 13 for setup packets + control words (up to 3 setup packets).
- // - 1 for global NAK (not required/used here).
- // - Largest-EPsize / 4 + 1. ( FS: 64 bytes, HS: 512 bytes). Recommended is "2 x (Largest-EPsize/4) + 1"
- // - 2 for each used OUT endpoint
- //
- // Therefore GRXFSIZ = 13 + 1 + 1 + 2 x (Largest-EPsize/4) + 2 x EPOUTnum
- // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x EP_MAX = 47 + 2 x EP_MAX
- // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x EP_MAX = 271 + 2 x EP_MAX
- //
- // NOTE: Largest-EPsize & EPOUTnum is actual used endpoints in configuration. Since DCD has no knowledge
- // of the overall picture yet. We will use the worst scenario: largest possible + EP_MAX
- //
- // For Isochronous, largest EP size can be 1023/1024 for FS/HS respectively. In addition if multiple ISO
- // are enabled at least "2 x (Largest-EPsize/4) + 1" are recommended. Maybe provide a macro for application to
- // overwrite this.
-
- #if TUD_OPT_HIGH_SPEED
- usb_otg->GRXFSIZ = calc_rx_ff_size(512);
- #else
- usb_otg->GRXFSIZ = calc_rx_ff_size(64);
- #endif
-
- _allocated_fifo_words_tx = 16;
-
- // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
- usb_otg->DIEPTXF0_HNPTXFSIZ = (16 << USB_OTG_TX0FD_Pos) | (EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
-
- // Fixed control EP0 size to 64 bytes
- in_ep[0].DIEPCTL &= ~(0x03 << USB_OTG_DIEPCTL_MPSIZ_Pos);
- xfer_status[0][TUSB_DIR_OUT].max_size = xfer_status[0][TUSB_DIR_IN].max_size = 64;
-
- out_ep[0].DOEPTSIZ |= (3 << USB_OTG_DOEPTSIZ_STUPCNT_Pos);
-
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_OEPINT | USB_OTG_GINTMSK_IEPINT;
-}
-
-// Set turn-around timeout according to link speed
-extern uint32_t SystemCoreClock;
-static void set_turnaround(USB_OTG_GlobalTypeDef * usb_otg, tusb_speed_t speed)
-{
- usb_otg->GUSBCFG &= ~USB_OTG_GUSBCFG_TRDT;
-
- if ( speed == TUSB_SPEED_HIGH )
- {
- // Use fixed 0x09 for Highspeed
- usb_otg->GUSBCFG |= (0x09 << USB_OTG_GUSBCFG_TRDT_Pos);
- }
- else
- {
- // Turnaround timeout depends on the MCU clock
- uint32_t turnaround;
-
- if ( SystemCoreClock >= 32000000U )
- turnaround = 0x6U;
- else if ( SystemCoreClock >= 27500000U )
- turnaround = 0x7U;
- else if ( SystemCoreClock >= 24000000U )
- turnaround = 0x8U;
- else if ( SystemCoreClock >= 21800000U )
- turnaround = 0x9U;
- else if ( SystemCoreClock >= 20000000U )
- turnaround = 0xAU;
- else if ( SystemCoreClock >= 18500000U )
- turnaround = 0xBU;
- else if ( SystemCoreClock >= 17200000U )
- turnaround = 0xCU;
- else if ( SystemCoreClock >= 16000000U )
- turnaround = 0xDU;
- else if ( SystemCoreClock >= 15000000U )
- turnaround = 0xEU;
- else
- turnaround = 0xFU;
-
- // Fullspeed depends on MCU clocks, but we will use 0x06 for 32+ Mhz
- usb_otg->GUSBCFG |= (turnaround << USB_OTG_GUSBCFG_TRDT_Pos);
- }
-}
-
-static tusb_speed_t get_speed(uint8_t rhport)
-{
- (void) rhport;
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- uint32_t const enum_spd = (dev->DSTS & USB_OTG_DSTS_ENUMSPD_Msk) >> USB_OTG_DSTS_ENUMSPD_Pos;
- return (enum_spd == DCD_HIGH_SPEED) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL;
-}
-
-static void set_speed(uint8_t rhport, tusb_speed_t speed)
-{
- uint32_t bitvalue;
-
- if ( rhport == 1 )
- {
- bitvalue = ((TUSB_SPEED_HIGH == speed) ? DCD_HIGH_SPEED : DCD_FULL_SPEED_USE_HS);
- }
- else
- {
- bitvalue = DCD_FULL_SPEED;
- }
-
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
-
- // Clear and set speed bits
- dev->DCFG &= ~(3 << USB_OTG_DCFG_DSPD_Pos);
- dev->DCFG |= (bitvalue << USB_OTG_DCFG_DSPD_Pos);
-}
-
-#if 0
-// From CM4IO xtal to usb hub, may not be correct
-#define HSE_VALUE 24000000
-
-static bool USB_HS_PHYCInit(void)
-{
- USB_HS_PHYC_GlobalTypeDef *usb_hs_phyc = (USB_HS_PHYC_GlobalTypeDef*) USB_HS_PHYC_CONTROLLER_BASE;
-
- // Enable LDO
- usb_hs_phyc->USB_HS_PHYC_LDO |= USB_HS_PHYC_LDO_ENABLE;
-
- // Wait until LDO ready
- while ( 0 == (usb_hs_phyc->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_STATUS) ) {}
-
- uint32_t phyc_pll = 0;
-
- // TODO Try to get HSE_VALUE from registers instead of depending CFLAGS
- switch ( HSE_VALUE )
- {
- case 12000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12MHZ ; break;
- case 12500000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12_5MHZ ; break;
- case 16000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_16MHZ ; break;
- case 24000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_24MHZ ; break;
- case 25000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_25MHZ ; break;
- case 32000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_Msk ; break; // Value not defined in header
- default:
- TU_ASSERT(0);
- }
- usb_hs_phyc->USB_HS_PHYC_PLL = phyc_pll;
-
- // Control the tuning interface of the High Speed PHY
- // Use magic value (USB_HS_PHYC_TUNE_VALUE) from ST driver
- usb_hs_phyc->USB_HS_PHYC_TUNE |= 0x00000F13U;
-
- // Enable PLL internal PHY
- usb_hs_phyc->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN;
-
- // Original ST code has 2 ms delay for PLL stabilization.
- // Primitive test shows that more than 10 USB un/replug cycle showed no error with enumeration
-
- return true;
-}
-#endif
-
-static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, uint16_t total_bytes)
-{
- (void) rhport;
-
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- // EP0 is limited to one packet each xfer
- // We use multiple transaction of xfer->max_size length to get a whole transfer done
- if(epnum == 0) {
- xfer_ctl_t * const xfer = XFER_CTL_BASE(epnum, dir);
- total_bytes = tu_min16(ep0_pending[dir], xfer->max_size);
- ep0_pending[dir] -= total_bytes;
- }
-
- // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here.
- if(dir == TUSB_DIR_IN) {
- // A full IN transfer (multiple packets, possibly) triggers XFRC.
- in_ep[epnum].DIEPTSIZ = (num_packets << USB_OTG_DIEPTSIZ_PKTCNT_Pos) |
- ((total_bytes << USB_OTG_DIEPTSIZ_XFRSIZ_Pos) & USB_OTG_DIEPTSIZ_XFRSIZ_Msk);
-
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK;
- // For ISO endpoint set correct odd/even bit for next frame.
- if ((in_ep[epnum].DIEPCTL & USB_OTG_DIEPCTL_EPTYP) == USB_OTG_DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1)
- {
- // Take odd/even bit from frame counter.
- uint32_t const odd_frame_now = (dev->DSTS & (1u << USB_OTG_DSTS_FNSOF_Pos));
- in_ep[epnum].DIEPCTL |= (odd_frame_now ? USB_OTG_DIEPCTL_SD0PID_SEVNFRM_Msk : USB_OTG_DIEPCTL_SODDFRM_Msk);
- }
- // Enable fifo empty interrupt only if there are something to put in the fifo.
- if(total_bytes != 0) {
- dev->DIEPEMPMSK |= (1 << epnum);
- }
- } else {
- // A full OUT transfer (multiple packets, possibly) triggers XFRC.
- out_ep[epnum].DOEPTSIZ &= ~(USB_OTG_DOEPTSIZ_PKTCNT_Msk | USB_OTG_DOEPTSIZ_XFRSIZ);
- out_ep[epnum].DOEPTSIZ |= (num_packets << USB_OTG_DOEPTSIZ_PKTCNT_Pos) |
- ((total_bytes << USB_OTG_DOEPTSIZ_XFRSIZ_Pos) & USB_OTG_DOEPTSIZ_XFRSIZ_Msk);
-
- out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
- if ((out_ep[epnum].DOEPCTL & USB_OTG_DOEPCTL_EPTYP) == USB_OTG_DOEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1)
- {
- // Take odd/even bit from frame counter.
- uint32_t const odd_frame_now = (dev->DSTS & (1u << USB_OTG_DSTS_FNSOF_Pos));
- out_ep[epnum].DOEPCTL |= (odd_frame_now ? USB_OTG_DOEPCTL_SD0PID_SEVNFRM_Msk : USB_OTG_DOEPCTL_SODDFRM_Msk);
- }
- }
-}
-
-/*------------------------------------------------------------------*/
-/* Controller API
- *------------------------------------------------------------------*/
-
-TU_ATTR_UNUSED
-static void reset_core(USB_OTG_GlobalTypeDef * usb_otg) {
- while ((usb_otg->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0) {}
-
- TU_LOG(2, " resetting\r\n");
- usb_otg->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
- TU_LOG(2, " waiting\r\n");
- while ((usb_otg->GRSTCTL & (USB_OTG_GRSTCTL_AHBIDL | USB_OTG_GRSTCTL_CSRST)) != USB_OTG_GRSTCTL_AHBIDL) {}
- TU_LOG(2, " reset done\r\n");
-}
-
-void dcd_init (uint8_t rhport)
-{
- printf("test done\r\n");
- // Programming model begins in the last section of the chapter on the USB
- // peripheral in each Reference Manual.
- TU_LOG(2, " dcd_init\r\n");
-
- TU_LOG2("Test 123\r\n");
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
-
-#if 1
- // No VBUS sense
- usb_otg->GCCFG &= ~(1UL << 21); // USB_OTG_GCCFG_VBDEN
-
- // B-peripheral session valid override enable
- usb_otg->GOTGCTL |= (1UL << 6); // USB_OTG_GOTGCTL_BVALOEN
- usb_otg->GOTGCTL |= (1UL << 7); // USB_OTG_GOTGCTL_BVALOVAL
-
- // Force device mode
- usb_otg->GUSBCFG &= ~USB_OTG_GUSBCFG_FHMOD;
- usb_otg->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD;
-
- // deactivate internal PHY
- usb_otg->GCCFG &= ~USB_OTG_GCCFG_PWRDWN;
-
- // Init The UTMI Interface
- usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_TSDPS | USB_OTG_GUSBCFG_ULPIFSLS | USB_OTG_GUSBCFG_PHYSEL);
-
- // Select default internal VBUS Indicator and Drive for ULPI
- usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_ULPIEVBUSD | USB_OTG_GUSBCFG_ULPIEVBUSI);
-
- // Select UTMI Interface
- usb_otg->GUSBCFG &= ~(1UL << 4); // USB_OTG_GUSBCFG_ULPI_UTMI_SEL
- usb_otg->GCCFG |= (1UL << 32); // USB_OTG_GCCFG_PHYHSEN
-
- // Enables control of a High Speed USB PHY
- //USB_HS_PHYCInit();
-
- // Reset core after selecting PHY
- // Wait AHB IDLE, reset then wait until it is cleared
-// while ((usb_otg->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U) {}
-// usb_otg->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
-// while ((usb_otg->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST) {}
-
- reset_core(usb_otg);
-
- // Restart PHY clock
- *((volatile uint32_t *)(RHPORT_REGS_BASE + USB_OTG_PCGCCTL_BASE)) = 0;
-
-#else
-
- // ReadBackReg(&Core->Usb);
- // Core->Usb.UlpiDriveExternalVbus = 0;
- // Core->Usb.TsDlinePulseEnable = 0;
- // WriteThroughReg(&Core->Usb);
-
- // This sequence is modeled after: https://github.com/Chadderz121/csud/blob/e13b9355d043a9cdd384b335060f1bc0416df61e/source/hcd/dwc/designware20.c#L689
- usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_TSDPS | USB_OTG_GUSBCFG_ULPIEVBUSD);
- reset_core(usb_otg);
-
- // Core->Usb.ModeSelect = UTMI;
- // LOG_DEBUG("HCD: Interface: UTMI+.\n");
- // Core->Usb.PhyInterface = false;
-
- // HcdReset();
- TU_LOG2("init phy\r\n");
- usb_otg->GUSBCFG |= (1 << 4); // bit four sets UTMI+ mode
- usb_otg->GUSBCFG &= ~(1 << 3); // bit three disables phy interface
- reset_core(usb_otg);
-
- // LOG_DEBUG("HCD: ULPI FSLS configuration: disabled.\n");
- // Core->Usb.UlpiFsls = false;
- // Core->Usb.ulpi_clk_sus_m = false;
- usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_ULPIFSLS | USB_OTG_GUSBCFG_ULPICSM);
-
- // LOG_DEBUG("HCD: DMA configuration: enabled.\n");
- // Core->Ahb.DmaEnable = true;
- // Core->Ahb.DmaRemainderMode = Incremental;
- usb_otg->GAHBCFG &= ~(1 << 23); // Remainder mode
- usb_otg->GAHBCFG |= USB_OTG_GAHBCFG_DMAEN;
-
- // LOG_DEBUG("HCD: HNP/SRP configuration: HNP, SRP.\n");
- // Core->Usb.HnpCapable = true;
- // Core->Usb.SrpCapable = true;
- usb_otg->GUSBCFG |= USB_OTG_GUSBCFG_SRPCAP | USB_OTG_GUSBCFG_HNPCAP;
-
-#endif
-
- // Clear all interrupts
- usb_otg->GINTSTS |= usb_otg->GINTSTS;
-
- // Required as part of core initialization.
- // TODO: How should mode mismatch be handled? It will cause
- // the core to stop working/require reset.
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_OTGINT | USB_OTG_GINTMSK_MMISM;
-
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
-
- // If USB host misbehaves during status portion of control xfer
- // (non zero-length packet), send STALL back and discard.
- dev->DCFG |= USB_OTG_DCFG_NZLSOHSK;
-
- set_speed(rhport, TUSB_SPEED_HIGH);
-
- // TODO internal phy (full speed)
- usb_otg->GCCFG |= USB_OTG_GCCFG_PWRDWN;
-
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_USBRST | USB_OTG_GINTMSK_ENUMDNEM |
- USB_OTG_GINTMSK_USBSUSPM | USB_OTG_GINTMSK_WUIM |
- USB_OTG_GINTMSK_RXFLVLM | (USE_SOF ? USB_OTG_GINTMSK_SOFM : 0);
-
- // Enable global interrupt
- usb_otg->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
-
- dcd_connect(rhport);
-}
-
-void dcd_int_enable (uint8_t rhport)
-{
- (void) rhport;
- BP_EnableIRQ(USB_IRQn);
-}
-
-void dcd_int_disable (uint8_t rhport)
-{
- (void) rhport;
- BP_DisableIRQ(USB_IRQn);
-}
-
-void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
-{
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- dev->DCFG = (dev->DCFG & ~USB_OTG_DCFG_DAD_Msk) | (dev_addr << USB_OTG_DCFG_DAD_Pos);
-
- // Response with status after changing device address
- dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
-}
-
-static void remote_wakeup_delay(void)
-{
- // try to delay for 1 ms
- uint32_t count = SystemCoreClock / 1000;
- while ( count-- )
- {
- // __NOP();
- }
-}
-
-void dcd_remote_wakeup(uint8_t rhport)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
-
- // set remote wakeup
- dev->DCTL |= USB_OTG_DCTL_RWUSIG;
-
- // enable SOF to detect bus resume
- usb_otg->GINTSTS = USB_OTG_GINTSTS_SOF;
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_SOFM;
-
- // Per specs: remote wakeup signal bit must be clear within 1-15ms
- remote_wakeup_delay();
-
- dev->DCTL &= ~USB_OTG_DCTL_RWUSIG;
-}
-
-void dcd_connect(uint8_t rhport)
-{
- (void) rhport;
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- dev->DCTL &= ~USB_OTG_DCTL_SDIS;
-}
-
-void dcd_disconnect(uint8_t rhport)
-{
- (void) rhport;
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- dev->DCTL |= USB_OTG_DCTL_SDIS;
-}
-
-
-/*------------------------------------------------------------------*/
-/* DCD Endpoint port
- *------------------------------------------------------------------*/
-
-bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
-
- TU_ASSERT(epnum < EP_MAX);
-
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->max_size = tu_edpt_packet_size(desc_edpt);
- xfer->interval = desc_edpt->bInterval;
-
- uint16_t const fifo_size = (xfer->max_size + 3) / 4; // Round up to next full word
-
- if(dir == TUSB_DIR_OUT)
- {
- // Calculate required size of RX FIFO
- uint16_t const sz = calc_rx_ff_size(4*fifo_size);
-
- // If size_rx needs to be extended check if possible and if so enlarge it
- if (usb_otg->GRXFSIZ < sz)
- {
- TU_ASSERT(sz + _allocated_fifo_words_tx <= EP_FIFO_SIZE/4);
-
- // Enlarge RX FIFO
- usb_otg->GRXFSIZ = sz;
- }
-
- out_ep[epnum].DOEPCTL |= (1 << USB_OTG_DOEPCTL_USBAEP_Pos) |
- (desc_edpt->bmAttributes.xfer << USB_OTG_DOEPCTL_EPTYP_Pos) |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_OTG_DOEPCTL_SD0PID_SEVNFRM : 0) |
- (xfer->max_size << USB_OTG_DOEPCTL_MPSIZ_Pos);
-
- dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_OEPM_Pos + epnum));
- }
- else
- {
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO 0 |
- // --------------- (320 or 1024) - 16
- // | IN FIFO 1 |
- // --------------- (320 or 1024) - 16 - x
- // | . . . . |
- // --------------- (320 or 1024) - 16 - x - y - ... - z
- // | IN FIFO MAX |
- // ---------------
- // | FREE |
- // --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
- // --------------- 0
- //
- // In FIFO is allocated by following rules:
- // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
-
- // Check if free space is available
- TU_ASSERT(_allocated_fifo_words_tx + fifo_size + usb_otg->GRXFSIZ <= EP_FIFO_SIZE/4);
-
- _allocated_fifo_words_tx += fifo_size;
-
- TU_LOG(2, " Allocated %u bytes at offset %u", fifo_size*4, EP_FIFO_SIZE-_allocated_fifo_words_tx*4);
-
- // DIEPTXF starts at FIFO #1.
- // Both TXFD and TXSA are in unit of 32-bit words.
- usb_otg->DIEPTXF[epnum - 1] = (fifo_size << USB_OTG_DIEPTXF_INEPTXFD_Pos) | (EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
-
- in_ep[epnum].DIEPCTL |= (1 << USB_OTG_DIEPCTL_USBAEP_Pos) |
- (epnum << USB_OTG_DIEPCTL_TXFNUM_Pos) |
- (desc_edpt->bmAttributes.xfer << USB_OTG_DIEPCTL_EPTYP_Pos) |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_OTG_DIEPCTL_SD0PID_SEVNFRM : 0) |
- (xfer->max_size << USB_OTG_DIEPCTL_MPSIZ_Pos);
-
- dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_IEPM_Pos + epnum));
- }
-
- return true;
-}
-
-// Close all non-control endpoints, cancel all pending transfers if any.
-void dcd_edpt_close_all (uint8_t rhport)
-{
- (void) rhport;
-
-// USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- // Disable non-control interrupt
- dev->DAINTMSK = (1 << USB_OTG_DAINTMSK_OEPM_Pos) | (1 << USB_OTG_DAINTMSK_IEPM_Pos);
-
- for(uint8_t n = 1; n < EP_MAX; n++)
- {
- // disable OUT endpoint
- out_ep[n].DOEPCTL = 0;
- xfer_status[n][TUSB_DIR_OUT].max_size = 0;
-
- // disable IN endpoint
- in_ep[n].DIEPCTL = 0;
- xfer_status[n][TUSB_DIR_IN].max_size = 0;
- }
-
- // reset allocated fifo IN
- _allocated_fifo_words_tx = 16;
-}
-
-bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = buffer;
- xfer->ff = NULL;
- xfer->total_len = total_bytes;
-
- // EP0 can only handle one packet
- if(epnum == 0) {
- ep0_pending[dir] = total_bytes;
- // Schedule the first transaction for EP0 transfer
- edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]);
- return true;
- }
-
- uint16_t num_packets = (total_bytes / xfer->max_size);
- uint16_t const short_packet_size = total_bytes % xfer->max_size;
-
- // Zero-size packet is special case.
- if(short_packet_size > 0 || (total_bytes == 0)) {
- num_packets++;
- }
-
- // Schedule packets to be sent within interrupt
- edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes);
-
- return true;
-}
-
-// The number of bytes has to be given explicitly to allow more flexible control of how many
-// bytes should be written and second to keep the return value free to give back a boolean
-// success message. If total_bytes is too big, the FIFO will copy only what is available
-// into the USB buffer!
-bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
-{
- // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
- TU_ASSERT(ff->item_size == 1);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = NULL;
- xfer->ff = ff;
- xfer->total_len = total_bytes;
-
- uint16_t num_packets = (total_bytes / xfer->max_size);
- uint16_t const short_packet_size = total_bytes % xfer->max_size;
-
- // Zero-size packet is special case.
- if(short_packet_size > 0 || (total_bytes == 0)) num_packets++;
-
- // Schedule packets to be sent within interrupt
- edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes);
-
- return true;
-}
-
-static void dcd_edpt_disable (uint8_t rhport, uint8_t ep_addr, bool stall)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if(dir == TUSB_DIR_IN) {
- // Only disable currently enabled non-control endpoint
- if ( (epnum == 0) || !(in_ep[epnum].DIEPCTL & USB_OTG_DIEPCTL_EPENA) ){
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_SNAK | (stall ? USB_OTG_DIEPCTL_STALL : 0);
- } else {
- // Stop transmitting packets and NAK IN xfers.
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_SNAK;
- while((in_ep[epnum].DIEPINT & USB_OTG_DIEPINT_INEPNE) == 0);
-
- // Disable the endpoint.
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_EPDIS | (stall ? USB_OTG_DIEPCTL_STALL : 0);
- while((in_ep[epnum].DIEPINT & USB_OTG_DIEPINT_EPDISD_Msk) == 0);
- in_ep[epnum].DIEPINT = USB_OTG_DIEPINT_EPDISD;
- }
-
- // Flush the FIFO, and wait until we have confirmed it cleared.
- usb_otg->GRSTCTL |= (epnum << USB_OTG_GRSTCTL_TXFNUM_Pos);
- usb_otg->GRSTCTL |= USB_OTG_GRSTCTL_TXFFLSH;
- while((usb_otg->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH_Msk) != 0);
- } else {
- // Only disable currently enabled non-control endpoint
- if ( (epnum == 0) || !(out_ep[epnum].DOEPCTL & USB_OTG_DOEPCTL_EPENA) ){
- out_ep[epnum].DOEPCTL |= stall ? USB_OTG_DOEPCTL_STALL : 0;
- } else {
- // Asserting GONAK is required to STALL an OUT endpoint.
- // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt
- // anyway, and it can't be cleared by user code. If this while loop never
- // finishes, we have bigger problems than just the stack.
- dev->DCTL |= USB_OTG_DCTL_SGONAK;
- while((usb_otg->GINTSTS & USB_OTG_GINTSTS_BOUTNAKEFF_Msk) == 0);
-
- // Ditto here- disable the endpoint.
- out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_EPDIS | (stall ? USB_OTG_DOEPCTL_STALL : 0);
- while((out_ep[epnum].DOEPINT & USB_OTG_DOEPINT_EPDISD_Msk) == 0);
- out_ep[epnum].DOEPINT = USB_OTG_DOEPINT_EPDISD;
-
- // Allow other OUT endpoints to keep receiving.
- dev->DCTL |= USB_OTG_DCTL_CGONAK;
- }
- }
-}
-
-/**
- * Close an endpoint.
- */
-void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
-{
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- dcd_edpt_disable(rhport, ep_addr, false);
-
- // Update max_size
- xfer_status[epnum][dir].max_size = 0; // max_size = 0 marks a disabled EP - required for changing FIFO allocation
-
- if (dir == TUSB_DIR_IN)
- {
- uint16_t const fifo_size = (usb_otg->DIEPTXF[epnum - 1] & USB_OTG_DIEPTXF_INEPTXFD_Msk) >> USB_OTG_DIEPTXF_INEPTXFD_Pos;
- uint16_t const fifo_start = (usb_otg->DIEPTXF[epnum - 1] & USB_OTG_DIEPTXF_INEPTXSA_Msk) >> USB_OTG_DIEPTXF_INEPTXSA_Pos;
- // For now only the last opened endpoint can be closed without fuss.
- TU_ASSERT(fifo_start == EP_FIFO_SIZE/4 - _allocated_fifo_words_tx,);
- _allocated_fifo_words_tx -= fifo_size;
- }
- else
- {
- _out_ep_closed = true; // Set flag such that RX FIFO gets reduced in size once RX FIFO is empty
- }
-}
-
-void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
-{
- dcd_edpt_disable(rhport, ep_addr, true);
-}
-
-void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
-{
- (void) rhport;
-
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- // Clear stall and reset data toggle
- if(dir == TUSB_DIR_IN) {
- in_ep[epnum].DIEPCTL &= ~USB_OTG_DIEPCTL_STALL;
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_SD0PID_SEVNFRM;
- } else {
- out_ep[epnum].DOEPCTL &= ~USB_OTG_DOEPCTL_STALL;
- out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_SD0PID_SEVNFRM;
- }
-}
-
-/*------------------------------------------------------------------*/
-
-// Read a single data packet from receive FIFO
-static void read_fifo_packet(uint8_t rhport, uint8_t * dst, uint16_t len)
-{
- (void) rhport;
-
- usb_fifo_t rx_fifo = FIFO_BASE(rhport, 0);
-
- // Reading full available 32 bit words from fifo
- uint16_t full_words = len >> 2;
- for(uint16_t i = 0; i < full_words; i++) {
- uint32_t tmp = *rx_fifo;
- dst[0] = tmp & 0x000000FF;
- dst[1] = (tmp & 0x0000FF00) >> 8;
- dst[2] = (tmp & 0x00FF0000) >> 16;
- dst[3] = (tmp & 0xFF000000) >> 24;
- dst += 4;
- }
-
- // Read the remaining 1-3 bytes from fifo
- uint8_t bytes_rem = len & 0x03;
- if(bytes_rem != 0) {
- uint32_t tmp = *rx_fifo;
- dst[0] = tmp & 0x000000FF;
- if(bytes_rem > 1) {
- dst[1] = (tmp & 0x0000FF00) >> 8;
- }
- if(bytes_rem > 2) {
- dst[2] = (tmp & 0x00FF0000) >> 16;
- }
- }
-}
-
-// Write a single data packet to EPIN FIFO
-static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t * src, uint16_t len)
-{
- (void) rhport;
-
- usb_fifo_t tx_fifo = FIFO_BASE(rhport, fifo_num);
-
- // Pushing full available 32 bit words to fifo
- uint16_t full_words = len >> 2;
- for(uint16_t i = 0; i < full_words; i++){
- *tx_fifo = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
- src += 4;
- }
-
- // Write the remaining 1-3 bytes into fifo
- uint8_t bytes_rem = len & 0x03;
- if(bytes_rem){
- uint32_t tmp_word = 0;
- tmp_word |= src[0];
- if(bytes_rem > 1){
- tmp_word |= src[1] << 8;
- }
- if(bytes_rem > 2){
- tmp_word |= src[2] << 16;
- }
- *tx_fifo = tmp_word;
- }
-}
-
-static void handle_rxflvl_ints(uint8_t rhport, USB_OTG_OUTEndpointTypeDef * out_ep) {
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- usb_fifo_t rx_fifo = FIFO_BASE(rhport, 0);
-
- // Pop control word off FIFO
- uint32_t ctl_word = usb_otg->GRXSTSP;
- uint8_t pktsts = (ctl_word & USB_OTG_GRXSTSP_PKTSTS_Msk) >> USB_OTG_GRXSTSP_PKTSTS_Pos;
- uint8_t epnum = (ctl_word & USB_OTG_GRXSTSP_EPNUM_Msk) >> USB_OTG_GRXSTSP_EPNUM_Pos;
- uint16_t bcnt = (ctl_word & USB_OTG_GRXSTSP_BCNT_Msk) >> USB_OTG_GRXSTSP_BCNT_Pos;
-
- switch(pktsts) {
- case 0x01: // Global OUT NAK (Interrupt)
- break;
-
- case 0x02: // Out packet recvd
- {
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
-
- // Read packet off RxFIFO
- if (xfer->ff)
- {
- // Ring buffer
- tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *)(uintptr_t) rx_fifo, bcnt);
- }
- else
- {
- // Linear buffer
- read_fifo_packet(rhport, xfer->buffer, bcnt);
-
- // Increment pointer to xfer data
- xfer->buffer += bcnt;
- }
-
- // Truncate transfer length in case of short packet
- if(bcnt < xfer->max_size) {
- xfer->total_len -= (out_ep[epnum].DOEPTSIZ & USB_OTG_DOEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DOEPTSIZ_XFRSIZ_Pos;
- if(epnum == 0) {
- xfer->total_len -= ep0_pending[TUSB_DIR_OUT];
- ep0_pending[TUSB_DIR_OUT] = 0;
- }
- }
- }
- break;
-
- case 0x03: // Out packet done (Interrupt)
- break;
-
- case 0x04: // Setup packet done (Interrupt)
- out_ep[epnum].DOEPTSIZ |= (3 << USB_OTG_DOEPTSIZ_STUPCNT_Pos);
- break;
-
- case 0x06: // Setup packet recvd
- // We can receive up to three setup packets in succession, but
- // only the last one is valid.
- _setup_packet[0] = (* rx_fifo);
- _setup_packet[1] = (* rx_fifo);
- break;
-
- default: // Invalid
- TU_BREAKPOINT();
- break;
- }
-}
-
-static void handle_epout_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OTG_OUTEndpointTypeDef * out_ep) {
- // DAINT for a given EP clears when DOEPINTx is cleared.
- // OEPINT will be cleared when DAINT's out bits are cleared.
- for(uint8_t n = 0; n < EP_MAX; n++) {
- xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
-
- if(dev->DAINT & (1 << (USB_OTG_DAINT_OEPINT_Pos + n))) {
- // SETUP packet Setup Phase done.
- if(out_ep[n].DOEPINT & USB_OTG_DOEPINT_STUP) {
- out_ep[n].DOEPINT = USB_OTG_DOEPINT_STUP;
- dcd_event_setup_received(rhport, (uint8_t*) &_setup_packet[0], true);
- }
-
- // OUT XFER complete
- if(out_ep[n].DOEPINT & USB_OTG_DOEPINT_XFRC) {
- out_ep[n].DOEPINT = USB_OTG_DOEPINT_XFRC;
-
- // EP0 can only handle one packet
- if((n == 0) && ep0_pending[TUSB_DIR_OUT]) {
- // Schedule another packet to be received.
- edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]);
- } else {
- dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true);
- }
- }
- }
- }
-}
-
-static void handle_epin_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointTypeDef * in_ep) {
- // DAINT for a given EP clears when DIEPINTx is cleared.
- // IEPINT will be cleared when DAINT's out bits are cleared.
- for ( uint8_t n = 0; n < EP_MAX; n++ )
- {
- xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
-
- if ( dev->DAINT & (1 << (USB_OTG_DAINT_IEPINT_Pos + n)) )
- {
- // IN XFER complete (entire xfer).
- if ( in_ep[n].DIEPINT & USB_OTG_DIEPINT_XFRC )
- {
- in_ep[n].DIEPINT = USB_OTG_DIEPINT_XFRC;
-
- // EP0 can only handle one packet
- if((n == 0) && ep0_pending[TUSB_DIR_IN]) {
- // Schedule another packet to be transmitted.
- edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]);
- } else {
- dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
- }
- }
-
- // XFER FIFO empty
- if ( (in_ep[n].DIEPINT & USB_OTG_DIEPINT_TXFE) && (dev->DIEPEMPMSK & (1 << n)) )
- {
- // DIEPINT's TXFE bit is read-only, software cannot clear it.
- // It will only be cleared by hardware when written bytes is more than
- // - 64 bytes or
- // - Half of TX FIFO size (configured by DIEPTXF)
-
- uint16_t remaining_packets = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_PKTCNT_Msk) >> USB_OTG_DIEPTSIZ_PKTCNT_Pos;
-
- // Process every single packet (only whole packets can be written to fifo)
- for(uint16_t i = 0; i < remaining_packets; i++)
- {
- uint16_t const remaining_bytes = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos;
-
- // Packet can not be larger than ep max size
- uint16_t const packet_size = tu_min16(remaining_bytes, xfer->max_size);
-
- // It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current
- // EP has to be checked if the buffer can take another WHOLE packet
- if(packet_size > ((in_ep[n].DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV_Msk) << 2)) break;
-
- // Push packet to Tx-FIFO
- if (xfer->ff)
- {
- usb_fifo_t tx_fifo = FIFO_BASE(rhport, n);
- tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *)(uintptr_t) tx_fifo, packet_size);
- }
- else
- {
- write_fifo_packet(rhport, n, xfer->buffer, packet_size);
-
- // Increment pointer to xfer data
- xfer->buffer += packet_size;
- }
- }
-
- // Turn off TXFE if all bytes are written.
- if (((in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos) == 0)
- {
- dev->DIEPEMPMSK &= ~(1 << n);
- }
- }
- }
- }
-}
-
-void dcd_int_handler(uint8_t rhport)
-{
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- uint32_t const int_status = usb_otg->GINTSTS & usb_otg->GINTMSK;
-
- if(int_status & USB_OTG_GINTSTS_USBRST)
- {
- // USBRST is start of reset.
- usb_otg->GINTSTS = USB_OTG_GINTSTS_USBRST;
- bus_reset(rhport);
- }
-
- if(int_status & USB_OTG_GINTSTS_ENUMDNE)
- {
- // ENUMDNE is the end of reset where speed of the link is detected
-
- usb_otg->GINTSTS = USB_OTG_GINTSTS_ENUMDNE;
-
- tusb_speed_t const speed = get_speed(rhport);
-
- set_turnaround(usb_otg, speed);
- dcd_event_bus_reset(rhport, speed, true);
- }
-
- if(int_status & USB_OTG_GINTSTS_USBSUSP)
- {
- usb_otg->GINTSTS = USB_OTG_GINTSTS_USBSUSP;
- dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
- }
-
- if(int_status & USB_OTG_GINTSTS_WKUINT)
- {
- usb_otg->GINTSTS = USB_OTG_GINTSTS_WKUINT;
- dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
- }
-
- // TODO check USB_OTG_GINTSTS_DISCINT for disconnect detection
- // if(int_status & USB_OTG_GINTSTS_DISCINT)
-
- if(int_status & USB_OTG_GINTSTS_OTGINT)
- {
- // OTG INT bit is read-only
- uint32_t const otg_int = usb_otg->GOTGINT;
-
- if (otg_int & USB_OTG_GOTGINT_SEDET)
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
- }
-
- usb_otg->GOTGINT = otg_int;
- }
-
- if(int_status & USB_OTG_GINTSTS_SOF)
- {
- usb_otg->GINTSTS = USB_OTG_GINTSTS_SOF;
-
- // Disable SOF interrupt since currently only used for remote wakeup detection
- usb_otg->GINTMSK &= ~USB_OTG_GINTMSK_SOFM;
-
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
- }
-
- // RxFIFO non-empty interrupt handling.
- if(int_status & USB_OTG_GINTSTS_RXFLVL)
- {
- // RXFLVL bit is read-only
-
- // Mask out RXFLVL while reading data from FIFO
- usb_otg->GINTMSK &= ~USB_OTG_GINTMSK_RXFLVLM;
-
- // Loop until all available packets were handled
- do
- {
- handle_rxflvl_ints(rhport, out_ep);
- } while(usb_otg->GINTSTS & USB_OTG_GINTSTS_RXFLVL);
-
- // Manage RX FIFO size
- if (_out_ep_closed)
- {
- update_grxfsiz(rhport);
-
- // Disable flag
- _out_ep_closed = false;
- }
-
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM;
- }
-
- // OUT endpoint interrupt handling.
- if(int_status & USB_OTG_GINTSTS_OEPINT)
- {
- // OEPINT is read-only
- handle_epout_ints(rhport, dev, out_ep);
- }
-
- // IN endpoint interrupt handling.
- if(int_status & USB_OTG_GINTSTS_IEPINT)
- {
- // IEPINT bit read-only
- handle_epin_ints(rhport, dev, in_ep);
- }
-
- // // Check for Incomplete isochronous IN transfer
- // if(int_status & USB_OTG_GINTSTS_IISOIXFR) {
- // printf(" IISOIXFR!\r\n");
- //// TU_LOG2(" IISOIXFR!\r\n");
- // }
-}
-
-#endif
diff --git a/src/portable/broadcom/synopsys/synopsys_common.h b/src/portable/broadcom/synopsys/synopsys_common.h
deleted file mode 100644
index 81ce3b4a9..000000000
--- a/src/portable/broadcom/synopsys/synopsys_common.h
+++ /dev/null
@@ -1,1476 +0,0 @@
-/**
- ******************************************************************************
- * @file synopsys_common.h
- * @author MCD Application Team
- * @brief CMSIS Cortex-M3 Device USB OTG peripheral Header File.
- * This file contains the USB OTG peripheral register's definitions, bits
- * definitions and memory mapping for STM32F1xx devices.
- *
- * This file contains:
- * - Data structures and the address mapping for the USB OTG peripheral
- * - The Peripheral's registers declarations and bits definition
- * - Macros to access the peripheral's registers hardware
- *
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; Copyright (c) 2017 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
- *
- ******************************************************************************
- */
-
-#include "stdint.h"
-
-#pragma once
-
-#ifdef __cplusplus
- #define __I volatile
-#else
- #define __I volatile const
-#endif
-#define __O volatile
-#define __IO volatile
-#define __IM volatile const
-#define __OM volatile
-#define __IOM volatile
-
-/**
- * @brief __USB_OTG_Core_register
- */
-
-typedef struct
-{
- __IO uint32_t GOTGCTL; /*!< USB_OTG Control and Status Register Address offset: 000h */
- __IO uint32_t GOTGINT; /*!< USB_OTG Interrupt Register Address offset: 004h */
- __IO uint32_t GAHBCFG; /*!< Core AHB Configuration Register Address offset: 008h */
- __IO uint32_t GUSBCFG; /*!< Core USB Configuration Register Address offset: 00Ch */
- __IO uint32_t GRSTCTL; /*!< Core Reset Register Address offset: 010h */
- __IO uint32_t GINTSTS; /*!< Core Interrupt Register Address offset: 014h */
- __IO uint32_t GINTMSK; /*!< Core Interrupt Mask Register Address offset: 018h */
- __IO uint32_t GRXSTSR; /*!< Receive Sts Q Read Register Address offset: 01Ch */
- __IO uint32_t GRXSTSP; /*!< Receive Sts Q Read & POP Register Address offset: 020h */
- __IO uint32_t GRXFSIZ; /*!< Receive FIFO Size Register Address offset: 024h */
- __IO uint32_t DIEPTXF0_HNPTXFSIZ; /*!< EP0 / Non Periodic Tx FIFO Size Register Address offset: 028h */
- __IO uint32_t HNPTXSTS; /*!< Non Periodic Tx FIFO/Queue Sts reg Address offset: 02Ch */
- uint32_t Reserved30[2]; /*!< Reserved 030h*/
- __IO uint32_t GCCFG; /*!< General Purpose IO Register Address offset: 038h */
- __IO uint32_t CID; /*!< User ID Register 03Ch */
- __IO uint32_t GSNPSID; /* USB_OTG core ID 040h*/
- __IO uint32_t GHWCFG1; /* User HW config1 044h*/
- __IO uint32_t GHWCFG2; /* User HW config2 048h*/
- __IO uint32_t GHWCFG3; /*!< User HW config3 04Ch */
- uint32_t Reserved6; /*!< Reserved 050h */
- __IO uint32_t GLPMCFG; /*!< LPM Register 054h */
- __IO uint32_t GPWRDN; /*!< Power Down Register 058h */
- __IO uint32_t GDFIFOCFG; /*!< DFIFO Software Config Register 05Ch */
- __IO uint32_t GADPCTL; /*!< ADP Timer, Control and Status Register 60Ch */
- uint32_t Reserved43[39]; /*!< Reserved 058h-0FFh */
- __IO uint32_t HPTXFSIZ; /*!< Host Periodic Tx FIFO Size Reg Address offset: 100h */
- __IO uint32_t DIEPTXF[0x0F]; /*!< dev Periodic Transmit FIFO Address offset: 0x104 */
-} USB_OTG_GlobalTypeDef;
-
-
-
-/**
- * @brief __device_Registers
- */
-
-typedef struct
-{
- __IO uint32_t DCFG; /*!< dev Configuration Register Address offset: 800h*/
- __IO uint32_t DCTL; /*!< dev Control Register Address offset: 804h*/
- __IO uint32_t DSTS; /*!< dev Status Register (RO) Address offset: 808h*/
- uint32_t Reserved0C; /*!< Reserved 80Ch*/
- __IO uint32_t DIEPMSK; /*!< dev IN Endpoint Mask Address offset: 810h*/
- __IO uint32_t DOEPMSK; /*!< dev OUT Endpoint Mask Address offset: 814h*/
- __IO uint32_t DAINT; /*!< dev All Endpoints Itr Reg Address offset: 818h*/
- __IO uint32_t DAINTMSK; /*!< dev All Endpoints Itr Mask Address offset: 81Ch*/
- uint32_t Reserved20; /*!< Reserved 820h*/
- uint32_t Reserved9; /*!< Reserved 824h*/
- __IO uint32_t DVBUSDIS; /*!< dev VBUS discharge Register Address offset: 828h*/
- __IO uint32_t DVBUSPULSE; /*!< dev VBUS Pulse Register Address offset: 82Ch*/
- __IO uint32_t DTHRCTL; /*!< dev thr Address offset: 830h*/
- __IO uint32_t DIEPEMPMSK; /*!< dev empty msk Address offset: 834h*/
- __IO uint32_t DEACHINT; /*!< dedicated EP interrupt Address offset: 838h*/
- __IO uint32_t DEACHMSK; /*!< dedicated EP msk Address offset: 83Ch*/
- uint32_t Reserved40; /*!< dedicated EP mask Address offset: 840h*/
- __IO uint32_t DINEP1MSK; /*!< dedicated EP mask Address offset: 844h*/
- uint32_t Reserved44[15]; /*!< Reserved 844-87Ch*/
- __IO uint32_t DOUTEP1MSK; /*!< dedicated EP msk Address offset: 884h*/
-} USB_OTG_DeviceTypeDef;
-
-/**
- * @brief __IN_Endpoint-Specific_Register
- */
-
-typedef struct
-{
- __IO uint32_t DIEPCTL; /*!< dev IN Endpoint Control Reg 900h + (ep_num * 20h) + 00h*/
- uint32_t Reserved04; /*!< Reserved 900h + (ep_num * 20h) + 04h*/
- __IO uint32_t DIEPINT; /*!< dev IN Endpoint Itr Reg 900h + (ep_num * 20h) + 08h*/
- uint32_t Reserved0C; /*!< Reserved 900h + (ep_num * 20h) + 0Ch*/
- __IO uint32_t DIEPTSIZ; /*!< IN Endpoint Txfer Size 900h + (ep_num * 20h) + 10h*/
- __IO uint32_t DIEPDMA; /*!< IN Endpoint DMA Address Reg 900h + (ep_num * 20h) + 14h*/
- __IO uint32_t DTXFSTS; /*!< IN Endpoint Tx FIFO Status Reg 900h + (ep_num * 20h) + 18h*/
- uint32_t Reserved18; /*!< Reserved 900h+(ep_num*20h)+1Ch-900h+ (ep_num * 20h) + 1Ch*/
-} USB_OTG_INEndpointTypeDef;
-
-/**
- * @brief __OUT_Endpoint-Specific_Registers
- */
-
-typedef struct
-{
- __IO uint32_t DOEPCTL; /*!< dev OUT Endpoint Control Reg B00h + (ep_num * 20h) + 00h*/
- uint32_t Reserved04; /*!< Reserved B00h + (ep_num * 20h) + 04h*/
- __IO uint32_t DOEPINT; /*!< dev OUT Endpoint Itr Reg B00h + (ep_num * 20h) + 08h*/
- uint32_t Reserved0C; /*!< Reserved B00h + (ep_num * 20h) + 0Ch*/
- __IO uint32_t DOEPTSIZ; /*!< dev OUT Endpoint Txfer Size B00h + (ep_num * 20h) + 10h*/
- __IO uint32_t DOEPDMA; /*!< dev OUT Endpoint DMA Address B00h + (ep_num * 20h) + 14h*/
- uint32_t Reserved18[2]; /*!< Reserved B00h + (ep_num * 20h) + 18h - B00h + (ep_num * 20h) + 1Ch*/
-} USB_OTG_OUTEndpointTypeDef;
-
-/**
- * @brief __Host_Mode_Register_Structures
- */
-
-typedef struct
-{
- __IO uint32_t HCFG; /*!< Host Configuration Register 400h*/
- __IO uint32_t HFIR; /*!< Host Frame Interval Register 404h*/
- __IO uint32_t HFNUM; /*!< Host Frame Nbr/Frame Remaining 408h*/
- uint32_t Reserved40C; /*!< Reserved 40Ch*/
- __IO uint32_t HPTXSTS; /*!< Host Periodic Tx FIFO/ Queue Status 410h*/
- __IO uint32_t HAINT; /*!< Host All Channels Interrupt Register 414h*/
- __IO uint32_t HAINTMSK; /*!< Host All Channels Interrupt Mask 418h*/
-} USB_OTG_HostTypeDef;
-
-/**
- * @brief __Host_Channel_Specific_Registers
- */
-
-typedef struct
-{
- __IO uint32_t HCCHAR;
- __IO uint32_t HCSPLT;
- __IO uint32_t HCINT;
- __IO uint32_t HCINTMSK;
- __IO uint32_t HCTSIZ;
- __IO uint32_t HCDMA;
- uint32_t Reserved[2];
-} USB_OTG_HostChannelTypeDef;
-
-/*!< USB registers base address */
-#define USB_OTG_FS_PERIPH_BASE 0x50000000UL
-
-// #define USB_OTG_GLOBAL_BASE 0x00000000UL
-// #define USB_OTG_DEVICE_BASE 0x00000800UL
-#define USB_OTG_IN_ENDPOINT_BASE 0x00000900UL
-#define USB_OTG_OUT_ENDPOINT_BASE 0x00000B00UL
-#define USB_OTG_EP_REG_SIZE 0x00000020UL
-// #define USB_OTG_HOST_BASE 0x00000400UL
-#define USB_OTG_HOST_PORT_BASE 0x00000440UL
-#define USB_OTG_HOST_CHANNEL_BASE 0x00000500UL
-#define USB_OTG_HOST_CHANNEL_SIZE 0x00000020UL
-#define USB_OTG_PCGCCTL_BASE 0x00000E00UL
-#define USB_OTG_FIFO_BASE 0x00001000UL
-#define USB_OTG_FIFO_SIZE 0x00001000UL
-
-/******************************************************************************/
-/* */
-/* USB_OTG */
-/* */
-/******************************************************************************/
-/******************** Bit definition for USB_OTG_GOTGCTL register ***********/
-#define USB_OTG_GOTGCTL_SRQSCS_Pos (0U)
-#define USB_OTG_GOTGCTL_SRQSCS_Msk (0x1UL << USB_OTG_GOTGCTL_SRQSCS_Pos) /*!< 0x00000001 */
-#define USB_OTG_GOTGCTL_SRQSCS USB_OTG_GOTGCTL_SRQSCS_Msk /*!< Session request success */
-#define USB_OTG_GOTGCTL_SRQ_Pos (1U)
-#define USB_OTG_GOTGCTL_SRQ_Msk (0x1UL << USB_OTG_GOTGCTL_SRQ_Pos) /*!< 0x00000002 */
-#define USB_OTG_GOTGCTL_SRQ USB_OTG_GOTGCTL_SRQ_Msk /*!< Session request */
-#define USB_OTG_GOTGCTL_HNGSCS_Pos (8U)
-#define USB_OTG_GOTGCTL_HNGSCS_Msk (0x1UL << USB_OTG_GOTGCTL_HNGSCS_Pos) /*!< 0x00000100 */
-#define USB_OTG_GOTGCTL_HNGSCS USB_OTG_GOTGCTL_HNGSCS_Msk /*!< Host set HNP enable */
-#define USB_OTG_GOTGCTL_HNPRQ_Pos (9U)
-#define USB_OTG_GOTGCTL_HNPRQ_Msk (0x1UL << USB_OTG_GOTGCTL_HNPRQ_Pos) /*!< 0x00000200 */
-#define USB_OTG_GOTGCTL_HNPRQ USB_OTG_GOTGCTL_HNPRQ_Msk /*!< HNP request */
-#define USB_OTG_GOTGCTL_HSHNPEN_Pos (10U)
-#define USB_OTG_GOTGCTL_HSHNPEN_Msk (0x1UL << USB_OTG_GOTGCTL_HSHNPEN_Pos) /*!< 0x00000400 */
-#define USB_OTG_GOTGCTL_HSHNPEN USB_OTG_GOTGCTL_HSHNPEN_Msk /*!< Host set HNP enable */
-#define USB_OTG_GOTGCTL_DHNPEN_Pos (11U)
-#define USB_OTG_GOTGCTL_DHNPEN_Msk (0x1UL << USB_OTG_GOTGCTL_DHNPEN_Pos) /*!< 0x00000800 */
-#define USB_OTG_GOTGCTL_DHNPEN USB_OTG_GOTGCTL_DHNPEN_Msk /*!< Device HNP enabled */
-#define USB_OTG_GOTGCTL_CIDSTS_Pos (16U)
-#define USB_OTG_GOTGCTL_CIDSTS_Msk (0x1UL << USB_OTG_GOTGCTL_CIDSTS_Pos) /*!< 0x00010000 */
-#define USB_OTG_GOTGCTL_CIDSTS USB_OTG_GOTGCTL_CIDSTS_Msk /*!< Connector ID status */
-#define USB_OTG_GOTGCTL_DBCT_Pos (17U)
-#define USB_OTG_GOTGCTL_DBCT_Msk (0x1UL << USB_OTG_GOTGCTL_DBCT_Pos) /*!< 0x00020000 */
-#define USB_OTG_GOTGCTL_DBCT USB_OTG_GOTGCTL_DBCT_Msk /*!< Long/short debounce time */
-#define USB_OTG_GOTGCTL_ASVLD_Pos (18U)
-#define USB_OTG_GOTGCTL_ASVLD_Msk (0x1UL << USB_OTG_GOTGCTL_ASVLD_Pos) /*!< 0x00040000 */
-#define USB_OTG_GOTGCTL_ASVLD USB_OTG_GOTGCTL_ASVLD_Msk /*!< A-session valid */
-#define USB_OTG_GOTGCTL_BSVLD_Pos (19U)
-#define USB_OTG_GOTGCTL_BSVLD_Msk (0x1UL << USB_OTG_GOTGCTL_BSVLD_Pos) /*!< 0x00080000 */
-#define USB_OTG_GOTGCTL_BSVLD USB_OTG_GOTGCTL_BSVLD_Msk /*!< B-session valid */
-
-/******************** Bit definition for USB_OTG_HCFG register ********************/
-
-#define USB_OTG_HCFG_FSLSPCS_Pos (0U)
-#define USB_OTG_HCFG_FSLSPCS_Msk (0x3UL << USB_OTG_HCFG_FSLSPCS_Pos) /*!< 0x00000003 */
-#define USB_OTG_HCFG_FSLSPCS USB_OTG_HCFG_FSLSPCS_Msk /*!< FS/LS PHY clock select */
-#define USB_OTG_HCFG_FSLSPCS_0 (0x1UL << USB_OTG_HCFG_FSLSPCS_Pos) /*!< 0x00000001 */
-#define USB_OTG_HCFG_FSLSPCS_1 (0x2UL << USB_OTG_HCFG_FSLSPCS_Pos) /*!< 0x00000002 */
-#define USB_OTG_HCFG_FSLSS_Pos (2U)
-#define USB_OTG_HCFG_FSLSS_Msk (0x1UL << USB_OTG_HCFG_FSLSS_Pos) /*!< 0x00000004 */
-#define USB_OTG_HCFG_FSLSS USB_OTG_HCFG_FSLSS_Msk /*!< FS- and LS-only support */
-
-/******************** Bit definition for USB_OTG_DCFG register ********************/
-
-#define USB_OTG_DCFG_DSPD_Pos (0U)
-#define USB_OTG_DCFG_DSPD_Msk (0x3UL << USB_OTG_DCFG_DSPD_Pos) /*!< 0x00000003 */
-#define USB_OTG_DCFG_DSPD USB_OTG_DCFG_DSPD_Msk /*!< Device speed */
-#define USB_OTG_DCFG_DSPD_0 (0x1UL << USB_OTG_DCFG_DSPD_Pos) /*!< 0x00000001 */
-#define USB_OTG_DCFG_DSPD_1 (0x2UL << USB_OTG_DCFG_DSPD_Pos) /*!< 0x00000002 */
-#define USB_OTG_DCFG_NZLSOHSK_Pos (2U)
-#define USB_OTG_DCFG_NZLSOHSK_Msk (0x1UL << USB_OTG_DCFG_NZLSOHSK_Pos) /*!< 0x00000004 */
-#define USB_OTG_DCFG_NZLSOHSK USB_OTG_DCFG_NZLSOHSK_Msk /*!< Nonzero-length status OUT handshake */
-
-#define USB_OTG_DCFG_DAD_Pos (4U)
-#define USB_OTG_DCFG_DAD_Msk (0x7FUL << USB_OTG_DCFG_DAD_Pos) /*!< 0x000007F0 */
-#define USB_OTG_DCFG_DAD USB_OTG_DCFG_DAD_Msk /*!< Device address */
-#define USB_OTG_DCFG_DAD_0 (0x01UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000010 */
-#define USB_OTG_DCFG_DAD_1 (0x02UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000020 */
-#define USB_OTG_DCFG_DAD_2 (0x04UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000040 */
-#define USB_OTG_DCFG_DAD_3 (0x08UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000080 */
-#define USB_OTG_DCFG_DAD_4 (0x10UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000100 */
-#define USB_OTG_DCFG_DAD_5 (0x20UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000200 */
-#define USB_OTG_DCFG_DAD_6 (0x40UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000400 */
-
-#define USB_OTG_DCFG_PFIVL_Pos (11U)
-#define USB_OTG_DCFG_PFIVL_Msk (0x3UL << USB_OTG_DCFG_PFIVL_Pos) /*!< 0x00001800 */
-#define USB_OTG_DCFG_PFIVL USB_OTG_DCFG_PFIVL_Msk /*!< Periodic (micro)frame interval */
-#define USB_OTG_DCFG_PFIVL_0 (0x1UL << USB_OTG_DCFG_PFIVL_Pos) /*!< 0x00000800 */
-#define USB_OTG_DCFG_PFIVL_1 (0x2UL << USB_OTG_DCFG_PFIVL_Pos) /*!< 0x00001000 */
-
-#define USB_OTG_DCFG_PERSCHIVL_Pos (24U)
-#define USB_OTG_DCFG_PERSCHIVL_Msk (0x3UL << USB_OTG_DCFG_PERSCHIVL_Pos) /*!< 0x03000000 */
-#define USB_OTG_DCFG_PERSCHIVL USB_OTG_DCFG_PERSCHIVL_Msk /*!< Periodic scheduling interval */
-#define USB_OTG_DCFG_PERSCHIVL_0 (0x1UL << USB_OTG_DCFG_PERSCHIVL_Pos) /*!< 0x01000000 */
-#define USB_OTG_DCFG_PERSCHIVL_1 (0x2UL << USB_OTG_DCFG_PERSCHIVL_Pos) /*!< 0x02000000 */
-
-/******************** Bit definition for USB_OTG_PCGCR register ********************/
-#define USB_OTG_PCGCR_STPPCLK_Pos (0U)
-#define USB_OTG_PCGCR_STPPCLK_Msk (0x1UL << USB_OTG_PCGCR_STPPCLK_Pos) /*!< 0x00000001 */
-#define USB_OTG_PCGCR_STPPCLK USB_OTG_PCGCR_STPPCLK_Msk /*!< Stop PHY clock */
-#define USB_OTG_PCGCR_GATEHCLK_Pos (1U)
-#define USB_OTG_PCGCR_GATEHCLK_Msk (0x1UL << USB_OTG_PCGCR_GATEHCLK_Pos) /*!< 0x00000002 */
-#define USB_OTG_PCGCR_GATEHCLK USB_OTG_PCGCR_GATEHCLK_Msk /*!< Gate HCLK */
-#define USB_OTG_PCGCR_PHYSUSP_Pos (4U)
-#define USB_OTG_PCGCR_PHYSUSP_Msk (0x1UL << USB_OTG_PCGCR_PHYSUSP_Pos) /*!< 0x00000010 */
-#define USB_OTG_PCGCR_PHYSUSP USB_OTG_PCGCR_PHYSUSP_Msk /*!< PHY suspended */
-
-/******************** Bit definition for USB_OTG_GOTGINT register ********************/
-#define USB_OTG_GOTGINT_SEDET_Pos (2U)
-#define USB_OTG_GOTGINT_SEDET_Msk (0x1UL << USB_OTG_GOTGINT_SEDET_Pos) /*!< 0x00000004 */
-#define USB_OTG_GOTGINT_SEDET USB_OTG_GOTGINT_SEDET_Msk /*!< Session end detected */
-#define USB_OTG_GOTGINT_SRSSCHG_Pos (8U)
-#define USB_OTG_GOTGINT_SRSSCHG_Msk (0x1UL << USB_OTG_GOTGINT_SRSSCHG_Pos) /*!< 0x00000100 */
-#define USB_OTG_GOTGINT_SRSSCHG USB_OTG_GOTGINT_SRSSCHG_Msk /*!< Session request success status change */
-#define USB_OTG_GOTGINT_HNSSCHG_Pos (9U)
-#define USB_OTG_GOTGINT_HNSSCHG_Msk (0x1UL << USB_OTG_GOTGINT_HNSSCHG_Pos) /*!< 0x00000200 */
-#define USB_OTG_GOTGINT_HNSSCHG USB_OTG_GOTGINT_HNSSCHG_Msk /*!< Host negotiation success status change */
-#define USB_OTG_GOTGINT_HNGDET_Pos (17U)
-#define USB_OTG_GOTGINT_HNGDET_Msk (0x1UL << USB_OTG_GOTGINT_HNGDET_Pos) /*!< 0x00020000 */
-#define USB_OTG_GOTGINT_HNGDET USB_OTG_GOTGINT_HNGDET_Msk /*!< Host negotiation detected */
-#define USB_OTG_GOTGINT_ADTOCHG_Pos (18U)
-#define USB_OTG_GOTGINT_ADTOCHG_Msk (0x1UL << USB_OTG_GOTGINT_ADTOCHG_Pos) /*!< 0x00040000 */
-#define USB_OTG_GOTGINT_ADTOCHG USB_OTG_GOTGINT_ADTOCHG_Msk /*!< A-device timeout change */
-#define USB_OTG_GOTGINT_DBCDNE_Pos (19U)
-#define USB_OTG_GOTGINT_DBCDNE_Msk (0x1UL << USB_OTG_GOTGINT_DBCDNE_Pos) /*!< 0x00080000 */
-#define USB_OTG_GOTGINT_DBCDNE USB_OTG_GOTGINT_DBCDNE_Msk /*!< Debounce done */
-
-/******************** Bit definition for USB_OTG_DCTL register ********************/
-#define USB_OTG_DCTL_RWUSIG_Pos (0U)
-#define USB_OTG_DCTL_RWUSIG_Msk (0x1UL << USB_OTG_DCTL_RWUSIG_Pos) /*!< 0x00000001 */
-#define USB_OTG_DCTL_RWUSIG USB_OTG_DCTL_RWUSIG_Msk /*!< Remote wakeup signaling */
-#define USB_OTG_DCTL_SDIS_Pos (1U)
-#define USB_OTG_DCTL_SDIS_Msk (0x1UL << USB_OTG_DCTL_SDIS_Pos) /*!< 0x00000002 */
-#define USB_OTG_DCTL_SDIS USB_OTG_DCTL_SDIS_Msk /*!< Soft disconnect */
-#define USB_OTG_DCTL_GINSTS_Pos (2U)
-#define USB_OTG_DCTL_GINSTS_Msk (0x1UL << USB_OTG_DCTL_GINSTS_Pos) /*!< 0x00000004 */
-#define USB_OTG_DCTL_GINSTS USB_OTG_DCTL_GINSTS_Msk /*!< Global IN NAK status */
-#define USB_OTG_DCTL_GONSTS_Pos (3U)
-#define USB_OTG_DCTL_GONSTS_Msk (0x1UL << USB_OTG_DCTL_GONSTS_Pos) /*!< 0x00000008 */
-#define USB_OTG_DCTL_GONSTS USB_OTG_DCTL_GONSTS_Msk /*!< Global OUT NAK status */
-
-#define USB_OTG_DCTL_TCTL_Pos (4U)
-#define USB_OTG_DCTL_TCTL_Msk (0x7UL << USB_OTG_DCTL_TCTL_Pos) /*!< 0x00000070 */
-#define USB_OTG_DCTL_TCTL USB_OTG_DCTL_TCTL_Msk /*!< Test control */
-#define USB_OTG_DCTL_TCTL_0 (0x1UL << USB_OTG_DCTL_TCTL_Pos) /*!< 0x00000010 */
-#define USB_OTG_DCTL_TCTL_1 (0x2UL << USB_OTG_DCTL_TCTL_Pos) /*!< 0x00000020 */
-#define USB_OTG_DCTL_TCTL_2 (0x4UL << USB_OTG_DCTL_TCTL_Pos) /*!< 0x00000040 */
-#define USB_OTG_DCTL_SGINAK_Pos (7U)
-#define USB_OTG_DCTL_SGINAK_Msk (0x1UL << USB_OTG_DCTL_SGINAK_Pos) /*!< 0x00000080 */
-#define USB_OTG_DCTL_SGINAK USB_OTG_DCTL_SGINAK_Msk /*!< Set global IN NAK */
-#define USB_OTG_DCTL_CGINAK_Pos (8U)
-#define USB_OTG_DCTL_CGINAK_Msk (0x1UL << USB_OTG_DCTL_CGINAK_Pos) /*!< 0x00000100 */
-#define USB_OTG_DCTL_CGINAK USB_OTG_DCTL_CGINAK_Msk /*!< Clear global IN NAK */
-#define USB_OTG_DCTL_SGONAK_Pos (9U)
-#define USB_OTG_DCTL_SGONAK_Msk (0x1UL << USB_OTG_DCTL_SGONAK_Pos) /*!< 0x00000200 */
-#define USB_OTG_DCTL_SGONAK USB_OTG_DCTL_SGONAK_Msk /*!< Set global OUT NAK */
-#define USB_OTG_DCTL_CGONAK_Pos (10U)
-#define USB_OTG_DCTL_CGONAK_Msk (0x1UL << USB_OTG_DCTL_CGONAK_Pos) /*!< 0x00000400 */
-#define USB_OTG_DCTL_CGONAK USB_OTG_DCTL_CGONAK_Msk /*!< Clear global OUT NAK */
-#define USB_OTG_DCTL_POPRGDNE_Pos (11U)
-#define USB_OTG_DCTL_POPRGDNE_Msk (0x1UL << USB_OTG_DCTL_POPRGDNE_Pos) /*!< 0x00000800 */
-#define USB_OTG_DCTL_POPRGDNE USB_OTG_DCTL_POPRGDNE_Msk /*!< Power-on programming done */
-
-/******************** Bit definition for USB_OTG_HFIR register ********************/
-#define USB_OTG_HFIR_FRIVL_Pos (0U)
-#define USB_OTG_HFIR_FRIVL_Msk (0xFFFFUL << USB_OTG_HFIR_FRIVL_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_HFIR_FRIVL USB_OTG_HFIR_FRIVL_Msk /*!< Frame interval */
-
-/******************** Bit definition for USB_OTG_HFNUM register ********************/
-#define USB_OTG_HFNUM_FRNUM_Pos (0U)
-#define USB_OTG_HFNUM_FRNUM_Msk (0xFFFFUL << USB_OTG_HFNUM_FRNUM_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_HFNUM_FRNUM USB_OTG_HFNUM_FRNUM_Msk /*!< Frame number */
-#define USB_OTG_HFNUM_FTREM_Pos (16U)
-#define USB_OTG_HFNUM_FTREM_Msk (0xFFFFUL << USB_OTG_HFNUM_FTREM_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_HFNUM_FTREM USB_OTG_HFNUM_FTREM_Msk /*!< Frame time remaining */
-
-/******************** Bit definition for USB_OTG_DSTS register ********************/
-#define USB_OTG_DSTS_SUSPSTS_Pos (0U)
-#define USB_OTG_DSTS_SUSPSTS_Msk (0x1UL << USB_OTG_DSTS_SUSPSTS_Pos) /*!< 0x00000001 */
-#define USB_OTG_DSTS_SUSPSTS USB_OTG_DSTS_SUSPSTS_Msk /*!< Suspend status */
-
-#define USB_OTG_DSTS_ENUMSPD_Pos (1U)
-#define USB_OTG_DSTS_ENUMSPD_Msk (0x3UL << USB_OTG_DSTS_ENUMSPD_Pos) /*!< 0x00000006 */
-#define USB_OTG_DSTS_ENUMSPD USB_OTG_DSTS_ENUMSPD_Msk /*!< Enumerated speed */
-#define USB_OTG_DSTS_ENUMSPD_0 (0x1UL << USB_OTG_DSTS_ENUMSPD_Pos) /*!< 0x00000002 */
-#define USB_OTG_DSTS_ENUMSPD_1 (0x2UL << USB_OTG_DSTS_ENUMSPD_Pos) /*!< 0x00000004 */
-#define USB_OTG_DSTS_EERR_Pos (3U)
-#define USB_OTG_DSTS_EERR_Msk (0x1UL << USB_OTG_DSTS_EERR_Pos) /*!< 0x00000008 */
-#define USB_OTG_DSTS_EERR USB_OTG_DSTS_EERR_Msk /*!< Erratic error */
-#define USB_OTG_DSTS_FNSOF_Pos (8U)
-#define USB_OTG_DSTS_FNSOF_Msk (0x3FFFUL << USB_OTG_DSTS_FNSOF_Pos) /*!< 0x003FFF00 */
-#define USB_OTG_DSTS_FNSOF USB_OTG_DSTS_FNSOF_Msk /*!< Frame number of the received SOF */
-
-/******************** Bit definition for USB_OTG_GAHBCFG register ********************/
-#define USB_OTG_GAHBCFG_GINT_Pos (0U)
-#define USB_OTG_GAHBCFG_GINT_Msk (0x1UL << USB_OTG_GAHBCFG_GINT_Pos) /*!< 0x00000001 */
-#define USB_OTG_GAHBCFG_GINT USB_OTG_GAHBCFG_GINT_Msk /*!< Global interrupt mask */
-#define USB_OTG_GAHBCFG_HBSTLEN_Pos (1U)
-#define USB_OTG_GAHBCFG_HBSTLEN_Msk (0xFUL << USB_OTG_GAHBCFG_HBSTLEN_Pos) /*!< 0x0000001E */
-#define USB_OTG_GAHBCFG_HBSTLEN USB_OTG_GAHBCFG_HBSTLEN_Msk /*!< Burst length/type */
-#define USB_OTG_GAHBCFG_HBSTLEN_0 (0x0UL << USB_OTG_GAHBCFG_HBSTLEN_Pos) /*!< Single */
-#define USB_OTG_GAHBCFG_HBSTLEN_1 (0x1UL << USB_OTG_GAHBCFG_HBSTLEN_Pos) /*!< INCR */
-#define USB_OTG_GAHBCFG_HBSTLEN_2 (0x3UL << USB_OTG_GAHBCFG_HBSTLEN_Pos) /*!< INCR4 */
-#define USB_OTG_GAHBCFG_HBSTLEN_3 (0x5UL << USB_OTG_GAHBCFG_HBSTLEN_Pos) /*!< INCR8 */
-#define USB_OTG_GAHBCFG_HBSTLEN_4 (0x7UL << USB_OTG_GAHBCFG_HBSTLEN_Pos) /*!< INCR16 */
-#define USB_OTG_GAHBCFG_DMAEN_Pos (5U)
-#define USB_OTG_GAHBCFG_DMAEN_Msk (0x1UL << USB_OTG_GAHBCFG_DMAEN_Pos) /*!< 0x00000020 */
-#define USB_OTG_GAHBCFG_DMAEN USB_OTG_GAHBCFG_DMAEN_Msk /*!< DMA enable */
-#define USB_OTG_GAHBCFG_TXFELVL_Pos (7U)
-#define USB_OTG_GAHBCFG_TXFELVL_Msk (0x1UL << USB_OTG_GAHBCFG_TXFELVL_Pos) /*!< 0x00000080 */
-#define USB_OTG_GAHBCFG_TXFELVL USB_OTG_GAHBCFG_TXFELVL_Msk /*!< TxFIFO empty level */
-#define USB_OTG_GAHBCFG_PTXFELVL_Pos (8U)
-#define USB_OTG_GAHBCFG_PTXFELVL_Msk (0x1UL << USB_OTG_GAHBCFG_PTXFELVL_Pos) /*!< 0x00000100 */
-#define USB_OTG_GAHBCFG_PTXFELVL USB_OTG_GAHBCFG_PTXFELVL_Msk /*!< Periodic TxFIFO empty level */
-
-/******************** Bit definition for USB_OTG_GUSBCFG register ********************/
-
-#define USB_OTG_GUSBCFG_TOCAL_Pos (0U)
-#define USB_OTG_GUSBCFG_TOCAL_Msk (0x7UL << USB_OTG_GUSBCFG_TOCAL_Pos) /*!< 0x00000007 */
-#define USB_OTG_GUSBCFG_TOCAL USB_OTG_GUSBCFG_TOCAL_Msk /*!< FS timeout calibration */
-#define USB_OTG_GUSBCFG_TOCAL_0 (0x1UL << USB_OTG_GUSBCFG_TOCAL_Pos) /*!< 0x00000001 */
-#define USB_OTG_GUSBCFG_TOCAL_1 (0x2UL << USB_OTG_GUSBCFG_TOCAL_Pos) /*!< 0x00000002 */
-#define USB_OTG_GUSBCFG_TOCAL_2 (0x4UL << USB_OTG_GUSBCFG_TOCAL_Pos) /*!< 0x00000004 */
-#define USB_OTG_GUSBCFG_PHYSEL_Pos (6U)
-#define USB_OTG_GUSBCFG_PHYSEL_Msk (0x1UL << USB_OTG_GUSBCFG_PHYSEL_Pos) /*!< 0x00000040 */
-#define USB_OTG_GUSBCFG_PHYSEL USB_OTG_GUSBCFG_PHYSEL_Msk /*!< USB 2.0 high-speed ULPI PHY or USB 1.1 full-speed serial transceiver select */
-#define USB_OTG_GUSBCFG_SRPCAP_Pos (8U)
-#define USB_OTG_GUSBCFG_SRPCAP_Msk (0x1UL << USB_OTG_GUSBCFG_SRPCAP_Pos) /*!< 0x00000100 */
-#define USB_OTG_GUSBCFG_SRPCAP USB_OTG_GUSBCFG_SRPCAP_Msk /*!< SRP-capable */
-#define USB_OTG_GUSBCFG_HNPCAP_Pos (9U)
-#define USB_OTG_GUSBCFG_HNPCAP_Msk (0x1UL << USB_OTG_GUSBCFG_HNPCAP_Pos) /*!< 0x00000200 */
-#define USB_OTG_GUSBCFG_HNPCAP USB_OTG_GUSBCFG_HNPCAP_Msk /*!< HNP-capable */
-#define USB_OTG_GUSBCFG_TRDT_Pos (10U)
-#define USB_OTG_GUSBCFG_TRDT_Msk (0xFUL << USB_OTG_GUSBCFG_TRDT_Pos) /*!< 0x00003C00 */
-#define USB_OTG_GUSBCFG_TRDT USB_OTG_GUSBCFG_TRDT_Msk /*!< USB turnaround time */
-#define USB_OTG_GUSBCFG_TRDT_0 (0x1UL << USB_OTG_GUSBCFG_TRDT_Pos) /*!< 0x00000400 */
-#define USB_OTG_GUSBCFG_TRDT_1 (0x2UL << USB_OTG_GUSBCFG_TRDT_Pos) /*!< 0x00000800 */
-#define USB_OTG_GUSBCFG_TRDT_2 (0x4UL << USB_OTG_GUSBCFG_TRDT_Pos) /*!< 0x00001000 */
-#define USB_OTG_GUSBCFG_TRDT_3 (0x8UL << USB_OTG_GUSBCFG_TRDT_Pos) /*!< 0x00002000 */
-#define USB_OTG_GUSBCFG_PHYLPCS_Pos (15U)
-#define USB_OTG_GUSBCFG_PHYLPCS_Msk (0x1UL << USB_OTG_GUSBCFG_PHYLPCS_Pos) /*!< 0x00008000 */
-#define USB_OTG_GUSBCFG_PHYLPCS USB_OTG_GUSBCFG_PHYLPCS_Msk /*!< PHY Low-power clock select */
-#define USB_OTG_GUSBCFG_ULPIFSLS_Pos (17U)
-#define USB_OTG_GUSBCFG_ULPIFSLS_Msk (0x1UL << USB_OTG_GUSBCFG_ULPIFSLS_Pos) /*!< 0x00020000 */
-#define USB_OTG_GUSBCFG_ULPIFSLS USB_OTG_GUSBCFG_ULPIFSLS_Msk /*!< ULPI FS/LS select */
-#define USB_OTG_GUSBCFG_ULPIAR_Pos (18U)
-#define USB_OTG_GUSBCFG_ULPIAR_Msk (0x1UL << USB_OTG_GUSBCFG_ULPIAR_Pos) /*!< 0x00040000 */
-#define USB_OTG_GUSBCFG_ULPIAR USB_OTG_GUSBCFG_ULPIAR_Msk /*!< ULPI Auto-resume */
-#define USB_OTG_GUSBCFG_ULPICSM_Pos (19U)
-#define USB_OTG_GUSBCFG_ULPICSM_Msk (0x1UL << USB_OTG_GUSBCFG_ULPICSM_Pos) /*!< 0x00080000 */
-#define USB_OTG_GUSBCFG_ULPICSM USB_OTG_GUSBCFG_ULPICSM_Msk /*!< ULPI Clock SuspendM */
-#define USB_OTG_GUSBCFG_ULPIEVBUSD_Pos (20U)
-#define USB_OTG_GUSBCFG_ULPIEVBUSD_Msk (0x1UL << USB_OTG_GUSBCFG_ULPIEVBUSD_Pos) /*!< 0x00100000 */
-#define USB_OTG_GUSBCFG_ULPIEVBUSD USB_OTG_GUSBCFG_ULPIEVBUSD_Msk /*!< ULPI External VBUS Drive */
-#define USB_OTG_GUSBCFG_ULPIEVBUSI_Pos (21U)
-#define USB_OTG_GUSBCFG_ULPIEVBUSI_Msk (0x1UL << USB_OTG_GUSBCFG_ULPIEVBUSI_Pos) /*!< 0x00200000 */
-#define USB_OTG_GUSBCFG_ULPIEVBUSI USB_OTG_GUSBCFG_ULPIEVBUSI_Msk /*!< ULPI external VBUS indicator */
-#define USB_OTG_GUSBCFG_TSDPS_Pos (22U)
-#define USB_OTG_GUSBCFG_TSDPS_Msk (0x1UL << USB_OTG_GUSBCFG_TSDPS_Pos) /*!< 0x00400000 */
-#define USB_OTG_GUSBCFG_TSDPS USB_OTG_GUSBCFG_TSDPS_Msk /*!< TermSel DLine pulsing selection */
-#define USB_OTG_GUSBCFG_PCCI_Pos (23U)
-#define USB_OTG_GUSBCFG_PCCI_Msk (0x1UL << USB_OTG_GUSBCFG_PCCI_Pos) /*!< 0x00800000 */
-#define USB_OTG_GUSBCFG_PCCI USB_OTG_GUSBCFG_PCCI_Msk /*!< Indicator complement */
-#define USB_OTG_GUSBCFG_PTCI_Pos (24U)
-#define USB_OTG_GUSBCFG_PTCI_Msk (0x1UL << USB_OTG_GUSBCFG_PTCI_Pos) /*!< 0x01000000 */
-#define USB_OTG_GUSBCFG_PTCI USB_OTG_GUSBCFG_PTCI_Msk /*!< Indicator pass through */
-#define USB_OTG_GUSBCFG_ULPIIPD_Pos (25U)
-#define USB_OTG_GUSBCFG_ULPIIPD_Msk (0x1UL << USB_OTG_GUSBCFG_ULPIIPD_Pos) /*!< 0x02000000 */
-#define USB_OTG_GUSBCFG_ULPIIPD USB_OTG_GUSBCFG_ULPIIPD_Msk /*!< ULPI interface protect disable */
-#define USB_OTG_GUSBCFG_FHMOD_Pos (29U)
-#define USB_OTG_GUSBCFG_FHMOD_Msk (0x1UL << USB_OTG_GUSBCFG_FHMOD_Pos) /*!< 0x20000000 */
-#define USB_OTG_GUSBCFG_FHMOD USB_OTG_GUSBCFG_FHMOD_Msk /*!< Forced host mode */
-#define USB_OTG_GUSBCFG_FDMOD_Pos (30U)
-#define USB_OTG_GUSBCFG_FDMOD_Msk (0x1UL << USB_OTG_GUSBCFG_FDMOD_Pos) /*!< 0x40000000 */
-#define USB_OTG_GUSBCFG_FDMOD USB_OTG_GUSBCFG_FDMOD_Msk /*!< Forced peripheral mode */
-#define USB_OTG_GUSBCFG_CTXPKT_Pos (31U)
-#define USB_OTG_GUSBCFG_CTXPKT_Msk (0x1UL << USB_OTG_GUSBCFG_CTXPKT_Pos) /*!< 0x80000000 */
-#define USB_OTG_GUSBCFG_CTXPKT USB_OTG_GUSBCFG_CTXPKT_Msk /*!< Corrupt Tx packet */
-
-/******************** Bit definition for USB_OTG_GRSTCTL register ********************/
-#define USB_OTG_GRSTCTL_CSRST_Pos (0U)
-#define USB_OTG_GRSTCTL_CSRST_Msk (0x1UL << USB_OTG_GRSTCTL_CSRST_Pos) /*!< 0x00000001 */
-#define USB_OTG_GRSTCTL_CSRST USB_OTG_GRSTCTL_CSRST_Msk /*!< Core soft reset */
-#define USB_OTG_GRSTCTL_HSRST_Pos (1U)
-#define USB_OTG_GRSTCTL_HSRST_Msk (0x1UL << USB_OTG_GRSTCTL_HSRST_Pos) /*!< 0x00000002 */
-#define USB_OTG_GRSTCTL_HSRST USB_OTG_GRSTCTL_HSRST_Msk /*!< HCLK soft reset */
-#define USB_OTG_GRSTCTL_FCRST_Pos (2U)
-#define USB_OTG_GRSTCTL_FCRST_Msk (0x1UL << USB_OTG_GRSTCTL_FCRST_Pos) /*!< 0x00000004 */
-#define USB_OTG_GRSTCTL_FCRST USB_OTG_GRSTCTL_FCRST_Msk /*!< Host frame counter reset */
-#define USB_OTG_GRSTCTL_RXFFLSH_Pos (4U)
-#define USB_OTG_GRSTCTL_RXFFLSH_Msk (0x1UL << USB_OTG_GRSTCTL_RXFFLSH_Pos) /*!< 0x00000010 */
-#define USB_OTG_GRSTCTL_RXFFLSH USB_OTG_GRSTCTL_RXFFLSH_Msk /*!< RxFIFO flush */
-#define USB_OTG_GRSTCTL_TXFFLSH_Pos (5U)
-#define USB_OTG_GRSTCTL_TXFFLSH_Msk (0x1UL << USB_OTG_GRSTCTL_TXFFLSH_Pos) /*!< 0x00000020 */
-#define USB_OTG_GRSTCTL_TXFFLSH USB_OTG_GRSTCTL_TXFFLSH_Msk /*!< TxFIFO flush */
-
-
-#define USB_OTG_GRSTCTL_TXFNUM_Pos (6U)
-#define USB_OTG_GRSTCTL_TXFNUM_Msk (0x1FUL << USB_OTG_GRSTCTL_TXFNUM_Pos) /*!< 0x000007C0 */
-#define USB_OTG_GRSTCTL_TXFNUM USB_OTG_GRSTCTL_TXFNUM_Msk /*!< TxFIFO number */
-#define USB_OTG_GRSTCTL_TXFNUM_0 (0x01UL << USB_OTG_GRSTCTL_TXFNUM_Pos) /*!< 0x00000040 */
-#define USB_OTG_GRSTCTL_TXFNUM_1 (0x02UL << USB_OTG_GRSTCTL_TXFNUM_Pos) /*!< 0x00000080 */
-#define USB_OTG_GRSTCTL_TXFNUM_2 (0x04UL << USB_OTG_GRSTCTL_TXFNUM_Pos) /*!< 0x00000100 */
-#define USB_OTG_GRSTCTL_TXFNUM_3 (0x08UL << USB_OTG_GRSTCTL_TXFNUM_Pos) /*!< 0x00000200 */
-#define USB_OTG_GRSTCTL_TXFNUM_4 (0x10UL << USB_OTG_GRSTCTL_TXFNUM_Pos) /*!< 0x00000400 */
-#define USB_OTG_GRSTCTL_DMAREQ_Pos (30U)
-#define USB_OTG_GRSTCTL_DMAREQ_Msk (0x1UL << USB_OTG_GRSTCTL_DMAREQ_Pos) /*!< 0x40000000 */
-#define USB_OTG_GRSTCTL_DMAREQ USB_OTG_GRSTCTL_DMAREQ_Msk /*!< DMA request signal */
-#define USB_OTG_GRSTCTL_AHBIDL_Pos (31U)
-#define USB_OTG_GRSTCTL_AHBIDL_Msk (0x1UL << USB_OTG_GRSTCTL_AHBIDL_Pos) /*!< 0x80000000 */
-#define USB_OTG_GRSTCTL_AHBIDL USB_OTG_GRSTCTL_AHBIDL_Msk /*!< AHB master idle */
-
-/******************** Bit definition for USB_OTG_DIEPMSK register ********************/
-#define USB_OTG_DIEPMSK_XFRCM_Pos (0U)
-#define USB_OTG_DIEPMSK_XFRCM_Msk (0x1UL << USB_OTG_DIEPMSK_XFRCM_Pos) /*!< 0x00000001 */
-#define USB_OTG_DIEPMSK_XFRCM USB_OTG_DIEPMSK_XFRCM_Msk /*!< Transfer completed interrupt mask */
-#define USB_OTG_DIEPMSK_EPDM_Pos (1U)
-#define USB_OTG_DIEPMSK_EPDM_Msk (0x1UL << USB_OTG_DIEPMSK_EPDM_Pos) /*!< 0x00000002 */
-#define USB_OTG_DIEPMSK_EPDM USB_OTG_DIEPMSK_EPDM_Msk /*!< Endpoint disabled interrupt mask */
-#define USB_OTG_DIEPMSK_TOM_Pos (3U)
-#define USB_OTG_DIEPMSK_TOM_Msk (0x1UL << USB_OTG_DIEPMSK_TOM_Pos) /*!< 0x00000008 */
-#define USB_OTG_DIEPMSK_TOM USB_OTG_DIEPMSK_TOM_Msk /*!< Timeout condition mask (nonisochronous endpoints) */
-#define USB_OTG_DIEPMSK_ITTXFEMSK_Pos (4U)
-#define USB_OTG_DIEPMSK_ITTXFEMSK_Msk (0x1UL << USB_OTG_DIEPMSK_ITTXFEMSK_Pos) /*!< 0x00000010 */
-#define USB_OTG_DIEPMSK_ITTXFEMSK USB_OTG_DIEPMSK_ITTXFEMSK_Msk /*!< IN token received when TxFIFO empty mask */
-#define USB_OTG_DIEPMSK_INEPNMM_Pos (5U)
-#define USB_OTG_DIEPMSK_INEPNMM_Msk (0x1UL << USB_OTG_DIEPMSK_INEPNMM_Pos) /*!< 0x00000020 */
-#define USB_OTG_DIEPMSK_INEPNMM USB_OTG_DIEPMSK_INEPNMM_Msk /*!< IN token received with EP mismatch mask */
-#define USB_OTG_DIEPMSK_INEPNEM_Pos (6U)
-#define USB_OTG_DIEPMSK_INEPNEM_Msk (0x1UL << USB_OTG_DIEPMSK_INEPNEM_Pos) /*!< 0x00000040 */
-#define USB_OTG_DIEPMSK_INEPNEM USB_OTG_DIEPMSK_INEPNEM_Msk /*!< IN endpoint NAK effective mask */
-#define USB_OTG_DIEPMSK_TXFURM_Pos (8U)
-#define USB_OTG_DIEPMSK_TXFURM_Msk (0x1UL << USB_OTG_DIEPMSK_TXFURM_Pos) /*!< 0x00000100 */
-#define USB_OTG_DIEPMSK_TXFURM USB_OTG_DIEPMSK_TXFURM_Msk /*!< FIFO underrun mask */
-#define USB_OTG_DIEPMSK_BIM_Pos (9U)
-#define USB_OTG_DIEPMSK_BIM_Msk (0x1UL << USB_OTG_DIEPMSK_BIM_Pos) /*!< 0x00000200 */
-#define USB_OTG_DIEPMSK_BIM USB_OTG_DIEPMSK_BIM_Msk /*!< BNA interrupt mask */
-
-/******************** Bit definition for USB_OTG_HPTXSTS register ********************/
-#define USB_OTG_HPTXSTS_PTXFSAVL_Pos (0U)
-#define USB_OTG_HPTXSTS_PTXFSAVL_Msk (0xFFFFUL << USB_OTG_HPTXSTS_PTXFSAVL_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_HPTXSTS_PTXFSAVL USB_OTG_HPTXSTS_PTXFSAVL_Msk /*!< Periodic transmit data FIFO space available */
-#define USB_OTG_HPTXSTS_PTXQSAV_Pos (16U)
-#define USB_OTG_HPTXSTS_PTXQSAV_Msk (0xFFUL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00FF0000 */
-#define USB_OTG_HPTXSTS_PTXQSAV USB_OTG_HPTXSTS_PTXQSAV_Msk /*!< Periodic transmit request queue space available */
-#define USB_OTG_HPTXSTS_PTXQSAV_0 (0x01UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00010000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_1 (0x02UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00020000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_2 (0x04UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00040000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_3 (0x08UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00080000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_4 (0x10UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00100000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_5 (0x20UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00200000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_6 (0x40UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00400000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_7 (0x80UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00800000 */
-
-#define USB_OTG_HPTXSTS_PTXQTOP_Pos (24U)
-#define USB_OTG_HPTXSTS_PTXQTOP_Msk (0xFFUL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0xFF000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP USB_OTG_HPTXSTS_PTXQTOP_Msk /*!< Top of the periodic transmit request queue */
-#define USB_OTG_HPTXSTS_PTXQTOP_0 (0x01UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x01000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_1 (0x02UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x02000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_2 (0x04UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x04000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_3 (0x08UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x08000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_4 (0x10UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x10000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_5 (0x20UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x20000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_6 (0x40UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x40000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_7 (0x80UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x80000000 */
-
-/******************** Bit definition for USB_OTG_HAINT register ********************/
-#define USB_OTG_HAINT_HAINT_Pos (0U)
-#define USB_OTG_HAINT_HAINT_Msk (0xFFFFUL << USB_OTG_HAINT_HAINT_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_HAINT_HAINT USB_OTG_HAINT_HAINT_Msk /*!< Channel interrupts */
-
-/******************** Bit definition for USB_OTG_DOEPMSK register ********************/
-#define USB_OTG_DOEPMSK_XFRCM_Pos (0U)
-#define USB_OTG_DOEPMSK_XFRCM_Msk (0x1UL << USB_OTG_DOEPMSK_XFRCM_Pos) /*!< 0x00000001 */
-#define USB_OTG_DOEPMSK_XFRCM USB_OTG_DOEPMSK_XFRCM_Msk /*!< Transfer completed interrupt mask */
-#define USB_OTG_DOEPMSK_EPDM_Pos (1U)
-#define USB_OTG_DOEPMSK_EPDM_Msk (0x1UL << USB_OTG_DOEPMSK_EPDM_Pos) /*!< 0x00000002 */
-#define USB_OTG_DOEPMSK_EPDM USB_OTG_DOEPMSK_EPDM_Msk /*!< Endpoint disabled interrupt mask */
-#define USB_OTG_DOEPMSK_AHBERRM_Pos (2U)
-#define USB_OTG_DOEPMSK_AHBERRM_Msk (0x1UL << USB_OTG_DOEPMSK_AHBERRM_Pos) /*!< 0x00000004 */
-#define USB_OTG_DOEPMSK_AHBERRM USB_OTG_DOEPMSK_AHBERRM_Msk /*!< OUT transaction AHB Error interrupt mask */
-#define USB_OTG_DOEPMSK_STUPM_Pos (3U)
-#define USB_OTG_DOEPMSK_STUPM_Msk (0x1UL << USB_OTG_DOEPMSK_STUPM_Pos) /*!< 0x00000008 */
-#define USB_OTG_DOEPMSK_STUPM USB_OTG_DOEPMSK_STUPM_Msk /*!< SETUP phase done mask */
-#define USB_OTG_DOEPMSK_OTEPDM_Pos (4U)
-#define USB_OTG_DOEPMSK_OTEPDM_Msk (0x1UL << USB_OTG_DOEPMSK_OTEPDM_Pos) /*!< 0x00000010 */
-#define USB_OTG_DOEPMSK_OTEPDM USB_OTG_DOEPMSK_OTEPDM_Msk /*!< OUT token received when endpoint disabled mask */
-#define USB_OTG_DOEPMSK_OTEPSPRM_Pos (5U)
-#define USB_OTG_DOEPMSK_OTEPSPRM_Msk (0x1UL << USB_OTG_DOEPMSK_OTEPSPRM_Pos) /*!< 0x00000020 */
-#define USB_OTG_DOEPMSK_OTEPSPRM USB_OTG_DOEPMSK_OTEPSPRM_Msk /*!< Status Phase Received mask */
-#define USB_OTG_DOEPMSK_B2BSTUP_Pos (6U)
-#define USB_OTG_DOEPMSK_B2BSTUP_Msk (0x1UL << USB_OTG_DOEPMSK_B2BSTUP_Pos) /*!< 0x00000040 */
-#define USB_OTG_DOEPMSK_B2BSTUP USB_OTG_DOEPMSK_B2BSTUP_Msk /*!< Back-to-back SETUP packets received mask */
-#define USB_OTG_DOEPMSK_OPEM_Pos (8U)
-#define USB_OTG_DOEPMSK_OPEM_Msk (0x1UL << USB_OTG_DOEPMSK_OPEM_Pos) /*!< 0x00000100 */
-#define USB_OTG_DOEPMSK_OPEM USB_OTG_DOEPMSK_OPEM_Msk /*!< OUT packet error mask */
-#define USB_OTG_DOEPMSK_BOIM_Pos (9U)
-#define USB_OTG_DOEPMSK_BOIM_Msk (0x1UL << USB_OTG_DOEPMSK_BOIM_Pos) /*!< 0x00000200 */
-#define USB_OTG_DOEPMSK_BOIM USB_OTG_DOEPMSK_BOIM_Msk /*!< BNA interrupt mask */
-#define USB_OTG_DOEPMSK_BERRM_Pos (12U)
-#define USB_OTG_DOEPMSK_BERRM_Msk (0x1UL << USB_OTG_DOEPMSK_BERRM_Pos) /*!< 0x00001000 */
-#define USB_OTG_DOEPMSK_BERRM USB_OTG_DOEPMSK_BERRM_Msk /*!< Babble error interrupt mask */
-#define USB_OTG_DOEPMSK_NAKM_Pos (13U)
-#define USB_OTG_DOEPMSK_NAKM_Msk (0x1UL << USB_OTG_DOEPMSK_NAKM_Pos) /*!< 0x00002000 */
-#define USB_OTG_DOEPMSK_NAKM USB_OTG_DOEPMSK_NAKM_Msk /*!< OUT Packet NAK interrupt mask */
-#define USB_OTG_DOEPMSK_NYETM_Pos (14U)
-#define USB_OTG_DOEPMSK_NYETM_Msk (0x1UL << USB_OTG_DOEPMSK_NYETM_Pos) /*!< 0x00004000 */
-#define USB_OTG_DOEPMSK_NYETM USB_OTG_DOEPMSK_NYETM_Msk /*!< NYET interrupt mask */
-/******************** Bit definition for USB_OTG_GINTSTS register ********************/
-#define USB_OTG_GINTSTS_CMOD_Pos (0U)
-#define USB_OTG_GINTSTS_CMOD_Msk (0x1UL << USB_OTG_GINTSTS_CMOD_Pos) /*!< 0x00000001 */
-#define USB_OTG_GINTSTS_CMOD USB_OTG_GINTSTS_CMOD_Msk /*!< Current mode of operation */
-#define USB_OTG_GINTSTS_MMIS_Pos (1U)
-#define USB_OTG_GINTSTS_MMIS_Msk (0x1UL << USB_OTG_GINTSTS_MMIS_Pos) /*!< 0x00000002 */
-#define USB_OTG_GINTSTS_MMIS USB_OTG_GINTSTS_MMIS_Msk /*!< Mode mismatch interrupt */
-#define USB_OTG_GINTSTS_OTGINT_Pos (2U)
-#define USB_OTG_GINTSTS_OTGINT_Msk (0x1UL << USB_OTG_GINTSTS_OTGINT_Pos) /*!< 0x00000004 */
-#define USB_OTG_GINTSTS_OTGINT USB_OTG_GINTSTS_OTGINT_Msk /*!< OTG interrupt */
-#define USB_OTG_GINTSTS_SOF_Pos (3U)
-#define USB_OTG_GINTSTS_SOF_Msk (0x1UL << USB_OTG_GINTSTS_SOF_Pos) /*!< 0x00000008 */
-#define USB_OTG_GINTSTS_SOF USB_OTG_GINTSTS_SOF_Msk /*!< Start of frame */
-#define USB_OTG_GINTSTS_RXFLVL_Pos (4U)
-#define USB_OTG_GINTSTS_RXFLVL_Msk (0x1UL << USB_OTG_GINTSTS_RXFLVL_Pos) /*!< 0x00000010 */
-#define USB_OTG_GINTSTS_RXFLVL USB_OTG_GINTSTS_RXFLVL_Msk /*!< RxFIFO nonempty */
-#define USB_OTG_GINTSTS_NPTXFE_Pos (5U)
-#define USB_OTG_GINTSTS_NPTXFE_Msk (0x1UL << USB_OTG_GINTSTS_NPTXFE_Pos) /*!< 0x00000020 */
-#define USB_OTG_GINTSTS_NPTXFE USB_OTG_GINTSTS_NPTXFE_Msk /*!< Nonperiodic TxFIFO empty */
-#define USB_OTG_GINTSTS_GINAKEFF_Pos (6U)
-#define USB_OTG_GINTSTS_GINAKEFF_Msk (0x1UL << USB_OTG_GINTSTS_GINAKEFF_Pos) /*!< 0x00000040 */
-#define USB_OTG_GINTSTS_GINAKEFF USB_OTG_GINTSTS_GINAKEFF_Msk /*!< Global IN nonperiodic NAK effective */
-#define USB_OTG_GINTSTS_BOUTNAKEFF_Pos (7U)
-#define USB_OTG_GINTSTS_BOUTNAKEFF_Msk (0x1UL << USB_OTG_GINTSTS_BOUTNAKEFF_Pos) /*!< 0x00000080 */
-#define USB_OTG_GINTSTS_BOUTNAKEFF USB_OTG_GINTSTS_BOUTNAKEFF_Msk /*!< Global OUT NAK effective */
-#define USB_OTG_GINTSTS_ESUSP_Pos (10U)
-#define USB_OTG_GINTSTS_ESUSP_Msk (0x1UL << USB_OTG_GINTSTS_ESUSP_Pos) /*!< 0x00000400 */
-#define USB_OTG_GINTSTS_ESUSP USB_OTG_GINTSTS_ESUSP_Msk /*!< Early suspend */
-#define USB_OTG_GINTSTS_USBSUSP_Pos (11U)
-#define USB_OTG_GINTSTS_USBSUSP_Msk (0x1UL << USB_OTG_GINTSTS_USBSUSP_Pos) /*!< 0x00000800 */
-#define USB_OTG_GINTSTS_USBSUSP USB_OTG_GINTSTS_USBSUSP_Msk /*!< USB suspend */
-#define USB_OTG_GINTSTS_USBRST_Pos (12U)
-#define USB_OTG_GINTSTS_USBRST_Msk (0x1UL << USB_OTG_GINTSTS_USBRST_Pos) /*!< 0x00001000 */
-#define USB_OTG_GINTSTS_USBRST USB_OTG_GINTSTS_USBRST_Msk /*!< USB reset */
-#define USB_OTG_GINTSTS_ENUMDNE_Pos (13U)
-#define USB_OTG_GINTSTS_ENUMDNE_Msk (0x1UL << USB_OTG_GINTSTS_ENUMDNE_Pos) /*!< 0x00002000 */
-#define USB_OTG_GINTSTS_ENUMDNE USB_OTG_GINTSTS_ENUMDNE_Msk /*!< Enumeration done */
-#define USB_OTG_GINTSTS_ISOODRP_Pos (14U)
-#define USB_OTG_GINTSTS_ISOODRP_Msk (0x1UL << USB_OTG_GINTSTS_ISOODRP_Pos) /*!< 0x00004000 */
-#define USB_OTG_GINTSTS_ISOODRP USB_OTG_GINTSTS_ISOODRP_Msk /*!< Isochronous OUT packet dropped interrupt */
-#define USB_OTG_GINTSTS_EOPF_Pos (15U)
-#define USB_OTG_GINTSTS_EOPF_Msk (0x1UL << USB_OTG_GINTSTS_EOPF_Pos) /*!< 0x00008000 */
-#define USB_OTG_GINTSTS_EOPF USB_OTG_GINTSTS_EOPF_Msk /*!< End of periodic frame interrupt */
-#define USB_OTG_GINTSTS_IEPINT_Pos (18U)
-#define USB_OTG_GINTSTS_IEPINT_Msk (0x1UL << USB_OTG_GINTSTS_IEPINT_Pos) /*!< 0x00040000 */
-#define USB_OTG_GINTSTS_IEPINT USB_OTG_GINTSTS_IEPINT_Msk /*!< IN endpoint interrupt */
-#define USB_OTG_GINTSTS_OEPINT_Pos (19U)
-#define USB_OTG_GINTSTS_OEPINT_Msk (0x1UL << USB_OTG_GINTSTS_OEPINT_Pos) /*!< 0x00080000 */
-#define USB_OTG_GINTSTS_OEPINT USB_OTG_GINTSTS_OEPINT_Msk /*!< OUT endpoint interrupt */
-#define USB_OTG_GINTSTS_IISOIXFR_Pos (20U)
-#define USB_OTG_GINTSTS_IISOIXFR_Msk (0x1UL << USB_OTG_GINTSTS_IISOIXFR_Pos) /*!< 0x00100000 */
-#define USB_OTG_GINTSTS_IISOIXFR USB_OTG_GINTSTS_IISOIXFR_Msk /*!< Incomplete isochronous IN transfer */
-#define USB_OTG_GINTSTS_PXFR_INCOMPISOOUT_Pos (21U)
-#define USB_OTG_GINTSTS_PXFR_INCOMPISOOUT_Msk (0x1UL << USB_OTG_GINTSTS_PXFR_INCOMPISOOUT_Pos) /*!< 0x00200000 */
-#define USB_OTG_GINTSTS_PXFR_INCOMPISOOUT USB_OTG_GINTSTS_PXFR_INCOMPISOOUT_Msk /*!< Incomplete periodic transfer */
-#define USB_OTG_GINTSTS_DATAFSUSP_Pos (22U)
-#define USB_OTG_GINTSTS_DATAFSUSP_Msk (0x1UL << USB_OTG_GINTSTS_DATAFSUSP_Pos) /*!< 0x00400000 */
-#define USB_OTG_GINTSTS_DATAFSUSP USB_OTG_GINTSTS_DATAFSUSP_Msk /*!< Data fetch suspended */
-#define USB_OTG_GINTSTS_HPRTINT_Pos (24U)
-#define USB_OTG_GINTSTS_HPRTINT_Msk (0x1UL << USB_OTG_GINTSTS_HPRTINT_Pos) /*!< 0x01000000 */
-#define USB_OTG_GINTSTS_HPRTINT USB_OTG_GINTSTS_HPRTINT_Msk /*!< Host port interrupt */
-#define USB_OTG_GINTSTS_HCINT_Pos (25U)
-#define USB_OTG_GINTSTS_HCINT_Msk (0x1UL << USB_OTG_GINTSTS_HCINT_Pos) /*!< 0x02000000 */
-#define USB_OTG_GINTSTS_HCINT USB_OTG_GINTSTS_HCINT_Msk /*!< Host channels interrupt */
-#define USB_OTG_GINTSTS_PTXFE_Pos (26U)
-#define USB_OTG_GINTSTS_PTXFE_Msk (0x1UL << USB_OTG_GINTSTS_PTXFE_Pos) /*!< 0x04000000 */
-#define USB_OTG_GINTSTS_PTXFE USB_OTG_GINTSTS_PTXFE_Msk /*!< Periodic TxFIFO empty */
-#define USB_OTG_GINTSTS_CIDSCHG_Pos (28U)
-#define USB_OTG_GINTSTS_CIDSCHG_Msk (0x1UL << USB_OTG_GINTSTS_CIDSCHG_Pos) /*!< 0x10000000 */
-#define USB_OTG_GINTSTS_CIDSCHG USB_OTG_GINTSTS_CIDSCHG_Msk /*!< Connector ID status change */
-#define USB_OTG_GINTSTS_DISCINT_Pos (29U)
-#define USB_OTG_GINTSTS_DISCINT_Msk (0x1UL << USB_OTG_GINTSTS_DISCINT_Pos) /*!< 0x20000000 */
-#define USB_OTG_GINTSTS_DISCINT USB_OTG_GINTSTS_DISCINT_Msk /*!< Disconnect detected interrupt */
-#define USB_OTG_GINTSTS_SRQINT_Pos (30U)
-#define USB_OTG_GINTSTS_SRQINT_Msk (0x1UL << USB_OTG_GINTSTS_SRQINT_Pos) /*!< 0x40000000 */
-#define USB_OTG_GINTSTS_SRQINT USB_OTG_GINTSTS_SRQINT_Msk /*!< Session request/new session detected interrupt */
-#define USB_OTG_GINTSTS_WKUINT_Pos (31U)
-#define USB_OTG_GINTSTS_WKUINT_Msk (0x1UL << USB_OTG_GINTSTS_WKUINT_Pos) /*!< 0x80000000 */
-#define USB_OTG_GINTSTS_WKUINT USB_OTG_GINTSTS_WKUINT_Msk /*!< Resume/remote wakeup detected interrupt */
-
-/******************** Bit definition for USB_OTG_GINTMSK register ********************/
-#define USB_OTG_GINTMSK_MMISM_Pos (1U)
-#define USB_OTG_GINTMSK_MMISM_Msk (0x1UL << USB_OTG_GINTMSK_MMISM_Pos) /*!< 0x00000002 */
-#define USB_OTG_GINTMSK_MMISM USB_OTG_GINTMSK_MMISM_Msk /*!< Mode mismatch interrupt mask */
-#define USB_OTG_GINTMSK_OTGINT_Pos (2U)
-#define USB_OTG_GINTMSK_OTGINT_Msk (0x1UL << USB_OTG_GINTMSK_OTGINT_Pos) /*!< 0x00000004 */
-#define USB_OTG_GINTMSK_OTGINT USB_OTG_GINTMSK_OTGINT_Msk /*!< OTG interrupt mask */
-#define USB_OTG_GINTMSK_SOFM_Pos (3U)
-#define USB_OTG_GINTMSK_SOFM_Msk (0x1UL << USB_OTG_GINTMSK_SOFM_Pos) /*!< 0x00000008 */
-#define USB_OTG_GINTMSK_SOFM USB_OTG_GINTMSK_SOFM_Msk /*!< Start of frame mask */
-#define USB_OTG_GINTMSK_RXFLVLM_Pos (4U)
-#define USB_OTG_GINTMSK_RXFLVLM_Msk (0x1UL << USB_OTG_GINTMSK_RXFLVLM_Pos) /*!< 0x00000010 */
-#define USB_OTG_GINTMSK_RXFLVLM USB_OTG_GINTMSK_RXFLVLM_Msk /*!< Receive FIFO nonempty mask */
-#define USB_OTG_GINTMSK_NPTXFEM_Pos (5U)
-#define USB_OTG_GINTMSK_NPTXFEM_Msk (0x1UL << USB_OTG_GINTMSK_NPTXFEM_Pos) /*!< 0x00000020 */
-#define USB_OTG_GINTMSK_NPTXFEM USB_OTG_GINTMSK_NPTXFEM_Msk /*!< Nonperiodic TxFIFO empty mask */
-#define USB_OTG_GINTMSK_GINAKEFFM_Pos (6U)
-#define USB_OTG_GINTMSK_GINAKEFFM_Msk (0x1UL << USB_OTG_GINTMSK_GINAKEFFM_Pos) /*!< 0x00000040 */
-#define USB_OTG_GINTMSK_GINAKEFFM USB_OTG_GINTMSK_GINAKEFFM_Msk /*!< Global nonperiodic IN NAK effective mask */
-#define USB_OTG_GINTMSK_GONAKEFFM_Pos (7U)
-#define USB_OTG_GINTMSK_GONAKEFFM_Msk (0x1UL << USB_OTG_GINTMSK_GONAKEFFM_Pos) /*!< 0x00000080 */
-#define USB_OTG_GINTMSK_GONAKEFFM USB_OTG_GINTMSK_GONAKEFFM_Msk /*!< Global OUT NAK effective mask */
-#define USB_OTG_GINTMSK_ESUSPM_Pos (10U)
-#define USB_OTG_GINTMSK_ESUSPM_Msk (0x1UL << USB_OTG_GINTMSK_ESUSPM_Pos) /*!< 0x00000400 */
-#define USB_OTG_GINTMSK_ESUSPM USB_OTG_GINTMSK_ESUSPM_Msk /*!< Early suspend mask */
-#define USB_OTG_GINTMSK_USBSUSPM_Pos (11U)
-#define USB_OTG_GINTMSK_USBSUSPM_Msk (0x1UL << USB_OTG_GINTMSK_USBSUSPM_Pos) /*!< 0x00000800 */
-#define USB_OTG_GINTMSK_USBSUSPM USB_OTG_GINTMSK_USBSUSPM_Msk /*!< USB suspend mask */
-#define USB_OTG_GINTMSK_USBRST_Pos (12U)
-#define USB_OTG_GINTMSK_USBRST_Msk (0x1UL << USB_OTG_GINTMSK_USBRST_Pos) /*!< 0x00001000 */
-#define USB_OTG_GINTMSK_USBRST USB_OTG_GINTMSK_USBRST_Msk /*!< USB reset mask */
-#define USB_OTG_GINTMSK_ENUMDNEM_Pos (13U)
-#define USB_OTG_GINTMSK_ENUMDNEM_Msk (0x1UL << USB_OTG_GINTMSK_ENUMDNEM_Pos) /*!< 0x00002000 */
-#define USB_OTG_GINTMSK_ENUMDNEM USB_OTG_GINTMSK_ENUMDNEM_Msk /*!< Enumeration done mask */
-#define USB_OTG_GINTMSK_ISOODRPM_Pos (14U)
-#define USB_OTG_GINTMSK_ISOODRPM_Msk (0x1UL << USB_OTG_GINTMSK_ISOODRPM_Pos) /*!< 0x00004000 */
-#define USB_OTG_GINTMSK_ISOODRPM USB_OTG_GINTMSK_ISOODRPM_Msk /*!< Isochronous OUT packet dropped interrupt mask */
-#define USB_OTG_GINTMSK_EOPFM_Pos (15U)
-#define USB_OTG_GINTMSK_EOPFM_Msk (0x1UL << USB_OTG_GINTMSK_EOPFM_Pos) /*!< 0x00008000 */
-#define USB_OTG_GINTMSK_EOPFM USB_OTG_GINTMSK_EOPFM_Msk /*!< End of periodic frame interrupt mask */
-#define USB_OTG_GINTMSK_EPMISM_Pos (17U)
-#define USB_OTG_GINTMSK_EPMISM_Msk (0x1UL << USB_OTG_GINTMSK_EPMISM_Pos) /*!< 0x00020000 */
-#define USB_OTG_GINTMSK_EPMISM USB_OTG_GINTMSK_EPMISM_Msk /*!< Endpoint mismatch interrupt mask */
-#define USB_OTG_GINTMSK_IEPINT_Pos (18U)
-#define USB_OTG_GINTMSK_IEPINT_Msk (0x1UL << USB_OTG_GINTMSK_IEPINT_Pos) /*!< 0x00040000 */
-#define USB_OTG_GINTMSK_IEPINT USB_OTG_GINTMSK_IEPINT_Msk /*!< IN endpoints interrupt mask */
-#define USB_OTG_GINTMSK_OEPINT_Pos (19U)
-#define USB_OTG_GINTMSK_OEPINT_Msk (0x1UL << USB_OTG_GINTMSK_OEPINT_Pos) /*!< 0x00080000 */
-#define USB_OTG_GINTMSK_OEPINT USB_OTG_GINTMSK_OEPINT_Msk /*!< OUT endpoints interrupt mask */
-#define USB_OTG_GINTMSK_IISOIXFRM_Pos (20U)
-#define USB_OTG_GINTMSK_IISOIXFRM_Msk (0x1UL << USB_OTG_GINTMSK_IISOIXFRM_Pos) /*!< 0x00100000 */
-#define USB_OTG_GINTMSK_IISOIXFRM USB_OTG_GINTMSK_IISOIXFRM_Msk /*!< Incomplete isochronous IN transfer mask */
-#define USB_OTG_GINTMSK_PXFRM_IISOOXFRM_Pos (21U)
-#define USB_OTG_GINTMSK_PXFRM_IISOOXFRM_Msk (0x1UL << USB_OTG_GINTMSK_PXFRM_IISOOXFRM_Pos) /*!< 0x00200000 */
-#define USB_OTG_GINTMSK_PXFRM_IISOOXFRM USB_OTG_GINTMSK_PXFRM_IISOOXFRM_Msk /*!< Incomplete periodic transfer mask */
-#define USB_OTG_GINTMSK_FSUSPM_Pos (22U)
-#define USB_OTG_GINTMSK_FSUSPM_Msk (0x1UL << USB_OTG_GINTMSK_FSUSPM_Pos) /*!< 0x00400000 */
-#define USB_OTG_GINTMSK_FSUSPM USB_OTG_GINTMSK_FSUSPM_Msk /*!< Data fetch suspended mask */
-#define USB_OTG_GINTMSK_PRTIM_Pos (24U)
-#define USB_OTG_GINTMSK_PRTIM_Msk (0x1UL << USB_OTG_GINTMSK_PRTIM_Pos) /*!< 0x01000000 */
-#define USB_OTG_GINTMSK_PRTIM USB_OTG_GINTMSK_PRTIM_Msk /*!< Host port interrupt mask */
-#define USB_OTG_GINTMSK_HCIM_Pos (25U)
-#define USB_OTG_GINTMSK_HCIM_Msk (0x1UL << USB_OTG_GINTMSK_HCIM_Pos) /*!< 0x02000000 */
-#define USB_OTG_GINTMSK_HCIM USB_OTG_GINTMSK_HCIM_Msk /*!< Host channels interrupt mask */
-#define USB_OTG_GINTMSK_PTXFEM_Pos (26U)
-#define USB_OTG_GINTMSK_PTXFEM_Msk (0x1UL << USB_OTG_GINTMSK_PTXFEM_Pos) /*!< 0x04000000 */
-#define USB_OTG_GINTMSK_PTXFEM USB_OTG_GINTMSK_PTXFEM_Msk /*!< Periodic TxFIFO empty mask */
-#define USB_OTG_GINTMSK_CIDSCHGM_Pos (28U)
-#define USB_OTG_GINTMSK_CIDSCHGM_Msk (0x1UL << USB_OTG_GINTMSK_CIDSCHGM_Pos) /*!< 0x10000000 */
-#define USB_OTG_GINTMSK_CIDSCHGM USB_OTG_GINTMSK_CIDSCHGM_Msk /*!< Connector ID status change mask */
-#define USB_OTG_GINTMSK_DISCINT_Pos (29U)
-#define USB_OTG_GINTMSK_DISCINT_Msk (0x1UL << USB_OTG_GINTMSK_DISCINT_Pos) /*!< 0x20000000 */
-#define USB_OTG_GINTMSK_DISCINT USB_OTG_GINTMSK_DISCINT_Msk /*!< Disconnect detected interrupt mask */
-#define USB_OTG_GINTMSK_SRQIM_Pos (30U)
-#define USB_OTG_GINTMSK_SRQIM_Msk (0x1UL << USB_OTG_GINTMSK_SRQIM_Pos) /*!< 0x40000000 */
-#define USB_OTG_GINTMSK_SRQIM USB_OTG_GINTMSK_SRQIM_Msk /*!< Session request/new session detected interrupt mask */
-#define USB_OTG_GINTMSK_WUIM_Pos (31U)
-#define USB_OTG_GINTMSK_WUIM_Msk (0x1UL << USB_OTG_GINTMSK_WUIM_Pos) /*!< 0x80000000 */
-#define USB_OTG_GINTMSK_WUIM USB_OTG_GINTMSK_WUIM_Msk /*!< Resume/remote wakeup detected interrupt mask */
-
-/******************** Bit definition for USB_OTG_DAINT register ********************/
-#define USB_OTG_DAINT_IEPINT_Pos (0U)
-#define USB_OTG_DAINT_IEPINT_Msk (0xFFFFUL << USB_OTG_DAINT_IEPINT_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_DAINT_IEPINT USB_OTG_DAINT_IEPINT_Msk /*!< IN endpoint interrupt bits */
-#define USB_OTG_DAINT_OEPINT_Pos (16U)
-#define USB_OTG_DAINT_OEPINT_Msk (0xFFFFUL << USB_OTG_DAINT_OEPINT_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_DAINT_OEPINT USB_OTG_DAINT_OEPINT_Msk /*!< OUT endpoint interrupt bits */
-
-/******************** Bit definition for USB_OTG_HAINTMSK register ********************/
-#define USB_OTG_HAINTMSK_HAINTM_Pos (0U)
-#define USB_OTG_HAINTMSK_HAINTM_Msk (0xFFFFUL << USB_OTG_HAINTMSK_HAINTM_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_HAINTMSK_HAINTM USB_OTG_HAINTMSK_HAINTM_Msk /*!< Channel interrupt mask */
-
-/******************** Bit definition for USB_OTG_GRXSTSP register ********************/
-#define USB_OTG_GRXSTSP_EPNUM_Pos (0U)
-#define USB_OTG_GRXSTSP_EPNUM_Msk (0xFUL << USB_OTG_GRXSTSP_EPNUM_Pos) /*!< 0x0000000F */
-#define USB_OTG_GRXSTSP_EPNUM USB_OTG_GRXSTSP_EPNUM_Msk /*!< IN EP interrupt mask bits */
-#define USB_OTG_GRXSTSP_BCNT_Pos (4U)
-#define USB_OTG_GRXSTSP_BCNT_Msk (0x7FFUL << USB_OTG_GRXSTSP_BCNT_Pos) /*!< 0x00007FF0 */
-#define USB_OTG_GRXSTSP_BCNT USB_OTG_GRXSTSP_BCNT_Msk /*!< OUT EP interrupt mask bits */
-#define USB_OTG_GRXSTSP_DPID_Pos (15U)
-#define USB_OTG_GRXSTSP_DPID_Msk (0x3UL << USB_OTG_GRXSTSP_DPID_Pos) /*!< 0x00018000 */
-#define USB_OTG_GRXSTSP_DPID USB_OTG_GRXSTSP_DPID_Msk /*!< OUT EP interrupt mask bits */
-#define USB_OTG_GRXSTSP_PKTSTS_Pos (17U)
-#define USB_OTG_GRXSTSP_PKTSTS_Msk (0xFUL << USB_OTG_GRXSTSP_PKTSTS_Pos) /*!< 0x001E0000 */
-#define USB_OTG_GRXSTSP_PKTSTS USB_OTG_GRXSTSP_PKTSTS_Msk /*!< OUT EP interrupt mask bits */
-
-/******************** Bit definition for USB_OTG_DAINTMSK register ********************/
-#define USB_OTG_DAINTMSK_IEPM_Pos (0U)
-#define USB_OTG_DAINTMSK_IEPM_Msk (0xFFFFUL << USB_OTG_DAINTMSK_IEPM_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_DAINTMSK_IEPM USB_OTG_DAINTMSK_IEPM_Msk /*!< IN EP interrupt mask bits */
-#define USB_OTG_DAINTMSK_OEPM_Pos (16U)
-#define USB_OTG_DAINTMSK_OEPM_Msk (0xFFFFUL << USB_OTG_DAINTMSK_OEPM_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_DAINTMSK_OEPM USB_OTG_DAINTMSK_OEPM_Msk /*!< OUT EP interrupt mask bits */
-
-/******************** Bit definition for USB_OTG_GRXFSIZ register ********************/
-#define USB_OTG_GRXFSIZ_RXFD_Pos (0U)
-#define USB_OTG_GRXFSIZ_RXFD_Msk (0xFFFFUL << USB_OTG_GRXFSIZ_RXFD_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_GRXFSIZ_RXFD USB_OTG_GRXFSIZ_RXFD_Msk /*!< RxFIFO depth */
-
-/******************** Bit definition for USB_OTG_DVBUSDIS register ********************/
-#define USB_OTG_DVBUSDIS_VBUSDT_Pos (0U)
-#define USB_OTG_DVBUSDIS_VBUSDT_Msk (0xFFFFUL << USB_OTG_DVBUSDIS_VBUSDT_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_DVBUSDIS_VBUSDT USB_OTG_DVBUSDIS_VBUSDT_Msk /*!< Device VBUS discharge time */
-
-/******************** Bit definition for OTG register ********************/
-#define USB_OTG_NPTXFSA_Pos (0U)
-#define USB_OTG_NPTXFSA_Msk (0xFFFFUL << USB_OTG_NPTXFSA_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_NPTXFSA USB_OTG_NPTXFSA_Msk /*!< Nonperiodic transmit RAM start address */
-#define USB_OTG_NPTXFD_Pos (16U)
-#define USB_OTG_NPTXFD_Msk (0xFFFFUL << USB_OTG_NPTXFD_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_NPTXFD USB_OTG_NPTXFD_Msk /*!< Nonperiodic TxFIFO depth */
-#define USB_OTG_TX0FSA_Pos (0U)
-#define USB_OTG_TX0FSA_Msk (0xFFFFUL << USB_OTG_TX0FSA_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_TX0FSA USB_OTG_TX0FSA_Msk /*!< Endpoint 0 transmit RAM start address */
-#define USB_OTG_TX0FD_Pos (16U)
-#define USB_OTG_TX0FD_Msk (0xFFFFUL << USB_OTG_TX0FD_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_TX0FD USB_OTG_TX0FD_Msk /*!< Endpoint 0 TxFIFO depth */
-
-/******************** Bit definition for USB_OTG_DVBUSPULSE register ********************/
-#define USB_OTG_DVBUSPULSE_DVBUSP_Pos (0U)
-#define USB_OTG_DVBUSPULSE_DVBUSP_Msk (0xFFFUL << USB_OTG_DVBUSPULSE_DVBUSP_Pos) /*!< 0x00000FFF */
-#define USB_OTG_DVBUSPULSE_DVBUSP USB_OTG_DVBUSPULSE_DVBUSP_Msk /*!< Device VBUS pulsing time */
-
-/******************** Bit definition for USB_OTG_GNPTXSTS register ********************/
-#define USB_OTG_GNPTXSTS_NPTXFSAV_Pos (0U)
-#define USB_OTG_GNPTXSTS_NPTXFSAV_Msk (0xFFFFUL << USB_OTG_GNPTXSTS_NPTXFSAV_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_GNPTXSTS_NPTXFSAV USB_OTG_GNPTXSTS_NPTXFSAV_Msk /*!< Nonperiodic TxFIFO space available */
-
-#define USB_OTG_GNPTXSTS_NPTQXSAV_Pos (16U)
-#define USB_OTG_GNPTXSTS_NPTQXSAV_Msk (0xFFUL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00FF0000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV USB_OTG_GNPTXSTS_NPTQXSAV_Msk /*!< Nonperiodic transmit request queue space available */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_0 (0x01UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00010000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_1 (0x02UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00020000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_2 (0x04UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00040000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_3 (0x08UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00080000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_4 (0x10UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00100000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_5 (0x20UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00200000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_6 (0x40UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00400000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_7 (0x80UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00800000 */
-
-#define USB_OTG_GNPTXSTS_NPTXQTOP_Pos (24U)
-#define USB_OTG_GNPTXSTS_NPTXQTOP_Msk (0x7FUL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x7F000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP USB_OTG_GNPTXSTS_NPTXQTOP_Msk /*!< Top of the nonperiodic transmit request queue */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_0 (0x01UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x01000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_1 (0x02UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x02000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_2 (0x04UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x04000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_3 (0x08UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x08000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_4 (0x10UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x10000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_5 (0x20UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x20000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_6 (0x40UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x40000000 */
-
-/******************** Bit definition for USB_OTG_DTHRCTL register ********************/
-#define USB_OTG_DTHRCTL_NONISOTHREN_Pos (0U)
-#define USB_OTG_DTHRCTL_NONISOTHREN_Msk (0x1UL << USB_OTG_DTHRCTL_NONISOTHREN_Pos) /*!< 0x00000001 */
-#define USB_OTG_DTHRCTL_NONISOTHREN USB_OTG_DTHRCTL_NONISOTHREN_Msk /*!< Nonisochronous IN endpoints threshold enable */
-#define USB_OTG_DTHRCTL_ISOTHREN_Pos (1U)
-#define USB_OTG_DTHRCTL_ISOTHREN_Msk (0x1UL << USB_OTG_DTHRCTL_ISOTHREN_Pos) /*!< 0x00000002 */
-#define USB_OTG_DTHRCTL_ISOTHREN USB_OTG_DTHRCTL_ISOTHREN_Msk /*!< ISO IN endpoint threshold enable */
-
-#define USB_OTG_DTHRCTL_TXTHRLEN_Pos (2U)
-#define USB_OTG_DTHRCTL_TXTHRLEN_Msk (0x1FFUL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x000007FC */
-#define USB_OTG_DTHRCTL_TXTHRLEN USB_OTG_DTHRCTL_TXTHRLEN_Msk /*!< Transmit threshold length */
-#define USB_OTG_DTHRCTL_TXTHRLEN_0 (0x001UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000004 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_1 (0x002UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000008 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_2 (0x004UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000010 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_3 (0x008UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000020 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_4 (0x010UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000040 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_5 (0x020UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000080 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_6 (0x040UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000100 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_7 (0x080UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000200 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_8 (0x100UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000400 */
-#define USB_OTG_DTHRCTL_RXTHREN_Pos (16U)
-#define USB_OTG_DTHRCTL_RXTHREN_Msk (0x1UL << USB_OTG_DTHRCTL_RXTHREN_Pos) /*!< 0x00010000 */
-#define USB_OTG_DTHRCTL_RXTHREN USB_OTG_DTHRCTL_RXTHREN_Msk /*!< Receive threshold enable */
-
-#define USB_OTG_DTHRCTL_RXTHRLEN_Pos (17U)
-#define USB_OTG_DTHRCTL_RXTHRLEN_Msk (0x1FFUL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x03FE0000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN USB_OTG_DTHRCTL_RXTHRLEN_Msk /*!< Receive threshold length */
-#define USB_OTG_DTHRCTL_RXTHRLEN_0 (0x001UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00020000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_1 (0x002UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00040000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_2 (0x004UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00080000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_3 (0x008UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00100000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_4 (0x010UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00200000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_5 (0x020UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00400000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_6 (0x040UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00800000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_7 (0x080UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x01000000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_8 (0x100UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x02000000 */
-#define USB_OTG_DTHRCTL_ARPEN_Pos (27U)
-#define USB_OTG_DTHRCTL_ARPEN_Msk (0x1UL << USB_OTG_DTHRCTL_ARPEN_Pos) /*!< 0x08000000 */
-#define USB_OTG_DTHRCTL_ARPEN USB_OTG_DTHRCTL_ARPEN_Msk /*!< Arbiter parking enable */
-
-/******************** Bit definition for USB_OTG_DIEPEMPMSK register ********************/
-#define USB_OTG_DIEPEMPMSK_INEPTXFEM_Pos (0U)
-#define USB_OTG_DIEPEMPMSK_INEPTXFEM_Msk (0xFFFFUL << USB_OTG_DIEPEMPMSK_INEPTXFEM_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_DIEPEMPMSK_INEPTXFEM USB_OTG_DIEPEMPMSK_INEPTXFEM_Msk /*!< IN EP Tx FIFO empty interrupt mask bits */
-
-/******************** Bit definition for USB_OTG_DEACHINT register ********************/
-#define USB_OTG_DEACHINT_IEP1INT_Pos (1U)
-#define USB_OTG_DEACHINT_IEP1INT_Msk (0x1UL << USB_OTG_DEACHINT_IEP1INT_Pos) /*!< 0x00000002 */
-#define USB_OTG_DEACHINT_IEP1INT USB_OTG_DEACHINT_IEP1INT_Msk /*!< IN endpoint 1interrupt bit */
-#define USB_OTG_DEACHINT_OEP1INT_Pos (17U)
-#define USB_OTG_DEACHINT_OEP1INT_Msk (0x1UL << USB_OTG_DEACHINT_OEP1INT_Pos) /*!< 0x00020000 */
-#define USB_OTG_DEACHINT_OEP1INT USB_OTG_DEACHINT_OEP1INT_Msk /*!< OUT endpoint 1 interrupt bit */
-
-/******************** Bit definition for USB_OTG_GCCFG register ********************/
-#define USB_OTG_GCCFG_PWRDWN_Pos (16U)
-#define USB_OTG_GCCFG_PWRDWN_Msk (0x1UL << USB_OTG_GCCFG_PWRDWN_Pos) /*!< 0x00010000 */
-#define USB_OTG_GCCFG_PWRDWN USB_OTG_GCCFG_PWRDWN_Msk /*!< Power down */
-#define USB_OTG_GCCFG_VBUSASEN_Pos (18U)
-#define USB_OTG_GCCFG_VBUSASEN_Msk (0x1UL << USB_OTG_GCCFG_VBUSASEN_Pos) /*!< 0x00040000 */
-#define USB_OTG_GCCFG_VBUSASEN USB_OTG_GCCFG_VBUSASEN_Msk /*!< Enable the VBUS sensing device */
-#define USB_OTG_GCCFG_VBUSBSEN_Pos (19U)
-#define USB_OTG_GCCFG_VBUSBSEN_Msk (0x1UL << USB_OTG_GCCFG_VBUSBSEN_Pos) /*!< 0x00080000 */
-#define USB_OTG_GCCFG_VBUSBSEN USB_OTG_GCCFG_VBUSBSEN_Msk /*!< Enable the VBUS sensing device */
-#define USB_OTG_GCCFG_SOFOUTEN_Pos (20U)
-#define USB_OTG_GCCFG_SOFOUTEN_Msk (0x1UL << USB_OTG_GCCFG_SOFOUTEN_Pos) /*!< 0x00100000 */
-#define USB_OTG_GCCFG_SOFOUTEN USB_OTG_GCCFG_SOFOUTEN_Msk /*!< SOF output enable */
-
-/******************** Bit definition for USB_OTG_DEACHINTMSK register ********************/
-#define USB_OTG_DEACHINTMSK_IEP1INTM_Pos (1U)
-#define USB_OTG_DEACHINTMSK_IEP1INTM_Msk (0x1UL << USB_OTG_DEACHINTMSK_IEP1INTM_Pos) /*!< 0x00000002 */
-#define USB_OTG_DEACHINTMSK_IEP1INTM USB_OTG_DEACHINTMSK_IEP1INTM_Msk /*!< IN Endpoint 1 interrupt mask bit */
-#define USB_OTG_DEACHINTMSK_OEP1INTM_Pos (17U)
-#define USB_OTG_DEACHINTMSK_OEP1INTM_Msk (0x1UL << USB_OTG_DEACHINTMSK_OEP1INTM_Pos) /*!< 0x00020000 */
-#define USB_OTG_DEACHINTMSK_OEP1INTM USB_OTG_DEACHINTMSK_OEP1INTM_Msk /*!< OUT Endpoint 1 interrupt mask bit */
-
-/******************** Bit definition for USB_OTG_CID register ********************/
-#define USB_OTG_CID_PRODUCT_ID_Pos (0U)
-#define USB_OTG_CID_PRODUCT_ID_Msk (0xFFFFFFFFUL << USB_OTG_CID_PRODUCT_ID_Pos) /*!< 0xFFFFFFFF */
-#define USB_OTG_CID_PRODUCT_ID USB_OTG_CID_PRODUCT_ID_Msk /*!< Product ID field */
-
-/******************** Bit definition for USB_OTG_DIEPEACHMSK1 register ********************/
-#define USB_OTG_DIEPEACHMSK1_XFRCM_Pos (0U)
-#define USB_OTG_DIEPEACHMSK1_XFRCM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_XFRCM_Pos) /*!< 0x00000001 */
-#define USB_OTG_DIEPEACHMSK1_XFRCM USB_OTG_DIEPEACHMSK1_XFRCM_Msk /*!< Transfer completed interrupt mask */
-#define USB_OTG_DIEPEACHMSK1_EPDM_Pos (1U)
-#define USB_OTG_DIEPEACHMSK1_EPDM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_EPDM_Pos) /*!< 0x00000002 */
-#define USB_OTG_DIEPEACHMSK1_EPDM USB_OTG_DIEPEACHMSK1_EPDM_Msk /*!< Endpoint disabled interrupt mask */
-#define USB_OTG_DIEPEACHMSK1_TOM_Pos (3U)
-#define USB_OTG_DIEPEACHMSK1_TOM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_TOM_Pos) /*!< 0x00000008 */
-#define USB_OTG_DIEPEACHMSK1_TOM USB_OTG_DIEPEACHMSK1_TOM_Msk /*!< Timeout condition mask (nonisochronous endpoints) */
-#define USB_OTG_DIEPEACHMSK1_ITTXFEMSK_Pos (4U)
-#define USB_OTG_DIEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_ITTXFEMSK_Pos) /*!< 0x00000010 */
-#define USB_OTG_DIEPEACHMSK1_ITTXFEMSK USB_OTG_DIEPEACHMSK1_ITTXFEMSK_Msk /*!< IN token received when TxFIFO empty mask */
-#define USB_OTG_DIEPEACHMSK1_INEPNMM_Pos (5U)
-#define USB_OTG_DIEPEACHMSK1_INEPNMM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_INEPNMM_Pos) /*!< 0x00000020 */
-#define USB_OTG_DIEPEACHMSK1_INEPNMM USB_OTG_DIEPEACHMSK1_INEPNMM_Msk /*!< IN token received with EP mismatch mask */
-#define USB_OTG_DIEPEACHMSK1_INEPNEM_Pos (6U)
-#define USB_OTG_DIEPEACHMSK1_INEPNEM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_INEPNEM_Pos) /*!< 0x00000040 */
-#define USB_OTG_DIEPEACHMSK1_INEPNEM USB_OTG_DIEPEACHMSK1_INEPNEM_Msk /*!< IN endpoint NAK effective mask */
-#define USB_OTG_DIEPEACHMSK1_TXFURM_Pos (8U)
-#define USB_OTG_DIEPEACHMSK1_TXFURM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_TXFURM_Pos) /*!< 0x00000100 */
-#define USB_OTG_DIEPEACHMSK1_TXFURM USB_OTG_DIEPEACHMSK1_TXFURM_Msk /*!< FIFO underrun mask */
-#define USB_OTG_DIEPEACHMSK1_BIM_Pos (9U)
-#define USB_OTG_DIEPEACHMSK1_BIM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_BIM_Pos) /*!< 0x00000200 */
-#define USB_OTG_DIEPEACHMSK1_BIM USB_OTG_DIEPEACHMSK1_BIM_Msk /*!< BNA interrupt mask */
-#define USB_OTG_DIEPEACHMSK1_NAKM_Pos (13U)
-#define USB_OTG_DIEPEACHMSK1_NAKM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_NAKM_Pos) /*!< 0x00002000 */
-#define USB_OTG_DIEPEACHMSK1_NAKM USB_OTG_DIEPEACHMSK1_NAKM_Msk /*!< NAK interrupt mask */
-
-/******************** Bit definition for USB_OTG_HPRT register ********************/
-#define USB_OTG_HPRT_PCSTS_Pos (0U)
-#define USB_OTG_HPRT_PCSTS_Msk (0x1UL << USB_OTG_HPRT_PCSTS_Pos) /*!< 0x00000001 */
-#define USB_OTG_HPRT_PCSTS USB_OTG_HPRT_PCSTS_Msk /*!< Port connect status */
-#define USB_OTG_HPRT_PCDET_Pos (1U)
-#define USB_OTG_HPRT_PCDET_Msk (0x1UL << USB_OTG_HPRT_PCDET_Pos) /*!< 0x00000002 */
-#define USB_OTG_HPRT_PCDET USB_OTG_HPRT_PCDET_Msk /*!< Port connect detected */
-#define USB_OTG_HPRT_PENA_Pos (2U)
-#define USB_OTG_HPRT_PENA_Msk (0x1UL << USB_OTG_HPRT_PENA_Pos) /*!< 0x00000004 */
-#define USB_OTG_HPRT_PENA USB_OTG_HPRT_PENA_Msk /*!< Port enable */
-#define USB_OTG_HPRT_PENCHNG_Pos (3U)
-#define USB_OTG_HPRT_PENCHNG_Msk (0x1UL << USB_OTG_HPRT_PENCHNG_Pos) /*!< 0x00000008 */
-#define USB_OTG_HPRT_PENCHNG USB_OTG_HPRT_PENCHNG_Msk /*!< Port enable/disable change */
-#define USB_OTG_HPRT_POCA_Pos (4U)
-#define USB_OTG_HPRT_POCA_Msk (0x1UL << USB_OTG_HPRT_POCA_Pos) /*!< 0x00000010 */
-#define USB_OTG_HPRT_POCA USB_OTG_HPRT_POCA_Msk /*!< Port overcurrent active */
-#define USB_OTG_HPRT_POCCHNG_Pos (5U)
-#define USB_OTG_HPRT_POCCHNG_Msk (0x1UL << USB_OTG_HPRT_POCCHNG_Pos) /*!< 0x00000020 */
-#define USB_OTG_HPRT_POCCHNG USB_OTG_HPRT_POCCHNG_Msk /*!< Port overcurrent change */
-#define USB_OTG_HPRT_PRES_Pos (6U)
-#define USB_OTG_HPRT_PRES_Msk (0x1UL << USB_OTG_HPRT_PRES_Pos) /*!< 0x00000040 */
-#define USB_OTG_HPRT_PRES USB_OTG_HPRT_PRES_Msk /*!< Port resume */
-#define USB_OTG_HPRT_PSUSP_Pos (7U)
-#define USB_OTG_HPRT_PSUSP_Msk (0x1UL << USB_OTG_HPRT_PSUSP_Pos) /*!< 0x00000080 */
-#define USB_OTG_HPRT_PSUSP USB_OTG_HPRT_PSUSP_Msk /*!< Port suspend */
-#define USB_OTG_HPRT_PRST_Pos (8U)
-#define USB_OTG_HPRT_PRST_Msk (0x1UL << USB_OTG_HPRT_PRST_Pos) /*!< 0x00000100 */
-#define USB_OTG_HPRT_PRST USB_OTG_HPRT_PRST_Msk /*!< Port reset */
-
-#define USB_OTG_HPRT_PLSTS_Pos (10U)
-#define USB_OTG_HPRT_PLSTS_Msk (0x3UL << USB_OTG_HPRT_PLSTS_Pos) /*!< 0x00000C00 */
-#define USB_OTG_HPRT_PLSTS USB_OTG_HPRT_PLSTS_Msk /*!< Port line status */
-#define USB_OTG_HPRT_PLSTS_0 (0x1UL << USB_OTG_HPRT_PLSTS_Pos) /*!< 0x00000400 */
-#define USB_OTG_HPRT_PLSTS_1 (0x2UL << USB_OTG_HPRT_PLSTS_Pos) /*!< 0x00000800 */
-#define USB_OTG_HPRT_PPWR_Pos (12U)
-#define USB_OTG_HPRT_PPWR_Msk (0x1UL << USB_OTG_HPRT_PPWR_Pos) /*!< 0x00001000 */
-#define USB_OTG_HPRT_PPWR USB_OTG_HPRT_PPWR_Msk /*!< Port power */
-
-#define USB_OTG_HPRT_PTCTL_Pos (13U)
-#define USB_OTG_HPRT_PTCTL_Msk (0xFUL << USB_OTG_HPRT_PTCTL_Pos) /*!< 0x0001E000 */
-#define USB_OTG_HPRT_PTCTL USB_OTG_HPRT_PTCTL_Msk /*!< Port test control */
-#define USB_OTG_HPRT_PTCTL_0 (0x1UL << USB_OTG_HPRT_PTCTL_Pos) /*!< 0x00002000 */
-#define USB_OTG_HPRT_PTCTL_1 (0x2UL << USB_OTG_HPRT_PTCTL_Pos) /*!< 0x00004000 */
-#define USB_OTG_HPRT_PTCTL_2 (0x4UL << USB_OTG_HPRT_PTCTL_Pos) /*!< 0x00008000 */
-#define USB_OTG_HPRT_PTCTL_3 (0x8UL << USB_OTG_HPRT_PTCTL_Pos) /*!< 0x00010000 */
-
-#define USB_OTG_HPRT_PSPD_Pos (17U)
-#define USB_OTG_HPRT_PSPD_Msk (0x3UL << USB_OTG_HPRT_PSPD_Pos) /*!< 0x00060000 */
-#define USB_OTG_HPRT_PSPD USB_OTG_HPRT_PSPD_Msk /*!< Port speed */
-#define USB_OTG_HPRT_PSPD_0 (0x1UL << USB_OTG_HPRT_PSPD_Pos) /*!< 0x00020000 */
-#define USB_OTG_HPRT_PSPD_1 (0x2UL << USB_OTG_HPRT_PSPD_Pos) /*!< 0x00040000 */
-
-/******************** Bit definition for USB_OTG_DOEPEACHMSK1 register ********************/
-#define USB_OTG_DOEPEACHMSK1_XFRCM_Pos (0U)
-#define USB_OTG_DOEPEACHMSK1_XFRCM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_XFRCM_Pos) /*!< 0x00000001 */
-#define USB_OTG_DOEPEACHMSK1_XFRCM USB_OTG_DOEPEACHMSK1_XFRCM_Msk /*!< Transfer completed interrupt mask */
-#define USB_OTG_DOEPEACHMSK1_EPDM_Pos (1U)
-#define USB_OTG_DOEPEACHMSK1_EPDM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_EPDM_Pos) /*!< 0x00000002 */
-#define USB_OTG_DOEPEACHMSK1_EPDM USB_OTG_DOEPEACHMSK1_EPDM_Msk /*!< Endpoint disabled interrupt mask */
-#define USB_OTG_DOEPEACHMSK1_TOM_Pos (3U)
-#define USB_OTG_DOEPEACHMSK1_TOM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_TOM_Pos) /*!< 0x00000008 */
-#define USB_OTG_DOEPEACHMSK1_TOM USB_OTG_DOEPEACHMSK1_TOM_Msk /*!< Timeout condition mask */
-#define USB_OTG_DOEPEACHMSK1_ITTXFEMSK_Pos (4U)
-#define USB_OTG_DOEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_ITTXFEMSK_Pos) /*!< 0x00000010 */
-#define USB_OTG_DOEPEACHMSK1_ITTXFEMSK USB_OTG_DOEPEACHMSK1_ITTXFEMSK_Msk /*!< IN token received when TxFIFO empty mask */
-#define USB_OTG_DOEPEACHMSK1_INEPNMM_Pos (5U)
-#define USB_OTG_DOEPEACHMSK1_INEPNMM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_INEPNMM_Pos) /*!< 0x00000020 */
-#define USB_OTG_DOEPEACHMSK1_INEPNMM USB_OTG_DOEPEACHMSK1_INEPNMM_Msk /*!< IN token received with EP mismatch mask */
-#define USB_OTG_DOEPEACHMSK1_INEPNEM_Pos (6U)
-#define USB_OTG_DOEPEACHMSK1_INEPNEM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_INEPNEM_Pos) /*!< 0x00000040 */
-#define USB_OTG_DOEPEACHMSK1_INEPNEM USB_OTG_DOEPEACHMSK1_INEPNEM_Msk /*!< IN endpoint NAK effective mask */
-#define USB_OTG_DOEPEACHMSK1_TXFURM_Pos (8U)
-#define USB_OTG_DOEPEACHMSK1_TXFURM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_TXFURM_Pos) /*!< 0x00000100 */
-#define USB_OTG_DOEPEACHMSK1_TXFURM USB_OTG_DOEPEACHMSK1_TXFURM_Msk /*!< OUT packet error mask */
-#define USB_OTG_DOEPEACHMSK1_BIM_Pos (9U)
-#define USB_OTG_DOEPEACHMSK1_BIM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_BIM_Pos) /*!< 0x00000200 */
-#define USB_OTG_DOEPEACHMSK1_BIM USB_OTG_DOEPEACHMSK1_BIM_Msk /*!< BNA interrupt mask */
-#define USB_OTG_DOEPEACHMSK1_BERRM_Pos (12U)
-#define USB_OTG_DOEPEACHMSK1_BERRM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_BERRM_Pos) /*!< 0x00001000 */
-#define USB_OTG_DOEPEACHMSK1_BERRM USB_OTG_DOEPEACHMSK1_BERRM_Msk /*!< Bubble error interrupt mask */
-#define USB_OTG_DOEPEACHMSK1_NAKM_Pos (13U)
-#define USB_OTG_DOEPEACHMSK1_NAKM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_NAKM_Pos) /*!< 0x00002000 */
-#define USB_OTG_DOEPEACHMSK1_NAKM USB_OTG_DOEPEACHMSK1_NAKM_Msk /*!< NAK interrupt mask */
-#define USB_OTG_DOEPEACHMSK1_NYETM_Pos (14U)
-#define USB_OTG_DOEPEACHMSK1_NYETM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_NYETM_Pos) /*!< 0x00004000 */
-#define USB_OTG_DOEPEACHMSK1_NYETM USB_OTG_DOEPEACHMSK1_NYETM_Msk /*!< NYET interrupt mask */
-
-/******************** Bit definition for USB_OTG_HPTXFSIZ register ********************/
-#define USB_OTG_HPTXFSIZ_PTXSA_Pos (0U)
-#define USB_OTG_HPTXFSIZ_PTXSA_Msk (0xFFFFUL << USB_OTG_HPTXFSIZ_PTXSA_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_HPTXFSIZ_PTXSA USB_OTG_HPTXFSIZ_PTXSA_Msk /*!< Host periodic TxFIFO start address */
-#define USB_OTG_HPTXFSIZ_PTXFD_Pos (16U)
-#define USB_OTG_HPTXFSIZ_PTXFD_Msk (0xFFFFUL << USB_OTG_HPTXFSIZ_PTXFD_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_HPTXFSIZ_PTXFD USB_OTG_HPTXFSIZ_PTXFD_Msk /*!< Host periodic TxFIFO depth */
-
-/******************** Bit definition for USB_OTG_DIEPCTL register ********************/
-#define USB_OTG_DIEPCTL_MPSIZ_Pos (0U)
-#define USB_OTG_DIEPCTL_MPSIZ_Msk (0x7FFUL << USB_OTG_DIEPCTL_MPSIZ_Pos) /*!< 0x000007FF */
-#define USB_OTG_DIEPCTL_MPSIZ USB_OTG_DIEPCTL_MPSIZ_Msk /*!< Maximum packet size */
-#define USB_OTG_DIEPCTL_USBAEP_Pos (15U)
-#define USB_OTG_DIEPCTL_USBAEP_Msk (0x1UL << USB_OTG_DIEPCTL_USBAEP_Pos) /*!< 0x00008000 */
-#define USB_OTG_DIEPCTL_USBAEP USB_OTG_DIEPCTL_USBAEP_Msk /*!< USB active endpoint */
-#define USB_OTG_DIEPCTL_EONUM_DPID_Pos (16U)
-#define USB_OTG_DIEPCTL_EONUM_DPID_Msk (0x1UL << USB_OTG_DIEPCTL_EONUM_DPID_Pos) /*!< 0x00010000 */
-#define USB_OTG_DIEPCTL_EONUM_DPID USB_OTG_DIEPCTL_EONUM_DPID_Msk /*!< Even/odd frame */
-#define USB_OTG_DIEPCTL_NAKSTS_Pos (17U)
-#define USB_OTG_DIEPCTL_NAKSTS_Msk (0x1UL << USB_OTG_DIEPCTL_NAKSTS_Pos) /*!< 0x00020000 */
-#define USB_OTG_DIEPCTL_NAKSTS USB_OTG_DIEPCTL_NAKSTS_Msk /*!< NAK status */
-
-#define USB_OTG_DIEPCTL_EPTYP_Pos (18U)
-#define USB_OTG_DIEPCTL_EPTYP_Msk (0x3UL << USB_OTG_DIEPCTL_EPTYP_Pos) /*!< 0x000C0000 */
-#define USB_OTG_DIEPCTL_EPTYP USB_OTG_DIEPCTL_EPTYP_Msk /*!< Endpoint type */
-#define USB_OTG_DIEPCTL_EPTYP_0 (0x1UL << USB_OTG_DIEPCTL_EPTYP_Pos) /*!< 0x00040000 */
-#define USB_OTG_DIEPCTL_EPTYP_1 (0x2UL << USB_OTG_DIEPCTL_EPTYP_Pos) /*!< 0x00080000 */
-#define USB_OTG_DIEPCTL_STALL_Pos (21U)
-#define USB_OTG_DIEPCTL_STALL_Msk (0x1UL << USB_OTG_DIEPCTL_STALL_Pos) /*!< 0x00200000 */
-#define USB_OTG_DIEPCTL_STALL USB_OTG_DIEPCTL_STALL_Msk /*!< STALL handshake */
-
-#define USB_OTG_DIEPCTL_TXFNUM_Pos (22U)
-#define USB_OTG_DIEPCTL_TXFNUM_Msk (0xFUL << USB_OTG_DIEPCTL_TXFNUM_Pos) /*!< 0x03C00000 */
-#define USB_OTG_DIEPCTL_TXFNUM USB_OTG_DIEPCTL_TXFNUM_Msk /*!< TxFIFO number */
-#define USB_OTG_DIEPCTL_TXFNUM_0 (0x1UL << USB_OTG_DIEPCTL_TXFNUM_Pos) /*!< 0x00400000 */
-#define USB_OTG_DIEPCTL_TXFNUM_1 (0x2UL << USB_OTG_DIEPCTL_TXFNUM_Pos) /*!< 0x00800000 */
-#define USB_OTG_DIEPCTL_TXFNUM_2 (0x4UL << USB_OTG_DIEPCTL_TXFNUM_Pos) /*!< 0x01000000 */
-#define USB_OTG_DIEPCTL_TXFNUM_3 (0x8UL << USB_OTG_DIEPCTL_TXFNUM_Pos) /*!< 0x02000000 */
-#define USB_OTG_DIEPCTL_CNAK_Pos (26U)
-#define USB_OTG_DIEPCTL_CNAK_Msk (0x1UL << USB_OTG_DIEPCTL_CNAK_Pos) /*!< 0x04000000 */
-#define USB_OTG_DIEPCTL_CNAK USB_OTG_DIEPCTL_CNAK_Msk /*!< Clear NAK */
-#define USB_OTG_DIEPCTL_SNAK_Pos (27U)
-#define USB_OTG_DIEPCTL_SNAK_Msk (0x1UL << USB_OTG_DIEPCTL_SNAK_Pos) /*!< 0x08000000 */
-#define USB_OTG_DIEPCTL_SNAK USB_OTG_DIEPCTL_SNAK_Msk /*!< Set NAK */
-#define USB_OTG_DIEPCTL_SD0PID_SEVNFRM_Pos (28U)
-#define USB_OTG_DIEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << USB_OTG_DIEPCTL_SD0PID_SEVNFRM_Pos) /*!< 0x10000000 */
-#define USB_OTG_DIEPCTL_SD0PID_SEVNFRM USB_OTG_DIEPCTL_SD0PID_SEVNFRM_Msk /*!< Set DATA0 PID */
-#define USB_OTG_DIEPCTL_SODDFRM_Pos (29U)
-#define USB_OTG_DIEPCTL_SODDFRM_Msk (0x1UL << USB_OTG_DIEPCTL_SODDFRM_Pos) /*!< 0x20000000 */
-#define USB_OTG_DIEPCTL_SODDFRM USB_OTG_DIEPCTL_SODDFRM_Msk /*!< Set odd frame */
-#define USB_OTG_DIEPCTL_EPDIS_Pos (30U)
-#define USB_OTG_DIEPCTL_EPDIS_Msk (0x1UL << USB_OTG_DIEPCTL_EPDIS_Pos) /*!< 0x40000000 */
-#define USB_OTG_DIEPCTL_EPDIS USB_OTG_DIEPCTL_EPDIS_Msk /*!< Endpoint disable */
-#define USB_OTG_DIEPCTL_EPENA_Pos (31U)
-#define USB_OTG_DIEPCTL_EPENA_Msk (0x1UL << USB_OTG_DIEPCTL_EPENA_Pos) /*!< 0x80000000 */
-#define USB_OTG_DIEPCTL_EPENA USB_OTG_DIEPCTL_EPENA_Msk /*!< Endpoint enable */
-
-/******************** Bit definition for USB_OTG_HCCHAR register ********************/
-#define USB_OTG_HCCHAR_MPSIZ_Pos (0U)
-#define USB_OTG_HCCHAR_MPSIZ_Msk (0x7FFUL << USB_OTG_HCCHAR_MPSIZ_Pos) /*!< 0x000007FF */
-#define USB_OTG_HCCHAR_MPSIZ USB_OTG_HCCHAR_MPSIZ_Msk /*!< Maximum packet size */
-
-#define USB_OTG_HCCHAR_EPNUM_Pos (11U)
-#define USB_OTG_HCCHAR_EPNUM_Msk (0xFUL << USB_OTG_HCCHAR_EPNUM_Pos) /*!< 0x00007800 */
-#define USB_OTG_HCCHAR_EPNUM USB_OTG_HCCHAR_EPNUM_Msk /*!< Endpoint number */
-#define USB_OTG_HCCHAR_EPNUM_0 (0x1UL << USB_OTG_HCCHAR_EPNUM_Pos) /*!< 0x00000800 */
-#define USB_OTG_HCCHAR_EPNUM_1 (0x2UL << USB_OTG_HCCHAR_EPNUM_Pos) /*!< 0x00001000 */
-#define USB_OTG_HCCHAR_EPNUM_2 (0x4UL << USB_OTG_HCCHAR_EPNUM_Pos) /*!< 0x00002000 */
-#define USB_OTG_HCCHAR_EPNUM_3 (0x8UL << USB_OTG_HCCHAR_EPNUM_Pos) /*!< 0x00004000 */
-#define USB_OTG_HCCHAR_EPDIR_Pos (15U)
-#define USB_OTG_HCCHAR_EPDIR_Msk (0x1UL << USB_OTG_HCCHAR_EPDIR_Pos) /*!< 0x00008000 */
-#define USB_OTG_HCCHAR_EPDIR USB_OTG_HCCHAR_EPDIR_Msk /*!< Endpoint direction */
-#define USB_OTG_HCCHAR_LSDEV_Pos (17U)
-#define USB_OTG_HCCHAR_LSDEV_Msk (0x1UL << USB_OTG_HCCHAR_LSDEV_Pos) /*!< 0x00020000 */
-#define USB_OTG_HCCHAR_LSDEV USB_OTG_HCCHAR_LSDEV_Msk /*!< Low-speed device */
-
-#define USB_OTG_HCCHAR_EPTYP_Pos (18U)
-#define USB_OTG_HCCHAR_EPTYP_Msk (0x3UL << USB_OTG_HCCHAR_EPTYP_Pos) /*!< 0x000C0000 */
-#define USB_OTG_HCCHAR_EPTYP USB_OTG_HCCHAR_EPTYP_Msk /*!< Endpoint type */
-#define USB_OTG_HCCHAR_EPTYP_0 (0x1UL << USB_OTG_HCCHAR_EPTYP_Pos) /*!< 0x00040000 */
-#define USB_OTG_HCCHAR_EPTYP_1 (0x2UL << USB_OTG_HCCHAR_EPTYP_Pos) /*!< 0x00080000 */
-
-#define USB_OTG_HCCHAR_MC_Pos (20U)
-#define USB_OTG_HCCHAR_MC_Msk (0x3UL << USB_OTG_HCCHAR_MC_Pos) /*!< 0x00300000 */
-#define USB_OTG_HCCHAR_MC USB_OTG_HCCHAR_MC_Msk /*!< Multi Count (MC) / Error Count (EC) */
-#define USB_OTG_HCCHAR_MC_0 (0x1UL << USB_OTG_HCCHAR_MC_Pos) /*!< 0x00100000 */
-#define USB_OTG_HCCHAR_MC_1 (0x2UL << USB_OTG_HCCHAR_MC_Pos) /*!< 0x00200000 */
-
-#define USB_OTG_HCCHAR_DAD_Pos (22U)
-#define USB_OTG_HCCHAR_DAD_Msk (0x7FUL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x1FC00000 */
-#define USB_OTG_HCCHAR_DAD USB_OTG_HCCHAR_DAD_Msk /*!< Device address */
-#define USB_OTG_HCCHAR_DAD_0 (0x01UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x00400000 */
-#define USB_OTG_HCCHAR_DAD_1 (0x02UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x00800000 */
-#define USB_OTG_HCCHAR_DAD_2 (0x04UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x01000000 */
-#define USB_OTG_HCCHAR_DAD_3 (0x08UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x02000000 */
-#define USB_OTG_HCCHAR_DAD_4 (0x10UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x04000000 */
-#define USB_OTG_HCCHAR_DAD_5 (0x20UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x08000000 */
-#define USB_OTG_HCCHAR_DAD_6 (0x40UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x10000000 */
-#define USB_OTG_HCCHAR_ODDFRM_Pos (29U)
-#define USB_OTG_HCCHAR_ODDFRM_Msk (0x1UL << USB_OTG_HCCHAR_ODDFRM_Pos) /*!< 0x20000000 */
-#define USB_OTG_HCCHAR_ODDFRM USB_OTG_HCCHAR_ODDFRM_Msk /*!< Odd frame */
-#define USB_OTG_HCCHAR_CHDIS_Pos (30U)
-#define USB_OTG_HCCHAR_CHDIS_Msk (0x1UL << USB_OTG_HCCHAR_CHDIS_Pos) /*!< 0x40000000 */
-#define USB_OTG_HCCHAR_CHDIS USB_OTG_HCCHAR_CHDIS_Msk /*!< Channel disable */
-#define USB_OTG_HCCHAR_CHENA_Pos (31U)
-#define USB_OTG_HCCHAR_CHENA_Msk (0x1UL << USB_OTG_HCCHAR_CHENA_Pos) /*!< 0x80000000 */
-#define USB_OTG_HCCHAR_CHENA USB_OTG_HCCHAR_CHENA_Msk /*!< Channel enable */
-
-/******************** Bit definition for USB_OTG_HCSPLT register ********************/
-
-#define USB_OTG_HCSPLT_PRTADDR_Pos (0U)
-#define USB_OTG_HCSPLT_PRTADDR_Msk (0x7FUL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x0000007F */
-#define USB_OTG_HCSPLT_PRTADDR USB_OTG_HCSPLT_PRTADDR_Msk /*!< Port address */
-#define USB_OTG_HCSPLT_PRTADDR_0 (0x01UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000001 */
-#define USB_OTG_HCSPLT_PRTADDR_1 (0x02UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000002 */
-#define USB_OTG_HCSPLT_PRTADDR_2 (0x04UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000004 */
-#define USB_OTG_HCSPLT_PRTADDR_3 (0x08UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000008 */
-#define USB_OTG_HCSPLT_PRTADDR_4 (0x10UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000010 */
-#define USB_OTG_HCSPLT_PRTADDR_5 (0x20UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000020 */
-#define USB_OTG_HCSPLT_PRTADDR_6 (0x40UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000040 */
-
-#define USB_OTG_HCSPLT_HUBADDR_Pos (7U)
-#define USB_OTG_HCSPLT_HUBADDR_Msk (0x7FUL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00003F80 */
-#define USB_OTG_HCSPLT_HUBADDR USB_OTG_HCSPLT_HUBADDR_Msk /*!< Hub address */
-#define USB_OTG_HCSPLT_HUBADDR_0 (0x01UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00000080 */
-#define USB_OTG_HCSPLT_HUBADDR_1 (0x02UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00000100 */
-#define USB_OTG_HCSPLT_HUBADDR_2 (0x04UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00000200 */
-#define USB_OTG_HCSPLT_HUBADDR_3 (0x08UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00000400 */
-#define USB_OTG_HCSPLT_HUBADDR_4 (0x10UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00000800 */
-#define USB_OTG_HCSPLT_HUBADDR_5 (0x20UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00001000 */
-#define USB_OTG_HCSPLT_HUBADDR_6 (0x40UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00002000 */
-
-#define USB_OTG_HCSPLT_XACTPOS_Pos (14U)
-#define USB_OTG_HCSPLT_XACTPOS_Msk (0x3UL << USB_OTG_HCSPLT_XACTPOS_Pos) /*!< 0x0000C000 */
-#define USB_OTG_HCSPLT_XACTPOS USB_OTG_HCSPLT_XACTPOS_Msk /*!< XACTPOS */
-#define USB_OTG_HCSPLT_XACTPOS_0 (0x1UL << USB_OTG_HCSPLT_XACTPOS_Pos) /*!< 0x00004000 */
-#define USB_OTG_HCSPLT_XACTPOS_1 (0x2UL << USB_OTG_HCSPLT_XACTPOS_Pos) /*!< 0x00008000 */
-#define USB_OTG_HCSPLT_COMPLSPLT_Pos (16U)
-#define USB_OTG_HCSPLT_COMPLSPLT_Msk (0x1UL << USB_OTG_HCSPLT_COMPLSPLT_Pos) /*!< 0x00010000 */
-#define USB_OTG_HCSPLT_COMPLSPLT USB_OTG_HCSPLT_COMPLSPLT_Msk /*!< Do complete split */
-#define USB_OTG_HCSPLT_SPLITEN_Pos (31U)
-#define USB_OTG_HCSPLT_SPLITEN_Msk (0x1UL << USB_OTG_HCSPLT_SPLITEN_Pos) /*!< 0x80000000 */
-#define USB_OTG_HCSPLT_SPLITEN USB_OTG_HCSPLT_SPLITEN_Msk /*!< Split enable */
-
-/******************** Bit definition for USB_OTG_HCINT register ********************/
-#define USB_OTG_HCINT_XFRC_Pos (0U)
-#define USB_OTG_HCINT_XFRC_Msk (0x1UL << USB_OTG_HCINT_XFRC_Pos) /*!< 0x00000001 */
-#define USB_OTG_HCINT_XFRC USB_OTG_HCINT_XFRC_Msk /*!< Transfer completed */
-#define USB_OTG_HCINT_CHH_Pos (1U)
-#define USB_OTG_HCINT_CHH_Msk (0x1UL << USB_OTG_HCINT_CHH_Pos) /*!< 0x00000002 */
-#define USB_OTG_HCINT_CHH USB_OTG_HCINT_CHH_Msk /*!< Channel halted */
-#define USB_OTG_HCINT_AHBERR_Pos (2U)
-#define USB_OTG_HCINT_AHBERR_Msk (0x1UL << USB_OTG_HCINT_AHBERR_Pos) /*!< 0x00000004 */
-#define USB_OTG_HCINT_AHBERR USB_OTG_HCINT_AHBERR_Msk /*!< AHB error */
-#define USB_OTG_HCINT_STALL_Pos (3U)
-#define USB_OTG_HCINT_STALL_Msk (0x1UL << USB_OTG_HCINT_STALL_Pos) /*!< 0x00000008 */
-#define USB_OTG_HCINT_STALL USB_OTG_HCINT_STALL_Msk /*!< STALL response received interrupt */
-#define USB_OTG_HCINT_NAK_Pos (4U)
-#define USB_OTG_HCINT_NAK_Msk (0x1UL << USB_OTG_HCINT_NAK_Pos) /*!< 0x00000010 */
-#define USB_OTG_HCINT_NAK USB_OTG_HCINT_NAK_Msk /*!< NAK response received interrupt */
-#define USB_OTG_HCINT_ACK_Pos (5U)
-#define USB_OTG_HCINT_ACK_Msk (0x1UL << USB_OTG_HCINT_ACK_Pos) /*!< 0x00000020 */
-#define USB_OTG_HCINT_ACK USB_OTG_HCINT_ACK_Msk /*!< ACK response received/transmitted interrupt */
-#define USB_OTG_HCINT_NYET_Pos (6U)
-#define USB_OTG_HCINT_NYET_Msk (0x1UL << USB_OTG_HCINT_NYET_Pos) /*!< 0x00000040 */
-#define USB_OTG_HCINT_NYET USB_OTG_HCINT_NYET_Msk /*!< Response received interrupt */
-#define USB_OTG_HCINT_TXERR_Pos (7U)
-#define USB_OTG_HCINT_TXERR_Msk (0x1UL << USB_OTG_HCINT_TXERR_Pos) /*!< 0x00000080 */
-#define USB_OTG_HCINT_TXERR USB_OTG_HCINT_TXERR_Msk /*!< Transaction error */
-#define USB_OTG_HCINT_BBERR_Pos (8U)
-#define USB_OTG_HCINT_BBERR_Msk (0x1UL << USB_OTG_HCINT_BBERR_Pos) /*!< 0x00000100 */
-#define USB_OTG_HCINT_BBERR USB_OTG_HCINT_BBERR_Msk /*!< Babble error */
-#define USB_OTG_HCINT_FRMOR_Pos (9U)
-#define USB_OTG_HCINT_FRMOR_Msk (0x1UL << USB_OTG_HCINT_FRMOR_Pos) /*!< 0x00000200 */
-#define USB_OTG_HCINT_FRMOR USB_OTG_HCINT_FRMOR_Msk /*!< Frame overrun */
-#define USB_OTG_HCINT_DTERR_Pos (10U)
-#define USB_OTG_HCINT_DTERR_Msk (0x1UL << USB_OTG_HCINT_DTERR_Pos) /*!< 0x00000400 */
-#define USB_OTG_HCINT_DTERR USB_OTG_HCINT_DTERR_Msk /*!< Data toggle error */
-
-/******************** Bit definition for USB_OTG_DIEPINT register ********************/
-#define USB_OTG_DIEPINT_XFRC_Pos (0U)
-#define USB_OTG_DIEPINT_XFRC_Msk (0x1UL << USB_OTG_DIEPINT_XFRC_Pos) /*!< 0x00000001 */
-#define USB_OTG_DIEPINT_XFRC USB_OTG_DIEPINT_XFRC_Msk /*!< Transfer completed interrupt */
-#define USB_OTG_DIEPINT_EPDISD_Pos (1U)
-#define USB_OTG_DIEPINT_EPDISD_Msk (0x1UL << USB_OTG_DIEPINT_EPDISD_Pos) /*!< 0x00000002 */
-#define USB_OTG_DIEPINT_EPDISD USB_OTG_DIEPINT_EPDISD_Msk /*!< Endpoint disabled interrupt */
-#define USB_OTG_DIEPINT_AHBERR_Pos (2U)
-#define USB_OTG_DIEPINT_AHBERR_Msk (0x1UL << USB_OTG_DIEPINT_AHBERR_Pos) /*!< 0x00000004 */
-#define USB_OTG_DIEPINT_AHBERR USB_OTG_DIEPINT_AHBERR_Msk /*!< AHB Error (AHBErr) during an IN transaction */
-#define USB_OTG_DIEPINT_TOC_Pos (3U)
-#define USB_OTG_DIEPINT_TOC_Msk (0x1UL << USB_OTG_DIEPINT_TOC_Pos) /*!< 0x00000008 */
-#define USB_OTG_DIEPINT_TOC USB_OTG_DIEPINT_TOC_Msk /*!< Timeout condition */
-#define USB_OTG_DIEPINT_ITTXFE_Pos (4U)
-#define USB_OTG_DIEPINT_ITTXFE_Msk (0x1UL << USB_OTG_DIEPINT_ITTXFE_Pos) /*!< 0x00000010 */
-#define USB_OTG_DIEPINT_ITTXFE USB_OTG_DIEPINT_ITTXFE_Msk /*!< IN token received when TxFIFO is empty */
-#define USB_OTG_DIEPINT_INEPNM_Pos (5U)
-#define USB_OTG_DIEPINT_INEPNM_Msk (0x1UL << USB_OTG_DIEPINT_INEPNM_Pos) /*!< 0x00000004 */
-#define USB_OTG_DIEPINT_INEPNM USB_OTG_DIEPINT_INEPNM_Msk /*!< IN token received with EP mismatch */
-#define USB_OTG_DIEPINT_INEPNE_Pos (6U)
-#define USB_OTG_DIEPINT_INEPNE_Msk (0x1UL << USB_OTG_DIEPINT_INEPNE_Pos) /*!< 0x00000040 */
-#define USB_OTG_DIEPINT_INEPNE USB_OTG_DIEPINT_INEPNE_Msk /*!< IN endpoint NAK effective */
-#define USB_OTG_DIEPINT_TXFE_Pos (7U)
-#define USB_OTG_DIEPINT_TXFE_Msk (0x1UL << USB_OTG_DIEPINT_TXFE_Pos) /*!< 0x00000080 */
-#define USB_OTG_DIEPINT_TXFE USB_OTG_DIEPINT_TXFE_Msk /*!< Transmit FIFO empty */
-#define USB_OTG_DIEPINT_TXFIFOUDRN_Pos (8U)
-#define USB_OTG_DIEPINT_TXFIFOUDRN_Msk (0x1UL << USB_OTG_DIEPINT_TXFIFOUDRN_Pos) /*!< 0x00000100 */
-#define USB_OTG_DIEPINT_TXFIFOUDRN USB_OTG_DIEPINT_TXFIFOUDRN_Msk /*!< Transmit Fifo Underrun */
-#define USB_OTG_DIEPINT_BNA_Pos (9U)
-#define USB_OTG_DIEPINT_BNA_Msk (0x1UL << USB_OTG_DIEPINT_BNA_Pos) /*!< 0x00000200 */
-#define USB_OTG_DIEPINT_BNA USB_OTG_DIEPINT_BNA_Msk /*!< Buffer not available interrupt */
-#define USB_OTG_DIEPINT_PKTDRPSTS_Pos (11U)
-#define USB_OTG_DIEPINT_PKTDRPSTS_Msk (0x1UL << USB_OTG_DIEPINT_PKTDRPSTS_Pos) /*!< 0x00000800 */
-#define USB_OTG_DIEPINT_PKTDRPSTS USB_OTG_DIEPINT_PKTDRPSTS_Msk /*!< Packet dropped status */
-#define USB_OTG_DIEPINT_BERR_Pos (12U)
-#define USB_OTG_DIEPINT_BERR_Msk (0x1UL << USB_OTG_DIEPINT_BERR_Pos) /*!< 0x00001000 */
-#define USB_OTG_DIEPINT_BERR USB_OTG_DIEPINT_BERR_Msk /*!< Babble error interrupt */
-#define USB_OTG_DIEPINT_NAK_Pos (13U)
-#define USB_OTG_DIEPINT_NAK_Msk (0x1UL << USB_OTG_DIEPINT_NAK_Pos) /*!< 0x00002000 */
-#define USB_OTG_DIEPINT_NAK USB_OTG_DIEPINT_NAK_Msk /*!< NAK interrupt */
-
-/******************** Bit definition for USB_OTG_HCINTMSK register ********************/
-#define USB_OTG_HCINTMSK_XFRCM_Pos (0U)
-#define USB_OTG_HCINTMSK_XFRCM_Msk (0x1UL << USB_OTG_HCINTMSK_XFRCM_Pos) /*!< 0x00000001 */
-#define USB_OTG_HCINTMSK_XFRCM USB_OTG_HCINTMSK_XFRCM_Msk /*!< Transfer completed mask */
-#define USB_OTG_HCINTMSK_CHHM_Pos (1U)
-#define USB_OTG_HCINTMSK_CHHM_Msk (0x1UL << USB_OTG_HCINTMSK_CHHM_Pos) /*!< 0x00000002 */
-#define USB_OTG_HCINTMSK_CHHM USB_OTG_HCINTMSK_CHHM_Msk /*!< Channel halted mask */
-#define USB_OTG_HCINTMSK_AHBERR_Pos (2U)
-#define USB_OTG_HCINTMSK_AHBERR_Msk (0x1UL << USB_OTG_HCINTMSK_AHBERR_Pos) /*!< 0x00000004 */
-#define USB_OTG_HCINTMSK_AHBERR USB_OTG_HCINTMSK_AHBERR_Msk /*!< AHB error */
-#define USB_OTG_HCINTMSK_STALLM_Pos (3U)
-#define USB_OTG_HCINTMSK_STALLM_Msk (0x1UL << USB_OTG_HCINTMSK_STALLM_Pos) /*!< 0x00000008 */
-#define USB_OTG_HCINTMSK_STALLM USB_OTG_HCINTMSK_STALLM_Msk /*!< STALL response received interrupt mask */
-#define USB_OTG_HCINTMSK_NAKM_Pos (4U)
-#define USB_OTG_HCINTMSK_NAKM_Msk (0x1UL << USB_OTG_HCINTMSK_NAKM_Pos) /*!< 0x00000010 */
-#define USB_OTG_HCINTMSK_NAKM USB_OTG_HCINTMSK_NAKM_Msk /*!< NAK response received interrupt mask */
-#define USB_OTG_HCINTMSK_ACKM_Pos (5U)
-#define USB_OTG_HCINTMSK_ACKM_Msk (0x1UL << USB_OTG_HCINTMSK_ACKM_Pos) /*!< 0x00000020 */
-#define USB_OTG_HCINTMSK_ACKM USB_OTG_HCINTMSK_ACKM_Msk /*!< ACK response received/transmitted interrupt mask */
-#define USB_OTG_HCINTMSK_NYET_Pos (6U)
-#define USB_OTG_HCINTMSK_NYET_Msk (0x1UL << USB_OTG_HCINTMSK_NYET_Pos) /*!< 0x00000040 */
-#define USB_OTG_HCINTMSK_NYET USB_OTG_HCINTMSK_NYET_Msk /*!< response received interrupt mask */
-#define USB_OTG_HCINTMSK_TXERRM_Pos (7U)
-#define USB_OTG_HCINTMSK_TXERRM_Msk (0x1UL << USB_OTG_HCINTMSK_TXERRM_Pos) /*!< 0x00000080 */
-#define USB_OTG_HCINTMSK_TXERRM USB_OTG_HCINTMSK_TXERRM_Msk /*!< Transaction error mask */
-#define USB_OTG_HCINTMSK_BBERRM_Pos (8U)
-#define USB_OTG_HCINTMSK_BBERRM_Msk (0x1UL << USB_OTG_HCINTMSK_BBERRM_Pos) /*!< 0x00000100 */
-#define USB_OTG_HCINTMSK_BBERRM USB_OTG_HCINTMSK_BBERRM_Msk /*!< Babble error mask */
-#define USB_OTG_HCINTMSK_FRMORM_Pos (9U)
-#define USB_OTG_HCINTMSK_FRMORM_Msk (0x1UL << USB_OTG_HCINTMSK_FRMORM_Pos) /*!< 0x00000200 */
-#define USB_OTG_HCINTMSK_FRMORM USB_OTG_HCINTMSK_FRMORM_Msk /*!< Frame overrun mask */
-#define USB_OTG_HCINTMSK_DTERRM_Pos (10U)
-#define USB_OTG_HCINTMSK_DTERRM_Msk (0x1UL << USB_OTG_HCINTMSK_DTERRM_Pos) /*!< 0x00000400 */
-#define USB_OTG_HCINTMSK_DTERRM USB_OTG_HCINTMSK_DTERRM_Msk /*!< Data toggle error mask */
-
-/******************** Bit definition for USB_OTG_DIEPTSIZ register ********************/
-
-#define USB_OTG_DIEPTSIZ_XFRSIZ_Pos (0U)
-#define USB_OTG_DIEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << USB_OTG_DIEPTSIZ_XFRSIZ_Pos) /*!< 0x0007FFFF */
-#define USB_OTG_DIEPTSIZ_XFRSIZ USB_OTG_DIEPTSIZ_XFRSIZ_Msk /*!< Transfer size */
-#define USB_OTG_DIEPTSIZ_PKTCNT_Pos (19U)
-#define USB_OTG_DIEPTSIZ_PKTCNT_Msk (0x3FFUL << USB_OTG_DIEPTSIZ_PKTCNT_Pos) /*!< 0x1FF80000 */
-#define USB_OTG_DIEPTSIZ_PKTCNT USB_OTG_DIEPTSIZ_PKTCNT_Msk /*!< Packet count */
-#define USB_OTG_DIEPTSIZ_MULCNT_Pos (29U)
-#define USB_OTG_DIEPTSIZ_MULCNT_Msk (0x3UL << USB_OTG_DIEPTSIZ_MULCNT_Pos) /*!< 0x60000000 */
-#define USB_OTG_DIEPTSIZ_MULCNT USB_OTG_DIEPTSIZ_MULCNT_Msk /*!< Packet count */
-/******************** Bit definition for USB_OTG_HCTSIZ register ********************/
-#define USB_OTG_HCTSIZ_XFRSIZ_Pos (0U)
-#define USB_OTG_HCTSIZ_XFRSIZ_Msk (0x7FFFFUL << USB_OTG_HCTSIZ_XFRSIZ_Pos) /*!< 0x0007FFFF */
-#define USB_OTG_HCTSIZ_XFRSIZ USB_OTG_HCTSIZ_XFRSIZ_Msk /*!< Transfer size */
-#define USB_OTG_HCTSIZ_PKTCNT_Pos (19U)
-#define USB_OTG_HCTSIZ_PKTCNT_Msk (0x3FFUL << USB_OTG_HCTSIZ_PKTCNT_Pos) /*!< 0x1FF80000 */
-#define USB_OTG_HCTSIZ_PKTCNT USB_OTG_HCTSIZ_PKTCNT_Msk /*!< Packet count */
-#define USB_OTG_HCTSIZ_DOPING_Pos (31U)
-#define USB_OTG_HCTSIZ_DOPING_Msk (0x1UL << USB_OTG_HCTSIZ_DOPING_Pos) /*!< 0x80000000 */
-#define USB_OTG_HCTSIZ_DOPING USB_OTG_HCTSIZ_DOPING_Msk /*!< Do PING */
-#define USB_OTG_HCTSIZ_DPID_Pos (29U)
-#define USB_OTG_HCTSIZ_DPID_Msk (0x3UL << USB_OTG_HCTSIZ_DPID_Pos) /*!< 0x60000000 */
-#define USB_OTG_HCTSIZ_DPID USB_OTG_HCTSIZ_DPID_Msk /*!< Data PID */
-#define USB_OTG_HCTSIZ_DPID_0 (0x1UL << USB_OTG_HCTSIZ_DPID_Pos) /*!< 0x20000000 */
-#define USB_OTG_HCTSIZ_DPID_1 (0x2UL << USB_OTG_HCTSIZ_DPID_Pos) /*!< 0x40000000 */
-
-/******************** Bit definition for USB_OTG_DIEPDMA register ********************/
-#define USB_OTG_DIEPDMA_DMAADDR_Pos (0U)
-#define USB_OTG_DIEPDMA_DMAADDR_Msk (0xFFFFFFFFUL << USB_OTG_DIEPDMA_DMAADDR_Pos) /*!< 0xFFFFFFFF */
-#define USB_OTG_DIEPDMA_DMAADDR USB_OTG_DIEPDMA_DMAADDR_Msk /*!< DMA address */
-
-/******************** Bit definition for USB_OTG_HCDMA register ********************/
-#define USB_OTG_HCDMA_DMAADDR_Pos (0U)
-#define USB_OTG_HCDMA_DMAADDR_Msk (0xFFFFFFFFUL << USB_OTG_HCDMA_DMAADDR_Pos) /*!< 0xFFFFFFFF */
-#define USB_OTG_HCDMA_DMAADDR USB_OTG_HCDMA_DMAADDR_Msk /*!< DMA address */
-
-/******************** Bit definition for USB_OTG_DTXFSTS register ********************/
-#define USB_OTG_DTXFSTS_INEPTFSAV_Pos (0U)
-#define USB_OTG_DTXFSTS_INEPTFSAV_Msk (0xFFFFUL << USB_OTG_DTXFSTS_INEPTFSAV_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_DTXFSTS_INEPTFSAV USB_OTG_DTXFSTS_INEPTFSAV_Msk /*!< IN endpoint TxFIFO space available */
-
-/******************** Bit definition for USB_OTG_DIEPTXF register ********************/
-#define USB_OTG_DIEPTXF_INEPTXSA_Pos (0U)
-#define USB_OTG_DIEPTXF_INEPTXSA_Msk (0xFFFFUL << USB_OTG_DIEPTXF_INEPTXSA_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_DIEPTXF_INEPTXSA USB_OTG_DIEPTXF_INEPTXSA_Msk /*!< IN endpoint FIFOx transmit RAM start address */
-#define USB_OTG_DIEPTXF_INEPTXFD_Pos (16U)
-#define USB_OTG_DIEPTXF_INEPTXFD_Msk (0xFFFFUL << USB_OTG_DIEPTXF_INEPTXFD_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_DIEPTXF_INEPTXFD USB_OTG_DIEPTXF_INEPTXFD_Msk /*!< IN endpoint TxFIFO depth */
-
-/******************** Bit definition for USB_OTG_DOEPCTL register ********************/
-
-#define USB_OTG_DOEPCTL_MPSIZ_Pos (0U)
-#define USB_OTG_DOEPCTL_MPSIZ_Msk (0x7FFUL << USB_OTG_DOEPCTL_MPSIZ_Pos) /*!< 0x000007FF */
-#define USB_OTG_DOEPCTL_MPSIZ USB_OTG_DOEPCTL_MPSIZ_Msk /*!< Maximum packet size */ /*!<Bit 1 */
-#define USB_OTG_DOEPCTL_USBAEP_Pos (15U)
-#define USB_OTG_DOEPCTL_USBAEP_Msk (0x1UL << USB_OTG_DOEPCTL_USBAEP_Pos) /*!< 0x00008000 */
-#define USB_OTG_DOEPCTL_USBAEP USB_OTG_DOEPCTL_USBAEP_Msk /*!< USB active endpoint */
-#define USB_OTG_DOEPCTL_NAKSTS_Pos (17U)
-#define USB_OTG_DOEPCTL_NAKSTS_Msk (0x1UL << USB_OTG_DOEPCTL_NAKSTS_Pos) /*!< 0x00020000 */
-#define USB_OTG_DOEPCTL_NAKSTS USB_OTG_DOEPCTL_NAKSTS_Msk /*!< NAK status */
-#define USB_OTG_DOEPCTL_SD0PID_SEVNFRM_Pos (28U)
-#define USB_OTG_DOEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << USB_OTG_DOEPCTL_SD0PID_SEVNFRM_Pos) /*!< 0x10000000 */
-#define USB_OTG_DOEPCTL_SD0PID_SEVNFRM USB_OTG_DOEPCTL_SD0PID_SEVNFRM_Msk /*!< Set DATA0 PID */
-#define USB_OTG_DOEPCTL_SODDFRM_Pos (29U)
-#define USB_OTG_DOEPCTL_SODDFRM_Msk (0x1UL << USB_OTG_DOEPCTL_SODDFRM_Pos) /*!< 0x20000000 */
-#define USB_OTG_DOEPCTL_SODDFRM USB_OTG_DOEPCTL_SODDFRM_Msk /*!< Set odd frame */
-#define USB_OTG_DOEPCTL_EPTYP_Pos (18U)
-#define USB_OTG_DOEPCTL_EPTYP_Msk (0x3UL << USB_OTG_DOEPCTL_EPTYP_Pos) /*!< 0x000C0000 */
-#define USB_OTG_DOEPCTL_EPTYP USB_OTG_DOEPCTL_EPTYP_Msk /*!< Endpoint type */
-#define USB_OTG_DOEPCTL_EPTYP_0 (0x1UL << USB_OTG_DOEPCTL_EPTYP_Pos) /*!< 0x00040000 */
-#define USB_OTG_DOEPCTL_EPTYP_1 (0x2UL << USB_OTG_DOEPCTL_EPTYP_Pos) /*!< 0x00080000 */
-#define USB_OTG_DOEPCTL_SNPM_Pos (20U)
-#define USB_OTG_DOEPCTL_SNPM_Msk (0x1UL << USB_OTG_DOEPCTL_SNPM_Pos) /*!< 0x00100000 */
-#define USB_OTG_DOEPCTL_SNPM USB_OTG_DOEPCTL_SNPM_Msk /*!< Snoop mode */
-#define USB_OTG_DOEPCTL_STALL_Pos (21U)
-#define USB_OTG_DOEPCTL_STALL_Msk (0x1UL << USB_OTG_DOEPCTL_STALL_Pos) /*!< 0x00200000 */
-#define USB_OTG_DOEPCTL_STALL USB_OTG_DOEPCTL_STALL_Msk /*!< STALL handshake */
-#define USB_OTG_DOEPCTL_CNAK_Pos (26U)
-#define USB_OTG_DOEPCTL_CNAK_Msk (0x1UL << USB_OTG_DOEPCTL_CNAK_Pos) /*!< 0x04000000 */
-#define USB_OTG_DOEPCTL_CNAK USB_OTG_DOEPCTL_CNAK_Msk /*!< Clear NAK */
-#define USB_OTG_DOEPCTL_SNAK_Pos (27U)
-#define USB_OTG_DOEPCTL_SNAK_Msk (0x1UL << USB_OTG_DOEPCTL_SNAK_Pos) /*!< 0x08000000 */
-#define USB_OTG_DOEPCTL_SNAK USB_OTG_DOEPCTL_SNAK_Msk /*!< Set NAK */
-#define USB_OTG_DOEPCTL_EPDIS_Pos (30U)
-#define USB_OTG_DOEPCTL_EPDIS_Msk (0x1UL << USB_OTG_DOEPCTL_EPDIS_Pos) /*!< 0x40000000 */
-#define USB_OTG_DOEPCTL_EPDIS USB_OTG_DOEPCTL_EPDIS_Msk /*!< Endpoint disable */
-#define USB_OTG_DOEPCTL_EPENA_Pos (31U)
-#define USB_OTG_DOEPCTL_EPENA_Msk (0x1UL << USB_OTG_DOEPCTL_EPENA_Pos) /*!< 0x80000000 */
-#define USB_OTG_DOEPCTL_EPENA USB_OTG_DOEPCTL_EPENA_Msk /*!< Endpoint enable */
-
-/******************** Bit definition for USB_OTG_DOEPINT register ********************/
-#define USB_OTG_DOEPINT_XFRC_Pos (0U)
-#define USB_OTG_DOEPINT_XFRC_Msk (0x1UL << USB_OTG_DOEPINT_XFRC_Pos) /*!< 0x00000001 */
-#define USB_OTG_DOEPINT_XFRC USB_OTG_DOEPINT_XFRC_Msk /*!< Transfer completed interrupt */
-#define USB_OTG_DOEPINT_EPDISD_Pos (1U)
-#define USB_OTG_DOEPINT_EPDISD_Msk (0x1UL << USB_OTG_DOEPINT_EPDISD_Pos) /*!< 0x00000002 */
-#define USB_OTG_DOEPINT_EPDISD USB_OTG_DOEPINT_EPDISD_Msk /*!< Endpoint disabled interrupt */
-#define USB_OTG_DOEPINT_AHBERR_Pos (2U)
-#define USB_OTG_DOEPINT_AHBERR_Msk (0x1UL << USB_OTG_DOEPINT_AHBERR_Pos) /*!< 0x00000004 */
-#define USB_OTG_DOEPINT_AHBERR USB_OTG_DOEPINT_AHBERR_Msk /*!< AHB Error (AHBErr) during an OUT transaction */
-#define USB_OTG_DOEPINT_STUP_Pos (3U)
-#define USB_OTG_DOEPINT_STUP_Msk (0x1UL << USB_OTG_DOEPINT_STUP_Pos) /*!< 0x00000008 */
-#define USB_OTG_DOEPINT_STUP USB_OTG_DOEPINT_STUP_Msk /*!< SETUP phase done */
-#define USB_OTG_DOEPINT_OTEPDIS_Pos (4U)
-#define USB_OTG_DOEPINT_OTEPDIS_Msk (0x1UL << USB_OTG_DOEPINT_OTEPDIS_Pos) /*!< 0x00000010 */
-#define USB_OTG_DOEPINT_OTEPDIS USB_OTG_DOEPINT_OTEPDIS_Msk /*!< OUT token received when endpoint disabled */
-#define USB_OTG_DOEPINT_OTEPSPR_Pos (5U)
-#define USB_OTG_DOEPINT_OTEPSPR_Msk (0x1UL << USB_OTG_DOEPINT_OTEPSPR_Pos) /*!< 0x00000020 */
-#define USB_OTG_DOEPINT_OTEPSPR USB_OTG_DOEPINT_OTEPSPR_Msk /*!< Status Phase Received For Control Write */
-#define USB_OTG_DOEPINT_B2BSTUP_Pos (6U)
-#define USB_OTG_DOEPINT_B2BSTUP_Msk (0x1UL << USB_OTG_DOEPINT_B2BSTUP_Pos) /*!< 0x00000040 */
-#define USB_OTG_DOEPINT_B2BSTUP USB_OTG_DOEPINT_B2BSTUP_Msk /*!< Back-to-back SETUP packets received */
-#define USB_OTG_DOEPINT_OUTPKTERR_Pos (8U)
-#define USB_OTG_DOEPINT_OUTPKTERR_Msk (0x1UL << USB_OTG_DOEPINT_OUTPKTERR_Pos) /*!< 0x00000100 */
-#define USB_OTG_DOEPINT_OUTPKTERR USB_OTG_DOEPINT_OUTPKTERR_Msk /*!< OUT packet error */
-#define USB_OTG_DOEPINT_NAK_Pos (13U)
-#define USB_OTG_DOEPINT_NAK_Msk (0x1UL << USB_OTG_DOEPINT_NAK_Pos) /*!< 0x00002000 */
-#define USB_OTG_DOEPINT_NAK USB_OTG_DOEPINT_NAK_Msk /*!< NAK Packet is transmitted by the device */
-#define USB_OTG_DOEPINT_NYET_Pos (14U)
-#define USB_OTG_DOEPINT_NYET_Msk (0x1UL << USB_OTG_DOEPINT_NYET_Pos) /*!< 0x00004000 */
-#define USB_OTG_DOEPINT_NYET USB_OTG_DOEPINT_NYET_Msk /*!< NYET interrupt */
-#define USB_OTG_DOEPINT_STPKTRX_Pos (15U)
-#define USB_OTG_DOEPINT_STPKTRX_Msk (0x1UL << USB_OTG_DOEPINT_STPKTRX_Pos) /*!< 0x00008000 */
-#define USB_OTG_DOEPINT_STPKTRX USB_OTG_DOEPINT_STPKTRX_Msk /*!< Setup Packet Received */
-/******************** Bit definition for USB_OTG_DOEPTSIZ register ********************/
-
-#define USB_OTG_DOEPTSIZ_XFRSIZ_Pos (0U)
-#define USB_OTG_DOEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << USB_OTG_DOEPTSIZ_XFRSIZ_Pos) /*!< 0x0007FFFF */
-#define USB_OTG_DOEPTSIZ_XFRSIZ USB_OTG_DOEPTSIZ_XFRSIZ_Msk /*!< Transfer size */
-#define USB_OTG_DOEPTSIZ_PKTCNT_Pos (19U)
-#define USB_OTG_DOEPTSIZ_PKTCNT_Msk (0x3FFUL << USB_OTG_DOEPTSIZ_PKTCNT_Pos) /*!< 0x1FF80000 */
-#define USB_OTG_DOEPTSIZ_PKTCNT USB_OTG_DOEPTSIZ_PKTCNT_Msk /*!< Packet count */
-
-#define USB_OTG_DOEPTSIZ_STUPCNT_Pos (29U)
-#define USB_OTG_DOEPTSIZ_STUPCNT_Msk (0x3UL << USB_OTG_DOEPTSIZ_STUPCNT_Pos) /*!< 0x60000000 */
-#define USB_OTG_DOEPTSIZ_STUPCNT USB_OTG_DOEPTSIZ_STUPCNT_Msk /*!< SETUP packet count */
-#define USB_OTG_DOEPTSIZ_STUPCNT_0 (0x1UL << USB_OTG_DOEPTSIZ_STUPCNT_Pos) /*!< 0x20000000 */
-#define USB_OTG_DOEPTSIZ_STUPCNT_1 (0x2UL << USB_OTG_DOEPTSIZ_STUPCNT_Pos) /*!< 0x40000000 */
-
-/******************** Bit definition for PCGCCTL register ********************/
-#define USB_OTG_PCGCCTL_STOPCLK_Pos (0U)
-#define USB_OTG_PCGCCTL_STOPCLK_Msk (0x1UL << USB_OTG_PCGCCTL_STOPCLK_Pos) /*!< 0x00000001 */
-#define USB_OTG_PCGCCTL_STOPCLK USB_OTG_PCGCCTL_STOPCLK_Msk /*!< SETUP packet count */
-#define USB_OTG_PCGCCTL_GATECLK_Pos (1U)
-#define USB_OTG_PCGCCTL_GATECLK_Msk (0x1UL << USB_OTG_PCGCCTL_GATECLK_Pos) /*!< 0x00000002 */
-#define USB_OTG_PCGCCTL_GATECLK USB_OTG_PCGCCTL_GATECLK_Msk /*!<Bit 0 */
-#define USB_OTG_PCGCCTL_PHYSUSP_Pos (4U)
-#define USB_OTG_PCGCCTL_PHYSUSP_Msk (0x1UL << USB_OTG_PCGCCTL_PHYSUSP_Pos) /*!< 0x00000010 */
-#define USB_OTG_PCGCCTL_PHYSUSP USB_OTG_PCGCCTL_PHYSUSP_Msk /*!<Bit 1 */
-
-/* Legacy define */
-/******************** Bit definition for OTG register ********************/
-#define USB_OTG_CHNUM_Pos (0U)
-#define USB_OTG_CHNUM_Msk (0xFUL << USB_OTG_CHNUM_Pos) /*!< 0x0000000F */
-#define USB_OTG_CHNUM USB_OTG_CHNUM_Msk /*!< Channel number */
-#define USB_OTG_CHNUM_0 (0x1UL << USB_OTG_CHNUM_Pos) /*!< 0x00000001 */
-#define USB_OTG_CHNUM_1 (0x2UL << USB_OTG_CHNUM_Pos) /*!< 0x00000002 */
-#define USB_OTG_CHNUM_2 (0x4UL << USB_OTG_CHNUM_Pos) /*!< 0x00000004 */
-#define USB_OTG_CHNUM_3 (0x8UL << USB_OTG_CHNUM_Pos) /*!< 0x00000008 */
-#define USB_OTG_BCNT_Pos (4U)
-#define USB_OTG_BCNT_Msk (0x7FFUL << USB_OTG_BCNT_Pos) /*!< 0x00007FF0 */
-#define USB_OTG_BCNT USB_OTG_BCNT_Msk /*!< Byte count */
-
-#define USB_OTG_DPID_Pos (15U)
-#define USB_OTG_DPID_Msk (0x3UL << USB_OTG_DPID_Pos) /*!< 0x00018000 */
-#define USB_OTG_DPID USB_OTG_DPID_Msk /*!< Data PID */
-#define USB_OTG_DPID_0 (0x1UL << USB_OTG_DPID_Pos) /*!< 0x00008000 */
-#define USB_OTG_DPID_1 (0x2UL << USB_OTG_DPID_Pos) /*!< 0x00010000 */
-
-#define USB_OTG_PKTSTS_Pos (17U)
-#define USB_OTG_PKTSTS_Msk (0xFUL << USB_OTG_PKTSTS_Pos) /*!< 0x001E0000 */
-#define USB_OTG_PKTSTS USB_OTG_PKTSTS_Msk /*!< Packet status */
-#define USB_OTG_PKTSTS_0 (0x1UL << USB_OTG_PKTSTS_Pos) /*!< 0x00020000 */
-#define USB_OTG_PKTSTS_1 (0x2UL << USB_OTG_PKTSTS_Pos) /*!< 0x00040000 */
-#define USB_OTG_PKTSTS_2 (0x4UL << USB_OTG_PKTSTS_Pos) /*!< 0x00080000 */
-#define USB_OTG_PKTSTS_3 (0x8UL << USB_OTG_PKTSTS_Pos) /*!< 0x00100000 */
-
-#define USB_OTG_EPNUM_Pos (0U)
-#define USB_OTG_EPNUM_Msk (0xFUL << USB_OTG_EPNUM_Pos) /*!< 0x0000000F */
-#define USB_OTG_EPNUM USB_OTG_EPNUM_Msk /*!< Endpoint number */
-#define USB_OTG_EPNUM_0 (0x1UL << USB_OTG_EPNUM_Pos) /*!< 0x00000001 */
-#define USB_OTG_EPNUM_1 (0x2UL << USB_OTG_EPNUM_Pos) /*!< 0x00000002 */
-#define USB_OTG_EPNUM_2 (0x4UL << USB_OTG_EPNUM_Pos) /*!< 0x00000004 */
-#define USB_OTG_EPNUM_3 (0x8UL << USB_OTG_EPNUM_Pos) /*!< 0x00000008 */
-
-#define USB_OTG_FRMNUM_Pos (21U)
-#define USB_OTG_FRMNUM_Msk (0xFUL << USB_OTG_FRMNUM_Pos) /*!< 0x01E00000 */
-#define USB_OTG_FRMNUM USB_OTG_FRMNUM_Msk /*!< Frame number */
-#define USB_OTG_FRMNUM_0 (0x1UL << USB_OTG_FRMNUM_Pos) /*!< 0x00200000 */
-#define USB_OTG_FRMNUM_1 (0x2UL << USB_OTG_FRMNUM_Pos) /*!< 0x00400000 */
-#define USB_OTG_FRMNUM_2 (0x4UL << USB_OTG_FRMNUM_Pos) /*!< 0x00800000 */
-#define USB_OTG_FRMNUM_3 (0x8UL << USB_OTG_FRMNUM_Pos) /*!< 0x01000000 */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/src/portable/chipidea/ci_hs/ci_hs_imxrt.h b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
new file mode 100644
index 000000000..2de0d9cb4
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
@@ -0,0 +1,58 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_HS_IMXRT_H_
+#define _CI_HS_IMXRT_H_
+
+#include "fsl_device_registers.h"
+
+#if !defined(USB1_BASE) && defined(USB_OTG1_BASE)
+#define USB1_BASE USB_OTG1_BASE
+#endif
+
+#if !defined(USB2_BASE) && defined(USB_OTG2_BASE)
+#define USB2_BASE USB_OTG2_BASE
+#endif
+
+static const ci_hs_controller_t _ci_controller[] =
+{
+ // RT1010 and RT1020 only has 1 USB controller
+ #if FSL_FEATURE_SOC_USBHS_COUNT == 1
+ { .reg_base = USB_BASE , .irqnum = USB_OTG1_IRQn, .ep_count = 8 }
+ #else
+ { .reg_base = USB1_BASE, .irqnum = USB_OTG1_IRQn, .ep_count = 8 },
+ { .reg_base = USB2_BASE, .irqnum = USB_OTG2_IRQn, .ep_count = 8 }
+ #endif
+};
+
+#define CI_DCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_DCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h b/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h
new file mode 100644
index 000000000..8c2e7dfa6
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h
@@ -0,0 +1,45 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_HS_LPC18_43_H_
+#define _CI_HS_LPC18_43_H_
+
+// LPCOpen for 18xx & 43xx
+#include "chip.h"
+
+static const ci_hs_controller_t _ci_controller[] =
+{
+ { .reg_base = LPC_USB0_BASE, .irqnum = USB0_IRQn, .ep_count = 6 },
+ { .reg_base = LPC_USB1_BASE, .irqnum = USB1_IRQn, .ep_count = 4 }
+};
+
+#define CI_DCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_DCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/ci_hs_type.h b/src/portable/chipidea/ci_hs/ci_hs_type.h
new file mode 100644
index 000000000..728a86b86
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_type.h
@@ -0,0 +1,144 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef CI_HS_TYPE_H_
+#define CI_HS_TYPE_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// USBCMD
+enum {
+ USBCMD_RUN_STOP = TU_BIT(0),
+ USBCMD_RESET = TU_BIT(1),
+ USBCMD_SETUP_TRIPWIRE = TU_BIT(13),
+ USBCMD_ADD_QTD_TRIPWIRE = TU_BIT(14) ///< This bit is used as a semaphore to ensure the to proper addition of a new dTD to an active (primed) endpoint’s linked list. This bit is set and cleared by software during the process of adding a new dTD
+// Interrupt Threshold bit 23:16
+};
+
+// PORTSC1
+#define PORTSC1_PORT_SPEED_POS 26
+
+enum {
+ PORTSC1_CURRENT_CONNECT_STATUS = TU_BIT(0),
+ PORTSC1_FORCE_PORT_RESUME = TU_BIT(6),
+ PORTSC1_SUSPEND = TU_BIT(7),
+ PORTSC1_FORCE_FULL_SPEED = TU_BIT(24),
+ PORTSC1_PORT_SPEED = TU_BIT(26) | TU_BIT(27)
+};
+
+// OTGSC
+enum {
+ OTGSC_VBUS_DISCHARGE = TU_BIT(0),
+ OTGSC_VBUS_CHARGE = TU_BIT(1),
+// OTGSC_HWASSIST_AUTORESET = TU_BIT(2),
+ OTGSC_OTG_TERMINATION = TU_BIT(3), ///< Must set to 1 when OTG go to device mode
+ OTGSC_DATA_PULSING = TU_BIT(4),
+ OTGSC_ID_PULLUP = TU_BIT(5),
+// OTGSC_HWASSIT_DATA_PULSE = TU_BIT(6),
+// OTGSC_HWASSIT_BDIS_ACONN = TU_BIT(7),
+ OTGSC_ID = TU_BIT(8), ///< 0 = A device, 1 = B Device
+ OTGSC_A_VBUS_VALID = TU_BIT(9),
+ OTGSC_A_SESSION_VALID = TU_BIT(10),
+ OTGSC_B_SESSION_VALID = TU_BIT(11),
+ OTGSC_B_SESSION_END = TU_BIT(12),
+ OTGSC_1MS_TOGGLE = TU_BIT(13),
+ OTGSC_DATA_BUS_PULSING_STATUS = TU_BIT(14),
+};
+
+// USBMode
+enum {
+ USBMODE_CM_DEVICE = 2,
+ USBMODE_CM_HOST = 3,
+
+ USBMODE_SLOM = TU_BIT(3),
+ USBMODE_SDIS = TU_BIT(4),
+
+ USBMODE_VBUS_POWER_SELECT = TU_BIT(5), // Need to be enabled for LPC18XX/43XX in host mode
+};
+
+// Device Registers
+typedef struct
+{
+ //------------- ID + HW Parameter Registers-------------//
+ volatile uint32_t TU_RESERVED[64]; ///< For iMX RT10xx, but not used by LPC18XX/LPC43XX
+
+ //------------- Capability Registers-------------//
+ volatile uint8_t CAPLENGTH; ///< Capability Registers Length
+ volatile uint8_t TU_RESERVED[1];
+ volatile uint16_t HCIVERSION; ///< Host Controller Interface Version
+
+ volatile uint32_t HCSPARAMS; ///< Host Controller Structural Parameters
+ volatile uint32_t HCCPARAMS; ///< Host Controller Capability Parameters
+ volatile uint32_t TU_RESERVED[5];
+
+ volatile uint16_t DCIVERSION; ///< Device Controller Interface Version
+ volatile uint8_t TU_RESERVED[2];
+
+ volatile uint32_t DCCPARAMS; ///< Device Controller Capability Parameters
+ volatile uint32_t TU_RESERVED[6];
+
+ //------------- Operational Registers -------------//
+ volatile uint32_t USBCMD; ///< USB Command Register
+ volatile uint32_t USBSTS; ///< USB Status Register
+ volatile uint32_t USBINTR; ///< Interrupt Enable Register
+ volatile uint32_t FRINDEX; ///< USB Frame Index
+ volatile uint32_t TU_RESERVED;
+ volatile uint32_t DEVICEADDR; ///< Device Address
+ volatile uint32_t ENDPTLISTADDR; ///< Endpoint List Address
+ volatile uint32_t TU_RESERVED;
+ volatile uint32_t BURSTSIZE; ///< Programmable Burst Size
+ volatile uint32_t TXFILLTUNING; ///< TX FIFO Fill Tuning
+ uint32_t TU_RESERVED[4];
+ volatile uint32_t ENDPTNAK; ///< Endpoint NAK
+ volatile uint32_t ENDPTNAKEN; ///< Endpoint NAK Enable
+ volatile uint32_t TU_RESERVED;
+ volatile uint32_t PORTSC1; ///< Port Status & Control
+ volatile uint32_t TU_RESERVED[7];
+ volatile uint32_t OTGSC; ///< On-The-Go Status & control
+ volatile uint32_t USBMODE; ///< USB Device Mode
+ volatile uint32_t ENDPTSETUPSTAT; ///< Endpoint Setup Status
+ volatile uint32_t ENDPTPRIME; ///< Endpoint Prime
+ volatile uint32_t ENDPTFLUSH; ///< Endpoint Flush
+ volatile uint32_t ENDPTSTAT; ///< Endpoint Status
+ volatile uint32_t ENDPTCOMPLETE; ///< Endpoint Complete
+ volatile uint32_t ENDPTCTRL[8]; ///< Endpoint Control 0 - 7
+} ci_hs_regs_t;
+
+
+typedef struct
+{
+ uint32_t reg_base;
+ uint32_t irqnum;
+ uint8_t ep_count; // Max bi-directional Endpoints
+}ci_hs_controller_t;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* CI_HS_TYPE_H_ */
diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
new file mode 100644
index 000000000..c7cc3e0e8
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
@@ -0,0 +1,644 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_CHIPIDEA_HS)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "device/dcd.h"
+#include "ci_hs_type.h"
+
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
+ #include "ci_hs_imxrt.h"
+#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
+ #include "ci_hs_lpc18_43.h"
+#else
+ #error "Unsupported MCUs"
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
+
+#if defined(__CORTEX_M) && __CORTEX_M == 7 && __DCACHE_PRESENT == 1
+ #define CleanInvalidateDCache_by_Addr SCB_CleanInvalidateDCache_by_Addr
+#else
+ #define CleanInvalidateDCache_by_Addr(_addr, _dsize)
+#endif
+
+
+// ENDPTCTRL
+enum {
+ ENDPTCTRL_STALL = TU_BIT(0),
+ ENDPTCTRL_TOGGLE_INHIBIT = TU_BIT(5), // used for test only
+ ENDPTCTRL_TOGGLE_RESET = TU_BIT(6),
+ ENDPTCTRL_ENABLE = TU_BIT(7)
+};
+
+enum {
+ ENDPTCTRL_TYPE_POS = 2, // Endpoint type is 2-bit field
+};
+
+// USBSTS, USBINTR
+enum {
+ INTR_USB = TU_BIT(0),
+ INTR_ERROR = TU_BIT(1),
+ INTR_PORT_CHANGE = TU_BIT(2),
+ INTR_RESET = TU_BIT(6),
+ INTR_SOF = TU_BIT(7),
+ INTR_SUSPEND = TU_BIT(8),
+ INTR_NAK = TU_BIT(16)
+};
+
+// Queue Transfer Descriptor
+typedef struct
+{
+ // Word 0: Next QTD Pointer
+ uint32_t next; ///< Next link pointer This field contains the physical memory address of the next dTD to be processed
+
+ // Word 1: qTQ Token
+ uint32_t : 3 ;
+ volatile uint32_t xact_err : 1 ;
+ uint32_t : 1 ;
+ volatile uint32_t buffer_err : 1 ;
+ volatile uint32_t halted : 1 ;
+ volatile uint32_t active : 1 ;
+ uint32_t : 2 ;
+ uint32_t iso_mult_override : 2 ; ///< This field can be used for transmit ISOs to override the MULT field in the dQH. This field must be zero for all packet types that are not transmit-ISO.
+ uint32_t : 3 ;
+ uint32_t int_on_complete : 1 ;
+ volatile uint32_t total_bytes : 15 ;
+ uint32_t : 1 ;
+
+ // Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page
+ uint32_t buffer[5]; ///< buffer1 has frame_n for TODO Isochronous
+
+ //--------------------------------------------------------------------+
+ // TD is 32 bytes aligned but occupies only 28 bytes
+ // Therefore there are 4 bytes padding that we can use.
+ //--------------------------------------------------------------------+
+ uint16_t expected_bytes;
+ uint8_t reserved[2];
+} dcd_qtd_t;
+
+TU_VERIFY_STATIC( sizeof(dcd_qtd_t) == 32, "size is not correct");
+
+// Queue Head
+typedef struct
+{
+ // Word 0: Capabilities and Characteristics
+ uint32_t : 15 ; ///< Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated by the USB variable length protocol where N is computed using Max_packet_length and the Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: Isochronous endpoints must set MULT = 01, 10, or 11 as needed.
+ uint32_t int_on_setup : 1 ; ///< Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is set in response to a setup being received.
+ uint32_t max_packet_size : 11 ; ///< Endpoint's wMaxPacketSize
+ uint32_t : 2 ;
+ uint32_t zero_length_termination : 1 ; ///< This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on transfers that are equal in length to a multiple Max_packet_length.
+ uint32_t iso_mult : 2 ; ///<
+
+ // Word 1: Current qTD Pointer
+ volatile uint32_t qtd_addr;
+
+ // Word 2-9: Transfer Overlay
+ volatile dcd_qtd_t qtd_overlay;
+
+ // Word 10-11: Setup request (control OUT only)
+ volatile tusb_control_request_t setup_request;
+
+ //--------------------------------------------------------------------+
+ // QHD is 64 bytes aligned but occupies only 48 bytes
+ // Therefore there are 16 bytes padding that we can use.
+ //--------------------------------------------------------------------+
+ tu_fifo_t * ff;
+ uint8_t reserved[12];
+} dcd_qhd_t;
+
+TU_VERIFY_STATIC( sizeof(dcd_qhd_t) == 64, "size is not correct");
+
+//--------------------------------------------------------------------+
+// Variables
+//--------------------------------------------------------------------+
+
+#define QTD_NEXT_INVALID 0x01
+
+typedef struct {
+ // Must be at 2K alignment
+ // Each endpoint with direction (IN/OUT) occupies a queue head
+ // for portability, TinyUSB only queue 1 TD for each Qhd
+ dcd_qhd_t qhd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64);
+ dcd_qtd_t qtd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32);
+}dcd_data_t;
+
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(2048)
+static dcd_data_t _dcd_data;
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+/// follows LPC43xx User Manual 23.10.3
+static void bus_reset(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ // The reset value for all endpoint types is the control endpoint. If one endpoint
+ // direction is enabled and the paired endpoint of opposite direction is disabled, then the
+ // endpoint type of the unused direction must be changed from the control type to any other
+ // type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
+ // for the data PID tracking on the active endpoint.
+ for( uint8_t i=1; i < _ci_controller[rhport].ep_count; i++)
+ {
+ dcd_reg->ENDPTCTRL[i] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS));
+ }
+
+ //------------- Clear All Registers -------------//
+ dcd_reg->ENDPTNAK = dcd_reg->ENDPTNAK;
+ dcd_reg->ENDPTNAKEN = 0;
+ dcd_reg->USBSTS = dcd_reg->USBSTS;
+ dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;
+ dcd_reg->ENDPTCOMPLETE = dcd_reg->ENDPTCOMPLETE;
+
+ while (dcd_reg->ENDPTPRIME) {}
+ dcd_reg->ENDPTFLUSH = 0xFFFFFFFF;
+ while (dcd_reg->ENDPTFLUSH) {}
+
+ // read reset bit in portsc
+
+ //------------- Queue Head & Queue TD -------------//
+ tu_memclr(&_dcd_data, sizeof(dcd_data_t));
+
+ //------------- Set up Control Endpoints (0 OUT, 1 IN) -------------//
+ _dcd_data.qhd[0][0].zero_length_termination = _dcd_data.qhd[0][1].zero_length_termination = 1;
+ _dcd_data.qhd[0][0].max_packet_size = _dcd_data.qhd[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
+ _dcd_data.qhd[0][0].qtd_overlay.next = _dcd_data.qhd[0][1].qtd_overlay.next = QTD_NEXT_INVALID;
+
+ _dcd_data.qhd[0][0].int_on_setup = 1; // OUT only
+}
+
+void dcd_init(uint8_t rhport)
+{
+ tu_memclr(&_dcd_data, sizeof(dcd_data_t));
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ // Reset controller
+ dcd_reg->USBCMD |= USBCMD_RESET;
+ while( dcd_reg->USBCMD & USBCMD_RESET ) {}
+
+ // Set mode to device, must be set immediately after reset
+ dcd_reg->USBMODE = USBMODE_CM_DEVICE;
+ dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION;
+
+#if !TUD_OPT_HIGH_SPEED
+ dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED;
+#endif
+
+ CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+
+ dcd_reg->ENDPTLISTADDR = (uint32_t) _dcd_data.qhd; // Endpoint List Address has to be 2K alignment
+ dcd_reg->USBSTS = dcd_reg->USBSTS;
+ dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_SUSPEND;
+
+ dcd_reg->USBCMD &= ~0x00FF0000; // Interrupt Threshold Interval = 0
+ dcd_reg->USBCMD |= USBCMD_RUN_STOP; // Connect
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ CI_DCD_INT_ENABLE(rhport);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ CI_DCD_INT_DISABLE(rhport);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ // Response with status first before changing device address
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->PORTSC1 |= PORTSC1_FORCE_PORT_RESUME;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->USBCMD |= USBCMD_RUN_STOP;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->USBCMD &= ~USBCMD_RUN_STOP;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+//--------------------------------------------------------------------+
+// HELPER
+//--------------------------------------------------------------------+
+
+static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes)
+{
+ // Force the CPU to flush the buffer. We increase the size by 31 because the call aligns the
+ // address to 32-byte boundaries. Buffer must be word aligned
+ CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) data_ptr, 4), total_bytes + 31);
+
+ tu_memclr(p_qtd, sizeof(dcd_qtd_t));
+
+ p_qtd->next = QTD_NEXT_INVALID;
+ p_qtd->active = 1;
+ p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
+ p_qtd->int_on_complete = true;
+
+ if (data_ptr != NULL)
+ {
+ p_qtd->buffer[0] = (uint32_t) data_ptr;
+
+ uint32_t const bufend = p_qtd->buffer[0] + total_bytes;
+ for(uint8_t i=1; i<5; i++)
+ {
+ uint32_t const next_page = tu_align4k( p_qtd->buffer[i-1] ) + 4096;
+ if ( bufend <= next_page ) break;
+
+ p_qtd->buffer[i] = next_page;
+
+ // TODO page[1] FRAME_N for ISO transfer
+ }
+ }
+}
+
+//--------------------------------------------------------------------+
+// DCD Endpoint Port
+//--------------------------------------------------------------------+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0);
+
+ // flush to abort any primed buffer
+ dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ // data toggle also need to be reset
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << ( dir ? 16 : 0 );
+ dcd_reg->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << ( dir ? 16 : 0));
+}
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+{
+ uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+ uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+
+ // Must not exceed max endpoint number
+ TU_ASSERT( epnum < _ci_controller[rhport].ep_count );
+
+ //------------- Prepare Queue Head -------------//
+ dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
+ tu_memclr(p_qhd, sizeof(dcd_qhd_t));
+
+ p_qhd->zero_length_termination = 1;
+ p_qhd->max_packet_size = tu_edpt_packet_size(p_endpoint_desc);
+ if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS)
+ {
+ p_qhd->iso_mult = 1;
+ }
+
+ p_qhd->qtd_overlay.next = QTD_NEXT_INVALID;
+
+ CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+
+ // Enable EP Control
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ uint32_t const epctrl = (p_endpoint_desc->bmAttributes.xfer << ENDPTCTRL_TYPE_POS) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET;
+
+ if ( dir == TUSB_DIR_OUT )
+ {
+ dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0xFFFF0000u) | epctrl;
+ }else
+ {
+ dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0x0000FFFFu) | (epctrl << 16);
+ }
+
+ return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ // Disable all non-control endpoints
+ for( uint8_t epnum=1; epnum < _ci_controller[rhport].ep_count; epnum++)
+ {
+ _dcd_data.qhd[epnum][TUSB_DIR_OUT].qtd_overlay.halted = 1;
+ _dcd_data.qhd[epnum][TUSB_DIR_IN ].qtd_overlay.halted = 1;
+
+ dcd_reg->ENDPTFLUSH = TU_BIT(epnum) | TU_BIT(epnum+16);
+ dcd_reg->ENDPTCTRL[epnum] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS));
+ }
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ _dcd_data.qhd[epnum][dir].qtd_overlay.halted = 1;
+
+ // Flush EP
+ uint32_t const flush_mask = TU_BIT(epnum + (dir ? 16 : 0));
+ dcd_reg->ENDPTFLUSH = flush_mask;
+ while(dcd_reg->ENDPTFLUSH & flush_mask);
+
+ // Clear EP enable
+ dcd_reg->ENDPTCTRL[epnum] &=~(ENDPTCTRL_ENABLE << (dir ? 16 : 0));
+}
+
+static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
+
+ p_qhd->qtd_overlay.halted = false; // clear any previous error
+ p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd
+
+ // flush cache
+ CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+
+ if ( epnum == 0 )
+ {
+ // follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism
+ // wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out
+ while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {}
+ }
+
+ // start transfer
+ dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0));
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
+
+ // Prepare qtd
+ qtd_init(p_qtd, buffer, total_bytes);
+
+ // Start qhd transfer
+ p_qhd->ff = NULL;
+ qhd_start_xfer(rhport, epnum, dir);
+
+ return true;
+}
+
+// fifo has to be aligned to 4k boundary
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
+
+ tu_fifo_buffer_info_t fifo_info;
+
+ if (dir)
+ {
+ tu_fifo_get_read_info(ff, &fifo_info);
+ } else
+ {
+ tu_fifo_get_write_info(ff, &fifo_info);
+ }
+
+ if ( fifo_info.len_lin >= total_bytes )
+ {
+ // Linear length is enough for this transfer
+ qtd_init(p_qtd, fifo_info.ptr_lin, total_bytes);
+ }
+ else
+ {
+ // linear part is not enough
+
+ // prepare TD up to linear length
+ qtd_init(p_qtd, fifo_info.ptr_lin, fifo_info.len_lin);
+
+ if ( !tu_offset4k((uint32_t) fifo_info.ptr_wrap) && !tu_offset4k(tu_fifo_depth(ff)) )
+ {
+ // If buffer is aligned to 4K & buffer size is multiple of 4K
+ // We can make use of buffer page array to also combine the linear + wrapped length
+ p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
+
+ for(uint8_t i = 1, page = 0; i < 5; i++)
+ {
+ // pick up buffer array where linear ends
+ if (p_qtd->buffer[i] == 0)
+ {
+ p_qtd->buffer[i] = (uint32_t) fifo_info.ptr_wrap + 4096 * page;
+ page++;
+ }
+ }
+
+ CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), total_bytes - fifo_info.len_wrap + 31);
+ }
+ else
+ {
+ // TODO we may need to carry the wrapped length after the linear part complete
+ // for now only transfer up to linear part
+ }
+ }
+
+ // Start qhd transfer
+ p_qhd->ff = ff;
+ qhd_start_xfer(rhport, epnum, dir);
+
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+
+static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir)
+{
+ dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
+
+ uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED :
+ ( p_qtd->xact_err || p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS;
+
+ if ( result != XFER_RESULT_SUCCESS )
+ {
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ // flush to abort error buffer
+ dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
+ }
+
+ uint16_t const xferred_bytes = p_qtd->expected_bytes - p_qtd->total_bytes;
+
+ if (p_qhd->ff)
+ {
+ if (dir == TUSB_DIR_IN)
+ {
+ tu_fifo_advance_read_pointer(p_qhd->ff, xferred_bytes);
+ } else
+ {
+ tu_fifo_advance_write_pointer(p_qhd->ff, xferred_bytes);
+ }
+ }
+
+ // only number of bytes in the IOC qtd
+ dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), xferred_bytes, result, true);
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ uint32_t const int_enable = dcd_reg->USBINTR;
+ uint32_t const int_status = dcd_reg->USBSTS & int_enable;
+ dcd_reg->USBSTS = int_status; // Acknowledge handled interrupt
+
+ // disabled interrupt sources
+ if (int_status == 0) return;
+
+ // Set if the port controller enters the full or high-speed operational state.
+ // either from Bus Reset or Suspended state
+ if (int_status & INTR_PORT_CHANGE)
+ {
+ // TU_LOG2("PortChange %08lx\r\n", dcd_reg->PORTSC1);
+
+ // Reset interrupt is not enabled, we manually check if Port Change is due
+ // to connection / disconnection
+ if ( dcd_reg->USBSTS & INTR_RESET )
+ {
+ dcd_reg->USBSTS = INTR_RESET;
+
+ if (dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS)
+ {
+ uint32_t const speed = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS;
+ bus_reset(rhport);
+ dcd_event_bus_reset(rhport, (tusb_speed_t) speed, true);
+ }else
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+ }
+ }
+ else
+ {
+ // Triggered by resuming from suspended state
+ if ( !(dcd_reg->PORTSC1 & PORTSC1_SUSPEND) )
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+ }
+ }
+ }
+
+ if (int_status & INTR_SUSPEND)
+ {
+ // TU_LOG2("Suspend %08lx\r\n", dcd_reg->PORTSC1);
+
+ if (dcd_reg->PORTSC1 & PORTSC1_SUSPEND)
+ {
+ // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
+ // Skip suspend event if we are not addressed
+ if ((dcd_reg->DEVICEADDR >> 25) & 0x0f)
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+ }
+ }
+ }
+
+ if (int_status & INTR_USB)
+ {
+ // Make sure we read the latest version of _dcd_data.
+ CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+
+ uint32_t const edpt_complete = dcd_reg->ENDPTCOMPLETE;
+ dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge
+
+ if (dcd_reg->ENDPTSETUPSTAT)
+ {
+ //------------- Set up Received -------------//
+ // 23.10.10.2 Operational model for setup transfers
+ dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;
+
+ dcd_event_setup_received(rhport, (uint8_t*)(uintptr_t) &_dcd_data.qhd[0][0].setup_request, true);
+ }
+
+ // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set
+ // nothing to do, we will submit xfer as error to usbd
+ // if (int_status & INTR_ERROR) { }
+
+ if ( edpt_complete )
+ {
+ for(uint8_t epnum = 0; epnum < TUP_DCD_ENDPOINT_MAX; epnum++)
+ {
+ if ( tu_bit_test(edpt_complete, epnum) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_OUT);
+ if ( tu_bit_test(edpt_complete, epnum+16) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_IN);
+ }
+ }
+ }
+
+ if (int_status & INTR_SOF)
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
+}
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/hcd_ci_hs.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
new file mode 100644
index 000000000..d0396daea
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
@@ -0,0 +1,94 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+// Chipidea Highspeed USB IP implement EHCI for host functionality
+
+#if CFG_TUH_ENABLED && \
+ (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "common/tusb_common.h"
+#include "host/hcd.h"
+#include "portable/ehci/ehci_api.h"
+#include "ci_hs_type.h"
+
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
+ #include "ci_hs_imxrt.h"
+#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
+ #include "ci_hs_lpc18_43.h"
+#else
+ #error "Unsupported MCUs"
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+bool hcd_init(uint8_t rhport)
+{
+ ci_hs_regs_t* hcd_reg = CI_HS_REG(rhport);
+
+ // Reset controller
+ hcd_reg->USBCMD |= USBCMD_RESET;
+ while( hcd_reg->USBCMD & USBCMD_RESET ) {}
+
+ // Set mode to device, must be set immediately after reset
+#if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX
+ // LPC18XX/43XX need to set VBUS Power Select to HIGH
+ // RHPORT1 is fullspeed only (need external PHY for Highspeed)
+ hcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT;
+ if (rhport == 1) hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
+#else
+ hcd_reg->USBMODE = USBMODE_CM_HOST;
+#endif
+
+ // FIXME force full speed, still have issue with Highspeed enumeration
+ hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
+
+ return ehci_init(rhport, (uint32_t) &hcd_reg->CAPLENGTH, (uint32_t) &hcd_reg->USBCMD);
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ CI_HCD_INT_ENABLE(rhport);
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ CI_HCD_INT_DISABLE(rhport);
+}
+
+#endif
diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c
index 311119747..0bb8b6e41 100644
--- a/src/portable/dialog/da146xx/dcd_da146xx.c
+++ b/src/portable/dialog/da146xx/dcd_da146xx.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_DA1469X
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_DA1469X
#include "mcu/mcu.h"
@@ -733,6 +733,15 @@ static void handle_alt_ev(void)
set_nfsr(NFSR_NODE_OPERATIONAL);
USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
USB_USB_ALTMSK_REG_USB_M_SD3_Msk;
+ // Re-enable reception of endpoint with pending transfer
+ for (int epnum = 1; epnum <= 3; ++epnum)
+ {
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
+ if (xfer->total_len > xfer->transferred)
+ {
+ start_rx_packet(xfer);
+ }
+ }
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
}
}
@@ -873,6 +882,14 @@ void dcd_disconnect(uint8_t rhport)
REG_CLR_BIT(USB_MCTRL_REG, USB_NAT);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
{
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
@@ -935,13 +952,13 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
if (dir == TUSB_DIR_OUT)
{
regs->epc_out = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
- USB->USB_RXMSK_REG |= 0x101 << (epnum - 1);
+ USB->USB_RXMSK_REG |= 0x11 << (epnum - 1);
REG_SET_BIT(USB_MAMSK_REG, USB_M_RX_EV);
}
else
{
regs->epc_in = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
- USB->USB_TXMSK_REG |= 0x101 << (epnum - 1);
+ USB->USB_TXMSK_REG |= 0x11 << (epnum - 1);
REG_SET_BIT(USB_MAMSK_REG, USB_M_TX_EV);
}
}
@@ -982,7 +999,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
regs->rxc = USB_USB_RXC1_REG_USB_FLUSH_Msk;
regs->epc_out = 0;
- USB->USB_RXMSK_REG &= ~(0x101 << (epnum - 1));
+ USB->USB_RXMSK_REG &= ~(0x11 << (epnum - 1));
// Release DMA if needed
if (_dcd.dma_ep[TUSB_DIR_OUT] == epnum)
{
@@ -994,7 +1011,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
regs->txc = USB_USB_TXC1_REG_USB_FLUSH_Msk;
regs->epc_in = 0;
- USB->USB_TXMSK_REG &= ~(0x101 << (epnum - 1));
+ USB->USB_TXMSK_REG &= ~(0x11 << (epnum - 1));
// Release DMA if needed
if (_dcd.dma_ep[TUSB_DIR_IN] == epnum)
{
diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c
index e92f8a951..76ba2a921 100644
--- a/src/portable/ehci/ehci.c
+++ b/src/portable/ehci/ehci.c
@@ -24,9 +24,9 @@
* This file is part of the TinyUSB stack.
*/
-#include "host/hcd_attr.h"
+#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && defined(HCD_ATTR_EHCI_TRANSDIMENSION)
+#if CFG_TUH_ENABLED && defined(TUP_USBIP_EHCI)
//--------------------------------------------------------------------+
// INCLUDE
@@ -45,7 +45,7 @@
#define EHCI_DBG 2
// Framelist size as small as possible to save SRAM
-#ifdef HCD_ATTR_EHCI_TRANSDIMENSION
+#ifdef TUP_USBIP_CHIPIDEA_HS
// NXP Transdimension: 8 elements
#define FRAMELIST_SIZE_BIT_VALUE 7u
#define FRAMELIST_SIZE_USBCMD_VALUE (((FRAMELIST_SIZE_BIT_VALUE & 3) << EHCI_USBCMD_POS_FRAMELIST_SIZE) | \
@@ -58,6 +58,9 @@
#define FRAMELIST_SIZE (1024 >> FRAMELIST_SIZE_BIT_VALUE)
+#define QHD_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX)
+#define QTD_MAX QHD_MAX
+
typedef struct
{
ehci_link_t period_framelist[FRAMELIST_SIZE];
@@ -73,8 +76,8 @@ typedef struct
ehci_qtd_t qtd;
}control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
- ehci_qhd_t qhd_pool[HCD_MAX_ENDPOINT];
- ehci_qtd_t qtd_pool[HCD_MAX_XFER] TU_ATTR_ALIGNED(32);
+ ehci_qhd_t qhd_pool[QHD_MAX];
+ ehci_qtd_t qtd_pool[QTD_MAX] TU_ATTR_ALIGNED(32);
ehci_registers_t* regs;
@@ -160,15 +163,15 @@ void hcd_port_reset(uint8_t rhport)
regs->portsc = portsc;
}
-#if 0
void hcd_port_reset_end(uint8_t rhport)
{
(void) rhport;
+#if 0
ehci_registers_t* regs = ehci_data.regs;
regs->portsc_bm.port_reset = 0;
-}
#endif
+}
bool hcd_port_connect_status(uint8_t rhport)
{
@@ -189,7 +192,11 @@ static void list_remove_qhd_by_addr(ehci_link_t* list_head, uint8_t dev_addr)
prev = list_next(prev) )
{
// TODO check type for ISO iTD and siTD
+ // TODO Suppress cast-align warning
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wcast-align"
ehci_qhd_t* qhd = (ehci_qhd_t*) list_next(prev);
+ #pragma GCC diagnostic pop
if ( qhd->dev_addr == dev_addr )
{
// TODO deactive all TD, wait for QHD to inactive before removal
@@ -474,7 +481,7 @@ static void async_advance_isr(uint8_t rhport)
(void) rhport;
ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
- for(uint32_t i = 0; i < HCD_MAX_ENDPOINT; i++)
+ for(uint32_t i = 0; i < QHD_MAX; i++)
{
if ( qhd_pool[i].removing )
{
@@ -542,7 +549,7 @@ static void period_list_xfer_complete_isr(uint8_t hostid, uint32_t interval_ms)
// TODO abstract max loop guard for period
while( !next_item.terminate &&
!(interval_ms > 1 && period_1ms_addr == tu_align32(next_item.address)) &&
- max_loop < (HCD_MAX_ENDPOINT + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUH_DEVICE_MAX)
+ max_loop < (QHD_MAX + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUH_DEVICE_MAX)
{
switch ( next_item.type )
{
@@ -649,6 +656,26 @@ static void xfer_error_isr(uint8_t hostid)
}
}
+#if CFG_TUSB_DEBUG >= EHCI_DBG
+
+static inline void print_portsc(ehci_registers_t* regs)
+{
+ TU_LOG_HEX(EHCI_DBG, regs->portsc);
+ TU_LOG(EHCI_DBG, " Current Connect Status: %u\r\n", regs->portsc_bm.current_connect_status);
+ TU_LOG(EHCI_DBG, " Connect Status Change : %u\r\n", regs->portsc_bm.connect_status_change);
+ TU_LOG(EHCI_DBG, " Port Enabled : %u\r\n", regs->portsc_bm.port_enabled);
+ TU_LOG(EHCI_DBG, " Port Enabled Change : %u\r\n", regs->portsc_bm.port_enable_change);
+
+ TU_LOG(EHCI_DBG, " Port Reset : %u\r\n", regs->portsc_bm.port_reset);
+ TU_LOG(EHCI_DBG, " Port Power : %u\r\n", regs->portsc_bm.port_power);
+}
+
+#else
+
+#define print_portsc(_reg)
+
+#endif
+
//------------- Host Controller Driver's Interrupt Handler -------------//
void hcd_int_handler(uint8_t rhport)
{
@@ -657,7 +684,7 @@ void hcd_int_handler(uint8_t rhport)
uint32_t int_status = regs->status;
int_status &= regs->inten;
- regs->status |= int_status; // Acknowledge handled interrupt
+ regs->status = int_status; // Acknowledge handled interrupt
if (int_status == 0) return;
@@ -668,9 +695,8 @@ void hcd_int_handler(uint8_t rhport)
if (int_status & EHCI_INT_MASK_PORT_CHANGE)
{
- uint32_t port_status = regs->portsc & EHCI_PORTSC_MASK_ALL;
-
- TU_LOG_HEX(EHCI_DBG, regs->portsc);
+ uint32_t const port_status = regs->portsc & EHCI_PORTSC_MASK_ALL;
+ print_portsc(regs);
if (regs->portsc_bm.connect_status_change)
{
@@ -714,7 +740,7 @@ void hcd_int_handler(uint8_t rhport)
//------------- queue head helper -------------//
static inline ehci_qhd_t* qhd_find_free (void)
{
- for (uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
+ for (uint32_t i=0; i<QHD_MAX; i++)
{
if ( !ehci_data.qhd_pool[i].used ) return &ehci_data.qhd_pool[i];
}
@@ -731,7 +757,7 @@ static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
{
ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
- for(uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
+ for(uint32_t i=0; i<QHD_MAX; i++)
{
if ( (qhd_pool[i].dev_addr == dev_addr) &&
ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) )
@@ -746,7 +772,7 @@ static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
//------------- TD helper -------------//
static inline ehci_qtd_t* qtd_find_free(void)
{
- for (uint32_t i=0; i<HCD_MAX_XFER; i++)
+ for (uint32_t i=0; i<QTD_MAX; i++)
{
if ( !ehci_data.qtd_pool[i].used ) return &ehci_data.qtd_pool[i];
}
diff --git a/src/portable/ehci/ehci.h b/src/portable/ehci/ehci.h
index c2bee67a5..ff9ae12e7 100644
--- a/src/portable/ehci/ehci.h
+++ b/src/portable/ehci/ehci.h
@@ -101,8 +101,8 @@ typedef struct
// Word 2: qTQ Token
volatile uint32_t ping_err : 1 ; ///< For Highspeed: 0 Out, 1 Ping. Full/Slow used as error indicator
- volatile uint32_t non_hs_split_state : 1 ; ///< Used by HC to track the state of slipt transaction
- volatile uint32_t non_hs_missed_uframe : 1 ; ///< HC misses a complete slip transaction
+ volatile uint32_t non_hs_split_state : 1 ; ///< Used by HC to track the state of split transaction
+ volatile uint32_t non_hs_missed_uframe : 1 ; ///< HC misses a complete split transaction
volatile uint32_t xact_err : 1 ; ///< Error (Timeout, CRC, Bad PID ... )
volatile uint32_t babble_err : 1 ; ///< Babble detected, also set Halted bit to 1
volatile uint32_t buffer_err : 1 ; ///< Data overrun/underrun error
diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c
index a9c311324..0b75af627 100644
--- a/src/portable/espressif/esp32sx/dcd_esp32sx.c
+++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c
@@ -28,13 +28,12 @@
#include "tusb_option.h"
-#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && TUSB_OPT_DEVICE_ENABLED)
+#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && CFG_TUD_ENABLED)
// Espressif
#include "freertos/xtensa_api.h"
#include "esp_intr_alloc.h"
#include "esp_log.h"
-#include "driver/gpio.h"
#include "soc/dport_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/usb_periph.h"
@@ -60,6 +59,7 @@ typedef struct {
uint16_t queued_len;
uint16_t max_size;
bool short_packet;
+ uint8_t interval;
} xfer_ctl_t;
static const char *TAG = "TUSB:DCD";
@@ -241,6 +241,14 @@ void dcd_disconnect(uint8_t rhport)
USB0.dctl |= USB_SFTDISCON_M;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
@@ -260,6 +268,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
xfer->max_size = tu_edpt_packet_size(desc_edpt);
+ xfer->interval = desc_edpt->bInterval;
if (dir == TUSB_DIR_OUT) {
out_ep[epnum].doepctl |= USB_USBACTEP1_M |
@@ -372,6 +381,13 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to
USB0.in_ep_reg[epnum].dieptsiz = (num_packets << USB_D_PKTCNT0_S) | total_bytes;
USB0.in_ep_reg[epnum].diepctl |= USB_D_EPENA1_M | USB_D_CNAK1_M; // Enable | CNAK
+ // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame
+ if ((USB0.in_ep_reg[epnum].diepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) {
+ // Take odd/even bit from frame counter.
+ uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S));
+ USB0.in_ep_reg[epnum].diepctl |= (odd_frame_now ? USB_DI_SETD0PID1 : USB_DI_SETD1PID1);
+ }
+
// Enable fifo empty interrupt only if there are something to put in the fifo.
if(total_bytes != 0) {
USB0.dtknqr4_fifoemptymsk |= (1 << epnum);
@@ -380,6 +396,13 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to
// Each complete packet for OUT xfers triggers XFRC.
USB0.out_ep_reg[epnum].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
USB0.out_ep_reg[epnum].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
+
+ // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame
+ if ((USB0.out_ep_reg[epnum].doepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) {
+ // Take odd/even bit from frame counter.
+ uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S));
+ USB0.out_ep_reg[epnum].doepctl |= (odd_frame_now ? USB_DO_SETD0PID1 : USB_DO_SETD1PID1);
+ }
}
return true;
}
diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c
index 4b4c2f9b2..0ba53d4d0 100644
--- a/src/portable/mentor/musb/dcd_musb.c
+++ b/src/portable/mentor/musb/dcd_musb.c
@@ -26,7 +26,8 @@
#include "tusb_option.h"
-#if TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+#if CFG_TUD_ENABLED && \
+ TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
#if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED)
/* GCC warns that an address may be unaligned, even though
@@ -169,13 +170,13 @@ static inline void print_block_list(free_block_t const *blk, unsigned num)
static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
{
- free_block_t free_blocks[2 * (DCD_ATTR_ENDPOINT_MAX - 1)];
+ free_block_t free_blocks[2 * (TUP_DCD_ENDPOINT_MAX - 1)];
unsigned num_blocks = 1;
/* Initialize free memory block list */
free_blocks[0].beg = 64 / 8;
free_blocks[0].end = (4 << 10) / 8; /* 4KiB / 8 bytes */
- for (int i = 1; i < DCD_ATTR_ENDPOINT_MAX; ++i) {
+ for (int i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
uint_fast16_t addr;
int num;
USB0->EPIDX = i;
@@ -250,12 +251,12 @@ static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
len -= 4;
}
if (len >= 2) {
- *(uint32_t *)addr = reg->u16;
+ *(uint16_t *)addr = reg->u16;
addr += 2;
len -= 2;
}
if (len) {
- *(uint32_t *)addr = reg->u8;
+ *(uint8_t *)addr = reg->u8;
}
}
@@ -574,7 +575,7 @@ static void process_bus_reset(uint8_t rhport)
USB0->RXIE = 0;
/* Clear FIFO settings */
- for (unsigned i = 1; i < DCD_ATTR_ENDPOINT_MAX; ++i) {
+ for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
USB0->EPIDX = i;
USB0->TXFIFOSZ = 0;
USB0->TXFIFOADD = 0;
@@ -647,6 +648,14 @@ void dcd_disconnect(uint8_t rhport)
USB0->POWER &= ~USB_POWER_SOFTCONN;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -662,7 +671,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
const unsigned xfer = ep_desc->bmAttributes.xfer;
const unsigned mps = tu_edpt_packet_size(ep_desc);
- TU_ASSERT(epn < DCD_ATTR_ENDPOINT_MAX);
+ TU_ASSERT(epn < TUP_DCD_ENDPOINT_MAX);
pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1];
pipe->buf = NULL;
@@ -714,7 +723,7 @@ void dcd_edpt_close_all(uint8_t rhport)
NVIC_DisableIRQ(USB0_IRQn);
USB0->TXIE = 1; /* Enable only EP0 */
USB0->RXIE = 0;
- for (unsigned i = 1; i < DCD_ATTR_ENDPOINT_MAX; ++i) {
+ for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
regs->TXMAXP = 0;
regs->TXCSRH = 0;
if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c
new file mode 100644
index 000000000..85e18e3aa
--- /dev/null
+++ b/src/portable/mentor/musb/hcd_musb.c
@@ -0,0 +1,881 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && \
+ TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+
+#if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED)
+/* GCC warns that an address may be unaligned, even though
+ * the target CPU has the capability for unaligned memory access. */
+_Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");
+#endif
+
+#include "host/hcd.h"
+
+#if TU_CHECK_MCU(OPT_MCU_MSP432E4)
+ #include "musb_msp432e.h"
+
+#elif TU_CHECK_MCU(OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+ #include "musb_tm4c.h"
+
+ // HACK generalize later
+ #include "musb_type.h"
+ #define FIFO0_WORD FIFO0
+
+#else
+ #error "Unsupported MCUs"
+#endif
+
+#ifndef HCD_ATTR_ENDPOINT_MAX
+# define HCD_ATTR_ENDPOINT_MAX 8
+#endif
+
+/*------------------------------------------------------------------
+ * MACRO TYPEDEF CONSTANT ENUM DECLARATION
+ *------------------------------------------------------------------*/
+#define REQUEST_TYPE_INVALID (0xFFu)
+
+typedef struct {
+ uint_fast16_t beg; /* offset of including first element */
+ uint_fast16_t end; /* offset of excluding the last element */
+} free_block_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint8_t TXFUNCADDR;
+ uint8_t RESERVED0;
+ uint8_t TXHUBADDR;
+ uint8_t TXHUBPORT;
+ uint8_t RXFUNCADDR;
+ uint8_t RESERVED1;
+ uint8_t RXHUBADDR;
+ uint8_t RXHUBPORT;
+} hw_addr_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint16_t TXMAXP;
+ uint8_t TXCSRL;
+ uint8_t TXCSRH;
+ uint16_t RXMAXP;
+ uint8_t RXCSRL;
+ uint8_t RXCSRH;
+ uint16_t RXCOUNT;
+ uint8_t TXTYPE;
+ uint8_t TXINTERVAL;
+ uint8_t RXTYPE;
+ uint8_t RXINTERVAL;
+ uint16_t RESERVED;
+} hw_endpoint_t;
+
+typedef union {
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+} hw_fifo_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ void *buf; /* the start address of a transfer data buffer */
+ uint16_t length; /* the number of bytes in the buffer */
+ uint16_t remaining; /* the number of bytes remaining in the buffer */
+} pipe_state_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ uint8_t dev;
+ uint8_t ep;
+} pipe_addr_t;
+
+typedef struct
+{
+ bool need_reset; /* The device has not been reset after connection. */
+ uint8_t bmRequestType;
+ uint8_t ctl_mps[7]; /* EP0 max packet size for each device */
+ pipe_state_t pipe0;
+ pipe_state_t pipe[7][2]; /* pipe[pipe number - 1][direction 0:RX 1:TX] */
+ pipe_addr_t addr[7][2]; /* addr[pipe number - 1][direction 0:RX 1:TX] */
+} hcd_data_t;
+
+/*------------------------------------------------------------------
+ * INTERNAL OBJECT & FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+static hcd_data_t _hcd;
+
+static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
+{
+ free_block_t *cur = beg;
+ for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ;
+ return cur;
+}
+
+static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size)
+{
+ free_block_t *p = find_containing_block(blks, blks + num, addr);
+ TU_ASSERT(p != blks + num, -2);
+ if (p->beg == addr) {
+ /* Shrink block */
+ p->beg = addr + size;
+ if (p->beg != p->end) return 0;
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ } else {
+ /* Split into 2 blocks */
+ free_block_t tmp = {
+ .beg = addr + size,
+ .end = p->end
+ };
+ p->end = addr;
+ if (p->beg == p->end) {
+ if (tmp.beg != tmp.end) {
+ *p = tmp;
+ return 0;
+ }
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ }
+ if (tmp.beg == tmp.end) return 0;
+ blks[num] = tmp;
+ return 1;
+ }
+}
+
+static inline unsigned free_block_size(free_block_t const *blk)
+{
+ return blk->end - blk->beg;
+}
+
+static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
+{
+ free_block_t free_blocks[2 * (HCD_ATTR_ENDPOINT_MAX - 1)];
+ unsigned num_blocks = 1;
+
+ /* Initialize free memory block list */
+ free_blocks[0].beg = 64 / 8;
+ free_blocks[0].end = (4 << 10) / 8; /* 4KiB / 8 bytes */
+ for (int i = 1; i < HCD_ATTR_ENDPOINT_MAX; ++i) {
+ uint_fast16_t addr;
+ int num;
+ USB0->EPIDX = i;
+ addr = USB0->TXFIFOADD;
+ if (addr) {
+ unsigned sz = USB0->TXFIFOSZ;
+ unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ }
+ addr = USB0->RXFIFOADD;
+ if (addr) {
+ unsigned sz = USB0->RXFIFOSZ;
+ unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ }
+ }
+
+ /* Find the best fit memory block */
+ uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3;
+ free_block_t const *min = NULL;
+ uint_fast16_t min_sz = 0xFFFFu;
+ free_block_t const *end = &free_blocks[num_blocks];
+ for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) {
+ uint_fast16_t sz = free_block_size(cur);
+ if (sz < size_in_8byte_unit) continue;
+ if (size_in_8byte_unit == sz) return cur->beg;
+ if (sz < min_sz) min = cur;
+ }
+ TU_ASSERT(min, 0);
+ return min->beg;
+}
+
+static inline volatile hw_endpoint_t* edpt_regs(unsigned epnum_minus1)
+{
+ volatile hw_endpoint_t *regs = (volatile hw_endpoint_t*)((uintptr_t)&USB0->TXMAXP1);
+ return regs + epnum_minus1;
+}
+
+static unsigned find_pipe(uint_fast8_t dev_addr, uint_fast8_t ep_addr)
+{
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ pipe_addr_t const *p = &_hcd.addr[0][dir_tx];
+ for (unsigned i = 0; i < sizeof(_hcd.addr)/sizeof(_hcd.addr[0]); ++i, p += 2) {
+ if ((dev_addr == p->dev) && (ep_addr == p->ep))
+ return i + 1;
+ }
+ return 0;
+}
+
+static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 4) {
+ reg->u32 = *(uint32_t const *)addr;
+ addr += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ reg->u16 = *(uint16_t const *)addr;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ reg->u8 = *(uint8_t const *)addr;
+ }
+}
+
+static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 4) {
+ *(uint32_t *)addr = reg->u32;
+ addr += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ *(uint16_t *)addr = reg->u16;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ *(uint8_t *)addr = reg->u8;
+ }
+}
+
+static bool edpt0_xfer_out(void)
+{
+ pipe_state_t *pipe = &_hcd.pipe0;
+ unsigned const rem = pipe->remaining;
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+ unsigned const dev_addr = USB0->TXFUNCADDR0;
+ unsigned const mps = _hcd.ctl_mps[dev_addr];
+ unsigned const len = TU_MIN(rem, mps);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, &USB0->FIFO0_WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ pipe->remaining = rem - len;
+ USB0->CSRL0 = USB_CSRL0_TXRDY;
+ return false;
+}
+
+static bool edpt0_xfer_in(void)
+{
+ pipe_state_t *pipe = &_hcd.pipe0;
+ unsigned const rem = pipe->remaining;
+ unsigned const dev_addr = USB0->TXFUNCADDR0;
+ unsigned const mps = _hcd.ctl_mps[dev_addr];
+ unsigned const vld = USB0->COUNT0;
+ unsigned const len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_read_packet(buf, &USB0->FIFO0_WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ pipe->remaining = rem - len;
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return true;
+ }
+ USB0->CSRL0 = USB_CSRL0_REQPKT;
+ return false;
+}
+
+static bool edpt0_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ (void)rhport;
+
+ unsigned const req = _hcd.bmRequestType;
+ TU_ASSERT(req != REQUEST_TYPE_INVALID);
+ TU_ASSERT(dev_addr < sizeof(_hcd.ctl_mps));
+
+ USB0->TXFUNCADDR0 = dev_addr;
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ if (tu_edpt_dir(req) == dir_in) { /* DATA stage */
+ TU_ASSERT(buffer);
+ _hcd.pipe0.buf = buffer;
+ _hcd.pipe0.length = buflen;
+ _hcd.pipe0.remaining = buflen;
+ if (dir_in)
+ USB0->CSRL0 = USB_CSRL0_REQPKT;
+ else
+ edpt0_xfer_out();
+ } else { /* STATUS stage */
+ _hcd.pipe0.buf = NULL;
+ _hcd.pipe0.length = 0;
+ _hcd.pipe0.remaining = 0;
+ USB0->CSRL0 = USB_CSRL0_STATUS | (dir_in ? USB_CSRL0_REQPKT: USB_CSRL0_TXRDY);
+ }
+ return true;
+}
+
+static bool pipe_xfer_out(uint_fast8_t pipenum)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][1];
+ unsigned const rem = pipe->remaining;
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+ hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
+ unsigned const mps = regs->TXMAXP;
+ unsigned const len = TU_MIN(rem, mps);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, &USB0->FIFO0_WORD + pipenum, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ pipe->remaining = rem - len;
+ regs->TXCSRL = USB_TXCSRL1_TXRDY;
+ return false;
+}
+
+static bool pipe_xfer_in(uint_fast8_t pipenum)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][0];
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+
+ TU_ASSERT(regs->RXCSRL & USB_RXCSRL1_RXRDY);
+
+ const unsigned mps = regs->RXMAXP;
+ const unsigned rem = pipe->remaining;
+ const unsigned vld = regs->RXCOUNT;
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_read_packet(buf, &USB0->FIFO0_WORD + pipenum, len);
+ pipe->buf = buf + len;
+ pipe->remaining = rem - len;
+ }
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return NULL != buf;
+ }
+ regs->RXCSRL = USB_RXCSRL1_REQPKT;
+ return false;
+}
+
+static bool edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ (void)rhport;
+ unsigned const pipenum = find_pipe(dev_addr, ep_addr);
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][dir_tx];
+ pipe->buf = buffer;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ if (dir_tx) {
+ pipe_xfer_out(pipenum);
+ } else {
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+ regs->RXCSRL = USB_RXCSRL1_REQPKT;
+ }
+ return true;
+}
+
+static void process_ep0(uint8_t rhport)
+{
+ (void)rhport;
+
+ uint_fast8_t csrl = USB0->CSRL0;
+ // TU_LOG1(" EP0 CSRL = %x\n", csrl);
+
+ unsigned const dev_addr = USB0->TXFUNCADDR0;
+ unsigned const req = _hcd.bmRequestType;
+ if (csrl & (USB_CSRL0_ERROR | USB_CSRL0_NAKTO | USB_CSRL0_STALLED)) {
+ /* No response / NAK timed out / Stall received */
+ if (csrl & (USB_CSRL0_RXRDY | USB_CSRL0_TXRDY))
+ USB0->CSRH0 = USB_CSRH0_FLUSH;
+ USB0->CSRL0 = 0;
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ uint8_t result = (csrl & USB_CSRL0_STALLED) ? XFER_RESULT_STALLED: XFER_RESULT_FAILED;
+ if (REQUEST_TYPE_INVALID == req) { /* SETUP */
+ uint8_t const ep_addr = tu_edpt_addr(0, TUSB_DIR_OUT);
+ hcd_event_xfer_complete(dev_addr, ep_addr,
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ result, true);
+ } else if (csrl & USB_CSRL0_STATUS) { /* STATUS */
+ uint8_t const ep_addr = tu_edpt_dir(req) ?
+ tu_edpt_addr(0, TUSB_DIR_OUT): tu_edpt_addr(0, TUSB_DIR_IN);
+ hcd_event_xfer_complete(dev_addr, ep_addr,
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ result, true);
+ } else { /* DATA */
+ uint8_t const ep_addr = tu_edpt_dir(req) ?
+ tu_edpt_addr(0, TUSB_DIR_IN): tu_edpt_addr(0, TUSB_DIR_OUT);
+ hcd_event_xfer_complete(dev_addr, ep_addr,
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ result, true);
+ }
+ return;
+ }
+ if (csrl & USB_CSRL0_STATUS) {
+ /* STATUS IN */
+ TU_ASSERT(USB_CSRL0_RXRDY == (csrl & USB_CSRL0_RXRDY),);
+ TU_ASSERT(0 == USB0->COUNT0,);
+ USB0->CSRH0 = USB_CSRH0_FLUSH;
+ USB0->CSRL0 = 0;
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_IN),
+ 0, XFER_RESULT_SUCCESS, true);
+ return;
+ }
+ if (csrl & USB_CSRL0_RXRDY) {
+ /* DATA IN */
+ TU_ASSERT(REQUEST_TYPE_INVALID != req,);
+ TU_ASSERT(_hcd.pipe0.buf,);
+ if (edpt0_xfer_in()) {
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_IN),
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+ return;
+ }
+
+ /* When CSRL0 is zero, it means that completion of sending a any length packet. */
+ if (!_hcd.pipe0.buf) {
+ /* STATUS OUT */
+ TU_ASSERT(REQUEST_TYPE_INVALID != req,);
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ /* EP address is the reverse direction of DATA stage */
+ uint8_t const ep_addr = tu_edpt_dir(req) ?
+ tu_edpt_addr(0, TUSB_DIR_OUT): tu_edpt_addr(0, TUSB_DIR_IN);
+ hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true);
+ return;
+ }
+ if (REQUEST_TYPE_INVALID == req) {
+ /* SETUP */
+ _hcd.bmRequestType = *(uint8_t*)_hcd.pipe0.buf;
+ _hcd.pipe0.buf = NULL;
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_OUT),
+ 8, XFER_RESULT_SUCCESS, true);
+ return;
+ }
+
+ /* DATA OUT */
+ if (edpt0_xfer_out()) {
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_OUT),
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_pipe_tx(uint8_t rhport, uint_fast8_t pipenum)
+{
+ (void)rhport;
+ bool completed;
+ uint8_t result;
+
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+ unsigned const csrl = regs->TXCSRL;
+ // TU_LOG1(" TXCSRL%d = %x\n", pipenum, csrl);
+ if (csrl & (USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR)) {
+ if (csrl & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = (csrl & ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR)) | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = csrl & ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR);
+ completed = true;
+ result = (csrl & USB_TXCSRL1_STALLED) ? XFER_RESULT_STALLED: XFER_RESULT_FAILED;
+ } else {
+ completed = pipe_xfer_out(pipenum);
+ result = XFER_RESULT_SUCCESS;
+ }
+ if (completed) {
+ pipe_addr_t *addr = &_hcd.addr[pipenum - 1][1];
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][1];
+ hcd_event_xfer_complete(addr->dev, addr->ep,
+ pipe->length - pipe->remaining,
+ result, true);
+ }
+}
+
+static void process_pipe_rx(uint8_t rhport, uint_fast8_t pipenum)
+{
+ (void)rhport;
+ bool completed;
+ uint8_t result;
+
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+ unsigned const csrl = regs->RXCSRL;
+ // TU_LOG1(" RXCSRL%d = %x\n", pipenum, csrl);
+ if (csrl & (USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR)) {
+ if (csrl & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = (csrl & ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR)) | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = csrl & ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR);
+ completed = true;
+ result = (csrl & USB_RXCSRL1_STALLED) ? XFER_RESULT_STALLED: XFER_RESULT_FAILED;
+ } else {
+ completed = pipe_xfer_in(pipenum);
+ result = XFER_RESULT_SUCCESS;
+ }
+ if (completed) {
+ pipe_addr_t *addr = &_hcd.addr[pipenum - 1][0];
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][0];
+ hcd_event_xfer_complete(addr->dev, addr->ep,
+ pipe->length - pipe->remaining,
+ result, true);
+ }
+}
+
+/*------------------------------------------------------------------
+ * Host API
+ *------------------------------------------------------------------*/
+
+bool hcd_init(uint8_t rhport)
+{
+ (void)rhport;
+
+ NVIC_ClearPendingIRQ(USB0_IRQn);
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ USB0->DEVCTL |= USB_DEVCTL_SESSION;
+ USB0->IE = USB_IE_DISCON | USB_IE_CONN | USB_IE_BABBLE | USB_IE_RESUME;
+ return true;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_DisableIRQ(USB0_IRQn);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void)rhport;
+ /* The device must be reset at least once after connection
+ * in order to start the frame counter. */
+ if (_hcd.need_reset) hcd_port_reset(rhport);
+ return USB0->FRAME;
+}
+
+//--------------------------------------------------------------------+
+// Port API
+//--------------------------------------------------------------------+
+
+bool hcd_port_connect_status(uint8_t rhport)
+{
+ (void)rhport;
+ unsigned devctl = USB0->DEVCTL;
+ if (!(devctl & USB_DEVCTL_HOST)) return false;
+ if (devctl & (USB_DEVCTL_LSDEV | USB_DEVCTL_FSDEV)) return true;
+ return false;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+ (void)rhport;
+ USB0->POWER |= USB_POWER_HSENAB | USB_POWER_RESET;
+ unsigned cnt = SystemCoreClock / 1000 * 20;
+ while (cnt--) __NOP();
+ USB0->POWER &= ~USB_POWER_RESET;
+ _hcd.need_reset = false;
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+ (void)rhport;
+ unsigned devctl = USB0->DEVCTL;
+ if (devctl & USB_DEVCTL_LSDEV) return TUSB_SPEED_LOW;
+ if (!(devctl & USB_DEVCTL_FSDEV)) return TUSB_SPEED_INVALID;
+ if (USB0->POWER & USB_POWER_HSMODE) return TUSB_SPEED_HIGH;
+ return TUSB_SPEED_FULL;
+}
+
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ if (sizeof(_hcd.ctl_mps) <= dev_addr) return;
+
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ _hcd.ctl_mps[dev_addr] = 0;
+ if (!dev_addr) return;
+
+ pipe_addr_t *p = &_hcd.addr[0][0];
+ for (unsigned i = 0; i < sizeof(_hcd.addr)/sizeof(_hcd.addr[0]); ++i) {
+ for (unsigned j = 0; j < 2; ++j, ++p) {
+ if (dev_addr != p->dev) continue;
+ hw_addr_t volatile *fadr = (hw_addr_t volatile*)&USB0->TXFUNCADDR0 + i + 1;
+ hw_endpoint_t volatile *regs = edpt_regs(i);
+ USB0->EPIDX = i + 1;
+ if (j) {
+ USB0->TXIE &= ~TU_BIT(i + 1);
+ if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ regs->TXMAXP = 0;
+ regs->TXTYPE = 0;
+ regs->TXINTERVAL = 0;
+ fadr->TXFUNCADDR = 0;
+ fadr->TXHUBADDR = 0;
+ fadr->TXHUBPORT = 0;
+ USB0->TXFIFOADD = 0;
+ USB0->TXFIFOSZ = 0;
+ } else {
+ USB0->RXIE &= ~TU_BIT(i + 1);
+ if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ regs->RXMAXP = 0;
+ regs->RXTYPE = 0;
+ regs->RXINTERVAL = 0;
+ fadr->RXFUNCADDR = 0;
+ fadr->RXHUBADDR = 0;
+ fadr->RXHUBPORT = 0;
+ USB0->RXFIFOADD = 0;
+ USB0->RXFIFOSZ = 0;
+ }
+ p->dev = 0;
+ p->ep = 0;
+ pipe_state_t *pipe = &_hcd.pipe[i][j];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+ }
+ }
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+//--------------------------------------------------------------------+
+// Endpoints API
+//--------------------------------------------------------------------+
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ (void)rhport;
+ pipe_write_packet((void*)(uintptr_t)setup_packet, &USB0->FIFO0_WORD, 8);
+ _hcd.pipe0.buf = (void*)(uintptr_t)setup_packet;
+ _hcd.pipe0.length = 8;
+ _hcd.pipe0.remaining = 0;
+
+ hcd_devtree_info_t devtree;
+ hcd_devtree_get_info(dev_addr, &devtree);
+ switch (devtree.speed) {
+ default: return false;
+ case TUSB_SPEED_LOW: USB0->TYPE0 = USB_TYPE0_SPEED_LOW; break;
+ case TUSB_SPEED_FULL: USB0->TYPE0 = USB_TYPE0_SPEED_FULL; break;
+ case TUSB_SPEED_HIGH: USB0->TYPE0 = USB_TYPE0_SPEED_HIGH; break;
+ }
+ USB0->TXHUBADDR0 = devtree.hub_addr;
+ USB0->TXHUBPORT0 = devtree.hub_port;
+ USB0->TXFUNCADDR0 = dev_addr;
+ USB0->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_SETUP;
+ return true;
+}
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void)rhport;
+ if (sizeof(_hcd.ctl_mps) <= dev_addr) return false;
+ unsigned const ep_addr = ep_desc->bEndpointAddress;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ if (0 == epn) {
+ _hcd.ctl_mps[dev_addr] = ep_desc->wMaxPacketSize;
+ return true;
+ }
+
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ /* Find a free pipe */
+ unsigned pipenum = 0;
+ pipe_addr_t *p = &_hcd.addr[0][dir_tx];
+ for (unsigned i = 0; i < sizeof(_hcd.addr)/sizeof(_hcd.addr[0]); ++i, p += 2) {
+ if (0 == p->ep) {
+ p->dev = dev_addr;
+ p->ep = ep_addr;
+ pipenum = i + 1;
+ break;
+ }
+ }
+ if (!pipenum) return false;
+
+ unsigned const xfer = ep_desc->bmAttributes.xfer;
+ unsigned const mps = tu_edpt_packet_size(ep_desc);
+
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][dir_tx];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+
+ uint8_t pipe_type = 0;
+ hcd_devtree_info_t devtree;
+ hcd_devtree_get_info(dev_addr, &devtree);
+ switch (devtree.speed) {
+ default: return false;
+ case TUSB_SPEED_LOW: pipe_type |= USB_TXTYPE1_SPEED_LOW; break;
+ case TUSB_SPEED_FULL: pipe_type |= USB_TXTYPE1_SPEED_FULL; break;
+ case TUSB_SPEED_HIGH: pipe_type |= USB_TXTYPE1_SPEED_HIGH; break;
+ }
+ switch (xfer) {
+ default: return false;
+ case TUSB_XFER_BULK: pipe_type |= USB_TXTYPE1_PROTO_BULK; break;
+ case TUSB_XFER_INTERRUPT: pipe_type |= USB_TXTYPE1_PROTO_INT; break;
+ case TUSB_XFER_ISOCHRONOUS: pipe_type |= USB_TXTYPE1_PROTO_ISOC; break;
+ }
+
+ hw_addr_t volatile *fadr = (hw_addr_t volatile*)&USB0->TXFUNCADDR0 + pipenum;
+ hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
+ if (dir_tx) {
+ fadr->TXFUNCADDR = dev_addr;
+ fadr->TXHUBADDR = devtree.hub_addr;
+ fadr->TXHUBPORT = devtree.hub_port;
+ regs->TXMAXP = mps;
+ regs->TXTYPE = pipe_type | epn;
+ regs->TXINTERVAL = ep_desc->bInterval;
+ if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ USB0->TXIE |= TU_BIT(pipenum);
+ } else {
+ fadr->RXFUNCADDR = dev_addr;
+ fadr->RXHUBADDR = devtree.hub_addr;
+ fadr->RXHUBPORT = devtree.hub_port;
+ regs->RXMAXP = mps;
+ regs->RXTYPE = pipe_type | epn;
+ regs->RXINTERVAL = ep_desc->bInterval;
+ if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ USB0->RXIE |= TU_BIT(pipenum);
+ }
+
+ /* Setup FIFO */
+ int size_in_log2_minus3 = 28 - TU_MIN(28, __CLZ((uint32_t)mps));
+ if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3;
+ unsigned addr = find_free_memory(size_in_log2_minus3);
+ TU_ASSERT(addr);
+
+ USB0->EPIDX = pipenum;
+ if (dir_tx) {
+ USB0->TXFIFOADD = addr;
+ USB0->TXFIFOSZ = size_in_log2_minus3;
+ } else {
+ USB0->RXFIFOADD = addr;
+ USB0->RXFIFOSZ = size_in_log2_minus3;
+ }
+ return true;
+}
+
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ (void)rhport;
+ bool ret = false;
+ if (0 == tu_edpt_number(ep_addr)) {
+ ret = edpt0_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
+ } else {
+ ret = edpt_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
+ }
+ return ret;
+}
+
+// clear stall, data toggle is also reset to DATA0
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+ unsigned const pipenum = find_pipe(dev_addr, ep_addr);
+ if (!pipenum) return false;
+ hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ if (dir_tx)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ return true;
+}
+
+/*-------------------------------------------------------------------
+ * ISR
+ *-------------------------------------------------------------------*/
+void hcd_int_handler(uint8_t rhport)
+{
+ uint_fast8_t is, txis, rxis;
+
+ is = USB0->IS; /* read and clear interrupt status */
+ txis = USB0->TXIS; /* read and clear interrupt status */
+ rxis = USB0->RXIS; /* read and clear interrupt status */
+ // TU_LOG1("D%2x T%2x R%2x\n", is, txis, rxis);
+
+ is &= USB0->IE; /* Clear disabled interrupts */
+ if (is & USB_IS_RESUME) {
+ }
+ if (is & USB_IS_CONN) {
+ _hcd.need_reset = true;
+ hcd_event_device_attach(rhport, true);
+ }
+ if (is & USB_IS_DISCON) {
+ hcd_event_device_remove(rhport, true);
+ }
+ if (is & USB_IS_BABBLE) {
+ }
+ txis &= USB0->TXIE; /* Clear disabled interrupts */
+ if (txis & USB_TXIE_EP0) {
+ process_ep0(rhport);
+ txis &= ~TU_BIT(0);
+ }
+ while (txis) {
+ unsigned const num = __builtin_ctz(txis);
+ process_pipe_tx(rhport, num);
+ txis &= ~TU_BIT(num);
+ }
+ rxis &= USB0->RXIE; /* Clear disabled interrupts */
+ while (rxis) {
+ unsigned const num = __builtin_ctz(rxis);
+ process_pipe_rx(rhport, num);
+ rxis &= ~TU_BIT(num);
+ }
+}
+
+#endif
diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c
new file mode 100644
index 000000000..6cf0e6285
--- /dev/null
+++ b/src/portable/microchip/pic/dcd_pic.c
@@ -0,0 +1,786 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Koji Kitayama
+ * Copyright (c) 2022 Reimu NotMoe <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && \
+ (CFG_TUSB_MCU == OPT_MCU_PIC32MX || CFG_TUSB_MCU == OPT_MCU_PIC32MM || \
+ CFG_TUSB_MCU == OPT_MCU_PIC32MK || CFG_TUSB_MCU == OPT_MCU_PIC24 || \
+ CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+
+#include <xc.h>
+
+#include "device/dcd.h"
+
+
+#if (CFG_TUSB_MCU == OPT_MCU_PIC32MX || CFG_TUSB_MCU == OPT_MCU_PIC32MM || CFG_TUSB_MCU == OPT_MCU_PIC32MK)
+
+#define TU_PIC_INT_SIZE 4
+
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24 || CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+
+#define TU_PIC_INT_SIZE 2
+
+#else
+
+#error Unsupportd PIC MCU
+
+#endif
+
+
+#if TU_PIC_INT_SIZE == 4
+
+#ifndef KVA_TO_PA
+#define KVA_TO_PA(kva) ((uint32_t)(kva) & 0x1fffffff)
+#endif
+
+#ifndef PA_TO_KVA1
+#define PA_TO_KVA1(pa) ((uint32_t)(pa) | 0xA0000000)
+#endif
+
+#else
+
+#ifndef KVA_TO_PA
+#define KVA_TO_PA(kva) (kva)
+#endif
+
+#ifndef PA_TO_KVA1
+#define PA_TO_KVA1(pa) (pa)
+#endif
+
+#endif
+
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+ TOK_PID_OUT = 0x1u,
+ TOK_PID_IN = 0x9u,
+ TOK_PID_SETUP = 0xDu,
+};
+
+// The BDT is 8 bytes on 32bit PICs and 4 bytes on 8/16bit PICs
+#if TU_PIC_INT_SIZE == 4
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t head;
+ struct {
+ union {
+ struct {
+ uint16_t : 2;
+ uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ uint16_t own : 1;
+ uint16_t : 8;
+ };
+ struct {
+ uint16_t : 2;
+ uint16_t bdt_stall : 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ uint16_t : 10;
+ };
+ };
+ uint16_t bc : 10;
+ uint16_t : 6;
+ };
+ };
+ uint8_t *addr;
+} buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" );
+#else
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint16_t head;
+
+ struct {
+ uint16_t : 10;
+ uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ uint16_t own : 1;
+ };
+ struct {
+ uint16_t : 10;
+ uint16_t bdt_stall : 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ };
+
+ struct {
+ uint16_t bc : 10;
+ uint16_t : 6;
+ };
+ };
+ uint8_t *addr;
+} buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 4, "size is not correct" );
+#endif
+
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t state;
+ struct {
+ uint32_t max_packet_size :11;
+ uint32_t : 5;
+ uint32_t odd : 1;
+ uint32_t :15;
+ };
+ };
+ uint16_t length;
+ uint16_t remaining;
+} endpoint_state_t;
+
+TU_VERIFY_STATIC( sizeof(endpoint_state_t) == 8, "size is not correct" );
+
+typedef struct
+{
+ union {
+ /* [#EP][OUT,IN][EVEN,ODD] */
+ buffer_descriptor_t bdt[16][2][2];
+#if TU_PIC_INT_SIZE == 4
+ uint16_t bda[256];
+#else
+ uint8_t bda[256];
+#endif
+ };
+ TU_ATTR_ALIGNED(4) union {
+ endpoint_state_t endpoint[16][2];
+ endpoint_state_t endpoint_unified[16 * 2];
+ };
+ uint8_t setup_packet[8];
+ uint8_t addr;
+} dcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+// BDT(Buffer Descriptor Table) must be 256-byte aligned
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) volatile static dcd_data_t _dcd;
+
+#if TU_PIC_INT_SIZE == 4
+TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
+#else
+TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 256, "size is not correct" );
+#endif
+
+#if TU_PIC_INT_SIZE == 4
+typedef uint32_t ep_reg_t;
+#elif TU_PIC_INT_SIZE == 2
+typedef uint16_t ep_reg_t;
+#endif
+
+static inline volatile void *ep_addr(uint8_t rhport, uint8_t ep_num) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ volatile void *ep_reg_base = rhport ? (&U2EP0) : (&U1EP0);
+#else
+ volatile void *ep_reg_base = &U1EP0;
+#endif
+#if TU_PIC_INT_SIZE == 4
+ const size_t offset = 0x10;
+#else
+ const size_t offset = 0x2;
+#endif
+ return ep_reg_base + offset * ep_num;
+}
+
+static inline ep_reg_t ep_read(uint8_t rhport, uint8_t ep_num) {
+ volatile ep_reg_t *ep = ep_addr(rhport, ep_num);
+ return *ep;
+}
+
+static inline void ep_write(uint8_t rhport, uint8_t ep_num, ep_reg_t val) {
+ volatile ep_reg_t *ep = ep_addr(rhport, ep_num);
+ *ep = val;
+}
+
+static inline void ep_clear(uint8_t rhport, uint8_t ep_num, ep_reg_t val) {
+#if TU_PIC_INT_SIZE == 4
+ volatile ep_reg_t *ep_clr = (ep_addr(rhport, ep_num) + 0x4);
+ *ep_clr = val;
+#else
+ ep_reg_t v = ep_read(rhport, ep_num);
+ v &= ~val;
+ ep_write(rhport, ep_num, v);
+#endif
+}
+
+static inline void ep_set(uint8_t rhport, uint8_t ep_num, ep_reg_t val) {
+#if TU_PIC_INT_SIZE == 4
+ volatile ep_reg_t *ep_s = (ep_addr(rhport, ep_num) + 0x8);
+ *ep_s = val;
+#else
+ ep_reg_t v = ep_read(rhport, ep_num);
+ v |= val;
+ ep_write(rhport, ep_num, v);
+#endif
+}
+
+static inline void intr_enable(uint8_t rhport) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ IEC0SET = _IEC0_USBIE_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ IEC1SET = _IEC1_USBIE_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ if (rhport == 0)
+ IEC1SET = _IEC1_USB1IE_MASK;
+ else
+ IEC7SET = _IEC7_USB2IE_MASK;
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+ IEC5bits.USB1IE = 1;
+#endif
+}
+
+static inline void intr_disable(uint8_t rhport) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ IEC0CLR = _IEC0_USBIE_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ IEC1CLR = _IEC1_USBIE_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ if (rhport == 0)
+ IEC1CLR = _IEC1_USB1IE_MASK;
+ else
+ IEC7CLR = _IEC7_USB2IE_MASK;
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+ IEC5bits.USB1IE = 0;
+#endif
+}
+
+static inline int intr_is_enabled(uint8_t rhport) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ return IEC0bits.USBIE;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ return IEC1bits.USBIE;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ if (rhport == 0)
+ return IEC1bits.USB1IE;
+ else
+ return IEC7bits.USB2IE;
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+ return IEC5bits.USB1IE;
+#endif
+}
+
+static inline void intr_clear(uint8_t rhport) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ IFS0CLR = _IFS0_USBIF_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ IFS1CLR = _IFS1_USBIF_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ if (rhport == 0)
+ IFS1CLR = _IFS1_USB1IF_MASK;
+ else
+ IFS7CLR = _IFS7_USB2IF_MASK;
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+ IFS5bits.USB1IF = 0;
+#endif
+}
+
+static void prepare_next_setup_packet(uint8_t rhport)
+{
+ const unsigned out_odd = _dcd.endpoint[0][0].odd;
+ const unsigned in_odd = _dcd.endpoint[0][1].odd;
+ TU_ASSERT(0 == _dcd.bdt[0][0][out_odd].own, );
+
+ _dcd.bdt[0][0][out_odd].data = 0;
+ _dcd.bdt[0][0][out_odd ^ 1].data = 1;
+ _dcd.bdt[0][1][in_odd].data = 1;
+ _dcd.bdt[0][1][in_odd ^ 1].data = 0;
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT),
+ _dcd.setup_packet, sizeof(_dcd.setup_packet));
+}
+
+static void process_stall(uint8_t rhport)
+{
+ for (int i = 0; i < 16; ++i) {
+ unsigned const endpt = ep_read(rhport, i);
+
+ if (endpt & _U1EP0_EPSTALL_MASK) {
+ // prepare next setup if endpoint0
+ if ( i == 0 ) prepare_next_setup_packet(rhport);
+
+ // clear stall bit
+ ep_clear(rhport, i, _U1EP0_EPSTALL_MASK);
+ }
+ }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+ ep_reg_t s = U1STAT;
+
+ U1IR = _U1IR_TRNIF_MASK;
+
+ uint8_t epnum = (s >> _U1STAT_ENDPT0_POSITION);
+ uint8_t dir = (s & _U1STAT_DIR_MASK) >> _U1STAT_DIR_POSITION;
+ unsigned odd = (s & _U1STAT_PPBI_MASK) ? 1 : 0;
+
+ buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s];
+ endpoint_state_t *ep = &_dcd.endpoint_unified[s >> 3];
+
+ /* fetch pid before discarded by the next steps */
+ const unsigned pid = bd->tok_pid;
+
+ /* reset values for a next transfer */
+ bd->bdt_stall = 0;
+ bd->dts = 1;
+ bd->ninc = 0;
+ bd->keep = 0;
+ /* update the odd variable to prepare for the next transfer */
+ ep->odd = odd ^ 1;
+ if (pid == TOK_PID_SETUP) {
+ dcd_event_setup_received(rhport, (uint8_t *)PA_TO_KVA1(bd->addr), true);
+#if TU_PIC_INT_SIZE == 4
+ U1CONCLR = _U1CON_PKTDIS_TOKBUSY_MASK;
+#else
+ U1CONbits.PKTDIS = 0;
+#endif
+ return;
+ }
+
+ const unsigned bc = bd->bc;
+ const unsigned remaining = ep->remaining - bc;
+ if (remaining && bc == ep->max_packet_size) {
+ /* continue the transferring consecutive data */
+ ep->remaining = remaining;
+ const int next_remaining = remaining - ep->max_packet_size;
+ if (next_remaining > 0) {
+ /* prepare to the after next transfer */
+ bd->addr += ep->max_packet_size * 2;
+ bd->bc = next_remaining > ep->max_packet_size ? ep->max_packet_size: next_remaining;
+ bd->own = 1; /* the own bit must set after addr */
+ }
+ return;
+ }
+ const unsigned length = ep->length;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(epnum, dir),
+ length - remaining, XFER_RESULT_SUCCESS, true);
+ if (0 == epnum && 0 == length) {
+ /* After completion a ZLP of control transfer,
+ * it prepares for the next steup transfer. */
+ if (_dcd.addr) {
+ /* When the transfer was the SetAddress,
+ * the device address should be updated here. */
+ U1ADDR = _dcd.addr;
+ _dcd.addr = 0;
+ }
+ prepare_next_setup_packet(rhport);
+ }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+#if TU_PIC_INT_SIZE == 4
+ U1PWRCCLR = _U1PWRC_USUSPEND_MASK;
+ U1CONSET = _U1CON_PPBRST_MASK;
+#else
+ U1PWRCbits.USUSPND = 0;
+ U1CONbits.PPBRST = 1;
+#endif
+ U1ADDR = 0;
+
+ U1IE = _U1IE_URSTIE_MASK | _U1IE_TRNIE_MASK | _U1IE_IDLEIE_MASK |
+ _U1IE_UERRIE_MASK | _U1IE_STALLIE_MASK;
+
+ U1EP0 = _U1EP0_EPHSHK_MASK | _U1EP0_EPRXEN_MASK | _U1EP0_EPTXEN_MASK;
+
+ for (unsigned i = 1; i < 16; ++i) {
+ ep_write(rhport, i, 0);
+ }
+
+ buffer_descriptor_t *bd = _dcd.bdt[0][0];
+ for (unsigned i = 0; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+ bd->head = 0;
+ }
+ const endpoint_state_t ep0 = {
+ .max_packet_size = CFG_TUD_ENDPOINT0_SIZE,
+ .odd = 0,
+ .length = 0,
+ .remaining = 0,
+ };
+ _dcd.endpoint[0][0] = ep0;
+ _dcd.endpoint[0][1] = ep0;
+ tu_memclr(_dcd.endpoint[1], sizeof(_dcd.endpoint) - sizeof(_dcd.endpoint[0]));
+ _dcd.addr = 0;
+ prepare_next_setup_packet(rhport);
+#if TU_PIC_INT_SIZE == 4
+ U1CONCLR = _U1CON_PPBRST_MASK;
+#else
+ U1CONbits.PPBRST = 0;
+#endif
+ dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+}
+
+static void process_bus_sleep(uint8_t rhport)
+{
+ // Enable resume & disable suspend interrupt
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+}
+
+static void process_bus_resume(uint8_t rhport)
+{
+ // Enable suspend & disable resume interrupt
+#if TU_PIC_INT_SIZE == 4
+ U1PWRCCLR = _U1PWRC_USUSPEND_MASK;
+ U1IECLR = _U1IE_RESUMEIE_MASK;
+ U1IESET = _U1IE_IDLEIE_MASK;
+#else
+ U1PWRCbits.USUSPND = 0;
+ U1IEbits.RESUMEIE = 0;
+ U1IEbits.IDLEIE = 1;
+#endif
+
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+ intr_disable(rhport);
+ intr_clear(rhport);
+
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ TRISBbits.TRISB6 = 1;
+#endif
+
+ tu_memclr(&_dcd, sizeof(_dcd));
+
+#if TU_PIC_INT_SIZE == 4
+ U1PWRCSET = _U1PWRC_USBPWR_MASK;
+#else
+ U1PWRCbits.USBPWR = 1;
+#endif
+
+#if TU_PIC_INT_SIZE == 4
+ uint32_t bdt_phys = KVA_TO_PA((uintptr_t)_dcd.bdt);
+
+ U1BDTP1 = (uint8_t)(bdt_phys >> 8);
+ U1BDTP2 = (uint8_t)(bdt_phys >> 16);
+ U1BDTP3 = (uint8_t)(bdt_phys >> 24);
+#else
+ U1BDTP1 = (uint8_t)((uint16_t)(void *)_dcd.bdt >> 8);
+
+ U1CNFG1bits.PPB = 2;
+#endif
+
+ U1IE = _U1IE_URSTIE_MASK;
+
+ dcd_connect(rhport);
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ intr_enable(rhport);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ intr_disable(rhport);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ _dcd.addr = dev_addr & 0x7F;
+ /* Response with status first before changing device address */
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+#if TU_PIC_INT_SIZE == 4
+ U1CONSET = _U1CON_RESUME_MASK;
+#else
+ U1CONbits.RESUME = 1;
+#endif
+ unsigned cnt = 25000000 / 1000;
+ while (cnt--) asm volatile("nop");
+
+#if TU_PIC_INT_SIZE == 4
+ U1CONCLR = _U1CON_RESUME_MASK;
+#else
+ U1CONbits.RESUME = 0;
+#endif
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ while (!U1CONbits.USBEN) {
+#if TU_PIC_INT_SIZE == 4
+ U1CONSET = _U1CON_USBEN_SOFEN_MASK;
+#else
+ U1CONbits.USBEN = 1;
+#endif
+ }
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ U1CON = 0;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ const unsigned odd = ep->odd;
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+
+ /* No support for control transfer */
+ TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL));
+
+ ep->max_packet_size = tu_edpt_packet_size(ep_desc);
+
+
+ unsigned val = _U1EP0_EPCONDIS_MASK;
+ val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? _U1EP0_EPHSHK_MASK : 0;
+ val |= dir ? _U1EP0_EPTXEN_MASK : _U1EP0_EPRXEN_MASK;
+
+ ep_reg_t tmp = ep_read(rhport, epn);
+ tmp |= val;
+ ep_write(rhport, epn, tmp);
+
+ if (xfer != TUSB_XFER_ISOCHRONOUS) {
+ bd[odd].dts = 1;
+ bd[odd].data = 0;
+ bd[odd ^ 1].dts = 1;
+ bd[odd ^ 1].data = 1;
+ }
+
+ return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ const unsigned ie = intr_is_enabled(rhport);
+ intr_disable(rhport);
+
+ for (unsigned i = 1; i < 16; ++i) {
+ ep_write(rhport, i, 0);
+ }
+
+ if (ie) intr_enable(rhport);
+
+ buffer_descriptor_t *bd = _dcd.bdt[1][0];
+ for (unsigned i = 2; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+ bd->head = 0;
+ }
+ endpoint_state_t *ep = &_dcd.endpoint[1][0];
+ for (unsigned i = 2; i < sizeof(_dcd.endpoint)/sizeof(*ep); ++i, ++ep) {
+ /* Clear except the odd */
+ ep->max_packet_size = 0;
+ ep->length = 0;
+ ep->remaining = 0;
+ }
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+ const unsigned msk = dir ? _U1EP0_EPTXEN_MASK : _U1EP0_EPRXEN_MASK;
+ const unsigned ie = intr_is_enabled(rhport);
+
+ intr_disable(rhport);
+
+ ep_clear(rhport, epn, msk);
+
+ ep->max_packet_size = 0;
+ ep->length = 0;
+ ep->remaining = 0;
+ bd[0].head = 0;
+ bd[1].head = 0;
+
+ if (ie) intr_enable(rhport);
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd];
+ TU_ASSERT(0 == bd->own);
+
+ const unsigned ie = intr_is_enabled(rhport);
+
+ intr_disable(rhport);
+
+ ep->length = total_bytes;
+ ep->remaining = total_bytes;
+
+ const unsigned mps = ep->max_packet_size;
+ if (total_bytes > mps) {
+ buffer_descriptor_t *next = ep->odd ? bd - 1: bd + 1;
+ /* When total_bytes is greater than the max packet size,
+ * it prepares to the next transfer to avoid NAK in advance. */
+ next->bc = total_bytes >= 2 * mps ? mps: total_bytes - mps;
+ next->addr = (uint8_t *)KVA_TO_PA(buffer + mps);
+ next->own = 1;
+ }
+ bd->bc = total_bytes >= mps ? mps: total_bytes;
+ bd->addr = (uint8_t *)KVA_TO_PA(buffer);
+ bd->own = 1; /* This bit must be set last */
+
+ if (ie) intr_enable(rhport);
+
+ return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ const unsigned epn = tu_edpt_number(ep_addr);
+
+ if (0 == epn) {
+ ep_set(rhport, epn, _U1EP0_EPSTALL_MASK);
+ } else {
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned odd = _dcd.endpoint[epn][dir].odd;
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][odd];
+ TU_ASSERT(0 == bd->own,);
+
+ const unsigned ie = intr_is_enabled(rhport);
+
+ intr_disable(rhport);
+
+ bd->bdt_stall = 1;
+ bd->own = 1; /* This bit must be set last */
+
+ if (ie) intr_enable(rhport);
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ TU_VERIFY(epn,);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned odd = _dcd.endpoint[epn][dir].odd;
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+ TU_VERIFY(bd[odd].own,);
+
+ const unsigned ie = intr_is_enabled(rhport);
+
+ intr_disable(rhport);
+
+ bd[odd].own = 0;
+
+ // clear stall
+ bd[odd].bdt_stall = 0;
+
+ // Reset data toggle
+ bd[odd ].data = 0;
+ bd[odd ^ 1].data = 1;
+
+ // We already cleared this in ISR, but just clear it here to be safe
+ const unsigned endpt = ep_read(rhport, epn);
+ if (endpt & _U1EP0_EPSTALL_MASK) {
+ ep_clear(rhport, endpt, _U1EP0_EPSTALL_MASK);
+ }
+
+ if (ie) intr_enable(rhport);
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void dcd_int_handler(uint8_t rhport)
+{
+ uint32_t is = U1IR;
+ uint32_t msk = U1IE;
+
+ U1IR = is & ~msk;
+ is &= msk;
+
+ if (is & _U1IR_UERRIF_MASK) {
+ uint32_t es = U1EIR;
+ U1EIR = es;
+ U1IR = is; /* discard any pending events */
+ }
+
+ if (is & _U1IR_URSTIF_MASK) {
+ U1IR = is; /* discard any pending events */
+ process_bus_reset(rhport);
+ }
+
+ if (is & _U1IR_IDLEIF_MASK) {
+ // Note Host usually has extra delay after bus reset (without SOF), which could falsely
+ // detected as Sleep event. Though usbd has debouncing logic so we are good
+ U1IR = _U1IR_IDLEIF_MASK;
+ process_bus_sleep(rhport);
+ }
+
+ if (is & _U1IR_RESUMEIF_MASK) {
+ U1IR = _U1IR_RESUMEIF_MASK;
+ process_bus_resume(rhport);
+ }
+
+ if (is & _U1IR_SOFIF_MASK) {
+ U1IR = _U1IR_SOFIF_MASK;
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
+
+ if (is & _U1IR_STALLIF_MASK) {
+ U1IR = _U1IR_STALLIF_MASK;
+ process_stall(rhport);
+ }
+
+ if (is & _U1IR_TRNIF_MASK) {
+ process_tokdne(rhport);
+ }
+
+ intr_clear(rhport);
+}
+
+#endif
diff --git a/src/portable/microchip/pic32mz/dcd_pic32mz.c b/src/portable/microchip/pic32mz/dcd_pic32mz.c
new file mode 100644
index 000000000..9ad755670
--- /dev/null
+++ b/src/portable/microchip/pic32mz/dcd_pic32mz.c
@@ -0,0 +1,753 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Jerzy Kasenberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_PIC32MZ
+
+#include <common/tusb_common.h>
+#include <device/dcd.h>
+
+#include <xc.h>
+#include "usbhs_registers.h"
+
+#define USB_REGS ((usbhs_registers_t *) (_USB_BASE_ADDRESS))
+
+// Maximum number of endpoints, could be trimmed down in tusb_config to reduce RAM usage.
+#ifndef EP_MAX
+#define EP_MAX 8
+#endif
+
+
+typedef enum {
+ EP0_STAGE_NONE,
+ EP0_STAGE_SETUP_IN_DATA,
+ EP0_STAGE_SETUP_OUT_NO_DATA,
+ EP0_STAGE_SETUP_OUT_DATA,
+ EP0_STAGE_DATA_IN,
+ EP0_STAGE_DATA_IN_LAST_PACKET_FILLED,
+ EP0_STAGE_DATA_IN_SENT,
+ EP0_STAGE_DATA_OUT,
+ EP0_STAGE_DATA_OUT_COMPLETE,
+ EP0_STAGE_STATUS_IN,
+ EP0_STAGE_ADDRESS_CHANGE,
+} ep0_stage_t;
+
+typedef struct {
+ uint8_t * buffer;
+ // Total length of current transfer
+ uint16_t total_len;
+ // Bytes transferred so far
+ uint16_t transferred;
+ uint16_t max_packet_size;
+ uint16_t fifo_size;
+ // Packet size sent or received so far. It is used to modify transferred field
+ // after ACK is received or when filling ISO endpoint with size larger then
+ // FIFO size.
+ uint16_t last_packet_size;
+ uint8_t ep_addr;
+} xfer_ctl_t;
+
+static struct
+{
+ // Current FIFO RAM address used for FIFO allocation
+ uint16_t fifo_addr_top;
+ // EP0 transfer stage
+ ep0_stage_t ep0_stage;
+ // Device address
+ uint8_t dev_addr;
+ xfer_ctl_t xfer_status[EP_MAX][2];
+} _dcd;
+
+// Two endpoint 0 descriptor definition for unified dcd_edpt_open()
+static tusb_desc_endpoint_t const ep0OUT_desc =
+{
+ .bLength = sizeof(tusb_desc_endpoint_t),
+ .bDescriptorType = TUSB_DESC_ENDPOINT,
+
+ .bEndpointAddress = 0x00,
+ .bmAttributes = { .xfer = TUSB_XFER_CONTROL },
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
+ .bInterval = 0
+};
+
+static tusb_desc_endpoint_t const ep0IN_desc =
+{
+ .bLength = sizeof(tusb_desc_endpoint_t),
+ .bDescriptorType = TUSB_DESC_ENDPOINT,
+
+ .bEndpointAddress = 0x80,
+ .bmAttributes = { .xfer = TUSB_XFER_CONTROL },
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
+ .bInterval = 0
+};
+
+#define XFER_CTL_BASE(_ep, _dir) &_dcd.xfer_status[_ep][_dir]
+
+static void ep0_set_stage(ep0_stage_t stage)
+{
+ _dcd.ep0_stage = stage;
+}
+
+static ep0_stage_t ep0_get_stage(void)
+{
+ return _dcd.ep0_stage;
+}
+
+/*------------------------------------------------------------------*/
+/* Controller API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+ // Disable endpoint interrupts for now
+ USB_REGS->INTRRXEbits.w = 0;
+ USB_REGS->INTRTXEbits.w = 0;
+ // Enable Reset/Suspend/Resume interrupts only
+ USB_REGS->INTRUSBEbits.w = 7;
+
+ dcd_connect(rhport);
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ (void) rhport;
+
+ USBCRCONbits.USBIE = 1;
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ (void) rhport;
+
+ USBCRCONbits.USBIE = 0;
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ (void) rhport;
+
+ ep0_set_stage(EP0_STAGE_ADDRESS_CHANGE);
+ // Store address it will be used later after status stage is done
+ _dcd.dev_addr = dev_addr;
+ // Confirm packet now, address will be set when status stage is detected
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.w = (USBHS_EP0_DEVICE_SERVICED_RXPKTRDY | USBHS_EP0_DEVICE_DATAEND);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void) rhport;
+
+ USB_REGS->POWERbits.RESUME = 1;
+#if CFG_TUSB_OS != OPT_OS_NONE
+ osal_task_delay(10);
+#else
+ // TODO: Wait in non blocking mode
+ unsigned cnt = 2000;
+ while (cnt--) __asm__("nop");
+#endif
+ USB_REGS->POWERbits.RESUME = 0;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ (void) rhport;
+
+ USB_REGS->POWERbits.HSEN = TUD_OPT_HIGH_SPEED ? 1 : 0;
+ USB_REGS->POWERbits.SOFTCONN = 1;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ (void) rhport;
+
+ USB_REGS->POWERbits.SOFTCONN = 1;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
+{
+ return (_CP0_GET_STATUS() & (_CP0_STATUS_EXL_MASK | _CP0_STATUS_IPL_MASK)) != 0;
+}
+
+static void epn_rx_configure(uint8_t endpoint, uint16_t endpointSize,
+ uint16_t fifoAddress, uint8_t fifoSize,
+ uint32_t transferType)
+{
+ uint8_t old_index = USB_REGS->INDEXbits.ENDPOINT;
+
+ // Select endpoint register set (same register address is used for all endpoints.
+ USB_REGS->INDEXbits.ENDPOINT = endpoint;
+
+ // Configure the Endpoint size
+ USB_REGS->INDEXED_EPCSR.RXMAXPbits.RXMAXP = endpointSize;
+
+ // Set up the fifo address.
+ USB_REGS->RXFIFOADDbits.RXFIFOAD = fifoAddress;
+
+ // Resets the endpoint data toggle to 0
+ USB_REGS->INDEXED_EPCSR.RXCSRL_DEVICEbits.CLRDT = 1;
+
+ // Set up the FIFO size
+ USB_REGS->RXFIFOSZbits.RXFIFOSZ = fifoSize;
+
+ USB_REGS->INDEXED_EPCSR.RXCSRH_DEVICEbits.ISO = transferType == 1 ? 1 : 0;
+ // Disable NYET Handshakes for interrupt endpoints
+ USB_REGS->INDEXED_EPCSR.RXCSRH_DEVICEbits.DISNYET = transferType == 3 ? 1 : 0;
+
+ // Restore the index register.
+ USB_REGS->INDEXbits.ENDPOINT = old_index;
+
+ // Enable the endpoint interrupt.
+ USB_REGS->INTRRXEbits.w |= (1 << endpoint);
+}
+
+static void epn_tx_configure(uint8_t endpoint, uint16_t endpointSize,
+ uint16_t fifoAddress, uint8_t fifoSize,
+ uint32_t transferType)
+{
+ uint8_t old_index = USB_REGS->INDEXbits.ENDPOINT;
+
+ // Select endpoint register set (same register address is used for all endpoints.
+ USB_REGS->INDEXbits.ENDPOINT = endpoint;
+
+ // Configure the Endpoint size
+ USB_REGS->INDEXED_EPCSR.TXMAXPbits.TXMAXP = endpointSize;
+
+ // Set up the fifo address
+ USB_REGS->TXFIFOADDbits.TXFIFOAD = fifoAddress;
+
+ // Resets the endpoint data toggle to 0
+ USB_REGS->INDEXED_EPCSR.TXCSRL_DEVICEbits.CLRDT = 1;
+
+ // Set up the FIFO size
+ USB_REGS->TXFIFOSZbits.TXFIFOSZ = fifoSize;
+
+ USB_REGS->INDEXED_EPCSR.TXCSRH_DEVICEbits.ISO = 1 == transferType ? 1 : 0;
+
+ // Restore the index register
+ USB_REGS->INDEXbits.ENDPOINT = old_index;
+
+ // Enable the interrupt
+ USB_REGS->INTRTXEbits.w |= (1 << endpoint);
+}
+
+static void tx_fifo_write(uint8_t endpoint, uint8_t const * buffer, size_t count)
+{
+ size_t i;
+ volatile uint8_t * fifo_reg;
+
+ fifo_reg = (volatile uint8_t *) (&USB_REGS->FIFO[endpoint]);
+
+ for (i = 0; i < count; i++)
+ {
+ *fifo_reg = buffer[i];
+ }
+}
+
+static int rx_fifo_read(uint8_t epnum, uint8_t * buffer)
+{
+ uint32_t i;
+ uint32_t count;
+ volatile uint8_t * fifo_reg;
+
+ fifo_reg = (volatile uint8_t *) (&USB_REGS->FIFO[epnum]);
+
+ count = USB_REGS->EPCSR[epnum].RXCOUNTbits.RXCNT;
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = fifo_reg[i & 3];
+ }
+
+ return count;
+}
+
+static void xfer_complete(xfer_ctl_t * xfer, uint8_t result, bool in_isr)
+{
+ dcd_event_xfer_complete(0, xfer->ep_addr, xfer->transferred, result, in_isr);
+}
+
+static void ep0_fill_tx(xfer_ctl_t * xfer_in)
+{
+ uint16_t left = xfer_in->total_len - xfer_in->transferred;
+
+ if (left)
+ {
+ xfer_in->last_packet_size = tu_min16(xfer_in->max_packet_size, left);
+ tx_fifo_write(0, xfer_in->buffer + xfer_in->transferred, xfer_in->last_packet_size);
+ xfer_in->transferred += xfer_in->last_packet_size;
+ left = xfer_in->total_len - xfer_in->transferred;
+ }
+
+ if (xfer_in->last_packet_size < xfer_in->max_packet_size || left == 0)
+ {
+ switch (ep0_get_stage())
+ {
+ case EP0_STAGE_SETUP_IN_DATA:
+ case EP0_STAGE_DATA_IN:
+ case EP0_STAGE_DATA_IN_SENT:
+ ep0_set_stage(EP0_STAGE_DATA_IN_LAST_PACKET_FILLED);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.TXPKTRDY = 1;
+ break;
+ case EP0_STAGE_SETUP_OUT_NO_DATA:
+ ep0_set_stage(EP0_STAGE_STATUS_IN);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.w = (USBHS_EP0_DEVICE_SERVICED_RXPKTRDY | USBHS_EP0_DEVICE_DATAEND);
+ break;
+ case EP0_STAGE_DATA_OUT_COMPLETE:
+ ep0_set_stage(EP0_STAGE_STATUS_IN);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.w = (USBHS_EP0_DEVICE_SERVICED_RXPKTRDY | USBHS_EP0_DEVICE_DATAEND);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (ep0_get_stage())
+ {
+ case EP0_STAGE_SETUP_IN_DATA:
+ ep0_set_stage(EP0_STAGE_DATA_IN);
+ // fall through
+ case EP0_STAGE_DATA_IN:
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.TXPKTRDY = 1;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void epn_fill_tx(xfer_ctl_t * xfer_in, uint8_t epnum)
+{
+ uint16_t left = xfer_in->total_len - xfer_in->transferred;
+ if (left)
+ {
+ xfer_in->last_packet_size = tu_min16(xfer_in->max_packet_size, left);
+ tx_fifo_write(epnum, xfer_in->buffer + xfer_in->transferred, xfer_in->last_packet_size);
+ }
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.TXPKTRDY = 1;
+}
+
+static bool ep0_xfer(xfer_ctl_t * xfer, int dir)
+{
+ if (dir == TUSB_DIR_OUT)
+ {
+ if (xfer->total_len)
+ {
+ switch (_dcd.ep0_stage)
+ {
+ case EP0_STAGE_DATA_OUT_COMPLETE:
+ case EP0_STAGE_SETUP_OUT_DATA:
+ ep0_set_stage(EP0_STAGE_DATA_OUT);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVCRPR = 1;
+ break;
+ default:
+ TU_ASSERT(0);
+ }
+ }
+ else
+ {
+ switch (_dcd.ep0_stage)
+ {
+ case EP0_STAGE_DATA_IN_SENT:
+ ep0_set_stage(EP0_STAGE_NONE);
+ // fall through
+ case EP0_STAGE_NONE:
+ xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else // IN
+ {
+ ep0_fill_tx(xfer);
+ }
+
+ return true;
+}
+
+/*------------------------------------------------------------------*/
+/* DCD Endpoint port
+ *------------------------------------------------------------------*/
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
+{
+ (void) rhport;
+ uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
+ uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+
+ TU_ASSERT(epnum < EP_MAX);
+
+ xfer->max_packet_size = tu_edpt_packet_size(desc_edpt);
+ xfer->fifo_size = xfer->max_packet_size;
+ xfer->ep_addr = desc_edpt->bEndpointAddress;
+
+ if (epnum != 0)
+ {
+ if (dir == TUSB_DIR_OUT)
+ {
+ epn_rx_configure(epnum, xfer->max_packet_size, _dcd.fifo_addr_top, __builtin_ctz(xfer->fifo_size) - 3, desc_edpt->bmAttributes.xfer);
+ _dcd.fifo_addr_top += (xfer->fifo_size + 7) >> 3;
+ }
+ else
+ {
+ epn_tx_configure(epnum, xfer->max_packet_size, _dcd.fifo_addr_top, __builtin_ctz(xfer->fifo_size) - 3, desc_edpt->bmAttributes.xfer);
+ _dcd.fifo_addr_top += (xfer->fifo_size + 7) >> 3;
+ }
+ }
+ return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+
+ // Reserve EP0 FIFO address
+ _dcd.fifo_addr_top = 64 >> 3;
+ for (int i = 1; i < EP_MAX; ++i)
+ {
+ tu_memclr(&_dcd.xfer_status[i], sizeof(_dcd.xfer_status[i]));
+ }
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ (void) ep_addr;
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+ (void) rhport;
+
+ xfer->buffer = buffer;
+ xfer->total_len = total_bytes;
+ xfer->last_packet_size = 0;
+ xfer->transferred = 0;
+
+ if (epnum == 0)
+ {
+ return ep0_xfer(xfer, dir);
+ }
+ if (dir == TUSB_DIR_OUT)
+ {
+ USB_REGS->INTRRXEbits.w |= (1u << epnum);
+ }
+ else // IN
+ {
+ epn_fill_tx(xfer, epnum);
+ }
+
+ return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ (void) rhport;
+
+ if (epnum == 0)
+ {
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SENDSTALL = 1;
+ }
+ else
+ {
+ if (dir == TUSB_DIR_OUT)
+ {
+ USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.SENDSTALL = 1;
+ }
+ else
+ {
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.SENDSTALL = 1;
+ }
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ (void) rhport;
+
+ if (epnum == 0)
+ {
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SENDSTALL = 0;
+ }
+ else
+ {
+ if (dir == TUSB_DIR_OUT)
+ {
+ USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.w &= ~(USBHS_EP_DEVICE_RX_SENT_STALL | USBHS_EP_DEVICE_RX_SEND_STALL);
+ USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.CLRDT = 1;
+ }
+ else
+ {
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.w &= ~(USBHS_EP_DEVICE_TX_SENT_STALL | USBHS_EP_DEVICE_TX_SEND_STALL);
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.CLRDT = 1;
+ }
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* Interrupt Handler
+ *------------------------------------------------------------------*/
+
+static void ep0_handle_rx(void)
+{
+ int transferred;
+ xfer_ctl_t * xfer = XFER_CTL_BASE(0, TUSB_DIR_OUT);
+
+ TU_ASSERT(xfer->buffer,);
+
+ transferred = rx_fifo_read(0, xfer->buffer + xfer->transferred);
+ xfer->transferred += transferred;
+ TU_ASSERT(xfer->transferred <= xfer->total_len,);
+ if (transferred < xfer->max_packet_size || xfer->transferred == xfer->total_len)
+ {
+ ep0_set_stage(EP0_STAGE_DATA_OUT_COMPLETE);
+ xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
+ }
+ else
+ {
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVCRPR = 1;
+ }
+}
+
+static void epn_handle_rx_int(uint8_t epnum)
+{
+ uint8_t ep_status;
+ int transferred;
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
+
+ ep_status = USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.w;
+ if (ep_status & USBHS_EP_DEVICE_RX_SENT_STALL)
+ {
+ USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.w &= ~USBHS_EP_DEVICE_RX_SENT_STALL;
+ }
+
+ if (ep_status & USBHS_EP0_HOST_RXPKTRDY)
+ {
+ TU_ASSERT(xfer->buffer != NULL,);
+
+ transferred = rx_fifo_read(epnum, xfer->buffer + xfer->transferred);
+ USB_REGS->EPCSR[epnum].RXCSRL_HOSTbits.RXPKTRDY = 0;
+ xfer->transferred += transferred;
+ TU_ASSERT(xfer->transferred <= xfer->total_len,);
+ if (transferred < xfer->max_packet_size || xfer->transferred == xfer->total_len)
+ {
+ USB_REGS->INTRRXEbits.w &= ~(1u << epnum);
+ xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
+ }
+ }
+}
+
+static void epn_handle_tx_int(uint8_t epnum)
+{
+ uint8_t ep_status = USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.w;
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
+
+ if (ep_status & USBHS_EP_DEVICE_TX_SENT_STALL)
+ {
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.w &= ~USBHS_EP_DEVICE_TX_SENT_STALL;
+ }
+ else
+ {
+ xfer->transferred += xfer->last_packet_size;
+ TU_ASSERT(xfer->transferred <= xfer->total_len,);
+ if (xfer->last_packet_size < xfer->max_packet_size || xfer->transferred == xfer->total_len)
+ {
+ xfer->last_packet_size = 0;
+ xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
+ }
+ else
+ {
+ epn_fill_tx(xfer, epnum);
+ }
+ }
+}
+
+static void ep0_handle_int(void)
+{
+ __USBHS_CSR0L_DEVICE_t ep0_status;
+ union {
+ tusb_control_request_t request;
+ uint32_t setup_buffer[2];
+ } setup_packet;
+ xfer_ctl_t * xfer_in = XFER_CTL_BASE(0, TUSB_DIR_IN);
+ uint8_t old_index = USB_REGS->INDEXbits.ENDPOINT;
+
+ // Select EP0 registers
+ USB_REGS->INDEXbits.ENDPOINT = 0;
+
+ ep0_status = USB_REGS->EPCSR[0].CSR0L_DEVICEbits;
+
+ if (ep0_status.SENTSTALL)
+ {
+ // Stall was sent. Reset the endpoint 0 state.
+ // Clear the sent stall bit.
+ ep0_set_stage(EP0_STAGE_NONE);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SENTSTALL = 0;
+ }
+
+ if (ep0_status.SETUPEND)
+ {
+ // This means the current control transfer end prematurely. We don't
+ // need to end any transfers. The device layer will manage the
+ // premature transfer end. We clear the SetupEnd bit and reset the
+ // driver control transfer state machine to waiting for next setup
+ // packet from host.
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVSSETEND = 1;
+ ep0_set_stage(EP0_STAGE_NONE);
+ }
+
+ if (ep0_status.RXPKTRDY)
+ {
+ switch (ep0_get_stage())
+ {
+ default:
+ // Data arrived at unexpected state, this must be setup stage packet after all.
+ // Fall through
+ case EP0_STAGE_NONE:
+ // This means we were expecting a SETUP packet and we got one.
+ setup_packet.setup_buffer[0] = USB_REGS->FIFO[0];
+ setup_packet.setup_buffer[1] = USB_REGS->FIFO[0];
+ if (setup_packet.request.bmRequestType_bit.direction == TUSB_DIR_OUT)
+ {
+ // SVCRPR is not set yet, it will be set later when out xfer is started
+ // Till then NAKs will hold incommint data
+ ep0_set_stage(setup_packet.request.wLength == 0 ? EP0_STAGE_SETUP_OUT_NO_DATA : EP0_STAGE_SETUP_OUT_DATA);
+ }
+ else
+ {
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVCRPR = 1;
+ ep0_set_stage(EP0_STAGE_SETUP_IN_DATA);
+ }
+ dcd_event_setup_received(0, &setup_packet.request.bmRequestType, true);
+ break;
+ case EP0_STAGE_DATA_OUT:
+ ep0_handle_rx();
+ break;
+ }
+ }
+ else
+ {
+ switch (ep0_get_stage())
+ {
+ case EP0_STAGE_STATUS_IN:
+ // Status was just sent, this concludes request, notify client
+ ep0_set_stage(EP0_STAGE_NONE);
+ xfer_complete(xfer_in, XFER_RESULT_SUCCESS, true);
+ break;
+ case EP0_STAGE_DATA_IN:
+ // Packet sent, fill more data
+ ep0_fill_tx(xfer_in);
+ break;
+ case EP0_STAGE_DATA_IN_LAST_PACKET_FILLED:
+ ep0_set_stage(EP0_STAGE_DATA_IN_SENT);
+ xfer_complete(xfer_in, XFER_RESULT_SUCCESS, true);
+ break;
+ case EP0_STAGE_ADDRESS_CHANGE:
+ // Status stage after set address request finished, address can be changed
+ USB_REGS->FADDRbits.FUNC = _dcd.dev_addr;
+ ep0_set_stage(EP0_STAGE_NONE);
+ break;
+ default:
+ break;
+ }
+ }
+ // Restore register index
+ USB_REGS->INDEXbits.ENDPOINT = old_index;
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+ int i;
+ uint8_t mask;
+ __USBCSR2bits_t csr2_bits;
+ uint16_t rxints = USB_REGS->INTRRX & USB_REGS->INTRRXEbits.w;
+ uint16_t txints = USB_REGS->INTRTX;
+ csr2_bits = USBCSR2bits;
+ (void) rhport;
+
+ IFS4CLR = _IFS4_USBIF_MASK;
+
+ if (csr2_bits.SOFIF && csr2_bits.SOFIE)
+ {
+ dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+ }
+ if (csr2_bits.RESETIF)
+ {
+ dcd_edpt_open(0, &ep0OUT_desc);
+ dcd_edpt_open(0, &ep0IN_desc);
+ dcd_event_bus_reset(0, USB_REGS->POWERbits.HSMODE ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL, true);
+ }
+ if (csr2_bits.SUSPIF)
+ {
+ dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+ }
+ if (csr2_bits.RESUMEIF)
+ {
+ dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+ }
+ // INTRTX has bit for EP0
+ if (txints & 1)
+ {
+ txints ^= 1;
+ ep0_handle_int();
+ }
+ for (mask = 0x02, i = 1; rxints != 0 && mask != 0; mask <<= 1, ++i)
+ {
+ if (rxints & mask)
+ {
+ rxints ^= mask;
+ epn_handle_rx_int(i);
+ }
+ }
+ for (mask = 0x02, i = 1; txints != 0 && mask != 0; mask <<= 1, ++i)
+ {
+ if (txints & mask)
+ {
+ txints ^= mask;
+ epn_handle_tx_int(i);
+ }
+ }
+}
+
+#endif
diff --git a/src/portable/microchip/pic32mz/usbhs_registers.h b/src/portable/microchip/pic32mz/usbhs_registers.h
new file mode 100644
index 000000000..757e3f083
--- /dev/null
+++ b/src/portable/microchip/pic32mz/usbhs_registers.h
@@ -0,0 +1,931 @@
+/*******************************************************************************
+* Copyright (C) 2019 Microchip Technology Inc. and its subsidiaries.
+*
+* Subject to your compliance with these terms, you may use Microchip software
+* and any derivatives exclusively with Microchip products. It is your
+* responsibility to comply with third party license terms applicable to your
+* use of third party software (including open source software) that may
+* accompany Microchip software.
+*
+* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
+* EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
+* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
+* PARTICULAR PURPOSE.
+*
+* IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
+* INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
+* WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
+* BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
+* FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
+* ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+*******************************************************************************/
+/*******************************************************************************
+ USBHS Peripheral Library Register Defintions
+
+ File Name:
+ usbhs_registers.h
+
+ Summary:
+ USBHS PLIB Register Defintions
+
+ Description:
+ This file contains the constants and defintions which are required by the
+ the USBHS library.
+*******************************************************************************/
+
+#ifndef __USBHS_REGISTERS_H__
+#define __USBHS_REGISTERS_H__
+
+#include <p32xxxx.h>
+#include <stdint.h>
+
+/*****************************************
+ * Module Register Offsets.
+ *****************************************/
+
+#define USBHS_REG_FADDR 0x000
+#define USBHS_REG_POWER 0x001
+#define USBHS_REG_INTRTX 0x002
+#define USBHS_REG_INTRRX 0x004
+#define USBHS_REG_INTRTXE 0x006
+#define USBHS_REG_INTRRXE 0x008
+#define USBHS_REG_INTRUSB 0x00A
+#define USBHS_REG_INTRUSBE 0x00B
+#define USBHS_REG_FRAME 0x00C
+#define USBHS_REG_INDEX 0x00E
+#define USBHS_REG_TESTMODE 0x00F
+
+/*******************************************************
+ * Endpoint Control Status Registers (CSR). These values
+ * should be added to either the 0x10 to access the
+ * register through Indexed CSR. To access the actual
+ * CSR, see ahead in this header file.
+ ******************************************************/
+
+#define USBHS_REG_EP_TXMAXP 0x000
+#define USBHS_REG_EP_CSR0L 0x002
+#define USBHS_REG_EP_CSR0H 0x003
+#define USBHS_REG_EP_TXCSRL 0x002
+#define USBHS_REG_EP_TXCSRH 0x003
+#define USBHS_REG_EP_RXMAXP 0x004
+#define USBHS_REG_EP_RXCSRL 0x006
+#define USBHS_REG_EP_RXCSRH 0x007
+#define USBHS_REG_EP_COUNT0 0x008
+#define USBHS_REG_EP_RXCOUNT 0x008
+#define USBHS_REG_EP_TYPE0 0x01A
+#define USBHS_REG_EP_TXTYPE 0x01A
+#define USBHS_REG_EP_NAKLIMIT0 0x01B
+#define USBHS_REG_EP_TXINTERVAL 0x01B
+#define USBHS_REG_EP_RXTYPE 0x01C
+#define USBHS_REG_EP_RXINTERVAL 0x01D
+#define USBHS_REG_EP_CONFIGDATA 0x01F
+#define USBHS_REG_EP_FIFOSIZE 0x01F
+
+#define USBHS_HOST_EP0_SETUPKT_SET 0x8
+#define USBHS_HOST_EP0_TXPKTRDY_SET 0x2
+#define USBHS_SOFT_RST_NRST_SET 0x1
+#define USBHS_SOFT_RST_NRSTX_SET 0x2
+#define USBHS_EP0_DEVICE_SERVICED_RXPKTRDY 0x40
+#define USBHS_EP0_DEVICE_DATAEND 0x08
+#define USBHS_EP0_DEVICE_TXPKTRDY 0x02
+#define USBHS_EP0_HOST_STATUS_STAGE_START 0x40
+#define USBHS_EP0_HOST_REQPKT 0x20
+#define USBHS_EP0_HOST_TXPKTRDY 0x02
+#define USBHS_EP0_HOST_RXPKTRDY 0x01
+#define USBHS_EP_DEVICE_TX_SENT_STALL 0x20
+#define USBHS_EP_DEVICE_TX_SEND_STALL 0x10
+#define USBHS_EP_DEVICE_RX_SENT_STALL 0x40
+#define USBHS_EP_DEVICE_RX_SEND_STALL 0x20
+
+/* FADDR - Device Function Address */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned FUNC:7;
+ unsigned :1;
+ };
+
+ uint8_t w;
+
+} __USBHS_FADDR_t;
+
+/* POWER - Control Resume and Suspend signalling */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned SUSPEN:1;
+ unsigned SUSPMODE:1;
+ unsigned RESUME:1;
+ unsigned RESET:1;
+ unsigned HSMODE:1;
+ unsigned HSEN:1;
+ unsigned SOFTCONN:1;
+ unsigned ISOUPD:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_POWER_t;
+
+/* INTRTXE - Transmit endpoint interrupt enable */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned EP0IE:1;
+ unsigned EP1TXIE:1;
+ unsigned EP2TXIE:1;
+ unsigned EP3TXIE:1;
+ unsigned EP4TXIE:1;
+ unsigned EP5TXIE:1;
+ unsigned EP6TXIE:1;
+ unsigned EP7TXIE:1;
+ unsigned :8;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_INTRTXE_t;
+
+/* INTRRXE - Receive endpoint interrupt enable */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned :1;
+ unsigned EP1RXIE:1;
+ unsigned EP2RXIE:1;
+ unsigned EP3RXIE:1;
+ unsigned EP4RXIE:1;
+ unsigned EP5RXIE:1;
+ unsigned EP6RXIE:1;
+ unsigned EP7RXIE:1;
+ unsigned :8;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_INTRRXE_t;
+
+/* INTRUSBE - General USB Interrupt enable */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned SUSPIE:1;
+ unsigned RESUMEIE:1;
+ unsigned RESETIE:1;
+ unsigned SOFIE:1;
+ unsigned CONNIE:1;
+ unsigned DISCONIE:1;
+ unsigned SESSRQIE:1;
+ unsigned VBUSERRIE:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_INTRUSBE_t;
+
+/* FRAME - Frame number */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RFRMNUM:11;
+ unsigned :5;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_FRAME_t;
+
+/* INDEX - Endpoint index */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned ENDPOINT:4;
+ unsigned :4;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_INDEX_t;
+
+/* TESTMODE - Test mode register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned NAK:1;
+ unsigned TESTJ:1;
+ unsigned TESTK:1;
+ unsigned PACKET:1;
+ unsigned FORCEHS:1;
+ unsigned FORCEFS:1;
+ unsigned FIFOACC:1;
+ unsigned FORCEHST:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TESTMODE_t;
+
+/* COUNT0 - Indicates the amount of data received in endpoint 0 */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXCNT:7;
+ unsigned :1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_COUNT0_t;
+
+/* TYPE0 - Operating speed of target device */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned :6;
+ unsigned SPEED:2;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TYPE0_t;
+
+/* DEVCTL - Module control register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned SESSION:1;
+ unsigned HOSTREQ:1;
+ unsigned HOSTMODE:1;
+ unsigned VBUS:2;
+ unsigned LSDEV:1;
+ unsigned FSDEV:1;
+ unsigned BDEV:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_DEVCTL_t;
+
+/* CSR0L Device - Endpoint Device Mode Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXPKTRDY:1;
+ unsigned TXPKTRDY:1;
+ unsigned SENTSTALL:1;
+ unsigned DATAEND:1;
+ unsigned SETUPEND:1;
+ unsigned SENDSTALL:1;
+ unsigned SVCRPR:1;
+ unsigned SVSSETEND:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_CSR0L_DEVICE_t;
+
+/* CSR0L Host - Endpoint Host Mode Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXPKTRDY:1;
+ unsigned TXPKTRDY:1;
+ unsigned RXSTALL:1;
+ unsigned SETUPPKT:1;
+ unsigned ERROR:1;
+ unsigned REQPKT:1;
+ unsigned STATPKT:1;
+ unsigned NAKTMOUT:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_CSR0L_HOST_t;
+
+/* TXCSRL Device - Endpoint Transmit Control Status Register Low */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXPKTRDY:1;
+ unsigned FIFOONE:1;
+ unsigned UNDERRUN:1;
+ unsigned FLUSH:1;
+ unsigned SENDSTALL:1;
+ unsigned SENTSTALL:1;
+ unsigned CLRDT:1;
+ unsigned INCOMPTX:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXCSRL_DEVICE_t;
+
+/* TXCSRL Host - Endpoint Transmit Control Status Register Low */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXPKTRDY:1;
+ unsigned FIFONE:1;
+ unsigned ERROR:1;
+ unsigned FLUSH:1;
+ unsigned SETUPPKT:1;
+ unsigned RXSTALL:1;
+ unsigned CLRDT:1;
+ unsigned INCOMPTX:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXCSRL_HOST_t;
+
+/* TXCSRH Device - Endpoint Transmit Control Status Register High */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned :2;
+ unsigned DMAREQMD:1;
+ unsigned FRCDATTG:1;
+ unsigned DMAREQENL:1;
+ unsigned MODE:1;
+ unsigned ISO:1;
+ unsigned AUTOSET:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXCSRH_DEVICE_t;
+
+/* TXCSRH Host - Endpoint Transmit Control Status Register High */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned DATATGGL:1;
+ unsigned DTWREN:1;
+ unsigned DMAREQMD:1;
+ unsigned FRCDATTG:1;
+ unsigned DMAREQEN:1;
+ unsigned MODE:1;
+ unsigned :1;
+ unsigned AUOTSET:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXCSRH_HOST_t;
+
+/* CSR0H Device - Endpoint 0 Control Status Register High */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned FLSHFIFO:1;
+ unsigned :7;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_CSR0H_DEVICE_t;
+
+/* CSR0H Host - Endpoint 0 Control Status Register High */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned FLSHFIFO:1;
+ unsigned DATATGGL:1;
+ unsigned DTWREN:1;
+ unsigned DISPING:1;
+ unsigned :4;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_CSR0H_HOST_t;
+
+/* RXMAXP - Receive Endpoint Max packet size. */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXMAXP:11;
+ unsigned MULT:5;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_RXMAXP_t;
+
+/* RXCSRL Device - Receive endpoint Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXPKTRDY:1;
+ unsigned FIFOFULL:1;
+ unsigned OVERRUN:1;
+ unsigned DATAERR:1;
+ unsigned FLUSH:1;
+ unsigned SENDSTALL:1;
+ unsigned SENTSTALL:1;
+ unsigned CLRDT:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXCSRL_DEVICE_t;
+
+/* RXCSRL Host - Receive endpoint Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXPKTRDY:1;
+ unsigned FIFOFULL:1;
+ unsigned ERROR:1;
+ unsigned DERRNAKT:1;
+ unsigned FLUSH:1;
+ unsigned REQPKT:1;
+ unsigned RXSTALL:1;
+ unsigned CLRDT:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXCSRL_HOST_t;
+
+/* RXCSRH Device - Receive endpoint Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned INCOMPRX:1;
+ unsigned :2;
+ unsigned DMAREQMODE:1;
+ unsigned DISNYET:1;
+ unsigned DMAREQEN:1;
+ unsigned ISO:1;
+ unsigned AUTOCLR:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXCSRH_DEVICE_t;
+
+/* RXCSRH Host - Receive endpoint Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned INCOMPRX:1;
+ unsigned DATATGGL:1;
+ unsigned DATATWEN:1;
+ unsigned DMAREQMD:1;
+ unsigned PIDERR:1;
+ unsigned DMAREQEN:1;
+ unsigned AUTORQ:1;
+ unsigned AUOTCLR:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXCSRH_HOST_t;
+
+/* RXCOUNT - Amount of data pending in RX FIFO */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXCNT:14;
+ unsigned :2;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_RXCOUNT_t;
+
+/* TXTYPE - Specifies the target transmit endpoint */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TEP:4;
+ unsigned PROTOCOL:2;
+ unsigned SPEED:2;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXTYPE_t;
+
+/* RXTYPE - Specifies the target receive endpoint */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TEP:4;
+ unsigned PROTOCOL:2;
+ unsigned SPEED:2;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXTYPE_t;
+
+/* TXINTERVAL - Defines the polling interval */
+typedef struct
+{
+ uint8_t TXINTERV;
+
+} __USBHS_TXINTERVAL_t;
+
+/* RXINTERVAL - Defines the polling interval */
+typedef struct
+{
+ uint8_t RXINTERV;
+
+} __USBHS_RXINTERVAL_t;
+
+/* TXMAXP - Maximum amount of data that can be transferred through a TX endpoint
+ * */
+
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXMAXP:11;
+ unsigned MULT:5;
+ };
+ uint16_t w;
+
+} __USBHS_TXMAXP_t;
+
+/* TXFIFOSZ - Size of the transmit endpoint FIFO */
+typedef struct __attribute__((packed))
+{
+ unsigned TXFIFOSZ:4;
+ unsigned TXDPB:1;
+ unsigned :3;
+
+} __USBHS_TXFIFOSZ_t;
+
+/* RXFIFOSZ - Size of the receive endpoint FIFO */
+typedef struct __attribute__((packed))
+{
+ unsigned RXFIFOSZ:4;
+ unsigned RXDPB:1;
+ unsigned :3;
+
+} __USBHS_RXFIFOSZ_t;
+
+/* TXFIFOADD - Start address of the transmit endpoint FIFO */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXFIFOAD:13;
+ unsigned :3;
+ };
+ uint16_t w;
+
+} __USBHS_TXFIFOADD_t;
+
+/* RXFIFOADD - Start address of the receive endpoint FIFO */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXFIFOAD:13;
+ unsigned :3;
+ };
+ uint16_t w;
+
+} __USBHS_RXFIFOADD_t;
+
+/* SOFTRST - Asserts NRSTO and NRSTOX */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned NRST:1;
+ unsigned NRSTX:1;
+ unsigned :6;
+ };
+ uint8_t w;
+
+} __USBHS_SOFTRST_t;
+
+/* TXFUNCADDR - Target address of transmit endpoint */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXFADDR:7;
+ unsigned :1;
+ };
+ uint8_t w;
+
+} __USBHS_TXFUNCADDR_t;
+
+/* RXFUNCADDR - Target address of receive endpoint */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXFADDR:7;
+ unsigned :1;
+ };
+ uint8_t w;
+
+} __USBHS_RXFUNCADDR_t;
+
+/* TXHUBADDR - Address of the hub to which the target transmit device endpoint
+ * is connected */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXHUBADDR:7;
+ unsigned MULTTRAN:1;
+ };
+ uint8_t w;
+
+} __USBHS_TXHUBADDR_t;
+
+/* RXHUBADDR - Address of the hub to which the target receive device endpoint is
+ * connected */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXHUBADDR:7;
+ unsigned MULTTRAN:1;
+ };
+ uint8_t w;
+
+} __USBHS_RXHUBADDR_t;
+
+/* TXHUBPORT - Address of the hub to which the target transmit device endpoint
+ * is connected. */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXHUBPRT:7;
+ unsigned :1;
+ };
+
+ uint8_t w;
+
+} __USBHS_TXHUBPORT_t;
+
+/* RXHUBPORT - Address of the hub to which the target receive device endpoint
+ * is connected. */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXHUBPRT:7;
+ unsigned :1;
+ };
+
+ uint8_t w;
+
+} __USBHS_RXHUBPORT_t;
+
+/* DMACONTROL - Configures a DMA channel */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned DMAEN:1;
+ unsigned DMADIR:1;
+ unsigned DMAMODE:1;
+ unsigned DMAIE:1;
+ unsigned DMAEP:4;
+ unsigned DMAERR:1;
+ unsigned DMABRSTM:2;
+ unsigned:21;
+ };
+
+ uint32_t w;
+
+} __USBHS_DMACNTL_t;
+
+/* Endpoint Control and Status Register Set */
+typedef struct __attribute__((packed))
+{
+ volatile __USBHS_TXMAXP_t TXMAXPbits;
+ union
+ {
+ struct
+ {
+ union
+ {
+ volatile __USBHS_CSR0L_DEVICE_t CSR0L_DEVICEbits;
+ volatile __USBHS_CSR0L_HOST_t CSR0L_HOSTbits;
+ };
+ union
+ {
+ volatile __USBHS_CSR0H_DEVICE_t CSR0H_DEVICEbits;
+ volatile __USBHS_CSR0H_HOST_t CSR0H_HOSTbits;
+ };
+ };
+
+ struct
+ {
+ union
+ {
+ volatile __USBHS_TXCSRL_DEVICE_t TXCSRL_DEVICEbits;
+ volatile __USBHS_TXCSRL_HOST_t TXCSRL_HOSTbits;
+ };
+
+ union
+ {
+ volatile __USBHS_TXCSRH_DEVICE_t TXCSRH_DEVICEbits;
+ volatile __USBHS_TXCSRH_HOST_t TXCSRH_HOSTbits;
+ };
+ };
+ };
+
+ volatile __USBHS_RXMAXP_t RXMAXPbits;
+
+ union
+ {
+ volatile __USBHS_RXCSRL_DEVICE_t RXCSRL_DEVICEbits;
+ volatile __USBHS_RXCSRL_HOST_t RXCSRL_HOSTbits;
+ };
+
+ union
+ {
+ volatile __USBHS_RXCSRH_DEVICE_t RXCSRH_DEVICEbits;
+ volatile __USBHS_RXCSRH_HOST_t RXCSRH_HOSTbits;
+ };
+
+ union
+ {
+ volatile __USBHS_COUNT0_t COUNT0bits;
+ volatile __USBHS_RXCOUNT_t RXCOUNTbits;
+ };
+
+ union
+ {
+ volatile __USBHS_TYPE0_t TYPE0bits;
+ volatile __USBHS_TXTYPE_t TXTYPEbits;
+ };
+
+ union
+ {
+ volatile uint8_t NAKLIMIT0;
+ volatile __USBHS_TXINTERVAL_t TXINTERVALbits;
+ };
+
+ volatile __USBHS_RXTYPE_t RXTYPEbits;
+ volatile __USBHS_RXINTERVAL_t RXINTERVALbits;
+ unsigned :8;
+ union
+ {
+ volatile uint8_t CONFIGDATA;
+ volatile uint8_t FIFOSIZE;
+ };
+
+} __USBHS_EPCSR_t;
+
+/* Set of registers that configure the multi-point option */
+typedef struct __attribute__((packed))
+{
+ volatile __USBHS_TXFUNCADDR_t TXFUNCADDRbits;
+ unsigned :8;
+ volatile __USBHS_TXHUBADDR_t TXHUBADDRbits;
+ volatile __USBHS_TXHUBPORT_t TXHUBPORTbits;
+ volatile __USBHS_RXFUNCADDR_t RXFUNCADDRbits;
+ unsigned :8;
+ volatile __USBHS_RXHUBADDR_t RXHUBADDRbits;
+ volatile __USBHS_RXHUBPORT_t RXHUBPORTbits;
+
+} __USBHS_TARGET_ADDR_t;
+
+/* Set of registers that configure the DMA channel */
+typedef struct __attribute__((packed))
+{
+ volatile __USBHS_DMACNTL_t DMACNTLbits;
+ volatile uint32_t DMAADDR;
+ volatile uint32_t DMACOUNT;
+ volatile uint32_t pad;
+} __USBHS_DMA_CHANNEL_t;
+
+/* USBHS module register set */
+typedef struct __attribute__((aligned(4),packed))
+{
+ volatile __USBHS_FADDR_t FADDRbits;
+ volatile __USBHS_POWER_t POWERbits;
+ volatile uint16_t INTRTX;
+ volatile uint16_t INTRRX;
+ volatile __USBHS_INTRTXE_t INTRTXEbits;
+ volatile __USBHS_INTRRXE_t INTRRXEbits;
+ volatile uint8_t INTRUSB;
+ volatile __USBHS_INTRUSBE_t INTRUSBEbits;
+ volatile __USBHS_FRAME_t FRAMEbits;
+ volatile __USBHS_INDEX_t INDEXbits;
+ volatile __USBHS_TESTMODE_t TESTMODEbits;
+ volatile __USBHS_EPCSR_t INDEXED_EPCSR;
+ volatile uint32_t FIFO[16];
+ volatile __USBHS_DEVCTL_t DEVCTLbits;
+ volatile uint8_t MISC;
+ volatile __USBHS_TXFIFOSZ_t TXFIFOSZbits;
+ volatile __USBHS_RXFIFOSZ_t RXFIFOSZbits;
+
+ volatile __USBHS_TXFIFOADD_t TXFIFOADDbits;
+ volatile __USBHS_RXFIFOADD_t RXFIFOADDbits;
+
+ volatile uint32_t VCONTROL;
+ volatile uint16_t HWVERS;
+ volatile uint8_t padding1[10];
+ volatile uint8_t EPINFO;
+ volatile uint8_t RAMINFO;
+ volatile uint8_t LINKINFO;
+ volatile uint8_t VPLEN;
+ volatile uint8_t HS_EOF1;
+ volatile uint8_t FS_EOF1;
+ volatile uint8_t LS_EOF1;
+
+ volatile __USBHS_SOFTRST_t SOFTRSTbits;
+
+ volatile __USBHS_TARGET_ADDR_t TADDR[16];
+ volatile __USBHS_EPCSR_t EPCSR[16];
+ volatile uint32_t DMA_INTR;
+ volatile __USBHS_DMA_CHANNEL_t DMA_CHANNEL[8];
+ volatile uint32_t RQPKTXOUNT[16];
+
+} usbhs_registers_t;
+
+#endif
diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c
index 46aabc5aa..976d3dfd0 100644
--- a/src/portable/microchip/samd/dcd_samd.c
+++ b/src/portable/microchip/samd/dcd_samd.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && \
+#if CFG_TUD_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \
CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAME5X || \
CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21)
@@ -180,6 +180,14 @@ void dcd_connect(uint8_t rhport)
USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
@@ -214,14 +222,14 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
UsbDeviceDescBank* bank = &sram_registers[epnum][dir];
uint32_t size_value = 0;
while (size_value < 7) {
- if (1 << (size_value + 3) == tu_edpt_packet_size(desc_edpt)) {
+ if (1 << (size_value + 3) >= tu_edpt_packet_size(desc_edpt)) {
break;
}
size_value++;
}
// unsupported endpoint size
- if ( size_value == 7 && tu_edpt_packet_size(desc_edpt) != 1023 ) return false;
+ if ( size_value == 7 && tu_edpt_packet_size(desc_edpt) > 1023 ) return false;
bank->PCKSIZE.bit.SIZE = size_value;
@@ -242,6 +250,13 @@ 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 if necessary?
+}
+
void dcd_edpt_close_all (uint8_t rhport)
{
(void) rhport;
@@ -271,14 +286,14 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
{
bank->PCKSIZE.bit.MULTI_PACKET_SIZE = total_bytes;
bank->PCKSIZE.bit.BYTE_COUNT = 0;
- ep->EPSTATUSCLR.reg |= USB_DEVICE_EPSTATUSCLR_BK0RDY;
- ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL0;
+ ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY;
+ ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRFAIL0;
} else
{
bank->PCKSIZE.bit.MULTI_PACKET_SIZE = 0;
bank->PCKSIZE.bit.BYTE_COUNT = total_bytes;
- ep->EPSTATUSSET.reg |= USB_DEVICE_EPSTATUSSET_BK1RDY;
- ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL1;
+ ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK1RDY;
+ ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRFAIL1;
}
return true;
diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c
index 2e9854153..814e680fb 100644
--- a/src/portable/microchip/samg/dcd_samg.c
+++ b/src/portable/microchip/samg/dcd_samg.c
@@ -210,6 +210,14 @@ void dcd_disconnect(uint8_t rhport)
UDP->UDP_TXVC = UDP_TXVC_TXVDIS_Msk;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
diff --git a/src/portable/microchip/samx7x/dcd_samx7x.c b/src/portable/microchip/samx7x/dcd_samx7x.c
index 9e3b43840..7507c0f69 100644
--- a/src/portable/microchip/samx7x/dcd_samx7x.c
+++ b/src/portable/microchip/samx7x/dcd_samx7x.c
@@ -27,7 +27,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMX7X
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMX7X
#include "device/dcd.h"
#include "sam.h"
@@ -191,6 +191,14 @@ void dcd_disconnect(uint8_t rhport)
USB_REG->DEVCTRL &=~(DEVCTRL_ADDEN | DEVCTRL_UADD);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
static tusb_speed_t get_speed(void)
{
switch (USB_REG->SR & SR_SPEED) {
diff --git a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
index a3b69b987..39b09db68 100644
--- a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
+++ b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MM32F327X )
+#if CFG_TUD_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MM32F327X )
#include "reg_usb_otg_fs.h"
#include "mm32_device.h"
@@ -305,6 +305,14 @@ void dcd_disconnect(uint8_t rhport)
USB_OTG_FS->CTL = 0;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 9d7db11b2..ca37d799f 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -26,8 +26,9 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_NRF5X
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_NRF5X
+#include <stdatomic.h>
#include "nrf.h"
#include "nrf_clock.h"
#include "nrf_power.h"
@@ -38,6 +39,10 @@
#include "device/usbd.h"
#include "device/usbd_pvt.h" // to use defer function helper
+#if CFG_TUSB_OS == OPT_OS_MYNEWT
+#include "mcu/mcu.h"
+#endif
+
/*------------------------------------------------------------------*/
/* MACRO TYPEDEF CONSTANT ENUM
*------------------------------------------------------------------*/
@@ -63,11 +68,12 @@ typedef struct
uint8_t* buffer;
uint16_t total_len;
volatile uint16_t actual_len;
- uint16_t mps; // max packet size
+ uint16_t mps; // max packet size
// nRF will auto accept OUT packet after DMA is done
// indicate packet is already ACK
volatile bool data_received;
+ volatile bool started;
// Set to true when data was transferred from RAM to ISO IN output buffer.
// New data can be put in ISO IN output buffer after SOF.
@@ -82,11 +88,8 @@ static struct
// +1 for ISO endpoints
xfer_td_t xfer[EP_CBI_COUNT + 1][2];
- // Number of pending DMA that is started but not handled yet by dcd_int_handler().
- // Since nRF can only carry one DMA can run at a time, this value is normally be either 0 or 1.
- // However, in critical section with interrupt disabled, the DMA can be finished and added up
- // until handled by dcd_int_handler() when exiting critical section.
- volatile uint8_t dma_pending;
+ // nRF can only carry one DMA at a time, this is used to guard the access to EasyDMA
+ atomic_bool dma_running;
}_dcd;
/*------------------------------------------------------------------*/
@@ -115,67 +118,36 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
}
// helper to start DMA
-// TODO use Cortex M4 LDREX and STREX command (atomic) to have better mutex access to EasyDMA
-// since current implementation does not 100% guarded against race condition
-static void edpt_dma_start(volatile uint32_t* reg_startep)
+static void start_dma(volatile uint32_t* reg_startep)
{
- // Only one dma can be active
- if ( _dcd.dma_pending )
- {
- if (is_in_isr())
- {
- // Called within ISR, use usbd task to defer later
- usbd_defer_func((osal_task_func_t) edpt_dma_start, (void*) (uintptr_t) reg_startep, true);
- return;
- }
- else
- {
- if ( __get_PRIMASK() || !NVIC_GetEnableIRQ(USBD_IRQn) )
- {
- // Called in critical section with interrupt disabled. We have to manually check
- // for the DMA complete by comparing current pending DMA with number of ENDED Events
- uint32_t ended = 0;
-
- while ( _dcd.dma_pending > ((uint8_t) ended) )
- {
- ended = NRF_USBD->EVENTS_ENDISOIN + NRF_USBD->EVENTS_ENDISOOUT;
-
- for (uint8_t i=0; i<EP_CBI_COUNT; i++)
- {
- ended += NRF_USBD->EVENTS_ENDEPIN[i] + NRF_USBD->EVENTS_ENDEPOUT[i];
- }
- }
- }else
- {
- // Called in non-critical thread-mode, should be 99% of the time.
- // Should be safe to blocking wait until previous DMA transfer complete
- while ( _dcd.dma_pending ) { }
- }
- }
- }
-
- _dcd.dma_pending++;
-
(*reg_startep) = 1;
__ISB(); __DSB();
+
+ // TASKS_EP0STATUS, TASKS_EP0RCVOUT seem to need EasyDMA to be available
+ // However these don't trigger any DMA transfer and got ENDED event subsequently
+ // Therefore dma_pending is corrected right away
+ if ( (reg_startep == &NRF_USBD->TASKS_EP0STATUS) || (reg_startep == &NRF_USBD->TASKS_EP0RCVOUT) )
+ {
+ atomic_flag_clear(&_dcd.dma_running);
+ }
}
-// DMA is complete
-static void edpt_dma_end(void)
+static void edpt_dma_start(volatile uint32_t* reg_startep)
{
- TU_ASSERT(_dcd.dma_pending, );
- _dcd.dma_pending = 0;
+ if ( atomic_flag_test_and_set(&_dcd.dma_running) )
+ {
+ usbd_defer_func((osal_task_func_t) edpt_dma_start, (void*) (uintptr_t) reg_startep, true);
+ }else
+ {
+ start_dma(reg_startep);
+ }
}
-// helper to set TASKS_EP0STATUS / TASKS_EP0RCVOUT since they also need EasyDMA
-// However TASKS_EP0STATUS doesn't trigger any DMA transfer and got ENDED event subsequently
-// Therefore dma_running state will be corrected right away
-void start_ep0_task(volatile uint32_t* reg_task)
+// DMA is complete
+static void edpt_dma_end(void)
{
- edpt_dma_start(reg_task);
-
- // correct the dma_running++ in dma start
- if (_dcd.dma_pending) _dcd.dma_pending--;
+ TU_ASSERT(_dcd.dma_running, );
+ atomic_flag_clear(&_dcd.dma_running);
}
// helper getting td
@@ -184,24 +156,42 @@ static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir)
return &_dcd.xfer[epnum][dir];
}
+static void xact_out_dma(uint8_t epnum);
+// Function wraps xact_out_dma which wants uint8_t while usbd_defer_func wants void (*)(void *)
+static void xact_out_dma_wrapper(void *epnum)
+{
+ xact_out_dma((uint8_t)((uintptr_t)epnum));
+}
+
// Start DMA to move data from Endpoint -> RAM
static void xact_out_dma(uint8_t epnum)
{
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
uint32_t xact_len;
+ // DMA can't be active during read of SIZE.EPOUT or SIZE.ISOOUT, so try to lock,
+ // If already running deffer call regardless if it was called from ISR or task,
+ if ( atomic_flag_test_and_set(&_dcd.dma_running) )
+ {
+ usbd_defer_func((osal_task_func_t)xact_out_dma_wrapper, (void *)(uint32_t)epnum, is_in_isr());
+ return;
+ }
if (epnum == EP_ISO_NUM)
{
xact_len = NRF_USBD->SIZE.ISOOUT;
// If ZERO bit is set, ignore ISOOUT length
- if (xact_len & USBD_SIZE_ISOOUT_ZERO_Msk) xact_len = 0;
+ if (xact_len & USBD_SIZE_ISOOUT_ZERO_Msk)
+ {
+ xact_len = 0;
+ atomic_flag_clear(&_dcd.dma_running);
+ }
else
{
// Trigger DMA move data from Endpoint -> SRAM
NRF_USBD->ISOOUT.PTR = (uint32_t) xfer->buffer;
NRF_USBD->ISOOUT.MAXCNT = xact_len;
- edpt_dma_start(&NRF_USBD->TASKS_STARTISOOUT);
+ start_dma(&NRF_USBD->TASKS_STARTISOOUT);
}
}
else
@@ -213,11 +203,8 @@ static void xact_out_dma(uint8_t epnum)
NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
- edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
+ start_dma(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
}
-
- xfer->buffer += xact_len;
- xfer->actual_len += xact_len;
}
// Prepare for a CBI transaction IN, call at the start
@@ -232,8 +219,6 @@ static void xact_in_dma(uint8_t epnum)
NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer;
NRF_USBD->EPIN[epnum].MAXCNT = xact_len;
- xfer->buffer += xact_len;
-
edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]);
}
@@ -242,6 +227,7 @@ static void xact_in_dma(uint8_t epnum)
//--------------------------------------------------------------------+
void dcd_init (uint8_t rhport)
{
+ TU_LOG1("dcd init\r\n");
(void) rhport;
}
@@ -300,6 +286,14 @@ void dcd_connect(uint8_t rhport)
NRF_USBD->USBPULLUP = 1;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -444,6 +438,7 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
// When both ISO endpoint are close there is no need for SOF any more.
if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps + _dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps == 0) NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
}
+ _dcd.xfer[epnum][dir].started = false;
__ISB(); __DSB();
}
@@ -456,6 +451,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
xfer_td_t* xfer = get_td(epnum, dir);
+ TU_ASSERT(!xfer->started);
xfer->buffer = buffer;
xfer->total_len = total_bytes;
xfer->actual_len = 0;
@@ -466,20 +462,27 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
if ( control_status )
{
// Status Phase also requires EasyDMA has to be available as well !!!!
- start_ep0_task(&NRF_USBD->TASKS_EP0STATUS);
+ 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());
}
else if ( dir == TUSB_DIR_OUT )
{
+ xfer->started = true;
if ( epnum == 0 )
{
// Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
- start_ep0_task(&NRF_USBD->TASKS_EP0RCVOUT);
+ edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
}else
{
- if ( xfer->data_received )
+ // started just set, it could start DMA transfer if interrupt was trigger after this line
+ // code only needs to start transfer (from Endpoint to RAM) when data_received was set
+ // before started was set. If started is NOT set but data_received is, it means that
+ // current transfer was already finished and next data is already present in endpoint and
+ // can be consumed by future transfer
+ __ISB(); __DSB();
+ if ( xfer->data_received && xfer->started )
{
// Data is already received previously
// start DMA to copy to SRAM
@@ -522,7 +525,6 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
// There maybe data in endpoint fifo already, we need to pull it out
if ( (dir == TUSB_DIR_OUT) && xfer->data_received )
{
- TU_LOG_LOCATION();
xfer->data_received = false;
xact_out_dma(epnum);
}
@@ -717,7 +719,8 @@ void dcd_int_handler(uint8_t rhport)
if ( int_status & EDPT_END_ALL_MASK )
{
- // DMA complete move data from SRAM -> Endpoint
+ // DMA complete move data from SRAM <-> Endpoint
+ // Must before endpoint transfer handling
edpt_dma_end();
}
@@ -732,7 +735,7 @@ void dcd_int_handler(uint8_t rhport)
* - Host -> Endpoint
* EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPOUT[i]
* to start DMA. For Bulk/Interrupt, this step can occur automatically (without sw),
- * which means data may or may not be ready (data_received flag).
+ * which means data may or may not be ready (out_received flag).
* - Endpoint -> RAM
* ENDEPOUT[i] interrupted, transaction complete, sw prepare next transaction
*
@@ -762,7 +765,10 @@ void dcd_int_handler(uint8_t rhport)
if ( tu_bit_test(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum))
{
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
- uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
+ uint16_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
+
+ xfer->buffer += xact_len;
+ xfer->actual_len += xact_len;
// Transfer complete if transaction len < Max Packet Size or total len is transferred
if ( (epnum != EP_ISO_NUM) && (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) )
@@ -770,14 +776,7 @@ void dcd_int_handler(uint8_t rhport)
if ( epnum == 0 )
{
// Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
- if ( _dcd.dma_pending )
- {
- // use usbd task to defer later
- usbd_defer_func((osal_task_func_t) start_ep0_task, (void*) (uintptr_t) &NRF_USBD->TASKS_EP0RCVOUT, true);
- }else
- {
- start_ep0_task(&NRF_USBD->TASKS_EP0RCVOUT);
- }
+ edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
}else
{
// nRF auto accept next Bulk/Interrupt OUT packet
@@ -785,7 +784,9 @@ void dcd_int_handler(uint8_t rhport)
}
}else
{
+ TU_ASSERT(xfer->started,);
xfer->total_len = xfer->actual_len;
+ xfer->started = false;
// CBI OUT complete
dcd_event_xfer_complete(0, epnum, xfer->actual_len, XFER_RESULT_SUCCESS, true);
@@ -814,8 +815,10 @@ void dcd_int_handler(uint8_t rhport)
if ( tu_bit_test(data_status, epnum) || (epnum == 0 && is_control_in) )
{
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
+ uint8_t const xact_len = NRF_USBD->EPIN[epnum].AMOUNT;
- xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT;
+ xfer->buffer += xact_len;
+ xfer->actual_len += xact_len;
if ( xfer->actual_len < xfer->total_len )
{
@@ -836,7 +839,7 @@ void dcd_int_handler(uint8_t rhport)
{
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
- if (xfer->actual_len < xfer->total_len)
+ if ( xfer->started && xfer->actual_len < xfer->total_len )
{
xact_out_dma(epnum);
}else
@@ -896,6 +899,11 @@ static bool hfclk_running(void)
static void hfclk_enable(void)
{
+#if CFG_TUSB_OS == OPT_OS_MYNEWT
+ usb_clock_request();
+ return;
+#else
+
// already running, nothing to do
if ( hfclk_running() ) return;
@@ -909,10 +917,16 @@ static void hfclk_enable(void)
nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
+#endif
}
static void hfclk_disable(void)
{
+#if CFG_TUSB_OS == OPT_OS_MYNEWT
+ usb_clock_release();
+ return;
+#else
+
#ifdef SOFTDEVICE_PRESENT
if ( is_sd_enabled() )
{
@@ -922,6 +936,7 @@ static void hfclk_disable(void)
#endif
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP);
+#endif
}
// Power & Clock Peripheral on nRF5x to manage USB
@@ -1064,7 +1079,13 @@ void tusb_hal_nrf_power_event (uint32_t event)
// Enable interrupt, priorities should be set by application
NVIC_ClearPendingIRQ(USBD_IRQn);
- NVIC_EnableIRQ(USBD_IRQn);
+ // Don't enable USBD interrupt yet, if dcd_init() did not finish yet
+ // Interrupt will be enabled by tud_init(), when USB stack is ready
+ // to handle interrupts.
+ if (tud_inited())
+ {
+ NVIC_EnableIRQ(USBD_IRQn);
+ }
// Wait for HFCLK
while ( !hfclk_running() ) { }
diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c
index 0d45090d1..2fdc05f36 100644
--- a/src/portable/nuvoton/nuc120/dcd_nuc120.c
+++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c
@@ -35,7 +35,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC120)
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC120)
#include "device/dcd.h"
#include "NUC100Series.h"
@@ -497,4 +497,12 @@ void dcd_connect(uint8_t rhport)
usb_attach();
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
#endif
diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c
index fc7150508..a56b5f8e8 100644
--- a/src/portable/nuvoton/nuc121/dcd_nuc121.c
+++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c
@@ -35,7 +35,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && ( (CFG_TUSB_MCU == OPT_MCU_NUC121) || (CFG_TUSB_MCU == OPT_MCU_NUC126) )
+#if CFG_TUD_ENABLED && ( (CFG_TUSB_MCU == OPT_MCU_NUC121) || (CFG_TUSB_MCU == OPT_MCU_NUC126) )
#include "device/dcd.h"
#include "NuMicro.h"
@@ -551,4 +551,12 @@ void dcd_connect(uint8_t rhport)
usb_attach();
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
#endif
diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c
index aefb09f4e..886720e33 100644
--- a/src/portable/nuvoton/nuc505/dcd_nuc505.c
+++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c
@@ -35,7 +35,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC505)
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC505)
#include "device/dcd.h"
#include "NUC505Series.h"
@@ -720,4 +720,12 @@ void dcd_connect(uint8_t rhport)
usb_attach();
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
#endif
diff --git a/src/portable/nxp/khci/dcd_khci.c b/src/portable/nxp/khci/dcd_khci.c
index 8de924f90..13eb105cd 100644
--- a/src/portable/nxp/khci/dcd_khci.c
+++ b/src/portable/nxp/khci/dcd_khci.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && ( \
+#if CFG_TUD_ENABLED && ( \
( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX ) || ( CFG_TUSB_MCU == OPT_MCU_K32L2BXX ) \
)
@@ -328,6 +328,14 @@ void dcd_disconnect(uint8_t rhport)
KHCI->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
diff --git a/src/portable/nxp/khci/hcd_khci.c b/src/portable/nxp/khci/hcd_khci.c
new file mode 100644
index 000000000..0f5fa6275
--- /dev/null
+++ b/src/portable/nxp/khci/hcd_khci.c
@@ -0,0 +1,626 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji Kitayama
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && ( \
+ ( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX ) || ( CFG_TUSB_MCU == OPT_MCU_K32L2BXX ) \
+ )
+
+#include "fsl_device_registers.h"
+#define KHCI USB0
+
+#include "host/hcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+ TOK_PID_OUT = 0x1u,
+ TOK_PID_IN = 0x9u,
+ TOK_PID_SETUP = 0xDu,
+ TOK_PID_DATA0 = 0x3u,
+ TOK_PID_DATA1 = 0xbu,
+ TOK_PID_ACK = 0x2u,
+ TOK_PID_STALL = 0xeu,
+ TOK_PID_NAK = 0xau,
+ TOK_PID_BUSTO = 0x0u,
+ TOK_PID_ERR = 0xfu,
+};
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t head;
+ struct {
+ union {
+ struct {
+ uint16_t : 2;
+ __IO uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ __IO uint16_t own : 1;
+ uint16_t : 8;
+ };
+ struct {
+ uint16_t : 2;
+ uint16_t bdt_stall : 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ uint16_t : 10;
+ };
+ };
+ __IO uint16_t bc : 10;
+ uint16_t : 6;
+ };
+ };
+ uint8_t *addr;
+}buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" );
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t state;
+ struct {
+ uint32_t pipenum:16;
+ uint32_t odd : 1;
+ uint32_t : 0;
+ };
+ };
+ uint8_t *buffer;
+ uint16_t length;
+ uint16_t remaining;
+} endpoint_state_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ uint8_t dev_addr;
+ uint8_t ep_addr;
+ uint16_t max_packet_size;
+ union {
+ uint8_t flags;
+ struct {
+ uint8_t data : 1;
+ uint8_t xfer : 2;
+ uint8_t : 0;
+ };
+ };
+ uint8_t *buffer;
+ uint16_t length;
+ uint16_t remaining;
+} pipe_state_t;
+
+
+typedef struct
+{
+ union {
+ /* [OUT,IN][EVEN,ODD] */
+ buffer_descriptor_t bdt[2][2];
+ uint16_t bda[2*2];
+ };
+ endpoint_state_t endpoint[2];
+ pipe_state_t pipe[CFG_TUH_ENDPOINT_MAX * 2];
+ uint32_t in_progress; /* Bitmap. Each bit indicates that a transfer of the corresponding pipe is in progress */
+ uint32_t pending; /* Bitmap. Each bit indicates that a transfer of the corresponding pipe will be resume the next frame */
+ bool need_reset; /* The device has not been reset after connection. */
+} hcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+// BDT(Buffer Descriptor Table) must be 256-byte aligned
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) static hcd_data_t _hcd;
+//CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _rx_buf[1024];
+
+int find_pipe(uint8_t dev_addr, uint8_t ep_addr)
+{
+ /* Find the target pipe */
+ int num;
+ for (num = 0; num < CFG_TUH_ENDPOINT_MAX * 2; ++num) {
+ pipe_state_t *p = &_hcd.pipe[num];
+ if ((p->dev_addr == dev_addr) && (p->ep_addr == ep_addr))
+ return num;
+ }
+ return -1;
+}
+
+static int prepare_packets(int pipenum)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ unsigned const dir_tx = tu_edpt_dir(pipe->ep_addr) ? 0 : 1;
+ endpoint_state_t *ep = &_hcd.endpoint[dir_tx];
+ unsigned const odd = ep->odd;
+ buffer_descriptor_t *bd = _hcd.bdt[dir_tx];
+ TU_ASSERT(0 == bd[odd].own, -1);
+
+ // TU_LOG1(" %p dir %d odd %d data %d\n", &bd[odd], dir_tx, odd, pipe->data);
+
+ ep->pipenum = pipenum;
+
+ bd[odd ].data = pipe->data;
+ bd[odd ^ 1].data = pipe->data ^ 1;
+ bd[odd ^ 1].own = 0;
+ /* reset values for a next transfer */
+
+ int num_tokens = 0; /* The number of prepared packets */
+ unsigned const mps = pipe->max_packet_size;
+ unsigned const rem = pipe->remaining;
+ if (rem > mps) {
+ /* When total_bytes is greater than the max packet size,
+ * it prepares to the next transfer to avoid NAK in advance. */
+ bd[odd ^ 1].bc = rem >= 2 * mps ? mps: rem - mps;
+ bd[odd ^ 1].addr = pipe->buffer + mps;
+ bd[odd ^ 1].own = 1;
+ if (dir_tx) ++num_tokens;
+ }
+ bd[odd].bc = rem >= mps ? mps: rem;
+ bd[odd].addr = pipe->buffer;
+ __DSB();
+ bd[odd].own = 1; /* This bit must be set last */
+ ++num_tokens;
+ return num_tokens;
+}
+
+static int select_next_pipenum(int pipenum)
+{
+ unsigned wip = _hcd.in_progress & ~_hcd.pending;
+ if (!wip) return -1;
+ unsigned msk = TU_GENMASK(31, pipenum);
+ int next = __builtin_ctz(wip & msk);
+ if (next) return next;
+ msk = TU_GENMASK(pipenum, 0);
+ next = __builtin_ctz(wip & msk);
+ return next;
+}
+
+/* When transfer is completed, return true. */
+static bool continue_transfer(int pipenum, buffer_descriptor_t *bd)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ unsigned const bc = bd->bc;
+ unsigned const rem = pipe->remaining - bc;
+
+ pipe->remaining = rem;
+ if (rem && bc == pipe->max_packet_size) {
+ int const next_rem = rem - pipe->max_packet_size;
+ if (next_rem > 0) {
+ /* Prepare to the after next transfer */
+ bd->addr += pipe->max_packet_size * 2;
+ bd->bc = next_rem > pipe->max_packet_size ? pipe->max_packet_size: next_rem;
+ __DSB();
+ bd->own = 1; /* This bit must be set last */
+ while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+ KHCI->TOKEN = KHCI->TOKEN; /* Queue the same token as the last */
+ } else if (TUSB_DIR_IN == tu_edpt_dir(pipe->ep_addr)) { /* IN */
+ while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+ KHCI->TOKEN = KHCI->TOKEN;
+ }
+ return true;
+ }
+ pipe->data = bd->data ^ 1;
+ return false;
+}
+
+static bool resume_transfer(int pipenum)
+{
+ int num_tokens = prepare_packets(pipenum);
+ TU_ASSERT(0 <= num_tokens);
+
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+
+ unsigned flags = KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_HOSTWOHUB_MASK;
+ flags |= USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+ switch (pipe->xfer) {
+ case TUSB_XFER_CONTROL:
+ flags |= USB_ENDPT_EPHSHK_MASK;
+ break;
+ case TUSB_XFER_ISOCHRONOUS:
+ flags |= USB_ENDPT_EPCTLDIS_MASK | USB_ENDPT_RETRYDIS_MASK;
+ break;
+ default:
+ flags |= USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPCTLDIS_MASK | USB_ENDPT_RETRYDIS_MASK;
+ break;
+ }
+ // TU_LOG1(" resume pipenum %d flags %x\n", pipenum, flags);
+
+ KHCI->ENDPOINT[0].ENDPT = flags;
+ KHCI->ADDR = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | pipe->dev_addr;
+
+ unsigned const token = tu_edpt_number(pipe->ep_addr) |
+ ((tu_edpt_dir(pipe->ep_addr) ? TOK_PID_IN: TOK_PID_OUT) << USB_TOKEN_TOKENPID_SHIFT);
+ do {
+ while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+ KHCI->TOKEN = token;
+ } while (--num_tokens);
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ return true;
+}
+
+static void suspend_transfer(int pipenum, buffer_descriptor_t *bd)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ pipe->buffer = bd->addr;
+ pipe->data = bd->data ^ 1;
+ if ((TUSB_XFER_INTERRUPT == pipe->xfer) ||
+ (TUSB_XFER_BULK == pipe->xfer)) {
+ _hcd.pending |= TU_BIT(pipenum);
+ KHCI->INTEN |= USB_ISTAT_SOFTOK_MASK;
+ }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+ (void)rhport;
+ const unsigned s = KHCI->STAT;
+ KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
+ uint8_t const dir_in = (s & USB_STAT_TX_MASK) ? TUSB_DIR_OUT: TUSB_DIR_IN;
+ unsigned const odd = (s & USB_STAT_ODD_MASK) ? 1 : 0;
+
+ buffer_descriptor_t *bd = (buffer_descriptor_t *)&_hcd.bda[s];
+ endpoint_state_t *ep = &_hcd.endpoint[s >> 3];
+
+ /* fetch status before discarded by the next steps */
+ const unsigned pid = bd->tok_pid;
+
+ /* reset values for a next transfer */
+ bd->bdt_stall = 0;
+ bd->dts = 1;
+ bd->ninc = 0;
+ bd->keep = 0;
+ /* Update the odd variable to prepare for the next transfer */
+ ep->odd = odd ^ 1;
+
+ int pipenum = ep->pipenum;
+ int next_pipenum;
+ // TU_LOG1("TOKDNE %x PID %x pipe %d\n", s, pid, pipenum);
+
+ xfer_result_t result;
+ switch (pid) {
+ default:
+ if (continue_transfer(pipenum, bd))
+ return;
+ result = XFER_RESULT_SUCCESS;
+ break;
+ case TOK_PID_NAK:
+ suspend_transfer(pipenum, bd);
+ next_pipenum = select_next_pipenum(pipenum);
+ if (0 <= next_pipenum)
+ resume_transfer(next_pipenum);
+ return;
+ case TOK_PID_STALL:
+ result = XFER_RESULT_STALLED;
+ break;
+ case TOK_PID_ERR: /* mismatch toggle bit */
+ case TOK_PID_BUSTO:
+ result = XFER_RESULT_FAILED;
+ break;
+ }
+ _hcd.in_progress &= ~TU_BIT(pipenum);
+ pipe_state_t *pipe = &_hcd.pipe[ep->pipenum];
+ hcd_event_xfer_complete(pipe->dev_addr,
+ tu_edpt_addr(KHCI->TOKEN & USB_TOKEN_TOKENENDPT_MASK, dir_in),
+ pipe->length - pipe->remaining,
+ result, true);
+ next_pipenum = select_next_pipenum(pipenum);
+ if (0 <= next_pipenum)
+ resume_transfer(next_pipenum);
+}
+
+static void process_attach(uint8_t rhport)
+{
+ unsigned ctl = KHCI->CTL;
+ if (!(ctl & USB_CTL_JSTATE_MASK)) {
+ /* The attached device is a low speed device. */
+ KHCI->ADDR = USB_ADDR_LSEN_MASK;
+ KHCI->ENDPOINT[0].ENDPT = USB_ENDPT_HOSTWOHUB_MASK;
+ }
+ hcd_event_device_attach(rhport, true);
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+ KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK;
+ KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+ KHCI->CTL &= ~USB_CTL_USBENSOFEN_MASK;
+ KHCI->ADDR = 0;
+ KHCI->ENDPOINT[0].ENDPT = 0;
+
+ hcd_event_device_remove(rhport, true);
+
+ _hcd.in_progress = 0;
+ _hcd.pending = 0;
+ buffer_descriptor_t *bd = &_hcd.bdt[0][0];
+ for (unsigned i = 0; i < 2; ++i, ++bd) {
+ bd->head = 0;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* Host API
+ *------------------------------------------------------------------*/
+bool hcd_init(uint8_t rhport)
+{
+ (void)rhport;
+
+ KHCI->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
+ while (KHCI->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+
+ tu_memclr(&_hcd, sizeof(_hcd));
+ KHCI->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */
+ KHCI->BDTPAGE1 = (uint8_t)((uintptr_t)_hcd.bdt >> 8);
+ KHCI->BDTPAGE2 = (uint8_t)((uintptr_t)_hcd.bdt >> 16);
+ KHCI->BDTPAGE3 = (uint8_t)((uintptr_t)_hcd.bdt >> 24);
+
+ KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+ KHCI->CTL |= USB_CTL_ODDRST_MASK;
+ for (unsigned i = 0; i < 16; ++i) {
+ KHCI->ENDPOINT[i].ENDPT = 0;
+ }
+ KHCI->CTL &= ~USB_CTL_ODDRST_MASK;
+
+ KHCI->SOFTHLD = 74; /* for 64-byte packets */
+ // KHCI->SOFTHLD = 144; /* for low speed 8-byte packets */
+ KHCI->CTL = USB_CTL_HOSTMODEEN_MASK | USB_CTL_SE0_MASK;
+ KHCI->USBCTRL = USB_USBCTRL_PDE_MASK;
+
+ NVIC_ClearPendingIRQ(USB0_IRQn);
+ KHCI->INTEN = USB_INTEN_ATTACHEN_MASK | USB_INTEN_TOKDNEEN_MASK |
+ USB_INTEN_USBRSTEN_MASK | USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
+ KHCI->ERREN = 0xff;
+
+ return true;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_DisableIRQ(USB0_IRQn);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void)rhport;
+ /* The device must be reset at least once after connection
+ * in order to start the frame counter. */
+ if (_hcd.need_reset) hcd_port_reset(rhport);
+ uint32_t frmnum = KHCI->FRMNUML;
+ frmnum |= KHCI->FRMNUMH << 8u;
+ return frmnum;
+}
+
+/*--------------------------------------------------------------------+
+ * Port API
+ *--------------------------------------------------------------------+ */
+bool hcd_port_connect_status(uint8_t rhport)
+{
+ (void)rhport;
+ if (KHCI->ISTAT & USB_ISTAT_ATTACH_MASK)
+ return true;
+ return false;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+ (void)rhport;
+ KHCI->CTL &= ~USB_CTL_USBENSOFEN_MASK;
+ KHCI->CTL |= USB_CTL_RESET_MASK;
+ unsigned cnt = SystemCoreClock / 100;
+ while (cnt--) __NOP();
+ KHCI->CTL &= ~USB_CTL_RESET_MASK;
+ KHCI->CTL |= USB_CTL_USBENSOFEN_MASK;
+ _hcd.need_reset = false;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+ (void)rhport;
+ tusb_speed_t speed = TUSB_SPEED_FULL;
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ if (KHCI->ADDR & USB_ADDR_LSEN_MASK)
+ speed = TUSB_SPEED_LOW;
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ return speed;
+}
+
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ pipe_state_t *p = &_hcd.pipe[0];
+ pipe_state_t *end = &_hcd.pipe[CFG_TUH_ENDPOINT_MAX * 2];
+ for (;p != end; ++p) {
+ if (p->dev_addr == dev_addr)
+ tu_memclr(p, sizeof(*p));
+ }
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+//--------------------------------------------------------------------+
+// Endpoints API
+//--------------------------------------------------------------------+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ (void)rhport;
+ // TU_LOG1("SETUP %u\n", dev_addr);
+ TU_ASSERT(0 == (_hcd.in_progress & TU_BIT(0)));
+
+ int pipenum = find_pipe(dev_addr, 0);
+ if (pipenum < 0) return false;
+
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ pipe[0].data = 0;
+ pipe[0].buffer = (uint8_t*)(uintptr_t)setup_packet;
+ pipe[0].length = 8;
+ pipe[0].remaining = 8;
+ pipe[1].data = 1;
+
+ if (1 != prepare_packets(pipenum))
+ return false;
+
+ _hcd.in_progress |= TU_BIT(pipenum);
+
+ unsigned hostwohub = KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_HOSTWOHUB_MASK;
+ KHCI->ENDPOINT[0].ENDPT = hostwohub |
+ USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+ KHCI->ADDR = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | dev_addr;
+ while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+ KHCI->TOKEN = (TOK_PID_SETUP << USB_TOKEN_TOKENPID_SHIFT);
+ return true;
+}
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void)rhport;
+ uint8_t const ep_addr = ep_desc->bEndpointAddress;
+ // TU_LOG1("O %u %x\n", dev_addr, ep_addr);
+ /* Find a free pipe */
+ pipe_state_t *p = &_hcd.pipe[0];
+ pipe_state_t *end = &_hcd.pipe[CFG_TUH_ENDPOINT_MAX * 2];
+ if (dev_addr || ep_addr) {
+ p += 2;
+ for (; p < end && (p->dev_addr || p->ep_addr); ++p) ;
+ if (p == end) return false;
+ }
+ p->dev_addr = dev_addr;
+ p->ep_addr = ep_addr;
+ p->max_packet_size = ep_desc->wMaxPacketSize;
+ p->xfer = ep_desc->bmAttributes.xfer;
+ p->data = 0;
+ if (!ep_addr) {
+ /* Open one more pipe for Control IN transfer */
+ TU_ASSERT(TUSB_XFER_CONTROL == p->xfer);
+ pipe_state_t *q = p + 1;
+ TU_ASSERT(!q->dev_addr && !q->ep_addr);
+ q->dev_addr = dev_addr;
+ q->ep_addr = tu_edpt_addr(0, TUSB_DIR_IN);
+ q->max_packet_size = ep_desc->wMaxPacketSize;
+ q->xfer = ep_desc->bmAttributes.xfer;
+ q->data = 1;
+ }
+ return true;
+}
+
+/* The address of buffer must be aligned to 4 byte boundary. And it must be at least 4 bytes long.
+ * DMA writes data in 4 byte unit */
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
+{
+ (void)rhport;
+ // TU_LOG1("X %u %x %x %d\n", dev_addr, ep_addr, (uintptr_t)buffer, buflen);
+
+ int pipenum = find_pipe(dev_addr, ep_addr);
+ TU_ASSERT(0 <= pipenum);
+
+ TU_ASSERT(0 == (_hcd.in_progress & TU_BIT(pipenum)));
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ pipe->buffer = buffer;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ _hcd.in_progress |= TU_BIT(pipenum);
+ _hcd.pending |= TU_BIT(pipenum); /* Send at the next Frame */
+ KHCI->INTEN |= USB_ISTAT_SOFTOK_MASK;
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ return true;
+}
+
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+ if (!tu_edpt_number(ep_addr)) return true;
+ int num = find_pipe(dev_addr, ep_addr);
+ if (num < 0) return false;
+ pipe_state_t *p = &_hcd.pipe[num];
+ p->data = 0; /* Reset data toggle */
+ return true;
+}
+
+/*--------------------------------------------------------------------+
+ * ISR
+ *--------------------------------------------------------------------+*/
+void hcd_int_handler(uint8_t rhport)
+{
+ uint32_t is = KHCI->ISTAT;
+ uint32_t msk = KHCI->INTEN;
+
+ // TU_LOG1("S %lx\n", is);
+
+ /* clear disabled interrupts */
+ KHCI->ISTAT = (is & ~msk & ~USB_ISTAT_TOKDNE_MASK) | USB_ISTAT_SOFTOK_MASK;
+ is &= msk;
+
+ if (is & USB_ISTAT_ERROR_MASK) {
+ unsigned err = KHCI->ERRSTAT;
+ if (err) {
+ TU_LOG1(" ERR %x\n", err);
+ KHCI->ERRSTAT = err;
+ } else {
+ KHCI->INTEN &= ~USB_ISTAT_ERROR_MASK;
+ }
+ }
+
+ if (is & USB_ISTAT_USBRST_MASK) {
+ KHCI->INTEN = (msk & ~USB_INTEN_USBRSTEN_MASK) | USB_INTEN_ATTACHEN_MASK;
+ process_bus_reset(rhport);
+ return;
+ }
+ if (is & USB_ISTAT_ATTACH_MASK) {
+ KHCI->INTEN = (msk & ~USB_INTEN_ATTACHEN_MASK) | USB_INTEN_USBRSTEN_MASK;
+ _hcd.need_reset = true;
+ process_attach(rhport);
+ return;
+ }
+ if (is & USB_ISTAT_STALL_MASK) {
+ KHCI->ISTAT = USB_ISTAT_STALL_MASK;
+ }
+ if (is & USB_ISTAT_SOFTOK_MASK) {
+ msk &= ~USB_ISTAT_SOFTOK_MASK;
+ KHCI->INTEN = msk;
+ if (_hcd.pending) {
+ int pipenum = __builtin_ctz(_hcd.pending);
+ _hcd.pending = 0;
+ if (!(is & USB_ISTAT_TOKDNE_MASK))
+ resume_transfer(pipenum);
+ }
+ }
+ if (is & USB_ISTAT_TOKDNE_MASK) {
+ process_tokdne(rhport);
+ }
+}
+
+#endif
diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
index 0f500a88f..0894a5eeb 100644
--- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
+++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && \
+#if CFG_TUD_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
#include "device/dcd.h"
@@ -228,6 +228,14 @@ void dcd_disconnect(uint8_t rhport)
sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 0);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// CONTROL HELPER
//--------------------------------------------------------------------+
diff --git a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
index 1c1faed94..ad9ed59b4 100644
--- a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
+++ b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && \
+#if CFG_TUH_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
#include "chip.h"
diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
index 1bdf72d6d..9b490c48c 100644
--- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
+++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
@@ -34,7 +34,7 @@
* - LPC54114
* - LPC55s69
*/
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_LPC11UXX || \
+#if CFG_TUD_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_LPC11UXX || \
CFG_TUSB_MCU == OPT_MCU_LPC13XX || \
CFG_TUSB_MCU == OPT_MCU_LPC15XX || \
CFG_TUSB_MCU == OPT_MCU_LPC51UXX || \
@@ -78,8 +78,10 @@ typedef struct {
// Max nbytes for each control/bulk/interrupt transfer
enum {
- NBYTES_CBI_FULLSPEED_MAX = 64,
- NBYTES_CBI_HIGHSPEED_MAX = 32767 // can be up to all 15-bit, but only tested with 4096
+ NBYTES_ISO_FS_MAX = 1023, // FS ISO
+ NBYTES_ISO_HS_MAX = 1024, // HS ISO
+ NBYTES_CBI_FS_MAX = 64, // FS control/bulk/interrupt
+ NBYTES_CBI_HS_MAX = 32767 // can be up to all 15-bit, but only tested with 4096
};
enum {
@@ -112,6 +114,8 @@ enum {
typedef union TU_ATTR_PACKED
{
// Full and High speed has different bit layout for buffer_offset and nbytes
+ // TODO FS/HS layout depends on the max speed of controller e.g
+ // lpc55s69 PORT0 is only FS but actually has the same layout as HS on port1
// Buffer (aligned 64) = DATABUFSTART [31:22] | buffer_offset [21:6]
volatile struct {
@@ -175,6 +179,9 @@ typedef struct
// Use CFG_TUSB_MEM_SECTION to place it accordingly.
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd;
+// Dummy buffer to fix ZLPs overwriting the buffer (probably an USB/DMA controller bug)
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(64) static uint8_t dummy[8];
+
//--------------------------------------------------------------------+
// Multiple Controllers
//--------------------------------------------------------------------+
@@ -225,8 +232,36 @@ static inline uint8_t ep_addr2id(uint8_t ep_addr)
//--------------------------------------------------------------------+
// CONTROLLER API
//--------------------------------------------------------------------+
+
+static void prepare_setup_packet(uint8_t rhport)
+{
+ if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
+ {
+ _dcd.ep[0][1].buffer_fs.offset = get_buf_offset(_dcd.setup_packet);
+ }else
+ {
+ _dcd.ep[0][1].buffer_hs.offset = get_buf_offset(_dcd.setup_packet);
+ }
+}
+
+static void edpt_reset(uint8_t rhport, uint8_t ep_id)
+{
+ (void) rhport;
+ tu_memclr(&_dcd.ep[ep_id], sizeof(_dcd.ep[ep_id]));
+}
+
+static void edpt_reset_all(uint8_t rhport)
+{
+ for (uint8_t ep_id = 0; ep_id < 2*_dcd_controller[rhport].ep_pairs; ++ep_id)
+ {
+ edpt_reset(rhport, ep_id);
+ }
+ prepare_setup_packet(rhport);
+}
void dcd_init(uint8_t rhport)
{
+ edpt_reset_all(rhport);
+
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
dcd_reg->EPLISTSTART = (uint32_t) _dcd.ep;
@@ -277,6 +312,14 @@ void dcd_disconnect(uint8_t rhport)
dcd_reg->DEVCMDSTAT &= ~CMDSTAT_DEVICE_CONNECT_MASK;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// DCD Endpoint Port
//--------------------------------------------------------------------+
@@ -302,18 +345,13 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
{
- (void) rhport;
-
- // TODO not support ISO yet
- TU_VERIFY(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
-
//------------- Prepare Queue Head -------------//
uint8_t ep_id = ep_addr2id(p_endpoint_desc->bEndpointAddress);
// Check if endpoint is available
TU_ASSERT( _dcd.ep[ep_id][0].disable && _dcd.ep[ep_id][1].disable );
- tu_memclr(_dcd.ep[ep_id], 2*sizeof(ep_cmd_sts_t));
+ edpt_reset(rhport, ep_id);
_dcd.ep[ep_id][0].is_iso = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS);
// Enable EP interrupt
@@ -325,19 +363,20 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
void dcd_edpt_close_all (uint8_t rhport)
{
- (void) rhport;
- // TODO implement dcd_edpt_close_all()
+ for (uint8_t ep_id = 0; ep_id < 2*_dcd_controller[rhport].ep_pairs; ++ep_id)
+ {
+ _dcd.ep[ep_id][0].active = _dcd.ep[ep_id][0].active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual)
+ _dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1;
+ }
}
-static void prepare_setup_packet(uint8_t rhport)
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
- if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
- {
- _dcd.ep[0][1].buffer_fs.offset = get_buf_offset(_dcd.setup_packet);;
- }else
- {
- _dcd.ep[0][1].buffer_hs.offset = get_buf_offset(_dcd.setup_packet);;
- }
+ (void) rhport;
+
+ uint8_t ep_id = ep_addr2id(ep_addr);
+ _dcd.ep[ep_id][0].active = _dcd.ep[ep_id][0].active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual)
+ _dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1;
}
static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, uint16_t total_bytes)
@@ -346,13 +385,12 @@ static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset,
if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
{
- // TODO ISO FullSpeed can have up to 1023 bytes
- nbytes = tu_min16(total_bytes, NBYTES_CBI_FULLSPEED_MAX);
+ nbytes = tu_min16(total_bytes, _dcd.ep[ep_id][0].is_iso ? NBYTES_ISO_FS_MAX : NBYTES_CBI_FS_MAX);
_dcd.ep[ep_id][0].buffer_fs.offset = buf_offset;
_dcd.ep[ep_id][0].buffer_fs.nbytes = nbytes;
}else
{
- nbytes = tu_min16(total_bytes, NBYTES_CBI_HIGHSPEED_MAX);
+ nbytes = tu_min16(total_bytes, NBYTES_CBI_HS_MAX);
_dcd.ep[ep_id][0].buffer_hs.offset = buf_offset;
_dcd.ep[ep_id][0].buffer_hs.nbytes = nbytes;
}
@@ -364,13 +402,19 @@ static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset,
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
{
- (void) rhport;
-
uint8_t const ep_id = ep_addr2id(ep_addr);
tu_memclr(&_dcd.dma[ep_id], sizeof(xfer_dma_t));
_dcd.dma[ep_id].total_bytes = total_bytes;
+ if (!buffer)
+ {
+ // Although having no data, ZLPs can cause buffer overwritten to zeroes.
+ // Probably due to USB/DMA controller side effect/bug.
+ // Assigned buffer offset to (valid) dummy to prevent overwriting to DATABUFSTART
+ buffer = (uint8_t*)(uint32_t)dummy;
+ }
+
prepare_ep_xfer(rhport, ep_id, get_buf_offset(buffer), total_bytes);
return true;
@@ -382,15 +426,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
static void bus_reset(uint8_t rhport)
{
tu_memclr(&_dcd, sizeof(dcd_data_t));
+ edpt_reset_all(rhport);
- // disable all non-control endpoints on bus reset
- for(uint8_t ep_id = 2; ep_id < 2*MAX_EP_PAIRS; ep_id++)
+ // disable all endpoints as specified by LPC55S69 UM Table 778
+ for(uint8_t ep_id = 0; ep_id < 2*MAX_EP_PAIRS; ep_id++)
{
_dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1;
}
- prepare_setup_packet(rhport);
-
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
dcd_reg->EPINUSE = 0;
@@ -498,23 +541,15 @@ void dcd_int_handler(uint8_t rhport)
}
}
- // TODO support suspend & resume
if (cmd_stat & CMDSTAT_SUSPEND_CHANGE_MASK)
{
- if (cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK)
- { // suspend signal, bus idle for more than 3ms
- // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
- if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
- }
+ // suspend signal, bus idle for more than 3ms
+ // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
+ if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
+ {
+ dcd_event_bus_signal(rhport, (cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME, true);
}
}
-// else
-// { // resume signal
-// dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
-// }
-// }
}
// Setup Receive
diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c
index 5ac041fbf..1f27a6872 100644
--- a/src/portable/nxp/transdimension/dcd_transdimension.c
+++ b/src/portable/nxp/transdimension/dcd_transdimension.c
@@ -26,13 +26,15 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX)
+#if CFG_TUD_ENABLED && \
+ (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT)
+
+#warning "transdimenion is renamed to chipidea (portable/chipidea/ci_hs) to match other opensource naming convention such as linux. This file will be removed in the future, please update your makefile accordingly"
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
#include "fsl_device_registers.h"
#define INCLUDE_FSL_DEVICE_REGISTERS
#else
@@ -151,7 +153,7 @@ typedef struct
const uint8_t ep_count; // Max bi-directional Endpoints
}dcd_controller_t;
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
static const dcd_controller_t _dcd_controller[] =
{
// RT1010 and RT1020 only has 1 USB controller
@@ -177,8 +179,8 @@ typedef struct {
// Must be at 2K alignment
// Each endpoint with direction (IN/OUT) occupies a queue head
// for portability, TinyUSB only queue 1 TD for each Qhd
- dcd_qhd_t qhd[DCD_ATTR_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64);
- dcd_qtd_t qtd[DCD_ATTR_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32);
+ dcd_qhd_t qhd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64);
+ dcd_qtd_t qtd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32);
}dcd_data_t;
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(2048)
@@ -292,6 +294,14 @@ void dcd_disconnect(uint8_t rhport)
dcd_reg->USBCMD &= ~USBCMD_RUN_STOP;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// HELPER
//--------------------------------------------------------------------+
@@ -645,7 +655,7 @@ void dcd_int_handler(uint8_t rhport)
if ( edpt_complete )
{
- for(uint8_t epnum = 0; epnum < DCD_ATTR_ENDPOINT_MAX; epnum++)
+ for(uint8_t epnum = 0; epnum < TUP_DCD_ENDPOINT_MAX; epnum++)
{
if ( tu_bit_test(edpt_complete, epnum) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_OUT);
if ( tu_bit_test(edpt_complete, epnum+16) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_IN);
diff --git a/src/portable/nxp/transdimension/hcd_transdimension.c b/src/portable/nxp/transdimension/hcd_transdimension.c
index d216f0728..392764ff6 100644
--- a/src/portable/nxp/transdimension/hcd_transdimension.c
+++ b/src/portable/nxp/transdimension/hcd_transdimension.c
@@ -28,13 +28,15 @@
// NXP Trans-Dimension USB IP implement EHCI for host functionality
-#if TUSB_OPT_HOST_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX)
+#if CFG_TUH_ENABLED && \
+ (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT)
+
+#warning "transdimenion is renamed to chipidea (portable/chipidea/ci_hs) to match other opensource naming convention such as linux. This file will be removed in the future, please update your makefile accordingly"
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
#include "fsl_device_registers.h"
#else
// LPCOpen for 18xx & 43xx
@@ -56,7 +58,7 @@ typedef struct
const IRQn_Type irqnum; // IRQ number
}hcd_controller_t;
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
static const hcd_controller_t _hcd_controller[] =
{
// RT1010 and RT1020 only has 1 USB controller
diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c
index daa8075b7..3e523ebc2 100644
--- a/src/portable/ohci/ohci.c
+++ b/src/portable/ohci/ohci.c
@@ -24,9 +24,9 @@
* This file is part of the TinyUSB stack.
*/
-#include "host/hcd_attr.h"
+#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && defined(HCD_ATTR_OHCI)
+#if CFG_TUH_ENABLED && defined(TUP_USBIP_OHCI)
//--------------------------------------------------------------------+
// INCLUDE
@@ -216,6 +216,11 @@ void hcd_port_reset(uint8_t hostid)
OHCI_REG->rhport_status[0] = RHPORT_PORT_RESET_STATUS_MASK;
}
+void hcd_port_reset_end(uint8_t rhport)
+{
+ (void) rhport;
+}
+
bool hcd_port_connect_status(uint8_t hostid)
{
(void) hostid;
@@ -313,7 +318,7 @@ static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
ohci_ed_t* ed_pool = ohci_data.ed_pool;
- for(uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
+ for(uint32_t i=0; i<ED_MAX; i++)
{
if ( (ed_pool[i].dev_addr == dev_addr) &&
ep_addr == tu_edpt_addr(ed_pool[i].ep_number, ed_pool[i].pid == PID_IN) )
@@ -329,7 +334,7 @@ static ohci_ed_t * ed_find_free(void)
{
ohci_ed_t* ed_pool = ohci_data.ed_pool;
- for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; i++)
+ for(uint8_t i = 0; i < ED_MAX; i++)
{
if ( !ed_pool[i].used ) return &ed_pool[i];
}
@@ -368,7 +373,7 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr)
static ohci_gtd_t * gtd_find_free(void)
{
- for(uint8_t i=0; i < HCD_MAX_XFER; i++)
+ for(uint8_t i=0; i < GTD_MAX; i++)
{
if ( !ohci_data.gtd_pool[i].used ) return &ohci_data.gtd_pool[i];
}
diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h
index cd90aa45a..9fc954c8f 100644
--- a/src/portable/ohci/ohci.h
+++ b/src/portable/ohci/ohci.h
@@ -42,6 +42,9 @@ enum {
OHCI_MAX_ITD = 4
};
+#define ED_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX)
+#define GTD_MAX ED_MAX
+
//--------------------------------------------------------------------+
// OHCI Data Structure
//--------------------------------------------------------------------+
@@ -159,11 +162,11 @@ typedef struct TU_ATTR_ALIGNED(256)
struct {
ohci_ed_t ed;
ohci_gtd_t gtd;
- }control[CFG_TUH_DEVICE_MAX+1];
+ }control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
// ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32
- ohci_ed_t ed_pool[HCD_MAX_ENDPOINT];
- ohci_gtd_t gtd_pool[HCD_MAX_XFER];
+ ohci_ed_t ed_pool[ED_MAX];
+ ohci_gtd_t gtd_pool[GTD_MAX];
volatile uint16_t frame_number_hi;
diff --git a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
new file mode 100644
index 000000000..1bc5594d8
--- /dev/null
+++ b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
@@ -0,0 +1,210 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018, hathach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && CFG_TUD_RPI_PIO_USB
+
+#include "pico.h"
+#include "pio_usb.h"
+#include "pio_usb_ll.h"
+
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+#define RHPORT_OFFSET 1
+#define RHPORT_PIO(_x) ((_x)-RHPORT_OFFSET)
+
+//------------- -------------//
+static usb_device_t *usb_device = NULL;
+static usb_descriptor_buffers_t desc;
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+
+// Initialize controller to device mode
+void dcd_init (uint8_t rhport)
+{
+ (void) rhport;
+
+ static pio_usb_configuration_t config = PIO_USB_DEFAULT_CONFIG;
+ usb_device = pio_usb_device_init(&config, &desc);
+}
+
+// Enable device interrupt
+void dcd_int_enable (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Disable device interrupt
+void dcd_int_disable (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
+{
+ // must be called before queuing status
+ pio_usb_device_set_address(dev_addr);
+ dcd_edpt_xfer(rhport, 0x80, NULL, 0);
+}
+
+// Wake up host
+void dcd_remote_wakeup (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
+{
+ (void) rhport;
+ return pio_usb_device_endpoint_open((uint8_t const*) desc_ep);
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ (void) rhport;
+ endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr);
+ return pio_usb_ll_transfer_start(ep, buffer, total_bytes);
+}
+
+// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
+//bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+//{
+// (void) rhport;
+// (void) ep_addr;
+// (void) ff;
+// (void) total_bytes;
+// return false;
+//}
+
+// Stall endpoint
+void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr);
+ ep->has_transfer = false;
+ ep->stalled = true;
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr);
+ ep->data_id = 0;
+ ep->stalled = false;
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+static void __no_inline_not_in_flash_func(handle_endpoint_irq)(uint8_t tu_rhport, xfer_result_t result, volatile uint32_t* ep_reg)
+{
+ const uint32_t ep_all = *ep_reg;
+
+ for(uint8_t ep_idx = 0; ep_idx < PIO_USB_EP_POOL_CNT; ep_idx++)
+ {
+ uint32_t const mask = (1u << ep_idx);
+
+ if (ep_all & mask)
+ {
+ endpoint_t* ep = PIO_USB_ENDPOINT(ep_idx);
+ dcd_event_xfer_complete(tu_rhport, ep->ep_num, ep->actual_len, result, true);
+ }
+ }
+
+ // clear all
+ (*ep_reg) &= ~ep_all;
+}
+
+// IRQ Handler
+void __no_inline_not_in_flash_func(pio_usb_device_irq_handler)(uint8_t root_id)
+{
+ uint8_t const tu_rhport = root_id + 1;
+ root_port_t* rport = PIO_USB_ROOT_PORT(root_id);
+ uint32_t const ints = rport->ints;
+
+ if (ints & PIO_USB_INTS_RESET_END_BITS)
+ {
+ dcd_event_bus_reset(tu_rhport, TUSB_SPEED_FULL, true);
+ }
+
+ if (ints & PIO_USB_INTS_SETUP_REQ_BITS)
+ {
+ dcd_event_setup_received(tu_rhport, rport->setup_packet, true);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS )
+ {
+ handle_endpoint_irq(tu_rhport, XFER_RESULT_SUCCESS, &rport->ep_complete);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_STALLED_BITS )
+ {
+ handle_endpoint_irq(tu_rhport, XFER_RESULT_STALLED, &rport->ep_stalled);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_ERROR_BITS )
+ {
+ handle_endpoint_irq(tu_rhport, XFER_RESULT_FAILED, &rport->ep_error);
+ }
+
+ // clear all
+ rport->ints &= ~ints;
+}
+
+#endif
diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
new file mode 100644
index 000000000..58b153ac3
--- /dev/null
+++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
@@ -0,0 +1,225 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && CFG_TUH_RPI_PIO_USB
+
+#include "pico.h"
+#include "pio_usb.h"
+#include "pio_usb_ll.h"
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "osal/osal.h"
+
+#include "host/hcd.h"
+#include "host/usbh.h"
+
+#define RHPORT_OFFSET 1
+#define RHPORT_PIO(_x) ((_x)-RHPORT_OFFSET)
+
+static pio_usb_configuration_t pio_host_cfg = PIO_USB_DEFAULT_CONFIG;
+
+//--------------------------------------------------------------------+
+// HCD API
+//--------------------------------------------------------------------+
+bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param)
+{
+ (void) rhport;
+ TU_VERIFY(cfg_id == TUH_CFGID_RPI_PIO_USB_CONFIGURATION);
+ memcpy(&pio_host_cfg, cfg_param, sizeof(pio_usb_configuration_t));
+ return true;
+}
+
+bool hcd_init(uint8_t rhport)
+{
+ (void) rhport;
+
+ // To run USB SOF interrupt in core1, call this init in core1
+ pio_usb_host_init(&pio_host_cfg);
+
+ return true;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ pio_usb_host_port_reset_start(pio_rhport);
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ pio_usb_host_port_reset_end(pio_rhport);
+}
+
+bool hcd_port_connect_status(uint8_t rhport)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+
+ root_port_t *root = PIO_USB_ROOT_PORT(pio_rhport);
+ port_pin_status_t line_state = pio_usb_bus_get_line_state(root);
+
+ return line_state != PORT_PIN_SE0;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+ // TODO determine link speed
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return PIO_USB_ROOT_PORT(pio_rhport)->is_fullspeed ? TUSB_SPEED_FULL : TUSB_SPEED_LOW;
+}
+
+// Close all opened endpoint belong to this device
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ pio_usb_host_close_device(pio_rhport, dev_addr);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void) rhport;
+ return 0;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep)
+{
+ hcd_devtree_info_t dev_tree;
+ hcd_devtree_get_info(dev_addr, &dev_tree);
+ bool const need_pre = (dev_tree.hub_addr && dev_tree.speed == TUSB_SPEED_LOW);
+
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_endpoint_open(pio_rhport, dev_addr, (uint8_t const*) desc_ep, need_pre);
+}
+
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_endpoint_transfer(pio_rhport, dev_addr, ep_addr, buffer, buflen);
+}
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_send_setup(pio_rhport, dev_addr, setup_packet);
+}
+
+//bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
+//{
+// // EPX is shared, so multiple device addresses and endpoint addresses share that
+// // so if any transfer is active on epx, we are busy. Interrupt endpoints have their own
+// // EPX so ep->active will only be busy if there is a pending transfer on that interrupt endpoint
+// // on that device
+// pico_trace("hcd_edpt_busy dev addr %d ep_addr 0x%x\n", dev_addr, ep_addr);
+// struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
+// assert(ep);
+// bool busy = ep->active;
+// pico_trace("busy == %d\n", busy);
+// return busy;
+//}
+
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+ (void) dev_addr;
+ (void) ep_addr;
+
+ return true;
+}
+
+static void __no_inline_not_in_flash_func(handle_endpoint_irq)(root_port_t* rport, xfer_result_t result, volatile uint32_t* ep_reg)
+{
+ (void) rport;
+ const uint32_t ep_all = *ep_reg;
+
+ for(uint8_t ep_idx = 0; ep_idx < PIO_USB_EP_POOL_CNT; ep_idx++)
+ {
+ uint32_t const mask = (1u << ep_idx);
+
+ if (ep_all & mask)
+ {
+ endpoint_t* ep = PIO_USB_ENDPOINT(ep_idx);
+ hcd_event_xfer_complete(ep->dev_addr, ep->ep_num, ep->actual_len, result, true);
+ }
+ }
+
+ // clear all
+ (*ep_reg) &= ~ep_all;
+}
+
+// IRQ Handler
+void __no_inline_not_in_flash_func(pio_usb_host_irq_handler)(uint8_t root_id)
+{
+ uint8_t const tu_rhport = root_id + 1;
+ root_port_t* rport = PIO_USB_ROOT_PORT(root_id);
+ uint32_t const ints = rport->ints;
+
+ if ( ints & PIO_USB_INTS_CONNECT_BITS )
+ {
+ hcd_event_device_attach(tu_rhport, true);
+ }
+
+ if ( ints & PIO_USB_INTS_DISCONNECT_BITS )
+ {
+ hcd_event_device_remove(tu_rhport, true);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS )
+ {
+ handle_endpoint_irq(rport, XFER_RESULT_SUCCESS, &rport->ep_complete);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_STALLED_BITS )
+ {
+ handle_endpoint_irq(rport, XFER_RESULT_STALLED, &rport->ep_stalled);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_ERROR_BITS )
+ {
+ handle_endpoint_irq(rport, XFER_RESULT_FAILED, &rport->ep_error);
+ }
+
+ // clear all
+ rport->ints &= ~ints;
+}
+
+#endif
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index e084478e0..4952d29b1 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_RP2040
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUD_RPI_PIO_USB
#include "pico.h"
#include "rp2040_usb.h"
@@ -55,7 +55,10 @@ static uint8_t *next_buffer_ptr;
// USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
-static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
+// SOF may be used by remote wakeup as RESUME, this indicate whether SOF is actually used by usbd
+static bool _sof_enable = false;
+
+TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
{
return &hw_endpoints[num][dir];
}
@@ -83,9 +86,9 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
assert(((uintptr_t )next_buffer_ptr & 0b111111u) == 0);
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
- assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
+ hard_assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
- pico_info(" Alloced %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
+ pico_info(" Allocated %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
// Fill in endpoint control register with buffer offset
uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
@@ -93,7 +96,6 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
*ep->endpoint_control = reg;
}
-#if 0 // todo unused
static void _hw_endpoint_close(struct hw_endpoint *ep)
{
// Clear hardware registers and then zero the struct
@@ -103,6 +105,21 @@ static void _hw_endpoint_close(struct hw_endpoint *ep)
*ep->buffer_control = 0;
// Clear any endpoint state
memset(ep, 0, sizeof(struct hw_endpoint));
+
+ // Reclaim buffer space if all endpoints are closed
+ bool reclaim_buffers = true;
+ for ( uint8_t i = 1; i < USB_MAX_ENDPOINTS; i++ )
+ {
+ if (hw_endpoint_get_by_num(i, TUSB_DIR_OUT)->hw_data_buf != NULL || hw_endpoint_get_by_num(i, TUSB_DIR_IN)->hw_data_buf != NULL)
+ {
+ reclaim_buffers = false;
+ break;
+ }
+ }
+ if (reclaim_buffers)
+ {
+ next_buffer_ptr = &usb_dpram->epx_data[0];
+ }
}
static void hw_endpoint_close(uint8_t ep_addr)
@@ -110,7 +127,6 @@ static void hw_endpoint_close(uint8_t ep_addr)
struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
_hw_endpoint_close(ep);
}
-#endif
static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
{
@@ -172,7 +188,7 @@ static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_by
hw_endpoint_xfer_start(ep, buffer, total_bytes);
}
-static void hw_handle_buff_status(void)
+static void __tusb_irq_path_func(hw_handle_buff_status)(void)
{
uint32_t remaining_buffers = usb_hw->buf_status;
pico_trace("buf_status = 0x%08x\n", remaining_buffers);
@@ -201,7 +217,7 @@ static void hw_handle_buff_status(void)
}
}
-static void reset_ep0_pid(void)
+TU_ATTR_ALWAYS_INLINE static inline void reset_ep0_pid(void)
{
// If we have finished this transfer on EP0 set pid back to 1 for next
// setup transfer. Also clear a stall in case
@@ -213,7 +229,7 @@ static void reset_ep0_pid(void)
}
}
-static void reset_non_control_endpoints(void)
+static void __tusb_irq_path_func(reset_non_control_endpoints)(void)
{
// Disable all non-control
for ( uint8_t i = 0; i < USB_MAX_ENDPOINTS-1; i++ )
@@ -224,14 +240,34 @@ static void reset_non_control_endpoints(void)
// clear non-control hw endpoints
tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2*sizeof(hw_endpoint_t));
+
+ // reclaim buffer space
next_buffer_ptr = &usb_dpram->epx_data[0];
}
-static void dcd_rp2040_irq(void)
+static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
{
uint32_t const status = usb_hw->ints;
uint32_t handled = 0;
+ if (status & USB_INTF_DEV_SOF_BITS)
+ {
+ handled |= USB_INTF_DEV_SOF_BITS;
+
+ // disable SOF interrupt if it is used for RESUME in remote wakeup
+ if (!_sof_enable) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
+
+ dcd_event_sof(0, usb_hw->sof_rd & USB_SOF_RD_BITS, true);
+ }
+
+ // xfer events are handled before setup req. So if a transfer completes immediately
+ // before closing the EP, the events will be delivered in same order.
+ if (status & USB_INTS_BUFF_STATUS_BITS)
+ {
+ handled |= USB_INTS_BUFF_STATUS_BITS;
+ hw_handle_buff_status();
+ }
+
if (status & USB_INTS_SETUP_REQ_BITS)
{
handled |= USB_INTS_SETUP_REQ_BITS;
@@ -245,12 +281,6 @@ static void dcd_rp2040_irq(void)
usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
}
- if (status & USB_INTS_BUFF_STATUS_BITS)
- {
- handled |= USB_INTS_BUFF_STATUS_BITS;
- hw_handle_buff_status();
- }
-
#if FORCE_VBUS_DETECT == 0
// Since we force VBUS detect On, device will always think it is connected and
// couldn't distinguish between disconnect and suspend
@@ -340,7 +370,7 @@ void dcd_init (uint8_t rhport)
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
#endif
- irq_set_exclusive_handler(USBCTRL_IRQ, dcd_rp2040_irq);
+ irq_add_shared_handler(USBCTRL_IRQ, dcd_rp2040_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
// Init control endpoints
tu_memclr(hw_endpoints[0], 2*sizeof(hw_endpoint_t));
@@ -388,9 +418,13 @@ void dcd_set_address (__unused uint8_t rhport, __unused uint8_t dev_addr)
void dcd_remote_wakeup(__unused uint8_t rhport)
{
- pico_info("dcd_remote_wakeup %d\n", rhport);
- assert(rhport == 0);
- usb_hw_set->sie_ctrl = USB_SIE_CTRL_RESUME_BITS;
+ pico_info("dcd_remote_wakeup %d\n", rhport);
+ assert(rhport == 0);
+
+ // since RESUME interrupt is not triggered if we are the one initiate
+ // briefly enable SOF to notify usbd when bus is ready
+ usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
+ usb_hw_set->sie_ctrl = USB_SIE_CTRL_RESUME_BITS;
}
// disconnect by disabling internal pull-up resistor on D+/D-
@@ -407,6 +441,21 @@ void dcd_connect(__unused uint8_t rhport)
usb_hw_set->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+
+ _sof_enable = en;
+
+ if (en)
+ {
+ usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
+ }else
+ {
+ usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
+ }
+}
+
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
@@ -479,13 +528,12 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
- (void) ep_addr;
- // usbd.c says: In progress transfers on this EP may be delivered after this call
pico_trace("dcd_edpt_close %02x\n", ep_addr);
+ hw_endpoint_close(ep_addr);
}
-void dcd_int_handler(uint8_t rhport)
+void __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport)
{
(void) rhport;
dcd_rp2040_irq();
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index 768cccc86..10237d1f9 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -27,7 +27,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && CFG_TUSB_MCU == OPT_MCU_RP2040
+#if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUH_RPI_PIO_USB
#include "pico.h"
#include "rp2040_usb.h"
@@ -40,7 +40,8 @@
#include "host/hcd.h"
#include "host/usbh.h"
-#define ROOT_PORT 0
+// port 0 is native USB port, other is counted as software PIO
+#define RHPORT_NATIVE 0
//--------------------------------------------------------------------+
// Low level rp2040 controller functions
@@ -78,7 +79,7 @@ static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
return NULL;
}
-static inline uint8_t dev_speed(void)
+TU_ATTR_ALWAYS_INLINE static inline uint8_t dev_speed(void)
{
return (usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS) >> USB_SIE_STATUS_SPEED_LSB;
}
@@ -90,7 +91,7 @@ static bool need_pre(uint8_t dev_addr)
return hcd_port_speed_get(0) != tuh_speed_get(dev_addr);
}
-static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result)
+static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_result_t xfer_result)
{
// Mark transfer as done before we tell the tinyusb stack
uint8_t dev_addr = ep->dev_addr;
@@ -100,9 +101,11 @@ static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result)
hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true);
}
-static void _handle_buff_status_bit(uint bit, struct hw_endpoint *ep)
+static void __tusb_irq_path_func(_handle_buff_status_bit)(uint bit, struct hw_endpoint *ep)
{
usb_hw_clear->buf_status = bit;
+ // EP may have been stalled?
+ assert(ep->active);
bool done = hw_endpoint_xfer_continue(ep);
if (done)
{
@@ -110,7 +113,7 @@ static void _handle_buff_status_bit(uint bit, struct hw_endpoint *ep)
}
}
-static void hw_handle_buff_status(void)
+static void __tusb_irq_path_func(hw_handle_buff_status)(void)
{
uint32_t remaining_buffers = usb_hw->buf_status;
pico_trace("buf_status 0x%08x\n", remaining_buffers);
@@ -135,20 +138,25 @@ static void hw_handle_buff_status(void)
_handle_buff_status_bit(bit, ep);
}
- // Check interrupt endpoints
+ // Check "interrupt" (asynchronous) endpoints for both IN and OUT
for (uint i = 1; i <= USB_HOST_INTERRUPT_ENDPOINTS && remaining_buffers; i++)
{
- // EPX is bit 0
- // IEP1 is bit 2
- // IEP2 is bit 4
- // IEP3 is bit 6
+ // EPX is bit 0 & 1
+ // IEP1 IN is bit 2
+ // IEP1 OUT is bit 3
+ // IEP2 IN is bit 4
+ // IEP2 OUT is bit 5
+ // IEP3 IN is bit 6
+ // IEP3 OUT is bit 7
// etc
- bit = 1 << (i*2);
-
- if (remaining_buffers & bit)
+ for(uint j = 0; j < 2; j++)
{
- remaining_buffers &= ~bit;
- _handle_buff_status_bit(bit, &ep_pool[i]);
+ bit = 1 << (i*2+j);
+ if (remaining_buffers & bit)
+ {
+ remaining_buffers &= ~bit;
+ _handle_buff_status_bit(bit, &ep_pool[i]);
+ }
}
}
@@ -158,13 +166,15 @@ static void hw_handle_buff_status(void)
}
}
-static void hw_trans_complete(void)
+static void __tusb_irq_path_func(hw_trans_complete)(void)
{
if (usb_hw->sie_ctrl & USB_SIE_CTRL_SEND_SETUP_BITS)
{
pico_trace("Sent setup packet\n");
struct hw_endpoint *ep = &epx;
assert(ep->active);
+ // Set transferred length to 8 for a setup packet
+ ep->xferred_len = 8;
hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
}
else
@@ -174,7 +184,7 @@ static void hw_trans_complete(void)
}
}
-static void hcd_rp2040_irq(void)
+static void __tusb_irq_path_func(hcd_rp2040_irq)(void)
{
uint32_t status = usb_hw->ints;
uint32_t handled = 0;
@@ -185,17 +195,29 @@ static void hcd_rp2040_irq(void)
if (dev_speed())
{
- hcd_event_device_attach(ROOT_PORT, true);
+ hcd_event_device_attach(RHPORT_NATIVE, true);
}
else
{
- hcd_event_device_remove(ROOT_PORT, true);
+ hcd_event_device_remove(RHPORT_NATIVE, true);
}
// Clear speed change interrupt
usb_hw_clear->sie_status = USB_SIE_STATUS_SPEED_BITS;
}
+ if (status & USB_INTS_STALL_BITS)
+ {
+ // We have rx'd a stall from the device
+ // NOTE THIS SHOULD HAVE PRIORITY OVER BUFF_STATUS
+ // AND TRANS_COMPLETE as the stall is an alternative response
+ // to one of those events
+ pico_trace("Stall REC\n");
+ handled |= USB_INTS_STALL_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_STALL_REC_BITS;
+ hw_xfer_complete(&epx, XFER_RESULT_STALLED);
+ }
+
if (status & USB_INTS_BUFF_STATUS_BITS)
{
handled |= USB_INTS_BUFF_STATUS_BITS;
@@ -211,15 +233,6 @@ static void hcd_rp2040_irq(void)
hw_trans_complete();
}
- if (status & USB_INTS_STALL_BITS)
- {
- // We have rx'd a stall from the device
- pico_trace("Stall REC\n");
- handled |= USB_INTS_STALL_BITS;
- usb_hw_clear->sie_status = USB_SIE_STATUS_STALL_REC_BITS;
- hw_xfer_complete(&epx, XFER_RESULT_STALLED);
- }
-
if (status & USB_INTS_ERROR_RX_TIMEOUT_BITS)
{
handled |= USB_INTS_ERROR_RX_TIMEOUT_BITS;
@@ -239,6 +252,12 @@ static void hcd_rp2040_irq(void)
}
}
+void __tusb_irq_path_func(hcd_int_handler)(uint8_t rhport)
+{
+ (void) rhport;
+ hcd_rp2040_irq();
+}
+
static struct hw_endpoint *_next_free_interrupt_ep(void)
{
struct hw_endpoint *ep = NULL;
@@ -248,7 +267,7 @@ static struct hw_endpoint *_next_free_interrupt_ep(void)
if (!ep->configured)
{
// Will be configured by _hw_endpoint_init / _hw_endpoint_allocate
- ep->interrupt_num = i - 1;
+ ep->interrupt_num = (uint8_t) (i - 1);
return ep;
}
}
@@ -259,10 +278,12 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
{
struct hw_endpoint *ep = NULL;
- if (transfer_type == TUSB_XFER_INTERRUPT)
+ if (transfer_type != TUSB_XFER_CONTROL)
{
+ // Note: even though datasheet name these "Interrupt" endpoints. These are actually
+ // "Asynchronous" endpoints and can be used for other type such as: Bulk (ISO need confirmation)
ep = _next_free_interrupt_ep();
- pico_info("Allocate interrupt ep %d\n", ep->interrupt_num);
+ pico_info("Allocate %s ep %d\n", tu_edpt_type_str(transfer_type), ep->interrupt_num);
assert(ep);
ep->buffer_control = &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl;
ep->endpoint_control = &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl;
@@ -283,7 +304,7 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
return ep;
}
-static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint wMaxPacketSize, uint8_t transfer_type, uint8_t bmInterval)
+static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type, uint8_t bmInterval)
{
// Already has data buffer, endpoint control, and buffer control allocated at this point
assert(ep->endpoint_control);
@@ -315,22 +336,27 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
| EP_CTRL_INTERRUPT_PER_BUFFER
| (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB)
| dpram_offset;
- ep_reg |= bmInterval ? (bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB : 0;
+ if (bmInterval)
+ {
+ ep_reg |= (uint32_t) ((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB);
+ }
*ep->endpoint_control = ep_reg;
pico_trace("endpoint control (0x%p) <- 0x%x\n", ep->endpoint_control, ep_reg);
ep->configured = true;
- if (bmInterval)
+ if (ep != &epx)
{
- // This is an interrupt endpoint
- // so need to set up interrupt endpoint address control register with:
- // device address
- // endpoint number / direction
- // preamble
- uint32_t reg = dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB);
- // Assert the interrupt endpoint is IN_TO_HOST
- // TODO Interrupt can also be OUT
- assert(dir == TUSB_DIR_IN);
+ // Endpoint has its own addr_endp and interrupt bits to be setup!
+ // This is an interrupt/async endpoint. so need to set up ADDR_ENDP register with:
+ // - device address
+ // - endpoint number / direction
+ // - preamble
+ uint32_t reg = (uint32_t) (dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB));
+
+ if (dir == TUSB_DIR_OUT)
+ {
+ reg |= USB_ADDR_ENDP1_INTEP_DIR_BITS;
+ }
if (need_pre(dev_addr))
{
@@ -351,71 +377,101 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
//--------------------------------------------------------------------+
bool hcd_init(uint8_t rhport)
{
- pico_trace("hcd_init %d\n", rhport);
- assert(rhport == 0);
+ (void) rhport;
+ pico_trace("hcd_init %d\n", rhport);
+ assert(rhport == 0);
- // Reset any previous state
- rp2040_usb_init();
+ // Reset any previous state
+ rp2040_usb_init();
- // Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En)
- usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
+ // Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En)
+ usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
- irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq);
+ // Remove shared irq if it was previously added so as not to fill up shared irq slots
+ irq_remove_handler(USBCTRL_IRQ, hcd_rp2040_irq);
- // clear epx and interrupt eps
- memset(&ep_pool, 0, sizeof(ep_pool));
+ irq_add_shared_handler(USBCTRL_IRQ, hcd_rp2040_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
- // Enable in host mode with SOF / Keep alive on
- usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS;
- usb_hw->sie_ctrl = SIE_CTRL_BASE;
- usb_hw->inte = USB_INTE_BUFF_STATUS_BITS |
- USB_INTE_HOST_CONN_DIS_BITS |
- USB_INTE_HOST_RESUME_BITS |
- USB_INTE_STALL_BITS |
- USB_INTE_TRANS_COMPLETE_BITS |
- USB_INTE_ERROR_RX_TIMEOUT_BITS |
- USB_INTE_ERROR_DATA_SEQ_BITS ;
+ // clear epx and interrupt eps
+ memset(&ep_pool, 0, sizeof(ep_pool));
- return true;
+ // Enable in host mode with SOF / Keep alive on
+ usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS;
+ usb_hw->sie_ctrl = SIE_CTRL_BASE;
+ usb_hw->inte = USB_INTE_BUFF_STATUS_BITS |
+ USB_INTE_HOST_CONN_DIS_BITS |
+ USB_INTE_HOST_RESUME_BITS |
+ USB_INTE_STALL_BITS |
+ USB_INTE_TRANS_COMPLETE_BITS |
+ USB_INTE_ERROR_RX_TIMEOUT_BITS |
+ USB_INTE_ERROR_DATA_SEQ_BITS ;
+
+ return true;
}
void hcd_port_reset(uint8_t rhport)
{
- pico_trace("hcd_port_reset\n");
- assert(rhport == 0);
- // TODO: Nothing to do here yet. Perhaps need to reset some state?
+ (void) rhport;
+ pico_trace("hcd_port_reset\n");
+ assert(rhport == 0);
+ // TODO: Nothing to do here yet. Perhaps need to reset some state?
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ (void) rhport;
}
bool hcd_port_connect_status(uint8_t rhport)
{
- pico_trace("hcd_port_connect_status\n");
- assert(rhport == 0);
- return usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS;
+ (void) rhport;
+ pico_trace("hcd_port_connect_status\n");
+ assert(rhport == 0);
+ return usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS;
}
tusb_speed_t hcd_port_speed_get(uint8_t rhport)
{
- assert(rhport == 0);
- // TODO: Should enumval this register
- switch (dev_speed())
- {
- case 1:
- return TUSB_SPEED_LOW;
- case 2:
- return TUSB_SPEED_FULL;
- default:
- panic("Invalid speed\n");
- return TUSB_SPEED_INVALID;
- }
+ (void) rhport;
+ assert(rhport == 0);
+ // TODO: Should enumval this register
+ switch (dev_speed())
+ {
+ case 1:
+ return TUSB_SPEED_LOW;
+ case 2:
+ return TUSB_SPEED_FULL;
+ default:
+ panic("Invalid speed\n");
+ return TUSB_SPEED_INVALID;
+ }
}
// Close all opened endpoint belong to this device
void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
{
- (void) rhport;
- (void) dev_addr;
+ pico_trace("hcd_device_close %d\n", dev_addr);
+ (void) rhport;
+
+ if (dev_addr == 0) return;
- pico_trace("hcd_device_close %d\n", dev_addr);
+ for (size_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++)
+ {
+ hw_endpoint_t* ep = &ep_pool[i];
+
+ if (ep->dev_addr == dev_addr && ep->configured)
+ {
+ // in case it is an interrupt endpoint, disable it
+ usb_hw_clear->int_ep_ctrl = (1 << (ep->interrupt_num + 1));
+ usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = 0;
+
+ // unconfigure the endpoint
+ ep->configured = false;
+ *ep->endpoint_control = 0;
+ *ep->buffer_control = 0;
+ hw_endpoint_reset_transfer(ep);
+ }
+ }
}
uint32_t hcd_frame_number(uint8_t rhport)
@@ -426,15 +482,17 @@ uint32_t hcd_frame_number(uint8_t rhport)
void hcd_int_enable(uint8_t rhport)
{
- assert(rhport == 0);
- irq_set_enabled(USBCTRL_IRQ, true);
+ (void) rhport;
+ assert(rhport == 0);
+ irq_set_enabled(USBCTRL_IRQ, true);
}
void hcd_int_disable(uint8_t rhport)
{
- // todo we should check this is disabling from the correct core; note currently this is never called
- assert(rhport == 0);
- irq_set_enabled(USBCTRL_IRQ, false);
+ (void) rhport;
+ // todo we should check this is disabling from the correct core; note currently this is never called
+ assert(rhport == 0);
+ irq_set_enabled(USBCTRL_IRQ, false);
}
//--------------------------------------------------------------------+
@@ -449,6 +507,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
// Allocated differently based on if it's an interrupt endpoint or not
struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
+ TU_ASSERT(ep);
_hw_endpoint_init(ep,
dev_addr,
@@ -471,7 +530,11 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
// Get appropriate ep. Either EPX or interrupt endpoint
struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
- assert(ep);
+
+ TU_ASSERT(ep);
+
+ // EP should be inactive
+ assert(!ep->active);
// Control endpoint can change direction 0x00 <-> 0x80
if ( ep_addr != ep->ep_addr )
@@ -490,7 +553,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
// That has set up buffer control, endpoint control etc
// for host we have to initiate the transfer
- usb_hw->dev_addr_ctrl = dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB);
+ usb_hw->dev_addr_ctrl = (uint32_t) (dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB));
uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | SIE_CTRL_BASE |
(ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS);
@@ -511,10 +574,17 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
(void) rhport;
// Copy data into setup packet buffer
- memcpy((void*)&usbh_dpram->setup_packet[0], setup_packet, 8);
+ for(uint8_t i=0; i<8; i++)
+ {
+ usbh_dpram->setup_packet[i] = setup_packet[i];
+ }
// Configure EP0 struct with setup info for the trans complete
struct hw_endpoint *ep = _hw_endpoint_allocate(0);
+ TU_ASSERT(ep);
+
+ // EPX should be inactive
+ assert(!ep->active);
// EP0 out
_hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
@@ -535,21 +605,6 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
return true;
}
-
-//bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
-//{
-// // EPX is shared, so multiple device addresses and endpoint addresses share that
-// // so if any transfer is active on epx, we are busy. Interrupt endpoints have their own
-// // EPX so ep->active will only be busy if there is a pending transfer on that interrupt endpoint
-// // on that device
-// pico_trace("hcd_edpt_busy dev addr %d ep_addr 0x%x\n", dev_addr, ep_addr);
-// struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
-// assert(ep);
-// bool busy = ep->active;
-// pico_trace("busy == %d\n", busy);
-// return busy;
-//}
-
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
{
(void) dev_addr;
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index c9e2f6b26..25c013bd2 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -38,7 +38,7 @@ const char *ep_dir_string[] = {
"in",
};
-static inline void _hw_endpoint_lock_update(__unused struct hw_endpoint * ep, __unused int delta) {
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_lock_update(__unused struct hw_endpoint * ep, __unused int delta) {
// todo add critsec as necessary to prevent issues between worker and IRQ...
// note that this is perhaps as simple as disabling IRQs because it would make
// sense to have worker and IRQ on same core, however I think using critsec is about equivalent.
@@ -58,14 +58,20 @@ void rp2040_usb_init(void)
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
// Clear any previous state just in case
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#if __GNUC__ > 6
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+#endif
memset(usb_hw, 0, sizeof(*usb_hw));
memset(usb_dpram, 0, sizeof(*usb_dpram));
+#pragma GCC diagnostic pop
// Mux the controller to the onboard usb phy
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
}
-void hw_endpoint_reset_transfer(struct hw_endpoint *ep)
+void __tusb_irq_path_func(hw_endpoint_reset_transfer)(struct hw_endpoint *ep)
{
ep->active = false;
ep->remaining_len = 0;
@@ -73,7 +79,7 @@ void hw_endpoint_reset_transfer(struct hw_endpoint *ep)
ep->user_buf = 0;
}
-void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask) {
+void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask) {
uint32_t value = 0;
if (and_mask) {
value = *ep->buffer_control & and_mask;
@@ -87,7 +93,7 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m
*ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL;
// 12 cycle delay.. (should be good for 48*12Mhz = 576Mhz)
// Don't need delay in host mode as host is in charge
-#if !TUSB_OPT_HOST_ENABLED
+#if !CFG_TUH_ENABLED
__asm volatile (
"b 1f\n"
"1: b 1f\n"
@@ -104,7 +110,7 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m
}
// prepare buffer, return buffer control
-static uint32_t prepare_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
+static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint *ep, uint8_t buf_id)
{
uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
ep->remaining_len = (uint16_t)(ep->remaining_len - buflen);
@@ -139,7 +145,7 @@ static uint32_t prepare_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
}
// Prepare buffer control register value
-static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
+static void __tusb_irq_path_func(_hw_endpoint_start_next_buffer)(struct hw_endpoint *ep)
{
uint32_t ep_ctrl = *ep->endpoint_control;
@@ -170,7 +176,7 @@ static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
*ep->endpoint_control = ep_ctrl;
- TU_LOG(3, " Prepare BufCtrl: [0] = 0x%04u [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
+ TU_LOG(3, " Prepare BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
// Finally, write to buffer_control which will trigger the transfer
// the next time the controller polls this dpram address
@@ -201,7 +207,7 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t to
}
// sync endpoint buffer and return transferred bytes
-static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
+static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint *ep, uint8_t buf_id)
{
uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
if (buf_id) buf_ctrl = buf_ctrl >> 16;
@@ -237,13 +243,13 @@ static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
return xferred_bytes;
}
-static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep)
+static void __tusb_irq_path_func(_hw_endpoint_xfer_sync) (struct hw_endpoint *ep)
{
// Update hw endpoint struct with info from hardware
// after a buff status interrupt
uint32_t __unused buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
- TU_LOG(3, " Sync BufCtrl: [0] = 0x%04u [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
+ TU_LOG(3, " Sync BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
// always sync buffer 0
uint16_t buf0_bytes = sync_ep_buffer(ep, 0);
@@ -281,20 +287,20 @@ static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep)
usb_hw->abort &= ~TU_BIT(ep_id);
TU_LOG(3, "----SHORT PACKET buffer0 on EP %02X:\r\n", ep->ep_addr);
- TU_LOG(3, " BufCtrl: [0] = 0x%04u [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
+ TU_LOG(3, " BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
#endif
}
}
}
// Returns true if transfer is complete
-bool hw_endpoint_xfer_continue(struct hw_endpoint *ep)
+bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint *ep)
{
_hw_endpoint_lock_update(ep, 1);
// Part way through a transfer
if (!ep->active)
{
- panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string);
+ panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
}
// Update EP struct from hardware state
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
index a9cf1dd07..c72dae64c 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.h
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -16,6 +16,15 @@
#define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX PICO_RP2040_USB_DEVICE_ENUMERATION_FIX
#endif
+#ifndef PICO_RP2040_USB_FAST_IRQ
+#define PICO_RP2040_USB_FAST_IRQ 0
+#endif
+
+#if PICO_RP2040_USB_FAST_IRQ
+#define __tusb_irq_path_func(x) __no_inline_not_in_flash_func(x)
+#else
+#define __tusb_irq_path_func(x) x
+#endif
#define pico_info(...) TU_LOG(2, __VA_ARGS__)
#define pico_trace(...) TU_LOG(3, __VA_ARGS__)
@@ -56,7 +65,7 @@ typedef struct hw_endpoint
// Interrupt, bulk, etc
uint8_t transfer_type;
-#if TUSB_OPT_HOST_ENABLED
+#if CFG_TUH_ENABLED
// Only needed for host
uint8_t dev_addr;
@@ -72,16 +81,20 @@ bool hw_endpoint_xfer_continue(struct hw_endpoint *ep);
void hw_endpoint_reset_transfer(struct hw_endpoint *ep);
void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask);
-static inline uint32_t _hw_endpoint_buffer_control_get_value32(struct hw_endpoint *ep) {
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t _hw_endpoint_buffer_control_get_value32(struct hw_endpoint *ep) {
return *ep->buffer_control;
}
-static inline void _hw_endpoint_buffer_control_set_value32(struct hw_endpoint *ep, uint32_t value) {
+
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_value32(struct hw_endpoint *ep, uint32_t value) {
return _hw_endpoint_buffer_control_update32(ep, 0, value);
}
-static inline void _hw_endpoint_buffer_control_set_mask32(struct hw_endpoint *ep, uint32_t value) {
+
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_mask32(struct hw_endpoint *ep, uint32_t value) {
return _hw_endpoint_buffer_control_update32(ep, ~value, value);
}
-static inline void _hw_endpoint_buffer_control_clear_mask32(struct hw_endpoint *ep, uint32_t value) {
+
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_clear_mask32(struct hw_endpoint *ep, uint32_t value) {
return _hw_endpoint_buffer_control_update32(ep, ~value, 0);
}
diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c
index ae7d2fd0c..fa87c9f4d 100644
--- a/src/portable/renesas/usba/dcd_usba.c
+++ b/src/portable/renesas/usba/dcd_usba.c
@@ -31,7 +31,7 @@
// We disable SOF for now until needed later on
#define USE_SOF 0
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X || \
+#if CFG_TUD_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X || \
CFG_TUSB_MCU == OPT_MCU_RX65X || \
CFG_TUSB_MCU == OPT_MCU_RX72N )
#include "device/dcd.h"
@@ -494,7 +494,11 @@ static bool process_pipe_xfer(int buffer_type, uint8_t ep_addr, void* buffer, ui
while (USB0.D0FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
}
} else {
+#if defined(__CCRX__)
+ __evenaccess volatile reg_pipetre_t *pt = get_pipetre(num);
+#else
volatile reg_pipetre_t *pt = get_pipetre(num);
+#endif
if (pt) {
const unsigned mps = edpt_max_packet_size(num);
volatile uint16_t *ctr = get_pipectr(num);
@@ -683,6 +687,14 @@ void dcd_disconnect(uint8_t rhport)
USB0.SYSCFG.BIT.DPRPU = 0;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -715,11 +727,11 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
*ctr = 0;
unsigned cfg = (dir << 4) | epn;
if (xfer == TUSB_XFER_BULK) {
- cfg |= USB_PIPECFG_BULK | USB_PIPECFG_SHTNAK | USB_PIPECFG_DBLB;
+ cfg |= (USB_PIPECFG_BULK | USB_PIPECFG_SHTNAK | USB_PIPECFG_DBLB);
} else if (xfer == TUSB_XFER_INTERRUPT) {
cfg |= USB_PIPECFG_INT;
} else {
- cfg |= USB_PIPECFG_ISO | USB_PIPECFG_DBLB;
+ cfg |= (USB_PIPECFG_ISO | USB_PIPECFG_DBLB);
}
USB0.PIPECFG.WORD = cfg;
USB0.BRDYSTS.WORD = 0x1FFu ^ TU_BIT(num);
diff --git a/src/portable/renesas/usba/hcd_usba.c b/src/portable/renesas/usba/hcd_usba.c
new file mode 100644
index 000000000..5246ecb94
--- /dev/null
+++ b/src/portable/renesas/usba/hcd_usba.c
@@ -0,0 +1,875 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji Kitayama
+ * Portions copyrighted (c) 2021 Roland Winistoerfer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X || \
+ CFG_TUSB_MCU == OPT_MCU_RX65X || \
+ CFG_TUSB_MCU == OPT_MCU_RX72N )
+#include "host/hcd.h"
+#include "iodefine.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+#define SYSTEM_PRCR_PRC1 (1<<1)
+#define SYSTEM_PRCR_PRKEY (0xA5u<<8)
+
+#define USB_DVSTCTR0_LOW (1u)
+#define USB_DVSTCTR0_FULL (2u)
+
+#define USB_FIFOSEL_TX ((uint16_t)(1u<<5))
+#define USB_FIFOSEL_BIGEND ((uint16_t)(1u<<8))
+#define USB_FIFOSEL_MBW_8 ((uint16_t)(0u<<10))
+#define USB_FIFOSEL_MBW_16 ((uint16_t)(1u<<10))
+#define USB_IS0_CTSQ ((uint16_t)(7u))
+#define USB_IS0_DVSQ ((uint16_t)(7u<<4))
+#define USB_IS0_VALID ((uint16_t)(1u<<3))
+#define USB_IS0_BRDY ((uint16_t)(1u<<8))
+#define USB_IS0_NRDY ((uint16_t)(1u<<9))
+#define USB_IS0_BEMP ((uint16_t)(1u<<10))
+#define USB_IS0_CTRT ((uint16_t)(1u<<11))
+#define USB_IS0_DVST ((uint16_t)(1u<<12))
+#define USB_IS0_SOFR ((uint16_t)(1u<<13))
+#define USB_IS0_RESM ((uint16_t)(1u<<14))
+#define USB_IS0_VBINT ((uint16_t)(1u<<15))
+#define USB_IS1_SACK ((uint16_t)(1u<<4))
+#define USB_IS1_SIGN ((uint16_t)(1u<<5))
+#define USB_IS1_EOFERR ((uint16_t)(1u<<6))
+#define USB_IS1_ATTCH ((uint16_t)(1u<<11))
+#define USB_IS1_DTCH ((uint16_t)(1u<<12))
+#define USB_IS1_BCHG ((uint16_t)(1u<<14))
+#define USB_IS1_OVRCR ((uint16_t)(1u<<15))
+
+#define USB_IS0_CTSQ_MSK (7u)
+#define USB_IS0_CTSQ_SETUP (1u)
+#define USB_IS0_DVSQ_DEF (1u<<4)
+#define USB_IS0_DVSQ_ADDR (2u<<4)
+#define USB_IS0_DVSQ_SUSP0 (4u<<4)
+#define USB_IS0_DVSQ_SUSP1 (5u<<4)
+#define USB_IS0_DVSQ_SUSP2 (6u<<4)
+#define USB_IS0_DVSQ_SUSP3 (7u<<4)
+
+#define USB_PIPECTR_PID_MSK (3u)
+#define USB_PIPECTR_PID_NAK (0u)
+#define USB_PIPECTR_PID_BUF (1u)
+#define USB_PIPECTR_PID_STALL (2u)
+#define USB_PIPECTR_CCPL (1u<<2)
+#define USB_PIPECTR_SQMON (1u<<6)
+#define USB_PIPECTR_SQCLR (1u<<8)
+#define USB_PIPECTR_ACLRM (1u<<9)
+#define USB_PIPECTR_INBUFM (1u<<14)
+#define USB_PIPECTR_BSTS (1u<<15)
+
+#define USB_FIFOCTR_DTLN (0x1FF)
+#define USB_FIFOCTR_FRDY (1u<<13)
+#define USB_FIFOCTR_BCLR (1u<<14)
+#define USB_FIFOCTR_BVAL (1u<<15)
+
+#define USB_PIPECFG_SHTNAK (1u<<7)
+#define USB_PIPECFG_DBLB (1u<<9)
+#define USB_PIPECFG_BULK (1u<<14)
+#define USB_PIPECFG_ISO (3u<<14)
+#define USB_PIPECFG_INT (2u<<14)
+
+#define USB_DEVADD_LOW (1u<<6)
+#define USB_DEVADD_FULL (2u<<6)
+
+#define FIFO_REQ_CLR (1u)
+#define FIFO_COMPLETE (1u<<1)
+
+// Start of definition of packed structs (used by the CCRX toolchain)
+TU_ATTR_PACKED_BEGIN
+TU_ATTR_BIT_FIELD_ORDER_BEGIN
+
+typedef struct {
+ union {
+ struct {
+ uint16_t : 8;
+ uint16_t TRCLR: 1;
+ uint16_t TRENB: 1;
+ uint16_t : 0;
+ };
+ uint16_t TRE;
+ };
+ uint16_t TRN;
+} reg_pipetre_t;
+
+typedef union {
+ struct {
+ volatile uint16_t u8: 8;
+ volatile uint16_t : 0;
+ };
+ volatile uint16_t u16;
+} hw_fifo_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ void *buf; /* the start address of a transfer data buffer */
+ uint16_t length; /* the number of bytes in the buffer */
+ uint16_t remaining; /* the number of bytes remaining in the buffer */
+ struct {
+ uint32_t ep : 8; /* an assigned endpoint address */
+ uint32_t dev : 8; /* an assigned device address */
+ uint32_t ff : 1; /* `buf` is TU_FUFO or POD */
+ uint32_t : 0;
+ };
+} pipe_state_t;
+
+TU_ATTR_PACKED_END // End of definition of packed structs (used by the CCRX toolchain)
+TU_ATTR_BIT_FIELD_ORDER_END
+
+typedef struct
+{
+ bool need_reset; /* The device has not been reset after connection. */
+ pipe_state_t pipe[10];
+ uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
+ uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
+} hcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+static hcd_data_t _hcd;
+
+static uint32_t disable_interrupt(void)
+{
+ uint32_t pswi;
+#if defined(__CCRX__)
+ pswi = get_psw() & 0x010000;
+ clrpsw_i();
+#else
+ pswi = __builtin_rx_mvfc(0) & 0x010000;
+ __builtin_rx_clrpsw('I');
+#endif
+ return pswi;
+}
+
+static void enable_interrupt(uint32_t pswi)
+{
+#if defined(__CCRX__)
+ set_psw(get_psw() | pswi);
+#else
+ __builtin_rx_mvtc(0, __builtin_rx_mvfc(0) | pswi);
+#endif
+}
+
+static unsigned find_pipe(unsigned xfer)
+{
+ switch (xfer) {
+ case TUSB_XFER_ISOCHRONOUS:
+ for (int i = 1; i <= 2; ++i) {
+ if (0 == _hcd.pipe[i].ep) return i;
+ }
+ break;
+ case TUSB_XFER_BULK:
+ for (int i = 3; i <= 5; ++i) {
+ if (0 == _hcd.pipe[i].ep) return i;
+ }
+ for (int i = 1; i <= 1; ++i) {
+ if (0 == _hcd.pipe[i].ep) return i;
+ }
+ break;
+ case TUSB_XFER_INTERRUPT:
+ for (int i = 6; i <= 9; ++i) {
+ if (0 == _hcd.pipe[i].ep) return i;
+ }
+ break;
+ default:
+ /* No support for control transfer */
+ break;
+ }
+ return 0;
+}
+
+static volatile uint16_t* get_pipectr(unsigned num)
+{
+ volatile uint16_t *ctr = NULL;
+ if (num) {
+ ctr = (volatile uint16_t*)&USB0.PIPE1CTR.WORD;
+ ctr += num - 1;
+ } else {
+ ctr = (volatile uint16_t*)&USB0.DCPCTR.WORD;
+ }
+ return ctr;
+}
+
+static volatile reg_pipetre_t* get_pipetre(unsigned num)
+{
+ volatile reg_pipetre_t* tre = NULL;
+ if ((1 <= num) && (num <= 5)) {
+ tre = (volatile reg_pipetre_t*)&USB0.PIPE1TRE.WORD;
+ tre += num - 1;
+ }
+ return tre;
+}
+
+static volatile uint16_t* addr_to_pipectr(uint8_t dev_addr, unsigned ep_addr)
+{
+ volatile uint16_t *ctr = NULL;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ if (epn) {
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned num = _hcd.ep[dev_addr][dir_in][epn - 1];
+ if (num) {
+ ctr = (volatile uint16_t*)&USB0.PIPE1CTR.WORD;
+ ctr += num - 1;
+ }
+ } else {
+ ctr = (volatile uint16_t*)&USB0.DCPCTR.WORD;
+ }
+ return ctr;
+}
+
+static unsigned edpt0_max_packet_size(void)
+{
+ return USB0.DCPMAXP.BIT.MXPS;
+}
+
+static unsigned edpt_max_packet_size(unsigned num)
+{
+ USB0.PIPESEL.WORD = num;
+ return USB0.PIPEMAXP.BIT.MXPS;
+}
+
+static inline void pipe_wait_for_ready(unsigned num)
+{
+ while (USB0.D0FIFOSEL.BIT.CURPIPE != num) ;
+ while (!USB0.D0FIFOCTR.BIT.FRDY) ;
+}
+
+static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 2) {
+ reg->u16 = *(const uint16_t *)addr;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ reg->u8 = *(const uint8_t *)addr;
+ ++addr;
+ }
+}
+
+static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ uint8_t *p = (uint8_t*)buf;
+ volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */
+ while (len--) *p++ = *reg;
+}
+
+static bool pipe0_xfer_in(void)
+{
+ pipe_state_t *pipe = &_hcd.pipe[0];
+ const unsigned rem = pipe->remaining;
+
+ const unsigned mps = edpt0_max_packet_size();
+ const unsigned vld = USB0.CFIFOCTR.BIT.DTLN;
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ USB0.DCPCTR.WORD = USB_PIPECTR_PID_NAK;
+ pipe_read_packet(buf, (volatile void*)&USB0.CFIFO.WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ if (len < mps) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BCLR;
+ pipe->remaining = rem - len;
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return true;
+ }
+ USB0.DCPCTR.WORD = USB_PIPECTR_PID_BUF;
+ return false;
+}
+
+static bool pipe0_xfer_out(void)
+{
+ pipe_state_t *pipe = &_hcd.pipe[0];
+ const unsigned rem = pipe->remaining;
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+ const unsigned mps = edpt0_max_packet_size();
+ const unsigned len = TU_MIN(mps, rem);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, (volatile void*)&USB0.CFIFO.WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ if (len < mps) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL;
+ pipe->remaining = rem - len;
+ return false;
+}
+
+static bool pipe_xfer_in(unsigned num)
+{
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ const unsigned rem = pipe->remaining;
+
+ USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_8;
+ const unsigned mps = edpt_max_packet_size(num);
+ pipe_wait_for_ready(num);
+ const unsigned vld = USB0.D0FIFOCTR.BIT.DTLN;
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_read_packet(buf, (volatile void*)&USB0.D0FIFO.WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ if (len < mps) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BCLR;
+ USB0.D0FIFOSEL.WORD = 0;
+ while (USB0.D0FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
+ pipe->remaining = rem - len;
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return NULL != buf;
+ }
+ return false;
+}
+
+static bool pipe_xfer_out(unsigned num)
+{
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ const unsigned rem = pipe->remaining;
+
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+
+ USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_16 | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? USB_FIFOSEL_BIGEND : 0);
+ const unsigned mps = edpt_max_packet_size(num);
+ pipe_wait_for_ready(num);
+ const unsigned len = TU_MIN(rem, mps);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, (volatile void*)&USB0.D0FIFO.WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ if (len < mps) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL;
+ USB0.D0FIFOSEL.WORD = 0;
+ while (USB0.D0FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
+ pipe->remaining = rem - len;
+ return false;
+}
+
+static bool process_pipe0_xfer(uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
+{
+ (void)dev_addr;
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+
+ /* configure fifo direction and access unit settings */
+ if (dir_in) { /* IN, a byte */
+ USB0.CFIFOSEL.WORD = USB_FIFOSEL_MBW_8;
+ while (USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX) ;
+ } else { /* OUT, 2 bytes */
+ USB0.CFIFOSEL.WORD = USB_FIFOSEL_TX | USB_FIFOSEL_MBW_16 | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? USB_FIFOSEL_BIGEND : 0);
+ while (!(USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX)) ;
+ }
+
+ pipe_state_t *pipe = &_hcd.pipe[0];
+ pipe->ep = ep_addr;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ if (buflen) {
+ pipe->buf = buffer;
+ if (!dir_in) { /* OUT */
+ TU_ASSERT(USB0.DCPCTR.BIT.BSTS && (USB0.USBREQ.WORD & 0x80));
+ pipe0_xfer_out();
+ }
+ } else { /* ZLP */
+ pipe->buf = NULL;
+ if (!dir_in) { /* OUT */
+ USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL;
+ }
+ if (dir_in == USB0.DCPCFG.BIT.DIR) {
+ TU_ASSERT(USB_PIPECTR_PID_NAK == USB0.DCPCTR.BIT.PID);
+ USB0.DCPCTR.BIT.SQSET = 1;
+ USB0.DCPCFG.BIT.DIR = dir_in ^ 1;
+ }
+ }
+ USB0.DCPCTR.WORD = USB_PIPECTR_PID_BUF;
+ return true;
+}
+
+static bool process_pipe_xfer(uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned num = _hcd.ep[dev_addr - 1][dir_in][epn - 1];
+
+ TU_ASSERT(num);
+
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ pipe->buf = buffer;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ if (!dir_in) { /* OUT */
+ if (buflen) {
+ pipe_xfer_out(num);
+ } else { /* ZLP */
+ USB0.D0FIFOSEL.WORD = num;
+ pipe_wait_for_ready(num);
+ USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL;
+ USB0.D0FIFOSEL.WORD = 0;
+ while (USB0.D0FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
+ }
+ } else {
+ volatile uint16_t *ctr = get_pipectr(num);
+ volatile reg_pipetre_t *pt = get_pipetre(num);
+ if (pt) {
+ const unsigned mps = edpt_max_packet_size(num);
+ if (*ctr & 0x3) *ctr = USB_PIPECTR_PID_NAK;
+ pt->TRE = TU_BIT(8);
+ pt->TRN = (buflen + mps - 1) / mps;
+ pt->TRENB = 1;
+ }
+ *ctr = USB_PIPECTR_PID_BUF;
+ }
+ return true;
+}
+
+static bool process_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ if (0 == epn) {
+ return process_pipe0_xfer(dev_addr, ep_addr, buffer, buflen);
+ } else {
+ return process_pipe_xfer(dev_addr, ep_addr, buffer, buflen);
+ }
+}
+
+static void process_pipe0_bemp(uint8_t rhport)
+{
+ (void)rhport;
+ bool completed = pipe0_xfer_out();
+ if (completed) {
+ pipe_state_t *pipe = &_hcd.pipe[0];
+ hcd_event_xfer_complete(pipe->dev,
+ tu_edpt_addr(0, TUSB_DIR_OUT),
+ pipe->length - pipe->remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_pipe_nrdy(uint8_t rhport, unsigned num)
+{
+ (void)rhport;
+ unsigned result;
+ uint16_t volatile *ctr = get_pipectr(num);
+ // TU_LOG1("NRDY %d %x\n", num, *ctr);
+ switch (*ctr & USB_PIPECTR_PID_MSK) {
+ default: return;
+ case USB_PIPECTR_PID_STALL: result = XFER_RESULT_STALLED; break;
+ case USB_PIPECTR_PID_NAK: result = XFER_RESULT_FAILED; break;
+ }
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ hcd_event_xfer_complete(pipe->dev, pipe->ep,
+ pipe->length - pipe->remaining,
+ result, true);
+}
+
+static void process_pipe_brdy(uint8_t rhport, unsigned num)
+{
+ (void)rhport;
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ const unsigned dir_in = tu_edpt_dir(pipe->ep);
+ bool completed;
+
+ if (dir_in) { /* IN */
+ if (num) {
+ completed = pipe_xfer_in(num);
+ } else {
+ completed = pipe0_xfer_in();
+ }
+ } else {
+ completed = pipe_xfer_out(num);
+ }
+ if (completed) {
+ hcd_event_xfer_complete(pipe->dev, pipe->ep,
+ pipe->length - pipe->remaining,
+ XFER_RESULT_SUCCESS, true);
+ // TU_LOG1("C %d %d\r\n", num, pipe->length - pipe->remaining);
+ }
+}
+
+
+/*------------------------------------------------------------------*/
+/* Host API
+ *------------------------------------------------------------------*/
+bool hcd_init(uint8_t rhport)
+{
+ (void)rhport;
+ /* Enable USB0 */
+ uint32_t pswi = disable_interrupt();
+ SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY | SYSTEM_PRCR_PRC1;
+ MSTP(USB0) = 0;
+ SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY;
+ enable_interrupt(pswi);
+ USB0.SYSCFG.BIT.SCKE = 1;
+ while (!USB0.SYSCFG.BIT.SCKE) ;
+ USB0.SYSCFG.BIT.DPRPU = 0;
+ USB0.SYSCFG.BIT.DRPD = 0;
+ USB0.SYSCFG.BIT.DCFM = 1;
+
+ USB0.DVSTCTR0.BIT.VBUSEN = 1;
+
+ USB0.SYSCFG.BIT.DRPD = 1;
+ for (volatile int i = 0; i < 30000; ++i) ;
+ USB0.SYSCFG.BIT.USBE = 1;
+
+ USB.DPUSR0R.BIT.FIXPHY0 = 0u; /* USB0 Transceiver Output fixed */
+#if ( CFG_TUSB_MCU == OPT_MCU_RX72N )
+ USB0.PHYSLEW.LONG = 0x5;
+ IR(PERIB, INTB185) = 0;
+#else
+ IR(USB0, USBI0) = 0;
+#endif
+
+ /* Setup default control pipe */
+ USB0.DCPCFG.WORD = USB_PIPECFG_SHTNAK;
+ USB0.DCPMAXP.WORD = 64;
+ USB0.INTENB0.WORD = USB_IS0_BRDY | USB_IS0_NRDY | USB_IS0_BEMP;
+ USB0.INTENB1.WORD = USB_IS1_SACK | USB_IS1_SIGN |
+ USB_IS1_ATTCH | USB_IS1_DTCH;
+ USB0.BEMPENB.WORD = 1;
+ USB0.NRDYENB.WORD = 1;
+ USB0.BRDYENB.WORD = 1;
+ return true;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+#if ( CFG_TUSB_MCU == OPT_MCU_RX72N )
+ IEN(PERIB, INTB185) = 1;
+#else
+ IEN(USB0, USBI0) = 1;
+#endif
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+#if ( CFG_TUSB_MCU == OPT_MCU_RX72N )
+ IEN(PERIB, INTB185) = 0;
+#else
+ IEN(USB0, USBI0) = 0;
+#endif
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void)rhport;
+ /* The device must be reset at least once after connection
+ * in order to start the frame counter. */
+ if (_hcd.need_reset) hcd_port_reset(rhport);
+ return USB0.FRMNUM.BIT.FRNM;
+}
+
+/*--------------------------------------------------------------------+
+ * Port API
+ *--------------------------------------------------------------------+*/
+bool hcd_port_connect_status(uint8_t rhport)
+{
+ (void)rhport;
+ return USB0.INTSTS1.BIT.ATTCH ? true: false;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+ USB0.DCPCTR.WORD = USB_PIPECTR_PID_NAK;
+ while (USB0.DCPCTR.BIT.PBUSY) ;
+ hcd_int_disable(rhport);
+ USB0.DVSTCTR0.BIT.UACT = 0;
+ if (USB0.DCPCTR.BIT.SUREQ)
+ USB0.DCPCTR.BIT.SUREQCLR = 1;
+ hcd_int_enable(rhport);
+ /* Reset should be asserted 10-20ms. */
+ USB0.DVSTCTR0.BIT.USBRST = 1;
+ for (volatile int i = 0; i < 2400000; ++i) ;
+ USB0.DVSTCTR0.BIT.USBRST = 0;
+ USB0.DVSTCTR0.BIT.UACT = 1;
+ _hcd.need_reset = false;
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+ (void)rhport;
+ switch (USB0.DVSTCTR0.BIT.RHST) {
+ default: return TUSB_SPEED_INVALID;
+ case USB_DVSTCTR0_FULL: return TUSB_SPEED_FULL;
+ case USB_DVSTCTR0_LOW: return TUSB_SPEED_LOW;
+ }
+}
+
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ uint16_t volatile *ctr;
+ TU_ASSERT(dev_addr < 6,); /* USBa can only handle addresses from 0 to 5. */
+ if (!dev_addr) return;
+ _hcd.ctl_mps[dev_addr] = 0;
+ uint8_t *ep = &_hcd.ep[dev_addr - 1][0][0];
+ for (int i = 0; i < 2 * 15; ++i, ++ep) {
+ unsigned num = *ep;
+ if (!num || dev_addr != _hcd.pipe[num].dev) continue;
+
+ ctr = (uint16_t volatile*)&USB0.PIPE1CTR.WORD + num - 1;
+ *ctr = 0;
+ USB0.NRDYENB.WORD &= ~TU_BIT(num);
+ USB0.BRDYENB.WORD &= ~TU_BIT(num);
+ USB0.PIPESEL.WORD = num;
+ USB0.PIPECFG.WORD = 0;
+ USB0.PIPEMAXP.WORD = 0;
+
+ _hcd.pipe[num].ep = 0;
+ _hcd.pipe[num].dev = 0;
+ *ep = 0;
+ }
+}
+
+/*--------------------------------------------------------------------+
+ * Endpoints API
+ *--------------------------------------------------------------------+*/
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ (void)rhport;
+ // TU_LOG1("S %d %x\n", dev_addr, USB0.DCPCTR.WORD);
+
+ TU_ASSERT(dev_addr < 6); /* USBa can only handle addresses from 0 to 5. */
+ TU_ASSERT(0 == USB0.DCPCTR.BIT.SUREQ);
+
+ USB0.DCPCTR.WORD = USB_PIPECTR_PID_NAK;
+
+ _hcd.pipe[0].buf = NULL;
+ _hcd.pipe[0].length = 8;
+ _hcd.pipe[0].remaining = 0;
+ _hcd.pipe[0].dev = dev_addr;
+
+ while (USB0.DCPCTR.BIT.PBUSY) ;
+ USB0.DCPMAXP.WORD = (dev_addr << 12) | _hcd.ctl_mps[dev_addr];
+
+ /* Set direction in advance for DATA stage */
+ uint8_t const bmRequesttype = setup_packet[0];
+ USB0.DCPCFG.BIT.DIR = tu_edpt_dir(bmRequesttype) ? 0: 1;
+
+ uint16_t const* p = (uint16_t const*)(uintptr_t)&setup_packet[0];
+ USB0.USBREQ.WORD = tu_htole16(p[0]);
+ USB0.USBVAL = p[1];
+ USB0.USBINDX = p[2];
+ USB0.USBLENG = p[3];
+
+ USB0.DCPCTR.BIT.SUREQ = 1;
+ return true;
+}
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void)rhport;
+ TU_ASSERT(dev_addr < 6); /* USBa can only handle addresses from 0 to 5. */
+
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned mps = tu_edpt_packet_size(ep_desc);
+ if (0 == epn) {
+ USB0.DCPCTR.WORD = USB_PIPECTR_PID_NAK;
+ hcd_devtree_info_t devtree;
+ hcd_devtree_get_info(dev_addr, &devtree);
+ uint16_t volatile *devadd = (uint16_t volatile *)(uintptr_t)&USB0.DEVADD0.WORD;
+ devadd += dev_addr;
+ while (USB0.DCPCTR.BIT.PBUSY) ;
+ USB0.DCPMAXP.WORD = (dev_addr << 12) | mps;
+ *devadd = (TUSB_SPEED_FULL == devtree.speed) ? USB_DEVADD_FULL : USB_DEVADD_LOW;
+ _hcd.ctl_mps[dev_addr] = mps;
+ return true;
+ }
+
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ if (xfer == TUSB_XFER_ISOCHRONOUS && mps > 256) {
+ /* USBa supports up to 256 bytes */
+ return false;
+ }
+ const unsigned num = find_pipe(xfer);
+ if (!num) return false;
+ _hcd.pipe[num].dev = dev_addr;
+ _hcd.pipe[num].ep = ep_addr;
+ _hcd.ep[dev_addr - 1][dir_in][epn - 1] = num;
+
+ /* setup pipe */
+ hcd_int_disable(rhport);
+ USB0.PIPESEL.WORD = num;
+ USB0.PIPEMAXP.WORD = (dev_addr << 12) | mps;
+ volatile uint16_t *ctr = get_pipectr(num);
+ *ctr = USB_PIPECTR_ACLRM | USB_PIPECTR_SQCLR;
+ *ctr = 0;
+ unsigned cfg = ((1 ^ dir_in) << 4) | epn;
+ if (xfer == TUSB_XFER_BULK) {
+ cfg |= USB_PIPECFG_BULK | USB_PIPECFG_SHTNAK | USB_PIPECFG_DBLB;
+ } else if (xfer == TUSB_XFER_INTERRUPT) {
+ cfg |= USB_PIPECFG_INT;
+ } else {
+ cfg |= USB_PIPECFG_ISO | USB_PIPECFG_DBLB;
+ }
+ USB0.PIPECFG.WORD = cfg;
+ USB0.BRDYSTS.WORD = 0x1FFu ^ TU_BIT(num);
+ USB0.NRDYENB.WORD |= TU_BIT(num);
+ USB0.BRDYENB.WORD |= TU_BIT(num);
+ if (!dir_in) {
+ *ctr = USB_PIPECTR_PID_BUF;
+ }
+ hcd_int_enable(rhport);
+
+ return true;
+}
+
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ bool r;
+ hcd_int_disable(rhport);
+ // TU_LOG1("X %d %x %u\n", dev_addr, ep_addr, buflen);
+ r = process_edpt_xfer(dev_addr, ep_addr, buffer, buflen);
+ hcd_int_enable(rhport);
+ return r;
+}
+
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+ uint16_t volatile *ctr = addr_to_pipectr(dev_addr, ep_addr);
+ TU_ASSERT(ctr);
+
+ const uint32_t pid = *ctr & 0x3;
+ if (pid & 2) {
+ *ctr = pid & 2;
+ *ctr = 0;
+ }
+ *ctr = USB_PIPECTR_SQCLR;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ if (!epn) return true;
+
+ if (!tu_edpt_dir(ep_addr)) { /* OUT */
+ *ctr = USB_PIPECTR_PID_BUF;
+ }
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void hcd_int_handler(uint8_t rhport)
+{
+ (void)rhport;
+#if defined(__CCRX__)
+ static const int Mod37BitPosition[] = {
+ -1, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4,
+ 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5,
+ 20, 8, 19, 18};
+#endif
+
+ unsigned is1 = USB0.INTSTS1.WORD;
+ unsigned is0 = USB0.INTSTS0.WORD;
+ /* clear active bits except VALID (don't write 0 to already cleared bits according to the HW manual) */
+ USB0.INTSTS1.WORD = ~((USB_IS1_SACK | USB_IS1_SIGN | USB_IS1_ATTCH | USB_IS1_DTCH) & is1);
+ USB0.INTSTS0.WORD = ~((USB_IS0_BRDY | USB_IS0_NRDY | USB_IS0_BEMP) & is0);
+ // TU_LOG1("IS %04x %04x\n", is0, is1);
+ is1 &= USB0.INTENB1.WORD;
+ is0 &= USB0.INTENB0.WORD;
+
+ if (is1 & USB_IS1_SACK) {
+ /* Set DATA1 in advance for the next transfer. */
+ USB0.DCPCTR.BIT.SQSET = 1;
+ hcd_event_xfer_complete(USB0.DCPMAXP.BIT.DEVSEL,
+ tu_edpt_addr(0, TUSB_DIR_OUT),
+ 8, XFER_RESULT_SUCCESS, true);
+ }
+ if (is1 & USB_IS1_SIGN) {
+ hcd_event_xfer_complete(USB0.DCPMAXP.BIT.DEVSEL,
+ tu_edpt_addr(0, TUSB_DIR_OUT),
+ 8, XFER_RESULT_FAILED, true);
+ }
+ if (is1 & USB_IS1_ATTCH) {
+ USB0.DVSTCTR0.BIT.UACT = 1;
+ _hcd.need_reset = true;
+ USB0.INTENB1.WORD = (USB0.INTENB1.WORD & ~USB_IS1_ATTCH) | USB_IS1_DTCH;
+ hcd_event_device_attach(rhport, true);
+ }
+ if (is1 & USB_IS1_DTCH) {
+ USB0.DVSTCTR0.BIT.UACT = 0;
+ if (USB0.DCPCTR.BIT.SUREQ)
+ USB0.DCPCTR.BIT.SUREQCLR = 1;
+ USB0.INTENB1.WORD = (USB0.INTENB1.WORD & ~USB_IS1_DTCH) | USB_IS1_ATTCH;
+ hcd_event_device_remove(rhport, true);
+ }
+
+ if (is0 & USB_IS0_BEMP) {
+ const unsigned s = USB0.BEMPSTS.WORD;
+ USB0.BEMPSTS.WORD = 0;
+ if (s & 1) {
+ process_pipe0_bemp(rhport);
+ }
+ }
+ if (is0 & USB_IS0_NRDY) {
+ const unsigned m = USB0.NRDYENB.WORD;
+ unsigned s = USB0.NRDYSTS.WORD & m;
+ USB0.NRDYSTS.WORD = ~s;
+ while (s) {
+#if defined(__CCRX__)
+ const unsigned num = Mod37BitPosition[(-s & s) % 37];
+#else
+ const unsigned num = __builtin_ctz(s);
+#endif
+ process_pipe_nrdy(rhport, num);
+ s &= ~TU_BIT(num);
+ }
+ }
+ if (is0 & USB_IS0_BRDY) {
+ const unsigned m = USB0.BRDYENB.WORD;
+ unsigned s = USB0.BRDYSTS.WORD & m;
+ /* clear active bits (don't write 0 to already cleared bits according to the HW manual) */
+ USB0.BRDYSTS.WORD = ~s;
+ while (s) {
+#if defined(__CCRX__)
+ const unsigned num = Mod37BitPosition[(-s & s) % 37];
+#else
+ const unsigned num = __builtin_ctz(s);
+#endif
+ process_pipe_brdy(rhport, num);
+ s &= ~TU_BIT(num);
+ }
+ }
+}
+
+#endif
diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c
index dfe409383..6677891a5 100644
--- a/src/portable/sony/cxd56/dcd_cxd56.c
+++ b/src/portable/sony/cxd56/dcd_cxd56.c
@@ -26,19 +26,20 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_CXD56
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_CXD56
#include <errno.h>
#include <nuttx/usb/usbdev.h>
#include <nuttx/arch.h>
#include "device/dcd.h"
+#include "device/usbd_pvt.h"
#define CXD56_EPNUM (7)
#define CXD56_SETUP_QUEUE_DEPTH (4)
#define CXD56_MAX_DATA_OUT_SIZE (64)
-OSAL_QUEUE_DEF(OPT_MODE_DEVICE, _setup_queue_def, CXD56_SETUP_QUEUE_DEPTH, struct usb_ctrlreq_s);
+OSAL_QUEUE_DEF(usbd_int_set, _setup_queue_def, CXD56_SETUP_QUEUE_DEPTH, struct usb_ctrlreq_s);
struct usbdcd_driver_s
{
@@ -246,6 +247,14 @@ void dcd_disconnect(uint8_t rhport)
DEV_DISCONNECT(usbdev);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -362,7 +371,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to
if (usbdcd_driver.setup_processed)
{
- if (osal_queue_receive(usbdcd_driver.setup_queue, &ctrl))
+ if (osal_queue_receive(usbdcd_driver.setup_queue, &ctrl, 100))
{
usbdcd_driver.setup_processed = false;
dcd_event_setup_received(0, (uint8_t *)&ctrl, false);
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index ec3964b4a..b90ab7d11 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -109,8 +109,8 @@
#define STM32F1_FSDEV
#endif
-#if TUSB_OPT_DEVICE_ENABLED && \
- ( TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F3, OPT_MCU_STM32L0, OPT_MCU_STM32L1, OPT_MCU_STM32G4) || \
+#if CFG_TUD_ENABLED && \
+ ( TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F3, OPT_MCU_STM32L0, OPT_MCU_STM32L1, OPT_MCU_STM32G4, OPT_MCU_STM32WB) || \
(TU_CHECK_MCU(OPT_MCU_STM32F1) && defined(STM32F1_FSDEV)) || \
(TU_CHECK_MCU(OPT_MCU_STM32L4) && !defined(DCD_ATTR_DWC2_STM32)) \
)
@@ -288,6 +288,14 @@ void dcd_connect(uint8_t rhport)
}
#endif
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
// Enable device interrupt
void dcd_int_enable (uint8_t rhport)
{
@@ -330,6 +338,10 @@ void dcd_int_enable (uint8_t rhport)
NVIC_EnableIRQ(USB_LP_IRQn);
NVIC_EnableIRQ(USBWakeUp_IRQn);
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ NVIC_EnableIRQ(USB_HP_IRQn);
+ NVIC_EnableIRQ(USB_LP_IRQn);
+
#else
#error Unknown arch in USB driver
#endif
@@ -373,6 +385,10 @@ void dcd_int_disable(uint8_t rhport)
NVIC_DisableIRQ(USB_LP_IRQn);
NVIC_DisableIRQ(USBWakeUp_IRQn);
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ NVIC_DisableIRQ(USB_HP_IRQn);
+ NVIC_DisableIRQ(USB_LP_IRQn);
+
#else
#error Unknown arch in USB driver
#endif
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
index eabefa687..920d12c1b 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
@@ -91,6 +91,13 @@
#include "stm32g4xx.h"
#define PMA_LENGTH (1024u)
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ #include "stm32wbxx.h"
+ #define PMA_LENGTH (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 PMA_LENGTH (1024u)
diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c
index 4782ead8c..2fc3adb4f 100644
--- a/src/portable/st/synopsys/dcd_synopsys.c
+++ b/src/portable/st/synopsys/dcd_synopsys.c
@@ -45,7 +45,7 @@
#define STM32L4_SYNOPSYS
#endif
-#if TUSB_OPT_DEVICE_ENABLED && \
+#if CFG_TUD_ENABLED && \
( (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_SYNOPSYS)) || \
CFG_TUSB_MCU == OPT_MCU_STM32F2 || \
CFG_TUSB_MCU == OPT_MCU_STM32F4 || \
@@ -602,6 +602,13 @@ void dcd_disconnect(uint8_t rhport)
dev->DCTL |= USB_OTG_DCTL_SDIS;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
/*------------------------------------------------------------------*/
/* DCD Endpoint port
diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c
new file mode 100644
index 000000000..a0be846a5
--- /dev/null
+++ b/src/portable/sunxi/dcd_sunxi_musb.c
@@ -0,0 +1,1219 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ * Copyright (c) 2021 Tian Yunhao (t123yh)
+ * Copyright (c) 2021 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include <stdint.h>
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_F1C100S
+
+#include "osal/osal.h"
+#include <f1c100s-irq.h>
+#include <device/dcd.h>
+#include "musb_def.h"
+#include "bsp/board.h"
+
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+
+
+#define REQUEST_TYPE_INVALID (0xFFu)
+
+typedef struct {
+ uint_fast16_t beg; /* offset of including first element */
+ uint_fast16_t end; /* offset of excluding the last element */
+} free_block_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ void *buf; /* the start address of a transfer data buffer */
+ uint16_t length; /* the number of bytes in the buffer */
+ uint16_t remaining; /* the number of bytes remaining in the buffer */
+} pipe_state_t;
+
+typedef struct
+{
+ tusb_control_request_t setup_packet;
+ uint16_t remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */
+ int8_t status_out;
+ pipe_state_t pipe0;
+ pipe_state_t pipe[2][7]; /* pipe[direction][endpoint number - 1] */
+ uint16_t pipe_buf_is_fifo[2]; /* Bitmap. Each bit means whether 1:TU_FIFO or 0:POD. */
+} dcd_data_t;
+
+/*------------------------------------------------------------------
+ * SUNXI FUNCTION
+ *------------------------------------------------------------------*/
+
+static void usb_phy_write(int addr, int data, int len)
+{
+ int j = 0, usbc_bit = 0;
+ void *dest = (void *)USBC_REG_CSR(USBC0_BASE);
+
+ usbc_bit = 1 << (0 * 2);
+ for (j = 0; j < len; j++)
+ {
+ /* set the bit address to be written */
+ USBC_ClrBit_Mask_l(dest, 0xff << 8);
+ USBC_SetBit_Mask_l(dest, (addr + j) << 8);
+
+ USBC_ClrBit_Mask_l(dest, usbc_bit);
+ /* set data bit */
+ if (data & 0x1)
+ USBC_SetBit_Mask_l(dest, 1 << 7);
+ else
+ USBC_ClrBit_Mask_l(dest, 1 << 7);
+
+ USBC_SetBit_Mask_l(dest, usbc_bit);
+
+ USBC_ClrBit_Mask_l(dest, usbc_bit);
+
+ data >>= 1;
+ }
+}
+
+static void delay_ms(uint32_t ms)
+{
+#if CFG_TUSB_OS == OPT_OS_NONE
+ int now = board_millis();
+ while (board_millis() - now <= ms) asm("nop");
+#else
+ osal_task_delay(ms);
+#endif
+}
+
+static void USBC_HardwareReset(void)
+{
+ // Reset phy and controller
+ USBC_REG_set_bit_l(USBPHY_CLK_RST_BIT, USBPHY_CLK_REG);
+ USBC_REG_set_bit_l(BUS_RST_USB_BIT, BUS_CLK_RST_REG);
+ delay_ms(2);
+
+ USBC_REG_set_bit_l(USBPHY_CLK_GAT_BIT, USBPHY_CLK_REG);
+ USBC_REG_set_bit_l(USBPHY_CLK_RST_BIT, USBPHY_CLK_REG);
+
+ USBC_REG_set_bit_l(BUS_CLK_USB_BIT, BUS_CLK_GATE0_REG);
+ USBC_REG_set_bit_l(BUS_RST_USB_BIT, BUS_CLK_RST_REG);
+}
+
+static void USBC_PhyConfig(void)
+{
+ /* Regulation 45 ohms */
+ usb_phy_write(0x0c, 0x01, 1);
+
+ /* adjust PHY's magnitude and rate */
+ usb_phy_write(0x20, 0x14, 5);
+
+ /* threshold adjustment disconnect */
+ usb_phy_write(0x2a, 3, 2);
+
+ return;
+}
+
+static void USBC_ConfigFIFO_Base(void)
+{
+ u32 reg_value;
+
+ /* config usb fifo, 8kb mode */
+ reg_value = USBC_Readl(SUNXI_SRAMC_BASE + 0x04);
+ reg_value &= ~(0x03 << 0);
+ reg_value |= (1 << 0);
+ USBC_Writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
+}
+
+static unsigned int USBC_WakeUp_ClearChangeDetect(unsigned int reg_val)
+{
+ unsigned int temp = reg_val;
+ /* vbus, id, dpdm, these bit is set 1 to clear, so we clear these bit when operate other bits */
+ temp &= ~(1 << USBC_BP_ISCR_VBUS_CHANGE_DETECT);
+ temp &= ~(1 << USBC_BP_ISCR_ID_CHANGE_DETECT);
+ temp &= ~(1 << USBC_BP_ISCR_DPDM_CHANGE_DETECT);
+
+ return temp;
+}
+
+static void USBC_EnableDpDmPullUp(void)
+{
+ u32 reg_val = USBC_Readl(USBC_REG_ISCR(USBC0_BASE));
+ reg_val |= (1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
+ reg_val |= 3<<USBC_BP_ISCR_VBUS_VALID_SRC;
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ USBC_Writel(reg_val, USBC_REG_ISCR(USBC0_BASE));
+}
+
+static void USBC_ForceIdToHigh(void)
+{
+ /* first write 00, then write 10 */
+ u32 reg_val = USBC_Readl(USBC_REG_ISCR(USBC0_BASE));
+ reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ USBC_Writel(reg_val, USBC_REG_ISCR(USBC0_BASE));
+}
+
+static void USBC_ForceVbusValidToHigh(void)
+{
+ /* first write 00, then write 11 */
+ u32 reg_val = USBC_Readl(USBC_REG_ISCR(USBC0_BASE));
+ reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ USBC_Writel(reg_val, USBC_REG_ISCR(USBC0_BASE));
+}
+
+void USBC_SelectBus(u32 io_type, u32 ep_type, u32 ep_index)
+{
+ u32 reg_val = 0;
+
+ reg_val = USBC_Readb(USBC_REG_VEND0(USBC0_BASE));
+ if (io_type == USBC_IO_TYPE_DMA) {
+ if (ep_type == USBC_EP_TYPE_TX) {
+ reg_val |= ((ep_index - 0x01) << 1) << USBC_BP_VEND0_DRQ_SEL; //drq_sel
+ reg_val |= 0x1<<USBC_BP_VEND0_BUS_SEL; //io_dma
+ } else {
+ reg_val |= ((ep_index << 1) - 0x01) << USBC_BP_VEND0_DRQ_SEL;
+ reg_val |= 0x1<<USBC_BP_VEND0_BUS_SEL;
+ }
+ } else {
+ //reg_val &= ~(0x1 << USBC_BP_VEND0_DRQ_SEL); //clear drq_sel, select pio
+ reg_val &= 0x00; // clear drq_sel, select pio
+ }
+
+ /* in 1667 1673 and later ic, FIFO_BUS_SEL bit(bit24 of reg0x40 for host/device)
+ * is fixed to 1, the hw guarantee that it's ok for cpu/inner_dma/outer_dma transfer */
+
+// reg_val |= 0x1<<USBC_BP_VEND0_BUS_SEL; //for 1663 set 1: enable dma, set 0: enable fifo
+
+ USBC_Writeb(reg_val, USBC_REG_VEND0(USBC0_BASE));
+}
+
+static void USBC_SelectActiveEp(u8 ep_index)
+{
+ USBC_Writeb(ep_index, USBC_REG_EPIND(USBC0_BASE));
+}
+
+static u8 USBC_GetActiveEp(void)
+{
+ return USBC_Readb(USBC_REG_EPIND(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_SendStall(void)
+{
+ USBC_REG_set_bit_w(USBC_BP_CSR0_D_SEND_STALL, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_ClearStall(void)
+{
+ USBC_REG_clear_bit_w(USBC_BP_CSR0_D_SEND_STALL, USBC_REG_CSR0(USBC0_BASE));
+ USBC_REG_clear_bit_w(USBC_BP_CSR0_D_SENT_STALL, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void USBC_Dev_Ctrl_ClearSetupEnd(void)
+{
+ USBC_REG_set_bit_w(USBC_BP_CSR0_D_SERVICED_SETUP_END, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void USBC_Dev_SetAddress(u8 address)
+{
+ USBC_Writeb(address, USBC_REG_FADDR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Tx_SendStall(void)
+{
+ //send stall, and fifo is flushed automaticly
+ USBC_REG_set_bit_w(USBC_BP_TXCSR_D_SEND_STALL, USBC_REG_TXCSR(USBC0_BASE));
+}
+static u32 __USBC_Dev_Tx_IsEpStall(void)
+{
+ return USBC_REG_test_bit_w(USBC_BP_TXCSR_D_SENT_STALL, USBC_REG_TXCSR(USBC0_BASE));
+}
+static void __USBC_Dev_Tx_ClearStall(void)
+{
+ u32 reg_val = USBC_Readw(USBC_REG_TXCSR(USBC0_BASE));
+ reg_val &= ~((1 << USBC_BP_TXCSR_D_SENT_STALL)|(1 << USBC_BP_TXCSR_D_SEND_STALL)|(1<<USBC_BP_TXCSR_D_UNDER_RUN));
+ reg_val |= (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE);
+ USBC_Writew(reg_val, USBC_REG_TXCSR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Rx_SendStall(void)
+{
+ USBC_REG_set_bit_w(USBC_BP_RXCSR_D_SEND_STALL, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static u32 __USBC_Dev_Rx_IsEpStall(void)
+{
+ return USBC_REG_test_bit_w(USBC_BP_RXCSR_D_SENT_STALL, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Rx_ClearStall(void)
+{
+ u32 reg_val = USBC_Readw(USBC_REG_RXCSR(USBC0_BASE));
+ reg_val &= ~((1 << USBC_BP_RXCSR_D_SENT_STALL)|(1 << USBC_BP_RXCSR_D_SEND_STALL)|(1<<USBC_BP_RXCSR_D_OVERRUN));
+ reg_val |= (1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE);
+ USBC_Writew(reg_val, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static tusb_speed_t USBC_Dev_QueryTransferMode(void)
+{
+ if (USBC_REG_test_bit_b(USBC_BP_POWER_D_HIGH_SPEED_FLAG, USBC_REG_PCTL(USBC0_BASE)))
+ return TUSB_SPEED_HIGH;
+ else
+ return TUSB_SPEED_FULL;
+}
+
+static void __USBC_Dev_ep0_ReadDataHalf(void)
+{
+ USBC_Writew(1<<USBC_BP_CSR0_D_SERVICED_RX_PKT_READY, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_ReadDataComplete(void)
+{
+ USBC_Writew((1<<USBC_BP_CSR0_D_SERVICED_RX_PKT_READY) | (1<<USBC_BP_CSR0_D_DATA_END),
+ USBC_REG_CSR0(USBC0_BASE));
+}
+
+
+static void __USBC_Dev_ep0_WriteDataHalf(void)
+{
+ USBC_Writew(1<<USBC_BP_CSR0_D_TX_PKT_READY, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_WriteDataComplete(void)
+{
+ USBC_Writew((1<<USBC_BP_CSR0_D_TX_PKT_READY) | (1<<USBC_BP_CSR0_D_DATA_END),
+ USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_Tx_WriteDataComplete(void)
+{
+ USBC_Writeb((1 << USBC_BP_TXCSR_D_TX_READY), USBC_REG_TXCSR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Rx_ReadDataComplete(void)
+{
+ USBC_Writeb(0, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static u32 __USBC_Dev_Rx_IsReadDataReady(void)
+{
+ return USBC_REG_test_bit_w(USBC_BP_RXCSR_D_RX_PKT_READY, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+/* open a tx ep's interrupt */
+static void USBC_INT_EnableTxEp(u8 ep_index)
+{
+ USBC_REG_set_bit_w(ep_index, USBC_REG_INTTxE(USBC0_BASE));
+}
+
+/* open a rx ep's interrupt */
+static void USBC_INT_EnableRxEp(u8 ep_index)
+{
+ USBC_REG_set_bit_w(ep_index, USBC_REG_INTRxE(USBC0_BASE));
+}
+
+/* close a tx ep's interrupt */
+static void USBC_INT_DisableTxEp(u8 ep_index)
+{
+ USBC_REG_clear_bit_w(ep_index, USBC_REG_INTTxE(USBC0_BASE));
+}
+
+/* close a rx ep's interrupt */
+static void USBC_INT_DisableRxEp(u8 ep_index)
+{
+ USBC_REG_clear_bit_w(ep_index, USBC_REG_INTRxE(USBC0_BASE));
+}
+
+/*------------------------------------------------------------------
+ * INTERNAL FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+
+static dcd_data_t _dcd;
+
+static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
+{
+ free_block_t *cur = beg;
+ for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ;
+ return cur;
+}
+
+static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size)
+{
+ free_block_t *p = find_containing_block(blks, blks + num, addr);
+ TU_ASSERT(p != blks + num, -2);
+ if (p->beg == addr) {
+ /* Shrink block */
+ p->beg = addr + size;
+ if (p->beg != p->end) return 0;
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ } else {
+ /* Split into 2 blocks */
+ free_block_t tmp = {
+ .beg = addr + size,
+ .end = p->end
+ };
+ p->end = addr;
+ if (p->beg == p->end) {
+ if (tmp.beg != tmp.end) {
+ *p = tmp;
+ return 0;
+ }
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ }
+ if (tmp.beg == tmp.end) return 0;
+ blks[num] = tmp;
+ return 1;
+ }
+}
+
+static inline unsigned free_block_size(free_block_t const *blk)
+{
+ return blk->end - blk->beg;
+}
+
+#if 0
+static inline void print_block_list(free_block_t const *blk, unsigned num)
+{
+ TU_LOG1("*************\n");
+ for (unsigned i = 0; i < num; ++i) {
+ TU_LOG1(" Blk%u %u %u\n", i, blk->beg, blk->end);
+ ++blk;
+ }
+}
+#else
+#define print_block_list(a,b)
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_F1C100S
+#define USB_FIFO_SIZE_KB 4
+#else
+#error "Unsupported MCU"
+#endif
+
+static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
+{
+ free_block_t free_blocks[2 * (TUP_DCD_ENDPOINT_MAX - 1)];
+ unsigned num_blocks = 1;
+ /* Backup current EP to restore later */
+ u8 backup_ep = USBC_GetActiveEp();
+
+ /* Initialize free memory block list */
+ free_blocks[0].beg = 64 / 8;
+ free_blocks[0].end = (USB_FIFO_SIZE_KB << 10) / 8; /* 2KiB / 8 bytes */
+ for (int i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
+ uint_fast16_t addr;
+ int num;
+ USBC_SelectActiveEp(i);
+ addr = USBC_Readw(USBC_REG_TXFIFOAD(USBC0_BASE));
+ if (addr) {
+ unsigned sz = USBC_Readb(USBC_REG_TXFIFOSZ(USBC0_BASE));
+ unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ print_block_list(free_blocks, num_blocks);
+ }
+ addr = USBC_Readw(USBC_REG_RXFIFOAD(USBC0_BASE));
+ if (addr) {
+ unsigned sz = USBC_Readb(USBC_REG_RXFIFOSZ(USBC0_BASE));
+ unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ print_block_list(free_blocks, num_blocks);
+ }
+ }
+ print_block_list(free_blocks, num_blocks);
+
+ USBC_SelectActiveEp(backup_ep);
+
+ /* Find the best fit memory block */
+ uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3;
+ free_block_t const *min = NULL;
+ uint_fast16_t min_sz = 0xFFFFu;
+ free_block_t const *end = &free_blocks[num_blocks];
+ for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) {
+ uint_fast16_t sz = free_block_size(cur);
+ if (sz < size_in_8byte_unit) continue;
+ if (size_in_8byte_unit == sz) return cur->beg;
+ if (sz < min_sz) min = cur;
+ }
+ TU_ASSERT(min, 0);
+ return min->beg;
+}
+
+static void pipe_write_packet(void *buff, volatile void *fifo, unsigned cnt)
+{
+ u32 len = 0;
+ u32 i32 = 0;
+ u32 i8 = 0;
+ u8 *buf8 = 0;
+ u32 *buf32 = 0;
+
+ //--<1>-- adjust data
+ buf32 = buff;
+ len = cnt;
+
+ i32 = len >> 2;
+ i8 = len & 0x03;
+
+ //--<2>-- deal with 4byte part
+ while (i32--) {
+ USBC_Writel(*buf32++, fifo);
+ }
+
+ //--<3>-- deal with no 4byte part
+ buf8 = (u8 *)buf32;
+ while (i8--) {
+ USBC_Writeb(*buf8++, fifo);
+ }
+}
+
+static void pipe_read_packet(void *buff, volatile void *fifo, unsigned cnt)
+{
+ u32 len = 0;
+ u32 i32 = 0;
+ u32 i8 = 0;
+ u8 *buf8 = 0;
+ u32 *buf32 = 0;
+
+ //--<1>-- adjust data
+ buf32 = buff;
+ len = cnt;
+
+ i32 = len >> 2;
+ i8 = len & 0x03;
+
+ //--<2>-- deal with 4byte part
+ while (i32--) {
+ *buf32++ = USBC_Readl(fifo);
+ }
+
+ //--<3>-- deal with no 4byte part
+ buf8 = (u8 *)buf32;
+ while (i8--) {
+ *buf8++ = USBC_Readb(fifo);
+ }
+}
+
+static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigned len, unsigned dir)
+{
+ static const struct {
+ void (*tu_fifo_get_info)(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
+ void (*tu_fifo_advance)(tu_fifo_t *f, uint16_t n);
+ void (*pipe_read_write)(void *buf, volatile void *fifo, unsigned len);
+ } ops[] = {
+ /* OUT */ {tu_fifo_get_write_info,tu_fifo_advance_write_pointer,pipe_read_packet},
+ /* IN */ {tu_fifo_get_read_info, tu_fifo_advance_read_pointer, pipe_write_packet},
+ };
+ tu_fifo_buffer_info_t info;
+ ops[dir].tu_fifo_get_info(f, &info);
+ unsigned total_len = len;
+ len = TU_MIN(total_len, info.len_lin);
+ ops[dir].pipe_read_write(info.ptr_lin, fifo, len);
+ unsigned rem = total_len - len;
+ if (rem) {
+ len = TU_MIN(rem, info.len_wrap);
+ ops[dir].pipe_read_write(info.ptr_wrap, fifo, len);
+ rem -= len;
+ }
+ ops[dir].tu_fifo_advance(f, total_len - rem);
+}
+
+/*------------------------------------------------------------------
+ * TRANSFER FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+
+static void process_setup_packet(uint8_t rhport)
+{
+ uint32_t *p = (uint32_t*)&_dcd.setup_packet;
+ p[0] = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
+ p[1] = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
+
+ _dcd.pipe0.buf = NULL;
+ _dcd.pipe0.length = 0;
+ _dcd.pipe0.remaining = 0;
+ dcd_event_setup_received(rhport, (const uint8_t*)(uintptr_t)&_dcd.setup_packet, true);
+
+ const unsigned len = _dcd.setup_packet.wLength;
+ _dcd.remaining_ctrl = len;
+ const unsigned dir_in = tu_edpt_dir(_dcd.setup_packet.bmRequestType);
+ /* Clear RX FIFO and reverse the transaction direction */
+ if (len && dir_in) __USBC_Dev_ep0_ReadDataHalf();
+}
+
+static bool handle_xfer_in(uint_fast8_t ep_addr)
+{
+ unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
+ const unsigned rem = pipe->remaining;
+
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+
+ const unsigned mps = USBC_Readw(USBC_REG_TXMAXP(USBC0_BASE));
+ const unsigned len = TU_MIN(mps, rem);
+ uint8_t *buf = pipe->buf;
+ // TU_LOG1(" %p mps %d len %d rem %d\n", buf, mps, len, rem);
+ if (len) {
+ volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
+ if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
+ pipe_read_write_packet_ff((tu_fifo_t *)buf, addr, len, TUSB_DIR_IN);
+ } else {
+ pipe_write_packet(buf, addr, len);
+ pipe->buf = buf + len;
+ }
+ pipe->remaining = rem - len;
+ }
+ __USBC_Dev_Tx_WriteDataComplete();
+ // TU_LOG1(" TXCSRL%d = %x %d\n", epnum_minus1 + 1, regs->TXCSRL, rem - len);
+ return false;
+}
+
+static bool handle_xfer_out(uint_fast8_t ep_addr)
+{
+ unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
+ // TU_LOG1(" RXCSRL%d = %x\n", epnum_minus1 + 1, regs->RXCSRL);
+
+ TU_ASSERT(__USBC_Dev_Rx_IsReadDataReady());
+
+ const unsigned mps = USBC_Readw(USBC_REG_RXMAXP(USBC0_BASE));
+ const unsigned rem = pipe->remaining;
+ const unsigned vld = USBC_Readw(USBC_REG_RXCOUNT(USBC0_BASE));
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ uint8_t *buf = pipe->buf;
+ if (len) {
+ volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
+ if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
+ pipe_read_write_packet_ff((tu_fifo_t *)buf, addr, len, TUSB_DIR_OUT);
+ } else {
+ pipe_read_packet(buf, addr, len);
+ pipe->buf = buf + len;
+ }
+ pipe->remaining = rem - len;
+ }
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return NULL != buf;
+ }
+ __USBC_Dev_Rx_ReadDataComplete();
+ return false;
+}
+
+static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+
+ unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ unsigned dir_in = tu_edpt_dir(ep_addr);
+
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][epnum_minus1];
+ pipe->buf = buffer;
+ pipe->length = total_bytes;
+ pipe->remaining = total_bytes;
+
+ USBC_SelectActiveEp(tu_edpt_number(ep_addr));
+
+ if (dir_in) {
+ handle_xfer_in(ep_addr);
+ } else {
+ if (__USBC_Dev_Rx_IsReadDataReady())
+ __USBC_Dev_Rx_ReadDataComplete();
+ }
+ return true;
+}
+
+static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+ TU_ASSERT(total_bytes <= 64); /* Current implementation supports for only up to 64 bytes. */
+
+ const unsigned req = _dcd.setup_packet.bmRequestType;
+ TU_ASSERT(req != REQUEST_TYPE_INVALID || total_bytes == 0);
+
+ USBC_SelectActiveEp(0);
+
+ if (req == REQUEST_TYPE_INVALID || _dcd.status_out) {
+ /* STATUS OUT stage.
+ * MUSB controller automatically handles STATUS OUT packets without
+ * software helps. We do not have to do anything. And STATUS stage
+ * may have already finished and received the next setup packet
+ * without calling this function, so we have no choice but to
+ * invoke the callback function of status packet here. */
+ // TU_LOG1(" STATUS OUT CSRL0 = %x\n", CSRL0);
+ _dcd.status_out = 0;
+ if (req == REQUEST_TYPE_INVALID) {
+ dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false);
+ } else {
+ /* The next setup packet has already been received, it aborts
+ * invoking callback function to avoid confusing TUSB stack. */
+ TU_LOG1("Drop CONTROL_STAGE_ACK\n");
+ }
+ return true;
+ }
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ if (tu_edpt_dir(req) == dir_in) { /* DATA stage */
+ TU_ASSERT(total_bytes <= _dcd.remaining_ctrl);
+ const unsigned rem = _dcd.remaining_ctrl;
+ const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes);
+ if (dir_in) {
+ pipe_write_packet(buffer, (volatile void*) USBC_REG_EPFIFO0(USBC0_BASE), len);
+
+ _dcd.pipe0.buf = buffer + len;
+ _dcd.pipe0.length = len;
+ _dcd.pipe0.remaining = 0;
+
+ _dcd.remaining_ctrl = rem - len;
+ if ((len < 64) || (rem == len)) {
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; /* Change to STATUS/SETUP stage */
+ _dcd.status_out = 1;
+ /* Flush TX FIFO and reverse the transaction direction. */
+ __USBC_Dev_ep0_WriteDataComplete();
+ } else {
+ __USBC_Dev_ep0_WriteDataHalf();
+ }
+ // TU_LOG1(" IN CSRL0 = %x\n", CSRL0);
+ } else {
+ // TU_LOG1(" OUT CSRL0 = %x\n", CSRL0);
+ _dcd.pipe0.buf = buffer;
+ _dcd.pipe0.length = len;
+ _dcd.pipe0.remaining = len;
+ __USBC_Dev_ep0_ReadDataHalf();
+ }
+ } else if (dir_in) {
+ // TU_LOG1(" STATUS IN CSRL0 = %x\n", CSRL0);
+ _dcd.pipe0.buf = NULL;
+ _dcd.pipe0.length = 0;
+ _dcd.pipe0.remaining = 0;
+ /* Clear RX FIFO and reverse the transaction direction */
+ __USBC_Dev_ep0_ReadDataComplete();
+ }
+ return true;
+}
+
+static void process_ep0(uint8_t rhport)
+{
+ USBC_SelectActiveEp(0);
+ uint_fast8_t csrl = USBC_Readw(USBC_REG_CSR0(USBC0_BASE));
+
+ // TU_LOG1(" EP0 CSRL0 = %x\n", csrl);
+
+ if (csrl & USB_CSRL0_STALLED) {
+ /* Returned STALL packet to HOST. */
+ __USBC_Dev_ep0_ClearStall();
+ return;
+ }
+
+ unsigned req = _dcd.setup_packet.bmRequestType;
+ if (csrl & USB_CSRL0_SETEND) {
+ // TU_LOG1(" ABORT by the next packets\n");
+ USBC_Dev_Ctrl_ClearSetupEnd();
+ if (req != REQUEST_TYPE_INVALID && _dcd.pipe0.buf) {
+ /* DATA stage was aborted by receiving STATUS or SETUP packet. */
+ _dcd.pipe0.buf = NULL;
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ dcd_event_xfer_complete(rhport,
+ req & TUSB_DIR_IN_MASK,
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+ req = REQUEST_TYPE_INVALID;
+ if (!(csrl & USB_CSRL0_RXRDY)) return; /* Received SETUP packet */
+ }
+
+ if (csrl & USB_CSRL0_RXRDY) {
+ /* Received SETUP or DATA OUT packet */
+ if (req == REQUEST_TYPE_INVALID) {
+ /* SETUP */
+ TU_ASSERT(sizeof(tusb_control_request_t) == USBC_Readw(USBC_REG_COUNT0(USBC0_BASE)),);
+ process_setup_packet(rhport);
+ return;
+ }
+ if (_dcd.pipe0.buf) {
+ /* DATA OUT */
+ const unsigned vld = USBC_Readw(USBC_REG_COUNT0(USBC0_BASE));
+ const unsigned rem = _dcd.pipe0.remaining;
+ const unsigned len = TU_MIN(TU_MIN(rem, 64), vld);
+ pipe_read_packet(_dcd.pipe0.buf, (volatile void*)USBC_REG_EPFIFO0(USBC0_BASE), len);
+
+ _dcd.pipe0.remaining = rem - len;
+ _dcd.remaining_ctrl -= len;
+
+ _dcd.pipe0.buf = NULL;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(0, TUSB_DIR_OUT),
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+ return;
+ }
+
+ /* When CSRL0 is zero, it means that completion of sending a any length packet
+ * or receiving a zero length packet. */
+ if (req != REQUEST_TYPE_INVALID && !tu_edpt_dir(req)) {
+ /* STATUS IN */
+ if (*(const uint16_t*)(uintptr_t)&_dcd.setup_packet == 0x0500) {
+ /* The address must be changed on completion of the control transfer. */
+ USBC_Dev_SetAddress((uint8_t)_dcd.setup_packet.wValue);
+ }
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(0, TUSB_DIR_IN),
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ return;
+ }
+ if (_dcd.pipe0.buf) {
+ /* DATA IN */
+ _dcd.pipe0.buf = NULL;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(0, TUSB_DIR_IN),
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_edpt_n(uint8_t rhport, uint_fast8_t ep_addr)
+{
+ bool completed;
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned epn = tu_edpt_number(ep_addr);
+
+ USBC_SelectActiveEp(epn);
+
+ if (dir_in) {
+ // TU_LOG1(" TXCSRL%d = %x\n", epn_minus1 + 1, regs->TXCSRL);
+ if (__USBC_Dev_Tx_IsEpStall()) {
+ __USBC_Dev_Tx_ClearStall();
+ return;
+ }
+ completed = handle_xfer_in(ep_addr);
+ } else {
+ // TU_LOG1(" RXCSRL%d = %x\n", epn_minus1 + 1, regs->RXCSRL);
+ if (__USBC_Dev_Rx_IsEpStall()) {
+ __USBC_Dev_Rx_ClearStall();
+ return;
+ }
+ completed = handle_xfer_out(ep_addr);
+ }
+
+ if (completed) {
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][tu_edpt_number(ep_addr) - 1];
+ dcd_event_xfer_complete(rhport, ep_addr,
+ pipe->length - pipe->remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+ /* When bmRequestType is REQUEST_TYPE_INVALID(0xFF),
+ * a control transfer state is SETUP or STATUS stage. */
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ _dcd.status_out = 0;
+ /* When pipe0.buf has not NULL, DATA stage works in progress. */
+ _dcd.pipe0.buf = NULL;
+
+ USBC_Writew(1, USBC_REG_INTTxE(USBC0_BASE)); /* Enable only EP0 */
+ USBC_Writew(0, USBC_REG_INTRxE(USBC0_BASE));
+
+ dcd_event_bus_reset(rhport, USBC_Dev_QueryTransferMode(), true);
+}
+
+/*------------------------------------------------------------------
+ * Device API
+ *------------------------------------------------------------------*/
+
+static void usb_isr_handler(void) {
+ dcd_int_handler(0);
+}
+
+void dcd_init(uint8_t rhport)
+{
+ dcd_disconnect(rhport);
+ USBC_HardwareReset();
+ USBC_PhyConfig();
+ USBC_ConfigFIFO_Base();
+ USBC_EnableDpDmPullUp();
+ USBC_ForceIdToHigh(); // Force device mode
+ USBC_ForceVbusValidToHigh();
+ USBC_SelectBus(USBC_IO_TYPE_PIO, 0, 0);
+ dcd_edpt_close_all(rhport);
+
+ #if TUD_OPT_HIGH_SPEED
+ USBC_REG_set_bit_b(USBC_BP_POWER_D_HIGH_SPEED_EN, USBC_REG_PCTL(USBC0_BASE));
+ #else
+ USBC_REG_clear_bit_b(USBC_BP_POWER_D_HIGH_SPEED_EN, USBC_REG_PCTL(USBC0_BASE));
+ #endif
+
+ USBC_Writeb((1 << USBC_BP_INTUSBE_EN_SUSPEND)
+ | (1 << USBC_BP_INTUSBE_EN_RESUME)
+ | (1 << USBC_BP_INTUSBE_EN_RESET)
+ | (1 << USBC_BP_INTUSBE_EN_SOF)
+ | (1 << USBC_BP_INTUSBE_EN_DISCONNECT)
+ , USBC_REG_INTUSBE(USBC0_BASE));
+ f1c100s_intc_clear_pend(F1C100S_IRQ_USBOTG);
+ f1c100s_intc_set_isr(F1C100S_IRQ_USBOTG, usb_isr_handler);
+
+ dcd_connect(rhport);
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ (void)rhport;
+ USBC_REG_set_bit_b(USBC_BP_POWER_D_SOFT_CONNECT, USBC_REG_PCTL(USBC0_BASE));
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ (void)rhport;
+ USBC_REG_clear_bit_b(USBC_BP_POWER_D_SOFT_CONNECT, USBC_REG_PCTL(USBC0_BASE));
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ f1c100s_intc_enable_irq(F1C100S_IRQ_USBOTG);
+}
+
+static void musb_int_mask(void)
+{
+ f1c100s_intc_mask_irq(F1C100S_IRQ_USBOTG);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ f1c100s_intc_disable_irq(F1C100S_IRQ_USBOTG);
+}
+
+static void musb_int_unmask(void)
+{
+ f1c100s_intc_unmask_irq(F1C100S_IRQ_USBOTG);
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ (void)dev_addr;
+ _dcd.pipe0.buf = NULL;
+ _dcd.pipe0.length = 0;
+ _dcd.pipe0.remaining = 0;
+ /* Clear RX FIFO to return ACK. */
+ USBC_SelectActiveEp(0);
+ __USBC_Dev_ep0_ReadDataComplete();
+}
+
+// Wake up host
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void)rhport;
+ USBC_REG_set_bit_b(USBC_BP_POWER_D_RESUME, USBC_REG_PCTL(USBC0_BASE));
+ delay_ms(10);
+ USBC_REG_clear_bit_b(USBC_BP_POWER_D_RESUME, USBC_REG_PCTL(USBC0_BASE));
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+#ifndef __ARMCC_VERSION
+#define __clz __builtin_clz
+#endif
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void) rhport;
+
+ uint16_t reg_val;
+
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ const unsigned mps = tu_edpt_packet_size(ep_desc);
+
+ TU_ASSERT(epn < TUP_DCD_ENDPOINT_MAX);
+
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+
+ musb_int_mask();
+
+ // volatile hw_endpoint_t *regs = edpt_regs(epn - 1);
+ USBC_SelectActiveEp(epn);
+ if (dir_in) {
+ USBC_Writew(mps, USBC_REG_TXMAXP(USBC0_BASE));
+
+ reg_val = (1 << USBC_BP_TXCSR_D_MODE)
+ | (1 << USBC_BP_TXCSR_D_FLUSH_FIFO)
+ | (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE);
+ if (xfer == TUSB_XFER_ISOCHRONOUS)
+ reg_val |= (1 << USBC_BP_TXCSR_D_ISO);
+ USBC_Writew(reg_val, USBC_REG_TXCSR(USBC0_BASE));
+
+ USBC_INT_EnableTxEp(epn);
+ } else {
+ USBC_Writew(mps, USBC_REG_RXMAXP(USBC0_BASE));
+
+ reg_val = (1 << USBC_BP_RXCSR_D_FLUSH_FIFO)
+ | (1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE);
+ if (xfer == TUSB_XFER_ISOCHRONOUS)
+ reg_val |= (1 << USBC_BP_RXCSR_D_ISO);
+ USBC_Writew(reg_val, USBC_REG_RXCSR(USBC0_BASE));
+
+ USBC_INT_EnableRxEp(epn);
+ }
+
+ /* Setup FIFO */
+ int size_in_log2_minus3 = 28 - TU_MIN(28, __clz((uint32_t)mps));
+ if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3;
+ unsigned addr = find_free_memory(size_in_log2_minus3);
+ TU_ASSERT(addr);
+
+ if (dir_in) {
+ USBC_Writew(addr, USBC_REG_TXFIFOAD(USBC0_BASE));
+ USBC_Writeb(size_in_log2_minus3, USBC_REG_TXFIFOSZ(USBC0_BASE));
+ } else {
+ USBC_Writew(addr, USBC_REG_RXFIFOAD(USBC0_BASE));
+ USBC_Writeb(size_in_log2_minus3, USBC_REG_RXFIFOSZ(USBC0_BASE));
+ }
+
+ musb_int_unmask();
+
+ return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ (void) rhport;
+ musb_int_mask();
+ USBC_Writew(1, USBC_REG_INTTxE(USBC0_BASE)); /* Enable only EP0 */
+ USBC_Writew(0, USBC_REG_INTRxE(USBC0_BASE));
+ for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
+ USBC_SelectActiveEp(i);
+ USBC_Writew(0, USBC_REG_TXMAXP(USBC0_BASE));
+ USBC_Writew((1 << USBC_BP_TXCSR_D_MODE) | (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_TXCSR_D_FLUSH_FIFO),
+ USBC_REG_TXCSR(USBC0_BASE));
+
+ USBC_Writew(0, USBC_REG_RXMAXP(USBC0_BASE));
+ USBC_Writew((1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_RXCSR_D_FLUSH_FIFO),
+ USBC_REG_RXCSR(USBC0_BASE));
+
+ USBC_Writew(0, USBC_REG_TXFIFOAD(USBC0_BASE));
+ USBC_Writeb(0, USBC_REG_TXFIFOSZ(USBC0_BASE));
+ USBC_Writew(0, USBC_REG_RXFIFOAD(USBC0_BASE));
+ USBC_Writeb(0, USBC_REG_RXFIFOSZ(USBC0_BASE));
+ }
+ musb_int_unmask();
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ unsigned const dir_in = tu_edpt_dir(ep_addr);
+
+ musb_int_mask();
+ USBC_SelectActiveEp(epn);
+ if (dir_in) {
+ USBC_INT_DisableTxEp(epn);
+ USBC_Writew(0, USBC_REG_TXMAXP(USBC0_BASE));
+ USBC_Writew((1 << USBC_BP_TXCSR_D_MODE) | (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_TXCSR_D_FLUSH_FIFO),
+ USBC_REG_TXCSR(USBC0_BASE));
+
+ USBC_Writew(0, USBC_REG_TXFIFOAD(USBC0_BASE));
+ USBC_Writeb(0, USBC_REG_TXFIFOSZ(USBC0_BASE));
+ } else {
+ USBC_INT_DisableRxEp(epn);
+ USBC_Writew(0, USBC_REG_RXMAXP(USBC0_BASE));
+ USBC_Writew((1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_RXCSR_D_FLUSH_FIFO),
+ USBC_REG_RXCSR(USBC0_BASE));
+
+ USBC_Writew(0, USBC_REG_RXFIFOAD(USBC0_BASE));
+ USBC_Writeb(0, USBC_REG_RXFIFOSZ(USBC0_BASE));
+ }
+ musb_int_unmask();
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+ bool ret;
+ // TU_LOG1("X %x %d\n", ep_addr, total_bytes);
+ unsigned const epnum = tu_edpt_number(ep_addr);
+ musb_int_mask();
+
+ if (epnum) {
+ _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] &= ~TU_BIT(epnum - 1);
+ ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes);
+ } else {
+ ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes);
+ }
+ musb_int_unmask();
+ return ret;
+}
+
+// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+ (void)rhport;
+ bool ret;
+ // TU_LOG1("X %x %d\n", ep_addr, total_bytes);
+ unsigned const epnum = tu_edpt_number(ep_addr);
+ TU_ASSERT(epnum);
+
+ musb_int_mask();
+ _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] |= TU_BIT(epnum - 1);
+ ret = edpt_n_xfer(rhport, ep_addr, (uint8_t*)ff, total_bytes);
+ musb_int_unmask();
+
+ return ret;
+}
+
+// Stall endpoint
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ musb_int_mask();
+ USBC_SelectActiveEp(epn);
+ if (0 == epn) {
+ if (!ep_addr) { /* Ignore EP80 */
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ _dcd.pipe0.buf = NULL;
+ __USBC_Dev_ep0_SendStall();
+ }
+ } else {
+ if (tu_edpt_dir(ep_addr)) { /* IN */
+ __USBC_Dev_Tx_SendStall();
+ } else { /* OUT */
+ TU_ASSERT(!__USBC_Dev_Rx_IsReadDataReady(),);
+ __USBC_Dev_Rx_SendStall();
+ }
+ }
+ musb_int_unmask();
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ musb_int_mask();
+ USBC_SelectActiveEp(epn);
+ if (0 != epn) {
+ if (tu_edpt_dir(ep_addr)) { /* IN */
+ __USBC_Dev_Tx_ClearStall();
+ } else { /* OUT */
+ __USBC_Dev_Rx_ClearStall();
+ }
+ }
+ musb_int_unmask();
+}
+
+
+void dcd_int_handler(uint8_t rhport)
+{
+ uint8_t is;
+ uint16_t txis, rxis;
+
+ is = USBC_Readb(USBC_REG_INTUSB(USBC0_BASE)); /* read interrupt status */
+ txis = USBC_Readw(USBC_REG_INTTx(USBC0_BASE)); /* read interrupt status */
+ rxis = USBC_Readw(USBC_REG_INTRx(USBC0_BASE)); /* read interrupt status */
+
+ is &= USBC_Readb(USBC_REG_INTUSBE(USBC0_BASE)); /* ignore disabled interrupts */
+ USBC_Writeb(is, USBC_REG_INTUSB(USBC0_BASE)); /* sunxi musb requires a write to interrupt register to clear */
+ if (is & USBC_INTUSB_DISCONNECT) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+ }
+ if (is & USBC_INTUSB_SOF) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
+ if (is & USBC_INTUSB_RESET) {
+ /* ep0 FADDR must be 0 when (re)entering peripheral mode */
+ USBC_SelectActiveEp(0);
+ USBC_Dev_SetAddress(0);
+ process_bus_reset(rhport);
+ }
+ if (is & USBC_INTUSB_RESUME) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+ }
+ if (is & USBC_INTUSB_SUSPEND) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+ }
+
+ txis &= USBC_Readw(USBC_REG_INTTxE(USBC0_BASE));
+ USBC_Writew(txis, USBC_REG_INTTx(USBC0_BASE));
+ if (txis & USBC_INTTx_FLAG_EP0) {
+ process_ep0(rhport);
+ txis &= ~TU_BIT(0);
+ }
+ while (txis) {
+ unsigned const num = __builtin_ctz(txis);
+ process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_IN));
+ txis &= ~TU_BIT(num);
+ }
+
+ rxis &= USBC_Readw(USBC_REG_INTRxE(USBC0_BASE));
+ USBC_Writew(rxis, USBC_REG_INTRx(USBC0_BASE));
+ while (rxis) {
+ unsigned const num = __builtin_ctz(rxis);
+ process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_OUT));
+ rxis &= ~TU_BIT(num);
+ }
+}
+
+#endif
diff --git a/src/portable/sunxi/musb_def.h b/src/portable/sunxi/musb_def.h
new file mode 100644
index 000000000..602b4f113
--- /dev/null
+++ b/src/portable/sunxi/musb_def.h
@@ -0,0 +1,643 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ * Copyright (c) 2021 Tian Yunhao (t123yh)
+ * Copyright (c) 2021 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_MUSB_DEF
+#define _TUSB_MUSB_DEF
+
+
+#define USBC_Readb(reg) (*(volatile unsigned char *)(reg))
+#define USBC_Readw(reg) (*(volatile unsigned short *)(reg))
+#define USBC_Readl(reg) (*(volatile unsigned long *)(reg))
+
+#define USBC_Writeb(value, reg) (*(volatile unsigned char *)(reg) = (value))
+#define USBC_Writew(value, reg) (*(volatile unsigned short *)(reg) = (value))
+#define USBC_Writel(value, reg) (*(volatile unsigned long *)(reg) = (value))
+
+
+#define USBC_SetBit_Mask_b(reg,mask) do { \
+ unsigned char _r = USBC_Readb(reg); \
+ _r |= (unsigned char)(mask); \
+ USBC_Writeb(_r,reg); \
+ }while(0)
+#define USBC_SetBit_Mask_w(reg,mask) do { \
+ unsigned short _r = USBC_Readw(reg); \
+ _r |= (unsigned short)(mask); \
+ USBC_Writew(_r,reg); \
+ }while(0)
+#define USBC_SetBit_Mask_l(reg,mask) do { \
+ unsigned int _r = USBC_Readl(reg); \
+ _r |= (unsigned int)(mask); \
+ USBC_Writel(_r,reg); \
+ }while(0)
+
+
+#define USBC_ClrBit_Mask_b(reg,mask) do { \
+ unsigned char _r = USBC_Readb(reg); \
+ _r &= (~(unsigned char)(mask)); \
+ USBC_Writeb(_r,reg); \
+ }while(0);
+#define USBC_ClrBit_Mask_w(reg,mask) do { \
+ unsigned short _r = USBC_Readw(reg); \
+ _r &= (~(unsigned short)(mask)); \
+ USBC_Writew(_r,reg); \
+ }while(0)
+#define USBC_ClrBit_Mask_l(reg,mask) do { \
+ unsigned int _r = USBC_Readl(reg); \
+ _r &= (~(unsigned int)(mask)); \
+ USBC_Writel(_r,reg); \
+ }while(0)
+#define USBC_REG_test_bit_b(bp, reg) (USBC_Readb(reg) & (1 << (bp)))
+#define USBC_REG_test_bit_w(bp, reg) (USBC_Readw(reg) & (1 << (bp)))
+#define USBC_REG_test_bit_l(bp, reg) (USBC_Readl(reg) & (1 << (bp)))
+
+#define USBC_REG_set_bit_b(bp, reg) (USBC_Writeb((USBC_Readb(reg) | (1 << (bp))) , (reg)))
+#define USBC_REG_set_bit_w(bp, reg) (USBC_Writew((USBC_Readw(reg) | (1 << (bp))) , (reg)))
+#define USBC_REG_set_bit_l(bp, reg) (USBC_Writel((USBC_Readl(reg) | (1 << (bp))) , (reg)))
+
+#define USBC_REG_clear_bit_b(bp, reg) (USBC_Writeb((USBC_Readb(reg) & (~ (1 << (bp)))) , (reg)))
+#define USBC_REG_clear_bit_w(bp, reg) (USBC_Writew((USBC_Readw(reg) & (~ (1 << (bp)))) , (reg)))
+#define USBC_REG_clear_bit_l(bp, reg) (USBC_Writel((USBC_Readl(reg) & (~ (1 << (bp)))) , (reg)))
+
+#define SW_UDC_EPNUMS 3
+
+#define SUNXI_SRAMC_BASE 0x01c00000
+//---------------------------------------------------------------
+// reg base
+//---------------------------------------------------------------
+#define USBC0_BASE 0x01c13000
+#define USBC1_BASE 0x01c14000
+#define USBC2_BASE 0x01c1E000
+
+//Some reg whithin musb
+#define USBPHY_CLK_REG 0x01c200CC
+#define USBPHY_CLK_RST_BIT 0
+#define USBPHY_CLK_GAT_BIT 1
+
+#define BUS_CLK_RST_REG 0x01c202c0 //Bus Clock Reset Register Bit24 : USB CLK RST
+#define BUS_RST_USB_BIT 24
+
+#define BUS_CLK_GATE0_REG 0x01c20060 //Bus Clock Gating Register Bit24 : USB CLK GATE 0: Mask 1 : Pass
+#define BUS_CLK_USB_BIT 24
+
+//#define USB_INTR
+
+#define NDMA_CFG_REG
+//-----------------------------------------------------------------------
+// musb reg offset
+//-----------------------------------------------------------------------
+
+#define USBC_REG_o_FADDR 0x0098
+#define USBC_REG_o_PCTL 0x0040
+#define USBC_REG_o_INTTx 0x0044
+#define USBC_REG_o_INTRx 0x0046
+#define USBC_REG_o_INTTxE 0x0048
+#define USBC_REG_o_INTRxE 0x004A
+#define USBC_REG_o_INTUSB 0x004C
+#define USBC_REG_o_INTUSBE 0x0050
+#define USBC_REG_o_FRNUM 0x0054
+#define USBC_REG_o_EPIND 0x0042
+#define USBC_REG_o_TMCTL 0x007C
+
+#define USBC_REG_o_TXMAXP 0x0080
+#define USBC_REG_o_CSR0 0x0082
+#define USBC_REG_o_TXCSR 0x0082
+#define USBC_REG_o_RXMAXP 0x0084
+#define USBC_REG_o_RXCSR 0x0086
+#define USBC_REG_o_COUNT0 0x0088
+#define USBC_REG_o_RXCOUNT 0x0088
+#define USBC_REG_o_EP0TYPE 0x008C
+#define USBC_REG_o_TXTYPE 0x008C
+#define USBC_REG_o_NAKLIMIT0 0x008D
+#define USBC_REG_o_TXINTERVAL 0x008D
+#define USBC_REG_o_RXTYPE 0x008E
+#define USBC_REG_o_RXINTERVAL 0x008F
+
+//#define USBC_REG_o_CONFIGDATA 0x001F //
+
+#define USBC_REG_o_EPFIFO0 0x0000
+#define USBC_REG_o_EPFIFO1 0x0004
+#define USBC_REG_o_EPFIFO2 0x0008
+#define USBC_REG_o_EPFIFO3 0x000C
+#define USBC_REG_o_EPFIFO4 0x0010
+#define USBC_REG_o_EPFIFO5 0x0014
+#define USBC_REG_o_EPFIFOx(n) (0x0000 + (n<<2))
+
+#define USBC_REG_o_DEVCTL 0x0041
+
+#define USBC_REG_o_TXFIFOSZ 0x0090
+#define USBC_REG_o_RXFIFOSZ 0x0094
+#define USBC_REG_o_TXFIFOAD 0x0092
+#define USBC_REG_o_RXFIFOAD 0x0096
+
+#define USBC_REG_o_VEND0 0x0043
+#define USBC_REG_o_VEND1 0x007D
+#define USBC_REG_o_VEND3 0x007E
+
+//#define USBC_REG_o_PHYCTL 0x006C
+#define USBC_REG_o_EPINFO 0x0078
+#define USBC_REG_o_RAMINFO 0x0079
+#define USBC_REG_o_LINKINFO 0x007A
+#define USBC_REG_o_VPLEN 0x007B
+#define USBC_REG_o_HSEOF 0x007C
+#define USBC_REG_o_FSEOF 0x007D
+#define USBC_REG_o_LSEOF 0x007E
+
+//new
+#define USBC_REG_o_FADDR0 0x0098
+#define USBC_REG_o_HADDR0 0x009A
+#define USBC_REG_o_HPORT0 0x009B
+#define USBC_REG_o_TXFADDRx 0x0098
+#define USBC_REG_o_TXHADDRx 0x009A
+#define USBC_REG_o_TXHPORTx 0x009B
+#define USBC_REG_o_RXFADDRx 0x009C
+#define USBC_REG_o_RXHADDRx 0x009E
+#define USBC_REG_o_RXHPORTx 0x009F
+
+
+#define USBC_REG_o_RPCOUNT 0x008A
+
+//new
+#define USBC_REG_o_ISCR 0x0400
+#define USBC_REG_o_PHYCTL 0x0404
+#define USBC_REG_o_PHYBIST 0x0408
+#define USBC_REG_o_PHYTUNE 0x040c
+
+#define USBC_REG_o_CSR 0x0410
+
+#define USBC_REG_o_PMU_IRQ 0x0800
+
+//-----------------------------------------------------------------------
+// registers
+//-----------------------------------------------------------------------
+
+#define USBC_REG_FADDR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_FADDR )
+#define USBC_REG_PCTL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PCTL )
+#define USBC_REG_INTTx(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTTx )
+#define USBC_REG_INTRx(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTRx )
+#define USBC_REG_INTTxE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTTxE )
+#define USBC_REG_INTRxE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTRxE )
+#define USBC_REG_INTUSB(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTUSB )
+#define USBC_REG_INTUSBE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTUSBE )
+#define USBC_REG_FRNUM(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_FRNUM )
+#define USBC_REG_EPIND(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPIND )
+#define USBC_REG_TMCTL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TMCTL )
+#define USBC_REG_TXMAXP(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXMAXP )
+
+#define USBC_REG_CSR0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_CSR0 )
+#define USBC_REG_TXCSR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXCSR )
+
+#define USBC_REG_RXMAXP(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXMAXP )
+#define USBC_REG_RXCSR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXCSR )
+
+#define USBC_REG_COUNT0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_COUNT0 )
+#define USBC_REG_RXCOUNT(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXCOUNT )
+
+#define USBC_REG_EP0TYPE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EP0TYPE )
+#define USBC_REG_TXTYPE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXTYPE )
+
+#define USBC_REG_NAKLIMIT0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_NAKLIMIT0 )
+#define USBC_REG_TXINTERVAL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXINTERVAL )
+
+#define USBC_REG_RXTYPE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXTYPE )
+#define USBC_REG_RXINTERVAL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXINTERVAL )
+//#define USBC_REG_CONFIGDATA(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_CONFIGDATA )
+#define USBC_REG_EPFIFO0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO0 )
+#define USBC_REG_EPFIFO1(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO1 )
+#define USBC_REG_EPFIFO2(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO2 )
+#define USBC_REG_EPFIFO3(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO3 )
+#define USBC_REG_EPFIFO4(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO4 )
+#define USBC_REG_EPFIFO5(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO5 )
+#define USBC_REG_EPFIFOx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_EPFIFOx(n) )
+#define USBC_REG_DEVCTL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_DEVCTL )
+#define USBC_REG_TXFIFOSZ(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXFIFOSZ )
+#define USBC_REG_RXFIFOSZ(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXFIFOSZ )
+#define USBC_REG_TXFIFOAD(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXFIFOAD )
+#define USBC_REG_RXFIFOAD(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXFIFOAD )
+#define USBC_REG_VEND0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_VEND0 )
+#define USBC_REG_VEND1(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_VEND1 )
+#define USBC_REG_EPINFO(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPINFO )
+#define USBC_REG_RAMINFO(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RAMINFO )
+#define USBC_REG_LINKINFO(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_LINKINFO )
+#define USBC_REG_VPLEN(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_VPLEN )
+#define USBC_REG_HSEOF(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_HSEOF )
+#define USBC_REG_FSEOF(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_FSEOF )
+#define USBC_REG_LSEOF(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_LSEOF )
+
+#define USBC_REG_FADDR0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_FADDR0 )
+#define USBC_REG_HADDR0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_HADDR0 )
+#define USBC_REG_HPORT0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_HPORT0 )
+
+#define USBC_REG_TXFADDRx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_TXFADDRx )
+#define USBC_REG_TXHADDRx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_TXHADDRx )
+#define USBC_REG_TXHPORTx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_TXHPORTx )
+#define USBC_REG_RXFADDRx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_RXFADDRx )
+#define USBC_REG_RXHADDRx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_RXHADDRx )
+#define USBC_REG_RXHPORTx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_RXHPORTx )
+
+#define USBC_REG_RPCOUNTx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_RPCOUNT )
+
+#define USBC_REG_ISCR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_ISCR )
+#define USBC_REG_PHYCTL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PHYCTL )
+#define USBC_REG_PHYBIST(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PHYBIST )
+#define USBC_REG_PHYTUNE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PHYTUNE )
+#define USBC_REG_PMU_IRQ(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PMU_IRQ )
+#define USBC_REG_CSR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_CSR)
+//-----------------------------------------------------------------------
+// bit position
+//-----------------------------------------------------------------------
+
+/* USB Power Control for Host only */
+#define USBC_BP_POWER_H_HIGH_SPEED_EN 5
+#define USBC_BP_POWER_H_HIGH_SPEED_FLAG 4
+#define USBC_BP_POWER_H_RESET 3
+#define USBC_BP_POWER_H_RESUME 2
+#define USBC_BP_POWER_H_SUSPEND 1
+#define USBC_BP_POWER_H_SUEPEND_EN 0
+
+/* USB Power Control for device only */
+#define USBC_BP_POWER_D_ISO_UPDATE_EN 7
+#define USBC_BP_POWER_D_SOFT_CONNECT 6
+#define USBC_BP_POWER_D_HIGH_SPEED_EN 5
+#define USBC_BP_POWER_D_HIGH_SPEED_FLAG 4
+#define USBC_BP_POWER_D_RESET_FLAG 3
+#define USBC_BP_POWER_D_RESUME 2
+#define USBC_BP_POWER_D_SUSPEND 1
+#define USBC_BP_POWER_D_ENABLE_SUSPENDM 0
+
+/* interrupt flags for ep0 and the Tx ep1~4 */
+#define USBC_BP_INTTx_FLAG_EP5 5
+#define USBC_BP_INTTx_FLAG_EP4 4
+#define USBC_BP_INTTx_FLAG_EP3 3
+#define USBC_BP_INTTx_FLAG_EP2 2
+#define USBC_BP_INTTx_FLAG_EP1 1
+#define USBC_BP_INTTx_FLAG_EP0 0
+
+/* interrupt flags for Rx ep1~4 */
+#define USBC_BP_INTRx_FLAG_EP5 5
+#define USBC_BP_INTRx_FLAG_EP4 4
+#define USBC_BP_INTRx_FLAG_EP3 3
+#define USBC_BP_INTRx_FLAG_EP2 2
+#define USBC_BP_INTRx_FLAG_EP1 1
+
+/* interrupt enable for Tx ep0~4 */
+#define USBC_BP_INTTxE_EN_EP5 5
+#define USBC_BP_INTTxE_EN_EP4 4
+#define USBC_BP_INTTxE_EN_EP3 3
+#define USBC_BP_INTTxE_EN_EP2 2
+#define USBC_BP_INTTxE_EN_EP1 1
+#define USBC_BP_INTTxE_EN_EP0 0
+
+/* interrupt enable for Rx ep1~4 */
+#define USBC_BP_INTRxE_EN_EP5 5
+#define USBC_BP_INTRxE_EN_EP4 4
+#define USBC_BP_INTRxE_EN_EP3 3
+#define USBC_BP_INTRxE_EN_EP2 2
+#define USBC_BP_INTRxE_EN_EP1 1
+
+/* USB interrupt */
+#define USBC_BP_INTUSB_VBUS_ERROR 7
+#define USBC_BP_INTUSB_SESSION_REQ 6
+#define USBC_BP_INTUSB_DISCONNECT 5
+#define USBC_BP_INTUSB_CONNECT 4
+#define USBC_BP_INTUSB_SOF 3
+#define USBC_BP_INTUSB_RESET 2
+#define USBC_BP_INTUSB_RESUME 1
+#define USBC_BP_INTUSB_SUSPEND 0
+
+/* USB interrupt enable */
+#define USBC_BP_INTUSBE_EN_VBUS_ERROR 7
+#define USBC_BP_INTUSBE_EN_SESSION_REQ 6
+#define USBC_BP_INTUSBE_EN_DISCONNECT 5
+#define USBC_BP_INTUSBE_EN_CONNECT 4
+#define USBC_BP_INTUSBE_EN_SOF 3
+#define USBC_BP_INTUSBE_EN_RESET 2
+#define USBC_BP_INTUSBE_EN_RESUME 1
+#define USBC_BP_INTUSBE_EN_SUSPEND 0
+
+/* Test Mode Control */
+#define USBC_BP_TMCTL_FORCE_HOST 7
+#define USBC_BP_TMCTL_FIFO_ACCESS 6
+#define USBC_BP_TMCTL_FORCE_FS 5
+#define USBC_BP_TMCTL_FORCE_HS 4
+#define USBC_BP_TMCTL_TEST_PACKET 3
+#define USBC_BP_TMCTL_TEST_K 2
+#define USBC_BP_TMCTL_TEST_J 1
+#define USBC_BP_TMCTL_TEST_SE0_NAK 0
+
+/* Tx Max packet */
+#define USBC_BP_TXMAXP_PACKET_COUNT 11
+#define USBC_BP_TXMAXP_MAXIMUM_PAYLOAD 0
+
+/* Control and Status Register for ep0 for Host only */
+#define USBC_BP_CSR0_H_DisPing 11
+#define USBC_BP_CSR0_H_FlushFIFO 8
+#define USBC_BP_CSR0_H_NAK_Timeout 7
+#define USBC_BP_CSR0_H_StatusPkt 6
+#define USBC_BP_CSR0_H_ReqPkt 5
+#define USBC_BP_CSR0_H_Error 4
+#define USBC_BP_CSR0_H_SetupPkt 3
+#define USBC_BP_CSR0_H_RxStall 2
+#define USBC_BP_CSR0_H_TxPkRdy 1
+#define USBC_BP_CSR0_H_RxPkRdy 0
+
+/* Control and Status Register for ep0 for device only */
+#define USBC_BP_CSR0_D_FLUSH_FIFO 8
+#define USBC_BP_CSR0_D_SERVICED_SETUP_END 7
+#define USBC_BP_CSR0_D_SERVICED_RX_PKT_READY 6
+#define USBC_BP_CSR0_D_SEND_STALL 5
+#define USBC_BP_CSR0_D_SETUP_END 4
+#define USBC_BP_CSR0_D_DATA_END 3
+#define USBC_BP_CSR0_D_SENT_STALL 2
+#define USBC_BP_CSR0_D_TX_PKT_READY 1
+#define USBC_BP_CSR0_D_RX_PKT_READY 0
+
+/* Tx ep Control and Status Register for Host only */
+#define USBC_BP_TXCSR_H_AUTOSET 15
+#define USBC_BP_TXCSR_H_RESERVED 14
+#define USBC_BP_TXCSR_H_MODE 13
+#define USBC_BP_TXCSR_H_DMA_REQ_EN 12
+#define USBC_BP_TXCSR_H_FORCE_DATA_TOGGLE 11
+#define USBC_BP_TXCSR_H_DMA_REQ_MODE 10
+#define USBC_BP_TXCSR_H_NAK_TIMEOUT 7
+#define USBC_BP_TXCSR_H_CLEAR_DATA_TOGGLE 6
+#define USBC_BP_TXCSR_H_TX_STALL 5
+#define USBC_BP_TXCSR_H_FLUSH_FIFO 3
+#define USBC_BP_TXCSR_H_ERROR 2
+#define USBC_BP_TXCSR_H_FIFO_NOT_EMPTY 1
+#define USBC_BP_TXCSR_H_TX_READY 0
+
+/* Tx ep Control and Status Register for Device only */
+#define USBC_BP_TXCSR_D_AUTOSET 15
+#define USBC_BP_TXCSR_D_ISO 14
+#define USBC_BP_TXCSR_D_MODE 13
+#define USBC_BP_TXCSR_D_DMA_REQ_EN 12
+#define USBC_BP_TXCSR_D_FORCE_DATA_TOGGLE 11
+#define USBC_BP_TXCSR_D_DMA_REQ_MODE 10
+#define USBC_BP_TXCSR_D_INCOMPLETE 7
+#define USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE 6
+#define USBC_BP_TXCSR_D_SENT_STALL 5
+#define USBC_BP_TXCSR_D_SEND_STALL 4
+#define USBC_BP_TXCSR_D_FLUSH_FIFO 3
+#define USBC_BP_TXCSR_D_UNDER_RUN 2
+#define USBC_BP_TXCSR_D_FIFO_NOT_EMPTY 1
+#define USBC_BP_TXCSR_D_TX_READY 0
+
+/* Rx Max Packet */
+#define USBC_BP_RXMAXP_PACKET_COUNT 11
+#define USBC_BP_RXMAXP_MAXIMUM_PAYLOAD 0
+
+/* Rx ep Control and Status Register for Host only */
+#define USBC_BP_RXCSR_H_AUTO_CLEAR 15
+#define USBC_BP_RXCSR_H_AUTO_REQ 14
+#define USBC_BP_RXCSR_H_DMA_REQ_EN 13
+#define USBC_BP_RXCSR_H_PID_ERROR 12
+#define USBC_BP_RXCSR_H_DMA_REQ_MODE 11
+
+#define USBC_BP_RXCSR_H_INCOMPLETE 8
+#define USBC_BP_RXCSR_H_CLEAR_DATA_TOGGLE 7
+#define USBC_BP_RXCSR_H_RX_STALL 6
+#define USBC_BP_RXCSR_H_REQ_PACKET 5
+#define USBC_BP_RXCSR_H_FLUSH_FIFO 4
+#define USBC_BP_RXCSR_H_NAK_TIMEOUT 3
+#define USBC_BP_RXCSR_H_ERROR 2
+#define USBC_BP_RXCSR_H_FIFO_FULL 1
+#define USBC_BP_RXCSR_H_RX_PKT_READY 0
+
+/* Rx ep Control and Status Register for Device only */
+#define USBC_BP_RXCSR_D_AUTO_CLEAR 15
+#define USBC_BP_RXCSR_D_ISO 14
+#define USBC_BP_RXCSR_D_DMA_REQ_EN 13
+#define USBC_BP_RXCSR_D_DISABLE_NYET 12
+#define USBC_BP_RXCSR_D_DMA_REQ_MODE 11
+
+#define USBC_BP_RXCSR_D_INCOMPLETE 8
+#define USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE 7
+#define USBC_BP_RXCSR_D_SENT_STALL 6
+#define USBC_BP_RXCSR_D_SEND_STALL 5
+#define USBC_BP_RXCSR_D_FLUSH_FIFO 4
+#define USBC_BP_RXCSR_D_DATA_ERROR 3
+#define USBC_BP_RXCSR_D_OVERRUN 2
+#define USBC_BP_RXCSR_D_FIFO_FULL 1
+#define USBC_BP_RXCSR_D_RX_PKT_READY 0
+
+/* Tx Type Register for host only */
+#define USBC_BP_TXTYPE_SPEED 6 //new
+#define USBC_BP_TXTYPE_PROROCOL 4
+#define USBC_BP_TXTYPE_TARGET_EP_NUM 0
+
+/* Rx Type Register for host only */
+#define USBC_BP_RXTYPE_SPEED 6 //new
+#define USBC_BP_RXTYPE_PROROCOL 4
+#define USBC_BP_RXTYPE_TARGET_EP_NUM 0
+
+/* Core Configueation */
+#define USBC_BP_CONFIGDATA_MPRXE 7
+#define USBC_BP_CONFIGDATA_MPTXE 6
+#define USBC_BP_CONFIGDATA_BIGENDIAN 5
+#define USBC_BP_CONFIGDATA_HBRXE 4
+#define USBC_BP_CONFIGDATA_HBTXE 3
+#define USBC_BP_CONFIGDATA_DYNFIFO_SIZING 2
+#define USBC_BP_CONFIGDATA_SOFTCONE 1
+#define USBC_BP_CONFIGDATA_UTMI_DATAWIDTH 0
+
+/* OTG Device Control */
+#define USBC_BP_DEVCTL_B_DEVICE 7
+#define USBC_BP_DEVCTL_FS_DEV 6
+#define USBC_BP_DEVCTL_LS_DEV 5
+
+#define USBC_BP_DEVCTL_VBUS 3
+#define USBC_BP_DEVCTL_HOST_MODE 2
+#define USBC_BP_DEVCTL_HOST_REQ 1
+#define USBC_BP_DEVCTL_SESSION 0
+
+/* Tx EP FIFO size control */
+#define USBC_BP_TXFIFOSZ_DPB 4
+#define USBC_BP_TXFIFOSZ_SZ 0
+
+/* Rx EP FIFO size control */
+#define USBC_BP_RXFIFOSZ_DPB 4
+#define USBC_BP_RXFIFOSZ_SZ 0
+
+/* vendor0 */
+#define USBC_BP_VEND0_DRQ_SEL 1
+#define USBC_BP_VEND0_BUS_SEL 0
+
+/* hub address */
+#define USBC_BP_HADDR_MULTI_TT 7
+
+/* Interface Status and Control */
+#define USBC_BP_ISCR_VBUS_VALID_FROM_DATA 30
+#define USBC_BP_ISCR_VBUS_VALID_FROM_VBUS 29
+#define USBC_BP_ISCR_EXT_ID_STATUS 28
+#define USBC_BP_ISCR_EXT_DM_STATUS 27
+#define USBC_BP_ISCR_EXT_DP_STATUS 26
+#define USBC_BP_ISCR_MERGED_VBUS_STATUS 25
+#define USBC_BP_ISCR_MERGED_ID_STATUS 24
+
+#define USBC_BP_ISCR_ID_PULLUP_EN 17
+#define USBC_BP_ISCR_DPDM_PULLUP_EN 16
+#define USBC_BP_ISCR_FORCE_ID 14
+#define USBC_BP_ISCR_FORCE_VBUS_VALID 12
+#define USBC_BP_ISCR_VBUS_VALID_SRC 10
+
+#define USBC_BP_ISCR_HOSC_EN 7
+#define USBC_BP_ISCR_VBUS_CHANGE_DETECT 6
+#define USBC_BP_ISCR_ID_CHANGE_DETECT 5
+#define USBC_BP_ISCR_DPDM_CHANGE_DETECT 4
+#define USBC_BP_ISCR_IRQ_ENABLE 3
+#define USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN 2
+#define USBC_BP_ISCR_ID_CHANGE_DETECT_EN 1
+#define USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN 0
+
+
+#define SUNXI_EHCI_AHB_ICHR8_EN (1 << 10)
+#define SUNXI_EHCI_AHB_INCR4_BURST_EN (1 << 9)
+#define SUNXI_EHCI_AHB_INCRX_ALIGN_EN (1 << 8)
+#define SUNXI_EHCI_ULPI_BYPASS_EN (1 << 0)
+//-----------------------------------------------------------------------
+// �Զ���
+//-----------------------------------------------------------------------
+
+/* usb��Դ���� */
+#define USBC_MAX_CTL_NUM 1
+#define USBC_MAX_EP_NUM 3 //ep0~2, ep�ĸ���
+#define USBC_MAX_FIFO_SIZE (2 * 1024)
+
+/* usb OTG mode */
+#define USBC_OTG_HOST 0
+#define USBC_OTG_DEVICE 1
+
+/* usb device type */
+#define USBC_DEVICE_HSDEV 0
+#define USBC_DEVICE_FSDEV 1
+#define USBC_DEVICE_LSDEV 2
+
+/* usb transfer type */
+#define USBC_TS_TYPE_IDLE 0
+#define USBC_TS_TYPE_CTRL 1
+#define USBC_TS_TYPE_ISO 2
+#define USBC_TS_TYPE_INT 3
+#define USBC_TS_TYPE_BULK 4
+
+/* usb transfer mode */
+#define USBC_TS_MODE_UNKOWN 0
+#define USBC_TS_MODE_LS 1
+#define USBC_TS_MODE_FS 2
+#define USBC_TS_MODE_HS 3
+
+/* usb Vbus status */
+#define USBC_VBUS_STATUS_BELOW_SESSIONEND 0
+#define USBC_VBUS_STATUS_ABOVE_SESSIONEND_BELOW_AVALID 1
+#define USBC_VBUS_STATUS_ABOVE_AVALID_BELOW_VBUSVALID 2
+#define USBC_VBUS_STATUS_ABOVE_VBUSVALID 3
+
+/* usb io type */
+#define USBC_IO_TYPE_PIO 0
+#define USBC_IO_TYPE_DMA 1
+
+/* usb ep type */
+#define USBC_EP_TYPE_IDLE 0
+#define USBC_EP_TYPE_EP0 1
+#define USBC_EP_TYPE_TX 2
+#define USBC_EP_TYPE_RX 3
+
+/* usb id type */
+#define USBC_ID_TYPE_DISABLE 0
+#define USBC_ID_TYPE_HOST 1
+#define USBC_ID_TYPE_DEVICE 2
+
+/* usb vbus valid type */
+#define USBC_VBUS_TYPE_DISABLE 0
+#define USBC_VBUS_TYPE_LOW 1
+#define USBC_VBUS_TYPE_HIGH 2
+
+/* usb a valid source */
+#define USBC_A_VALID_SOURCE_UTMI_AVALID 0
+#define USBC_A_VALID_SOURCE_UTMI_VBUS 1
+
+/* usb device switch */
+#define USBC_DEVICE_SWITCH_OFF 0
+#define USBC_DEVICE_SWITCH_ON 1
+
+/* usb fifo config mode */
+#define USBC_FIFO_MODE_4K 0
+#define USBC_FIFO_MODE_8K 1
+
+/*
+ **************************************************
+ * usb interrupt mask
+ *
+ **************************************************
+ */
+
+/* interrupt flags for ep0 and the Tx ep1~4 */
+#define USBC_INTTx_FLAG_EP5 (1 << USBC_BP_INTTx_FLAG_EP5)
+#define USBC_INTTx_FLAG_EP4 (1 << USBC_BP_INTTx_FLAG_EP4)
+#define USBC_INTTx_FLAG_EP3 (1 << USBC_BP_INTTx_FLAG_EP3)
+#define USBC_INTTx_FLAG_EP2 (1 << USBC_BP_INTTx_FLAG_EP2)
+#define USBC_INTTx_FLAG_EP1 (1 << USBC_BP_INTTx_FLAG_EP1)
+#define USBC_INTTx_FLAG_EP0 (1 << USBC_BP_INTTx_FLAG_EP0)
+
+/* interrupt flags for Rx ep1~4 */
+#define USBC_INTRx_FLAG_EP5 (1 << USBC_BP_INTRx_FLAG_EP5)
+#define USBC_INTRx_FLAG_EP4 (1 << USBC_BP_INTRx_FLAG_EP4)
+#define USBC_INTRx_FLAG_EP3 (1 << USBC_BP_INTRx_FLAG_EP3)
+#define USBC_INTRx_FLAG_EP2 (1 << USBC_BP_INTRx_FLAG_EP2)
+#define USBC_INTRx_FLAG_EP1 (1 << USBC_BP_INTRx_FLAG_EP1)
+
+/* USB interrupt */
+#define USBC_INTUSB_VBUS_ERROR (1 << USBC_BP_INTUSB_VBUS_ERROR)
+#define USBC_INTUSB_SESSION_REQ (1 << USBC_BP_INTUSB_SESSION_REQ)
+#define USBC_INTUSB_DISCONNECT (1 << USBC_BP_INTUSB_DISCONNECT)
+#define USBC_INTUSB_CONNECT (1 << USBC_BP_INTUSB_CONNECT)
+#define USBC_INTUSB_SOF (1 << USBC_BP_INTUSB_SOF)
+#define USBC_INTUSB_RESET (1 << USBC_BP_INTUSB_RESET)
+#define USBC_INTUSB_RESUME (1 << USBC_BP_INTUSB_RESUME)
+#define USBC_INTUSB_SUSPEND (1 << USBC_BP_INTUSB_SUSPEND)
+
+#define USB_CSRL0_NAKTO 0x00000080 // NAK Timeout
+#define USB_CSRL0_SETENDC 0x00000080 // Setup End Clear
+#define USB_CSRL0_STATUS 0x00000040 // STATUS Packet
+#define USB_CSRL0_RXRDYC 0x00000040 // RXRDY Clear
+#define USB_CSRL0_REQPKT 0x00000020 // Request Packet
+#define USB_CSRL0_STALL 0x00000020 // Send Stall
+#define USB_CSRL0_SETEND 0x00000010 // Setup End
+#define USB_CSRL0_ERROR 0x00000010 // Error
+#define USB_CSRL0_DATAEND 0x00000008 // Data End
+#define USB_CSRL0_SETUP 0x00000008 // Setup Packet
+#define USB_CSRL0_STALLED 0x00000004 // Endpoint Stalled
+#define USB_CSRL0_TXRDY 0x00000002 // Transmit Packet Ready
+#define USB_CSRL0_RXRDY 0x00000001 // Receive Packet Ready
+
+#define USB_RXFIFOSZ_DPB 0x00000010 // Double Packet Buffer Support
+#define USB_RXFIFOSZ_SIZE_M 0x0000000F // Max Packet Size
+
+#define USB_TXFIFOSZ_DPB 0x00000010 // Double Packet Buffer Support
+#define USB_TXFIFOSZ_SIZE_M 0x0000000F // Max Packet Size
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index bb21b3dcd..f5ecdfe4f 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -28,23 +28,26 @@
*/
#include "tusb_option.h"
-#include "device/dcd_attr.h"
-#if TUSB_OPT_DEVICE_ENABLED && \
- ( defined(DCD_ATTR_DWC2_STM32) || \
- TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_GD32VF103) || \
- TU_CHECK_MCU(OPT_MCU_EFM32GG, OPT_MCU_BCM2711, OPT_MCU_XMC4000) )
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_DWC2)
#include "device/dcd.h"
#include "dwc2_type.h"
-#if defined(DCD_ATTR_DWC2_STM32)
+// Following symbols must be defined by port header
+// - _dwc2_controller[]: array of controllers
+// - DWC2_EP_MAX: largest EP counts of all controllers
+// - dwc2_phy_init/dwc2_phy_update: phy init called before and after core reset
+// - dwc2_dcd_int_enable/dwc2_dcd_int_disable
+// - dwc2_remote_wakeup_delay
+
+#if defined(TUP_USBIP_DWC2_STM32)
#include "dwc2_stm32.h"
#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
#include "dwc2_esp32.h"
#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
#include "dwc2_gd32.h"
-#elif TU_CHECK_MCU(OPT_MCU_BCM2711)
+#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837)
#include "dwc2_bcm.h"
#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
#include "dwc2_efm32.h"
@@ -59,7 +62,7 @@
//--------------------------------------------------------------------+
// DWC2 registers
-#define DWC2_REG(_port) ((dwc2_regs_t*) DWC2_REG_BASE)
+#define DWC2_REG(_port) ((dwc2_regs_t*) _dwc2_controller[_port].reg_base)
// Debug level for DWC2
#define DWC2_DEBUG 2
@@ -76,7 +79,6 @@
#define dcache_clean_invalidate(_addr, _size)
#endif
-
static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2];
typedef struct {
@@ -97,44 +99,47 @@ static uint16_t ep0_pending[2]; // Index determines direction
static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs)
static bool _out_ep_closed; // Flag to check if RX FIFO size needs an update (reduce its size)
+// 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 recommendations from reference manual
-static inline uint16_t calc_rx_ff_size(uint16_t ep_size)
+static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count)
{
- return 15 + 2*(ep_size/4) + 2*DWC2_EP_MAX;
+ return 15 + 2*(max_ep_size/4) + 2*ep_count;
}
static void update_grxfsiz(uint8_t rhport)
{
- (void) rhport;
-
- dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
// Determine largest EP size for RX FIFO
uint16_t max_epsize = 0;
- for (uint8_t epnum = 0; epnum < DWC2_EP_MAX; epnum++)
+ for (uint8_t epnum = 0; epnum < ep_count; epnum++)
{
max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size);
}
// Update size of RX FIFO
- dwc2->grxfsiz = calc_rx_ff_size(max_epsize);
+ dwc2->grxfsiz = calc_grxfsiz(max_epsize, ep_count);
}
-// Setup the control endpoint 0.
+// Start of Bus Reset
static void bus_reset(uint8_t rhport)
{
- (void) rhport;
-
- dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
tu_memclr(xfer_status, sizeof(xfer_status));
_out_ep_closed = false;
+ _sof_en = false;
+
// clear device address
dwc2->dcfg &= ~DCFG_DAD_Msk;
// 1. NAK for all OUT endpoints
- for ( uint8_t n = 0; n < DWC2_EP_MAX; n++ )
+ for ( uint8_t n = 0; n < ep_count; n++ )
{
dwc2->epout[n].doepctl |= DOEPCTL_SNAK;
}
@@ -184,22 +189,24 @@ static void bus_reset(uint8_t rhport)
// - 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 DWC2_EP_MAX = 47 + 2 x DWC2_EP_MAX
- // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x DWC2_EP_MAX = 271 + 2 x DWC2_EP_MAX
+ // - 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 + DWC2_EP_MAX
+ // 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.
- dwc2->grxfsiz = calc_rx_ff_size(TUD_OPT_HIGH_SPEED ? 512 : 64);
+ // EP0 out max is 64
+ dwc2->grxfsiz = calc_grxfsiz(64, ep_count);
+ // Setup the control endpoint 0
_allocated_fifo_words_tx = 16;
// Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
- dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
+ dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx);
// Fixed control EP0 size to 64 bytes
dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos);
@@ -362,7 +369,11 @@ static void reset_core(dwc2_regs_t * dwc2)
static bool phy_hs_supported(dwc2_regs_t * dwc2)
{
// note: esp32 incorrect report its hs_phy_type as utmi
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+ return false;
+#else
return TUD_OPT_HIGH_SPEED && dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE;
+#endif
}
static void phy_fs_init(dwc2_regs_t * dwc2)
@@ -461,6 +472,7 @@ static bool check_dwc2(dwc2_regs_t * dwc2)
#endif
// For some reasons: GD32VF103 snpsid and all hwcfg register are always zero (skip it)
+ (void) dwc2;
#if !TU_CHECK_MCU(OPT_MCU_GD32VF103)
uint32_t const gsnpsid = dwc2->gsnpsid & GSNPSID_ID_MASK;
TU_ASSERT(gsnpsid == DWC2_OTG_ID || gsnpsid == DWC2_FS_IOT_ID || gsnpsid == DWC2_HS_IOT_ID);
@@ -592,6 +604,24 @@ void dcd_disconnect(uint8_t rhport)
dwc2->dctl |= DCTL_SDIS;
}
+// Be advised: audio, video and possibly other iso-ep classes use dcd_sof_enable() to enable/disable its corresponding ISR on purpose!
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+
+ _sof_en = en;
+
+ if (en)
+ {
+ dwc2->gintsts = GINTSTS_SOF;
+ dwc2->gintmsk |= GINTMSK_SOFM;
+ }
+ else
+ {
+ dwc2->gintmsk &= ~GINTMSK_SOFM;
+ }
+}
/*------------------------------------------------------------------*/
/* DCD Endpoint port
@@ -601,12 +631,13 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
{
(void) rhport;
- dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
- TU_ASSERT(epnum < DWC2_EP_MAX);
+ TU_ASSERT(epnum < ep_count);
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
xfer->max_size = tu_edpt_packet_size(desc_edpt);
@@ -617,12 +648,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
if(dir == TUSB_DIR_OUT)
{
// Calculate required size of RX FIFO
- uint16_t const sz = calc_rx_ff_size(4*fifo_size);
+ uint16_t const sz = calc_grxfsiz(4*fifo_size, ep_count);
// If size_rx needs to be extended check if possible and if so enlarge it
if (dwc2->grxfsiz < sz)
{
- TU_ASSERT(sz + _allocated_fifo_words_tx <= DWC2_EP_FIFO_SIZE/4);
+ TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size/4);
// Enlarge RX FIFO
dwc2->grxfsiz = sz;
@@ -659,15 +690,15 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
// - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
// Check if free space is available
- TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= DWC2_EP_FIFO_SIZE/4);
+ 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 %u", fifo_size*4, DWC2_EP_FIFO_SIZE-_allocated_fifo_words_tx*4);
+ TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %lu", fifo_size*4, _dwc2_controller[rhport].ep_fifo_size-_allocated_fifo_words_tx*4);
// DIEPTXF starts at FIFO #1.
// Both TXFD and TXSA are in unit of 32-bit words.
- dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
+ dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx);
dwc2->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) |
(epnum << DIEPCTL_TXFNUM_Pos) |
@@ -684,14 +715,13 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
// Close all non-control endpoints, cancel all pending transfers if any.
void dcd_edpt_close_all (uint8_t rhport)
{
- (void) rhport;
-
- dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
// Disable non-control interrupt
dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos);
- for(uint8_t n = 1; n < DWC2_EP_MAX; n++)
+ for(uint8_t n = 1; n < ep_count; n++)
{
// disable OUT endpoint
dwc2->epout[n].doepctl = 0;
@@ -800,8 +830,7 @@ static void dcd_edpt_disable (uint8_t rhport, uint8_t ep_addr, bool stall)
}
// Flush the FIFO, and wait until we have confirmed it cleared.
- dwc2->grstctl |= (epnum << GRSTCTL_TXFNUM_Pos);
- dwc2->grstctl |= GRSTCTL_TXFFLSH;
+ dwc2->grstctl = ((epnum << GRSTCTL_TXFNUM_Pos) | GRSTCTL_TXFFLSH);
while ( (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) != 0 ) {}
}
else
@@ -853,8 +882,9 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
{
uint16_t const fifo_size = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXFD_Msk) >> DIEPTXF_INEPTXFD_Pos;
uint16_t const fifo_start = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXSA_Msk) >> DIEPTXF_INEPTXSA_Pos;
+
// For now only the last opened endpoint can be closed without fuss.
- TU_ASSERT(fifo_start == DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx,);
+ TU_ASSERT(fifo_start == _dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx,);
_allocated_fifo_words_tx -= fifo_size;
}
else
@@ -1057,11 +1087,12 @@ static void handle_rxflvl_irq(uint8_t rhport)
static void handle_epout_irq (uint8_t rhport)
{
- dwc2_regs_t *dwc2 = DWC2_REG(rhport);
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
// DAINT for a given EP clears when DOEPINTx is cleared.
// OEPINT will be cleared when DAINT's out bits are cleared.
- for ( uint8_t n = 0; n < DWC2_EP_MAX; n++ )
+ for ( uint8_t n = 0; n < ep_count; n++ )
{
if ( dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n) )
{
@@ -1108,12 +1139,13 @@ static void handle_epout_irq (uint8_t rhport)
static void handle_epin_irq (uint8_t rhport)
{
- dwc2_regs_t *dwc2 = DWC2_REG(rhport);
- dwc2_epin_t* epin = dwc2->epin;
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
+ dwc2_epin_t* epin = dwc2->epin;
// DAINT for a given EP clears when DIEPINTx is cleared.
// IEPINT will be cleared when DAINT's out bits are cleared.
- for ( uint8_t n = 0; n < DWC2_EP_MAX; n++ )
+ for ( uint8_t n = 0; n < ep_count; n++ )
{
if ( dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n) )
{
@@ -1255,8 +1287,16 @@ void dcd_int_handler(uint8_t rhport)
{
dwc2->gotgint = GINTSTS_SOF;
- // Disable SOF interrupt since currently only used for remote wakeup detection
- dwc2->gintmsk &= ~GINTMSK_SOFM;
+ if (_sof_en)
+ {
+ uint32_t frame = (dwc2->dsts & (DSTS_FNSOF)) >> 8;
+ dcd_event_sof(rhport, frame, true);
+ }
+ else
+ {
+ // Disable SOF interrupt if SOF was not explicitly enabled. SOF was used for remote wakeup detection
+ dwc2->gintmsk &= ~GINTMSK_SOFM;
+ }
dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
}
diff --git a/src/portable/synopsys/dwc2/dwc2_bcm.h b/src/portable/synopsys/dwc2/dwc2_bcm.h
index 353bc21ee..732d96ae0 100644
--- a/src/portable/synopsys/dwc2/dwc2_bcm.h
+++ b/src/portable/synopsys/dwc2/dwc2_bcm.h
@@ -31,12 +31,16 @@
extern "C" {
#endif
+#include "broadcom/defines.h"
#include "broadcom/interrupts.h"
#include "broadcom/caches.h"
-#define DWC2_REG_BASE USB_OTG_GLOBAL_BASE
#define DWC2_EP_MAX 8
-#define DWC2_EP_FIFO_SIZE 4096
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ { .reg_base = USB_OTG_GLOBAL_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 4096 }
+};
#define dcache_clean(_addr, _size) data_clean(_addr, _size)
#define dcache_invalidate(_addr, _size) data_invalidate(_addr, _size)
@@ -45,17 +49,13 @@
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
- (void) rhport;
- BP_EnableIRQ(USB_IRQn);
- __asm__ volatile("isb"); // needed if TIMER1 IRQ is not enabled !?
+ BP_EnableIRQ(_dwc2_controller[rhport].irqnum);
}
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_disable (uint8_t rhport)
{
- (void) rhport;
- BP_DisableIRQ(USB_IRQn);
- __asm__ volatile("isb"); // needed if TIMER1 IRQ is not enabled !?
+ BP_DisableIRQ(_dwc2_controller[rhport].irqnum);
}
static inline void dwc2_remote_wakeup_delay(void)
diff --git a/src/portable/synopsys/dwc2/dwc2_efm32.h b/src/portable/synopsys/dwc2/dwc2_efm32.h
index ee4c3c715..0e3570cbb 100644
--- a/src/portable/synopsys/dwc2/dwc2_efm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_efm32.h
@@ -37,20 +37,22 @@
// EFM32 has custom control register before DWC registers
#define DWC2_REG_BASE (USB_BASE + offsetof(USB_TypeDef, GOTGCTL))
#define DWC2_EP_MAX 7
-#define DWC2_EP_FIFO_SIZE 2048
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ { .reg_base = DWC2_REG_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 2048 }
+};
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
- (void) rhport;
- NVIC_EnableIRQ(USB_IRQn);
+ NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum);
}
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_disable (uint8_t rhport)
{
- (void) rhport;
- NVIC_DisableIRQ(USB_IRQn);
+ NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum);
}
static inline void dwc2_remote_wakeup_delay(void)
diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h
index 78da277d5..c50dd66b8 100644
--- a/src/portable/synopsys/dwc2/dwc2_esp32.h
+++ b/src/portable/synopsys/dwc2/dwc2_esp32.h
@@ -37,10 +37,12 @@
//#include "soc/usb_periph.h"
#define DWC2_REG_BASE 0x60080000UL
-#define DWC2_EP_MAX 5 // USB_OUT_EP_NUM
-#define DWC2_EP_FIFO_SIZE 1024
+#define DWC2_EP_MAX 6 // USB_OUT_EP_NUM. TODO ESP32Sx only has 5 tx fifo (5 endpoint IN)
-// #define EP_FIFO_NUM 5
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ { .reg_base = DWC2_REG_BASE, .irqnum = 0, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1024 }
+};
static intr_handle_t usb_ih;
diff --git a/src/portable/synopsys/dwc2/dwc2_gd32.h b/src/portable/synopsys/dwc2/dwc2_gd32.h
index f8fa01ee0..0375fffe4 100644
--- a/src/portable/synopsys/dwc2/dwc2_gd32.h
+++ b/src/portable/synopsys/dwc2/dwc2_gd32.h
@@ -34,8 +34,11 @@
#define DWC2_REG_BASE 0x50000000UL
#define DWC2_EP_MAX 4
-#define DWC2_EP_FIFO_SIZE 1280
-#define RHPORT_IRQn 86
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ { .reg_base = DWC2_REG_BASE, .irqnum = 86, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1280 }
+};
extern uint32_t SystemCoreClock;
@@ -57,15 +60,13 @@ static inline void __eclic_disable_interrupt (uint32_t irq){
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
- (void) rhport;
- __eclic_enable_interrupt(RHPORT_IRQn);
+ __eclic_enable_interrupt(_dwc2_controller[rhport].irqnum);
}
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_disable (uint8_t rhport)
{
- (void) rhport;
- __eclic_disable_interrupt(RHPORT_IRQn);
+ __eclic_disable_interrupt(_dwc2_controller[rhport].irqnum);
}
static inline void dwc2_remote_wakeup_delay(void)
diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h
index 469045ac4..ea786362e 100644
--- a/src/portable/synopsys/dwc2/dwc2_stm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_stm32.h
@@ -43,10 +43,14 @@
#define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS
#define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE
+ #define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS
+ #define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE
+
#elif CFG_TUSB_MCU == OPT_MCU_STM32F4
#include "stm32f4xx.h"
#define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS
#define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE
+
#define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS
#define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE
@@ -54,13 +58,22 @@
#include "stm32h7xx.h"
#define EP_MAX_FS 9
#define EP_FIFO_SIZE_FS 4096
+
#define EP_MAX_HS 9
#define EP_FIFO_SIZE_HS 4096
+ // NOTE: H7 with only 1 USB port: H72x / H73x / H7Ax / H7Bx
+ // USB_OTG_FS_PERIPH_BASE and OTG_FS_IRQn not defined
+ #if (! defined USB2_OTG_FS)
+ #define USB_OTG_FS_PERIPH_BASE USB1_OTG_HS_PERIPH_BASE
+ #define OTG_FS_IRQn OTG_HS_IRQn
+ #endif
+
#elif CFG_TUSB_MCU == OPT_MCU_STM32F7
#include "stm32f7xx.h"
#define EP_MAX_FS 6
#define EP_FIFO_SIZE_FS 1280
+
#define EP_MAX_HS 9
#define EP_FIFO_SIZE_HS 4096
@@ -69,39 +82,53 @@
#define EP_MAX_FS 6
#define EP_FIFO_SIZE_FS 1280
+#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
+ #include "stm32u5xx.h"
+ #define USB_OTG_FS_PERIPH_BASE USB_OTG_FS_BASE
+ #define EP_MAX_FS 6
+ #define EP_FIFO_SIZE_FS 1280
+
#else
#error "Unsupported MCUs"
#endif
-// On STM32 we associate Port0 to OTG_FS, and Port1 to OTG_HS
-#if TUD_OPT_RHPORT == 0
- #define DWC2_REG_BASE USB_OTG_FS_PERIPH_BASE
- #define DWC2_EP_MAX EP_MAX_FS
- #define DWC2_EP_FIFO_SIZE EP_FIFO_SIZE_FS
- #define RHPORT_IRQn OTG_FS_IRQn
-
+// OTG HS always has higher number of endpoints than FS
+#ifdef USB_OTG_HS_PERIPH_BASE
+ #define DWC2_EP_MAX EP_MAX_HS
#else
- #define DWC2_REG_BASE USB_OTG_HS_PERIPH_BASE
- #define DWC2_EP_MAX EP_MAX_HS
- #define DWC2_EP_FIFO_SIZE EP_FIFO_SIZE_HS
- #define RHPORT_IRQn OTG_HS_IRQn
+ #define DWC2_EP_MAX EP_MAX_FS
+#endif
+// On STM32 for consistency we associate
+// - Port0 to OTG_FS, and Port1 to OTG_HS
+static const dwc2_controller_t _dwc2_controller[] =
+{
+#ifdef USB_OTG_FS_PERIPH_BASE
+ { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .ep_fifo_size = EP_FIFO_SIZE_FS },
+#endif
+
+#ifdef USB_OTG_HS_PERIPH_BASE
+ { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .ep_fifo_size = EP_FIFO_SIZE_HS },
#endif
+};
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
-extern uint32_t SystemCoreClock;
+// SystemCoreClock is alrady included by family header
+// extern uint32_t SystemCoreClock;
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
- (void) rhport;
- NVIC_EnableIRQ(RHPORT_IRQn);
+ NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum);
}
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_disable (uint8_t rhport)
{
- (void) rhport;
- NVIC_DisableIRQ(RHPORT_IRQn);
+ NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum);
}
TU_ATTR_ALWAYS_INLINE
diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h
index dbef20314..3fc979337 100644
--- a/src/portable/synopsys/dwc2/dwc2_type.h
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -19,6 +19,19 @@
#include "stdint.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// Controller
+typedef struct
+{
+ uintptr_t reg_base;
+ uint32_t irqnum;
+ uint8_t ep_count;
+ uint32_t ep_fifo_size;
+}dwc2_controller_t;
+
/* DWC OTG HW Release versions */
#define DWC2_CORE_REV_2_71a 0x4f54271a
#define DWC2_CORE_REV_2_72a 0x4f54272a
@@ -40,10 +53,6 @@
#define DWC2_FS_IOT_ID 0x55310000
#define DWC2_HS_IOT_ID 0x55320000
-#ifdef __cplusplus
- extern "C" {
-#endif
-
#if 0
// HS PHY
typedef struct
@@ -986,16 +995,16 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
/******************** Bit definition for OTG register ********************/
#define GNPTXFSIZ_NPTXFSA_Pos (0U)
-#define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << NPTXFSA_Pos) // 0x0000FFFF */
+#define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFSA_Pos) // 0x0000FFFF */
#define GNPTXFSIZ_NPTXFSA GNPTXFSIZ_NPTXFSA_Msk // Nonperiodic transmit RAM start address */
#define GNPTXFSIZ_NPTXFD_Pos (16U)
-#define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << NPTXFD_Pos) // 0xFFFF0000 */
+#define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFD_Pos) // 0xFFFF0000 */
#define GNPTXFSIZ_NPTXFD GNPTXFSIZ_NPTXFD_Msk // Nonperiodic TxFIFO depth */
#define DIEPTXF0_TX0FSA_Pos (0U)
-#define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << TX0FSA_Pos) // 0x0000FFFF */
+#define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << DIEPTXF0_TX0FSA_Pos) // 0x0000FFFF */
#define DIEPTXF0_TX0FSA DIEPTXF0_TX0FSA_Msk // Endpoint 0 transmit RAM start address */
#define DIEPTXF0_TX0FD_Pos (16U)
-#define DIEPTXF0_TX0FD_Msk (0xFFFFUL << TX0FD_Pos) // 0xFFFF0000 */
+#define DIEPTXF0_TX0FD_Msk (0xFFFFUL << DIEPTXF0_TX0FD_Pos) // 0xFFFF0000 */
#define DIEPTXF0_TX0FD DIEPTXF0_TX0FD_Msk // Endpoint 0 TxFIFO depth */
/******************** Bit definition for DVBUSPULSE register ********************/
diff --git a/src/portable/synopsys/dwc2/dwc2_xmc.h b/src/portable/synopsys/dwc2/dwc2_xmc.h
index 4e6bebb01..63419abf7 100644
--- a/src/portable/synopsys/dwc2/dwc2_xmc.h
+++ b/src/portable/synopsys/dwc2/dwc2_xmc.h
@@ -34,23 +34,24 @@
#include "xmc_device.h"
-// XMC has custom control register before DWC registers
-#define DWC2_REG_BASE USB0_BASE
#define DWC2_EP_MAX 7
-#define DWC2_EP_FIFO_SIZE 2048
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ // Note: XMC has some custom control registers before DWC registers
+ { .reg_base = USB0_BASE, .irqnum = USB0_0_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 2048 }
+};
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
- (void) rhport;
- NVIC_EnableIRQ(USB0_0_IRQn);
+ NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum);
}
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_disable (uint8_t rhport)
{
- (void) rhport;
- NVIC_DisableIRQ(USB0_0_IRQn);
+ NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum);
}
static inline void dwc2_remote_wakeup_delay(void)
diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c
index 977369300..26b5dce9d 100644
--- a/src/portable/template/dcd_template.c
+++ b/src/portable/template/dcd_template.c
@@ -82,6 +82,14 @@ void dcd_disconnect(uint8_t rhport)
(void) rhport;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
index 3b91f2798..b4dfda575 100644
--- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
+++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
@@ -27,7 +27,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MSP430x5xx )
+#if CFG_TUD_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MSP430x5xx )
#include "msp430.h"
#include "device/dcd.h"
@@ -222,6 +222,14 @@ void dcd_disconnect(uint8_t rhport)
dcd_int_enable(rhport);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
@@ -623,7 +631,18 @@ void dcd_int_handler(uint8_t rhport)
handle_setup_packet();
}
- uint16_t curr_vector = USBVECINT;
+ // Workaround possible bug in MSP430 GCC 9.3.0 where volatile variable
+ // USBVECINT is read from twice when only once is intended. The second
+ // (garbage) read seems to be triggered by certain switch statement
+ // configurations.
+ uint16_t curr_vector;
+ #if __GNUC__ > 9 || (__GNUC__ == 9 && __GNUC_MINOR__ > 2)
+ asm volatile ("mov %1, %0"
+ : "=r" (curr_vector)
+ : "m" (USBVECINT));
+ #else
+ curr_vector = USBVECINT;
+ #endif
switch(curr_vector)
{
diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c
index 837d0c0ce..e368b5f39 100644
--- a/src/portable/valentyusb/eptri/dcd_eptri.c
+++ b/src/portable/valentyusb/eptri/dcd_eptri.c
@@ -24,6 +24,10 @@
* This file is part of the TinyUSB stack.
*/
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI)
+
#ifndef DEBUG
#define DEBUG 0
#endif
@@ -32,10 +36,6 @@
#define LOG_USB 0
#endif
-#include "tusb_option.h"
-
-#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI)
-
#include "device/dcd.h"
#include "dcd_eptri.h"
#include "csr.h"
@@ -401,6 +401,13 @@ void dcd_disconnect(uint8_t rhport)
usb_pullup_out_write(0);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
//--------------------------------------------------------------------+
// DCD Endpoint Port