summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzhouqiyusth <[email protected]>2022-04-14 20:17:04 +0800
committersakumisu <[email protected]>2022-04-14 20:21:43 +0800
commitb300b42a471bfe02266577432fc077c3891fd136 (patch)
tree031403a73711a3375a951ee469c23616428efc51
parentc6495ac5af87f854234c1a526a5a8fb40078fa2f (diff)
add imxrt usb device port
-rw-r--r--port/imxrt/README.md12
-rw-r--r--port/imxrt/usb_dc_imxrt.c1501
-rw-r--r--port/imxrt/usb_dc_imxrt_port.h42
-rw-r--r--port/imxrt/usb_imxrt_reg.h368
4 files changed, 1923 insertions, 0 deletions
diff --git a/port/imxrt/README.md b/port/imxrt/README.md
new file mode 100644
index 00000000..40b4df55
--- /dev/null
+++ b/port/imxrt/README.md
@@ -0,0 +1,12 @@
+# Note
+
+## Support Chip List
+
+- IMXRT105x
+- IMXRT106x
+
+## Before Use
+
+- You should set the heap size on greater than the sum of all usb endpoint buffers.
+- Open the clock on USBPHY1.
+- Set macro CONFIG_USB_HS for use the high-speed mode otherwise the full-speed mode. \ No newline at end of file
diff --git a/port/imxrt/usb_dc_imxrt.c b/port/imxrt/usb_dc_imxrt.c
new file mode 100644
index 00000000..b59ada2a
--- /dev/null
+++ b/port/imxrt/usb_dc_imxrt.c
@@ -0,0 +1,1501 @@
+#include "usbd_core.h"
+#include "fsl_common.h"
+#include "usb_dc_imxrt_port.h"
+#include "usb_imxrt_reg.h"
+
+#define USB_GET_INDEX(ep) ((USB_EP_GET_IDX(ep) << 1U) | USB_EP_DIR_IS_IN(ep))
+#define USB_GET_PRIMEBIT(ep) (1UL << (USB_EP_GET_IDX(ep) + (USB_EP_GET_DIR(ep) >> 0x03U)))
+
+/*
+ * alloc the temporary memory to store the status
+ */
+#define OSA_SR_ALLOC() uint32_t osaCurrentSr = 0U;
+/*
+ * Enter critical mode
+ */
+#define OSA_ENTER_CRITICAL() (osaCurrentSr = DisableGlobalIRQ())
+/*
+ * Exit critical mode and retore the previous mode
+ */
+#define OSA_EXIT_CRITICAL() EnableGlobalIRQ(osaCurrentSr)
+
+/* Apply for dtd buffer list */
+USB_RAM_ADDRESS_ALIGNMENT(4)
+static usb_dtd_buffer_t g_UsbDtdBufList[USB_DEVICE_USE_PORT][USB_DEVICE_MAX_DTD] = {0};
+
+/* Apply for QH buffer, 2048-byte alignment */
+USB_RAM_ADDRESS_ALIGNMENT(2048)
+USB_CONTROLLER_DATA static uint8_t qh_buffer[(USB_DEVICE_USE_PORT - 1) * 2048 +
+ 2 * USB_DEVICE_ENDPOINTS * sizeof(usb_device_ehci_qh_struct_t)];
+
+/* Apply for DTD buffer, 32-byte alignment */
+USB_RAM_ADDRESS_ALIGNMENT(32)
+USB_CONTROLLER_DATA static usb_device_ehci_dtd_struct_t s_UsbDeviceEhciDtd[USB_DEVICE_USE_PORT][USB_DEVICE_MAX_DTD];
+
+/* Apply for ehci device state structure */
+static usb_device_ehci_state_struct_t g_UsbDeviceEhciState[USB_DEVICE_USE_PORT];
+
+/* device function */
+static void usb_clock_init(uint8_t instance)
+{
+ USBPHY_Type *usbPhyBase;
+
+ if(instance == 0)
+ {
+ CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
+ CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
+ usbPhyBase = USBPHY1;
+ }
+ else if(instance == 1)
+ {
+ CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
+ CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U);
+ usbPhyBase = USBPHY2;
+ }
+ else
+ {
+ while(1);
+ }
+
+ USB_ANALOG->INSTANCE[instance].CHRG_DETECT_SET =
+ USB_ANALOG_CHRG_DETECT_CHK_CHRG_B(1) | USB_ANALOG_CHRG_DETECT_EN_B(1);
+
+#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT)))
+ usbPhyBase->TRIM_OVERRIDE_EN = 0x001fU; /* override IFR value */
+#endif
+ usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK; /* support LS device. */
+ usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL3_MASK; /* support external FS Hub with LS device connected. */
+ /* PWD register provides overall control of the PHY power state */
+ usbPhyBase->PWD = 0U;
+
+ /* Decode to trim the nominal 17.78mA current source for the High Speed TX drivers on USB_DP and USB_DM. */
+ usbPhyBase->TX =
+ ((usbPhyBase->TX & (~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK))) |
+ (USBPHY_TX_D_CAL(BOARD_USB_PHY_D_CAL) | USBPHY_TX_TXCAL45DP(BOARD_USB_PHY_TXCAL45DP) |
+ USBPHY_TX_TXCAL45DM(BOARD_USB_PHY_TXCAL45DM)));
+}
+
+/*!
+ * @brief Get dtds and link to QH.
+ *
+ * The function is used to get dtds and link to QH.
+ *
+ * @param ehciState Pointer of the device EHCI state structure.
+ * @param endpointAddress The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN.
+ * @param buffer The memory address needed to be transferred.
+ * @param length Data length.
+ *
+ * @return A USB error code or kStatus_USB_Success.
+ */
+static usb_status_t USB_DeviceEhciTransfer(usb_device_ehci_state_struct_t *ehciState,
+ uint8_t endpointAddress,
+ uint8_t *buffer,
+ uint32_t length)
+{
+ usb_device_ehci_dtd_struct_t *dtd;
+ usb_device_ehci_dtd_struct_t *dtdHead;
+ uint32_t index = USB_GET_INDEX(endpointAddress);
+ uint32_t primeBit = USB_GET_PRIMEBIT(endpointAddress);
+ uint32_t epStatus = primeBit;
+ uint32_t sendLength;
+ uint32_t currentIndex = 0U;
+ uint32_t dtdRequestCount = (length + USB_DEVICE_ECHI_DTD_TOTAL_BYTES - 1U) / USB_DEVICE_ECHI_DTD_TOTAL_BYTES;
+ uint8_t qhIdle = 0U;
+ uint8_t waitingSafelyAccess = 1U;
+ uint32_t primeTimesCount = 0U;
+ OSA_SR_ALLOC();
+
+ if (NULL == ehciState)
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+
+ if (0U == ehciState->qh[index].endpointStatusUnion.endpointStatusBitmap.isOpened)
+ {
+ return kStatus_USB_Error;
+ }
+ /* Return error when ehci is doing reset */
+ if (0U != ehciState->isResetting)
+ {
+ return kStatus_USB_Error;
+ }
+
+ if (0U == dtdRequestCount)
+ {
+ dtdRequestCount = 1U;
+ }
+
+ OSA_ENTER_CRITICAL();
+ /* The free dtd count need to not less than the transfer requests. */
+ if (dtdRequestCount > (uint32_t)ehciState->dtdCount)
+ {
+ OSA_EXIT_CRITICAL();
+ return kStatus_USB_Busy;
+ }
+
+ do
+ {
+ /* The transfer length need to not more than USB_DEVICE_ECHI_DTD_TOTAL_BYTES for each dtd. */
+ sendLength = (length > USB_DEVICE_ECHI_DTD_TOTAL_BYTES) ? USB_DEVICE_ECHI_DTD_TOTAL_BYTES : length;
+ length -= sendLength;
+
+ /* Get a free dtd */
+ dtd = ehciState->dtdFree;
+
+ ehciState->dtdFree = (usb_device_ehci_dtd_struct_t *)dtd->nextDtdPointer;
+ ehciState->dtdCount--;
+
+ /* Save the dtd head when current active buffer offset is zero. */
+ if (0U == currentIndex)
+ {
+ dtdHead = dtd;
+ }
+
+ /* Set the dtd field */
+ dtd->nextDtdPointer = USB_DEVICE_ECHI_DTD_TERMINATE_MASK;
+ dtd->dtdTokenUnion.dtdToken = 0U;
+ dtd->bufferPointerPage[0] = (uint32_t)(buffer + currentIndex);
+ dtd->bufferPointerPage[1] =
+ (dtd->bufferPointerPage[0] + USB_DEVICE_ECHI_DTD_PAGE_BLOCK) & USB_DEVICE_ECHI_DTD_PAGE_MASK;
+ dtd->bufferPointerPage[2] = dtd->bufferPointerPage[1] + USB_DEVICE_ECHI_DTD_PAGE_BLOCK;
+ dtd->bufferPointerPage[3] = dtd->bufferPointerPage[2] + USB_DEVICE_ECHI_DTD_PAGE_BLOCK;
+ dtd->bufferPointerPage[4] = dtd->bufferPointerPage[3] + USB_DEVICE_ECHI_DTD_PAGE_BLOCK;
+
+ dtd->dtdTokenUnion.dtdTokenBitmap.totalBytes = sendLength;
+
+ /* Save the data length needed to be transferred. */
+ dtd->reservedUnion.originalBufferInfo.originalBufferLength = sendLength;
+ /* Save the original buffer address */
+ dtd->reservedUnion.originalBufferInfo.originalBufferOffest =
+ dtd->bufferPointerPage[0] & USB_DEVICE_ECHI_DTD_PAGE_OFFSET_MASK;
+ dtd->reservedUnion.originalBufferInfo.dtdInvalid = 0U;
+
+ /* Set the IOC field in last dtd. */
+ // if (0U == length)
+ // {
+ dtd->dtdTokenUnion.dtdTokenBitmap.ioc = 1U;
+ // }
+
+ /* Set dtd active */
+ dtd->dtdTokenUnion.dtdTokenBitmap.status = USB_DEVICE_ECHI_DTD_STATUS_ACTIVE;
+
+ /* Move the buffer offset index */
+ currentIndex += sendLength;
+
+ /* Add dtd to the in-used dtd queue */
+ if (NULL != (ehciState->dtdTail[index]))
+ {
+ ehciState->dtdTail[index]->nextDtdPointer = (uint32_t)dtd;
+ ehciState->dtdTail[index] = dtd;
+ }
+ else
+ {
+ ehciState->dtdHead[index] = dtd;
+ ehciState->dtdTail[index] = dtd;
+ qhIdle = 1U;
+ }
+ } while (0U != length);
+
+ /* If the QH is not empty */
+ if (0U == qhIdle)
+ {
+ /* If the prime bit is set, nothing need to do. */
+ if (0U != (ehciState->registerBase->EPPRIME & primeBit))
+ {
+ OSA_EXIT_CRITICAL();
+ return kStatus_USB_Success;
+ }
+
+ /* To safely a dtd */
+ while (0U != waitingSafelyAccess)
+ {
+ /* set the ATDTW flag to USBHS_USBCMD_REG. */
+ ehciState->registerBase->USBCMD |= USBHS_USBCMD_ATDTW_MASK;
+ /* Read EPSR */
+ epStatus = ehciState->registerBase->EPSR;
+ /* Wait the ATDTW bit set */
+ if (0U != (ehciState->registerBase->USBCMD & USBHS_USBCMD_ATDTW_MASK))
+ {
+ waitingSafelyAccess = 0U;
+ }
+ }
+ /* Clear the ATDTW bit */
+ ehciState->registerBase->USBCMD &= ~USBHS_USBCMD_ATDTW_MASK;
+ }
+
+ /* If QH is empty or the endpoint is not primed, need to link current dtd head to the QH. */
+ /* When the endpoint is not primed if qhIdle is zero, it means the QH is empty. */
+ if ((0U != qhIdle) || (0U == (epStatus & primeBit)))
+ {
+ ehciState->qh[index].nextDtdPointer = (uint32_t)dtdHead;
+ ehciState->qh[index].dtdTokenUnion.dtdToken = 0U;
+ /*make sure dtd is linked to dqh*/
+ __DSB();
+ ehciState->registerBase->EPPRIME = primeBit;
+ while (0U == (ehciState->registerBase->EPSR & primeBit))
+ {
+ primeTimesCount++;
+ if (primeTimesCount == USB_DEVICE_MAX_TRANSFER_PRIME_TIMES)
+ {
+ OSA_EXIT_CRITICAL();
+ return kStatus_USB_Error;
+ }
+ if (0U != (ehciState->registerBase->EPCOMPLETE & primeBit))
+ {
+ break;
+ }
+ else
+ {
+ ehciState->registerBase->EPPRIME = primeBit;
+ }
+ }
+ }
+
+ OSA_EXIT_CRITICAL();
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief Get setup packet data.
+ *
+ * The function is used to get setup packet data and copy to a backup buffer.
+ *
+ * @param ehciState Pointer of the device EHCI state structure.
+ * @param ep The endpoint number.
+ *
+ */
+static void USB_DeviceEhciGetSetupData(usb_device_ehci_state_struct_t *ehciState, uint8_t index, uint8_t *data)
+{
+ uint8_t waitingSafelyAccess = 1U;
+ uint8_t *temp;
+
+ /* Write 1U to clear corresponding bit in EPSETUPSR. */
+ ehciState->registerBase->ENDPTSETUPSTAT = 1UL << (index >> 1);
+ /* Get last setup packet */
+ temp = (uint8_t *)&ehciState->qh[index].setupBuffer;
+
+ while (0U != waitingSafelyAccess)
+ {
+ /* Set the setup tripwire bit. */
+ ehciState->registerBase->USBCMD |= USBHS_USBCMD_SUTW_MASK;
+
+ /* Copy setup packet data to data buffer */
+ for(uint8_t i = 0; i < 8; i++)
+ {
+ data[i] = temp[i];
+ }
+
+ /* Read the USBCMD[SUTW] bit. If set, jump out from the while loop; if cleared continue */
+ if (0U != (ehciState->registerBase->USBCMD & USBHS_USBCMD_SUTW_MASK))
+ {
+ waitingSafelyAccess = 0U;
+ }
+ }
+ /* Clear the setup tripwire bit */
+ ehciState->registerBase->USBCMD &= ~USBHS_USBCMD_SUTW_MASK;
+}
+
+/*!
+ * @brief Cancel the transfer of the control pipe.
+ *
+ * The function is used to cancel the transfer of the control pipe.
+ *
+ * @param ehciState Pointer of the device EHCI state structure.
+ * @param index The dQH index.
+ * @param direction The direction of the endpoint.
+ *
+ */
+static void USB_DeviceEhciCancelControlPipe(usb_device_ehci_state_struct_t *ehciState,
+ uint8_t index)
+{
+ usb_device_ehci_dtd_struct_t *currentDtd;
+
+ /* Get the dtd of the control pipe */
+ currentDtd =
+ (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHead[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK);
+ while (NULL != currentDtd)
+ {
+ /* Move the dtd head pointer to next. */
+ /* If the pointer of the head equals to the tail, set the dtd queue to null. */
+ if (ehciState->dtdHead[index] == ehciState->dtdTail[index])
+ {
+ ehciState->dtdHead[index] = NULL;
+ ehciState->dtdTail[index] = NULL;
+ ehciState->qh[index].nextDtdPointer = USB_DEVICE_ECHI_DTD_TERMINATE_MASK;
+ ehciState->qh[index].dtdTokenUnion.dtdToken = 0U;
+ }
+ else
+ {
+ ehciState->dtdHead[index] = (usb_device_ehci_dtd_struct_t *)ehciState->dtdHead[index]->nextDtdPointer;
+ }
+
+ /* Clear the token field of the dtd. */
+ currentDtd->dtdTokenUnion.dtdToken = 0U;
+ /* Add the dtd to the free dtd queue. */
+ currentDtd->nextDtdPointer = (uint32_t)ehciState->dtdFree;
+ ehciState->dtdFree = currentDtd;
+ ehciState->dtdCount++;
+
+ /* Get the next in-used dtd. */
+ currentDtd =
+ (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHead[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK);
+ }
+}
+
+/*!
+ * @brief Cancel the pending transfer in a specified endpoint.
+ *
+ * The function is used to cancel the pending transfer in a specified endpoint.
+ *
+ * @param ehciHandle Pointer of the device EHCI handle.
+ * @param ep Endpoint address, bit7 is the direction of endpoint, 1U - IN, 0U - OUT.
+ *
+ * @return A USB error code or kStatus_USB_Success.
+ */
+static usb_status_t USB_DeviceEhciCancel(usb_device_ehci_state_struct_t *ehciState, uint8_t ep)
+{
+ usb_device_ehci_dtd_struct_t *currentDtd;
+ uint32_t primeBit = USB_GET_PRIMEBIT(ep);
+ uint8_t index = USB_GET_INDEX(ep);
+
+ OSA_SR_ALLOC();
+
+ OSA_ENTER_CRITICAL();
+
+ /* Get the first dtd */
+ currentDtd =
+ (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHead[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK);
+
+ /* In the next loop, USB_DeviceNotificationTrigger function may trigger a new transfer and the context always
+ * keep in the critical section, so the Dtd sequence would still keep non-empty and the loop would be endless.
+ * We set the Dtd's dtdInvalid in this while and add an if statement in the next loop so that this issue could
+ * be fixed.
+ */
+ while (NULL != currentDtd)
+ {
+ currentDtd->reservedUnion.originalBufferInfo.dtdInvalid = 1U;
+ currentDtd = (usb_device_ehci_dtd_struct_t *)(currentDtd->nextDtdPointer & USB_DEVICE_ECHI_DTD_POINTER_MASK);
+ }
+
+ /* Get the first dtd */
+ currentDtd =
+ (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHead[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK);
+ while (NULL != currentDtd)
+ {
+ /* this if statement is used with the previous while loop to avoid the endless loop */
+ if (0U == currentDtd->reservedUnion.originalBufferInfo.dtdInvalid)
+ {
+ break;
+ }
+ else
+ {
+ if (0U != (currentDtd->dtdTokenUnion.dtdTokenBitmap.status & USB_DEVICE_ECHI_DTD_STATUS_ACTIVE))
+ {
+ /* Flush the endpoint to stop a transfer. */
+ do
+ {
+ /* Set the corresponding bit(s) in the EPFLUSH register */
+ ehciState->registerBase->EPFLUSH |= primeBit;
+
+ /* Wait until all bits in the EPFLUSH register are cleared. */
+ while (0U != (ehciState->registerBase->EPFLUSH & primeBit))
+ {
+ }
+ /*
+ * Read the EPSR register to ensure that for all endpoints
+ * commanded to be flushed, that the corresponding bits
+ * are now cleared.
+ */
+ } while (0U != (ehciState->registerBase->EPSR & primeBit));
+ }
+
+ /* Remove the dtd from the dtd in-used queue. */
+ if (ehciState->dtdHead[index] == ehciState->dtdTail[index])
+ {
+ ehciState->dtdHead[index] = NULL;
+ ehciState->dtdTail[index] = NULL;
+ }
+ else
+ {
+ ehciState->dtdHead[index] = (usb_device_ehci_dtd_struct_t *)ehciState->dtdHead[index]->nextDtdPointer;
+ }
+
+ /* When the ioc is set or the dtd queue is empty, the up layer will be notified. */
+
+ /* Clear the token field. */
+ currentDtd->dtdTokenUnion.dtdToken = 0U;
+ /* Save the dtd to the free queue. */
+ currentDtd->nextDtdPointer = (uint32_t)ehciState->dtdFree;
+ ehciState->dtdFree = currentDtd;
+ ehciState->dtdCount++;
+ }
+ /* Get the next dtd. */
+ currentDtd =
+ (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHead[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK);
+ }
+ if (NULL == currentDtd)
+ {
+ /* Set the QH to empty. */
+ ehciState->qh[index].nextDtdPointer = USB_DEVICE_ECHI_DTD_TERMINATE_MASK;
+ ehciState->qh[index].dtdTokenUnion.dtdToken = 0U;
+ }
+ OSA_EXIT_CRITICAL();
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief Initialize a specified endpoint.
+ *
+ * The function is used to initialize a specified endpoint.
+ *
+ * @param ehciState Pointer of the device EHCI state structure.
+ * @param epInit The endpoint initialization structure pointer.
+ *
+ * @return A USB error code or kStatus_USB_Success.
+ */
+static usb_status_t USB_DeviceEhciEndpointInit(usb_device_ehci_state_struct_t *ehciState,
+ usb_device_endpoint_init_struct_t *epInit)
+{
+ uint32_t primeBit = USB_GET_PRIMEBIT(epInit->endpointAddress);
+ uint16_t maxPacketSize = epInit->maxPacketSize & USB_MAXPACKETSIZE_MASK;
+ uint8_t endpoint = USB_EP_GET_IDX(epInit->endpointAddress);
+ uint8_t direction = USB_EP_DIR_IS_IN(epInit->endpointAddress);
+ uint8_t index = ((uint8_t)((uint32_t)endpoint << 1U)) | direction;
+ uint8_t transferType = epInit->transferType & USB_ENDPOINT_TYPE_MASK;
+
+ /* Cancel pending transfer of the endpoint */
+ (void)USB_DeviceEhciCancel(ehciState, epInit->endpointAddress);
+
+ if ((0U != (ehciState->registerBase->EPPRIME & primeBit)) || (0U != (ehciState->registerBase->EPSR & primeBit)))
+ {
+ return kStatus_USB_Busy;
+ }
+
+ /* Make the endpoint max packet size align with USB Specification 2.0. */
+ if (USB_ENDPOINT_TYPE_ISOCHRONOUS == transferType)
+ {
+ if (maxPacketSize > USB_DEVICE_MAX_HS_ISO_MAX_PACKET_SIZE)
+ {
+ maxPacketSize = USB_DEVICE_MAX_HS_ISO_MAX_PACKET_SIZE;
+ }
+ ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.mult =
+ 1UL + ((((uint32_t)epInit->maxPacketSize) & USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK) >>
+ USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_SHFIT);
+ }
+ else
+ {
+ ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.mult = 0U;
+ }
+
+ /* Save the max packet size of the endpoint */
+ ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.maxPacketSize =
+ maxPacketSize;
+ ehciState->qh[index].endpointStatusUnion.endpointStatusBitmap.zlt = epInit->zlt;
+ if ((USB_CONTROL_OUT_EP0 == endpoint))
+ {
+ /* Set ZLT bit. disable control endpoint automatic zlt by default,only send zlt when it is needed*/
+ ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.zlt = 1U;
+ }
+ else
+ {
+ /* Set ZLT bit. */
+ ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.zlt =
+ ((0U == epInit->zlt) ? 1U : 0U);
+ }
+
+ /* Enable the endpoint. */
+ if ((USB_CONTROL_OUT_EP0 == endpoint))
+ {
+ ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.ios = 1U;
+ ehciState->registerBase->EPCR0 |=
+ ((0U != direction) ?
+ (USBHS_EPCR_TXE_MASK | USBHS_EPCR_TXR_MASK | ((uint32_t)transferType << USBHS_EPCR_TXT_SHIFT)) :
+ (USBHS_EPCR_RXE_MASK | USBHS_EPCR_RXR_MASK | ((uint32_t)transferType << USBHS_EPCR_RXT_SHIFT)));
+ }
+ else
+ {
+ ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.ios = 0U;
+ ehciState->registerBase->EPCR[endpoint - 1U] |=
+ ((0U != direction) ?
+ (USBHS_EPCR_TXE_MASK | USBHS_EPCR_TXR_MASK | ((uint32_t)transferType << USBHS_EPCR_TXT_SHIFT)) :
+ (USBHS_EPCR_RXE_MASK | USBHS_EPCR_RXR_MASK | ((uint32_t)transferType << USBHS_EPCR_RXT_SHIFT)));
+ }
+
+ ehciState->qh[index].endpointStatusUnion.endpointStatusBitmap.isOpened = 1U;
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief De-initialize a specified endpoint.
+ *
+ * The function is used to de-initialize a specified endpoint.
+ * Current transfer of the endpoint will be cancelled and the specified endpoint will be disabled.
+ *
+ * @param ehciState Pointer of the device EHCI state structure.
+ * @param ep The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN.
+ *
+ * @return A USB error code or kStatus_USB_Success.
+ */
+static usb_status_t USB_DeviceEhciEndpointDeinit(usb_device_ehci_state_struct_t *ehciState, uint8_t ep)
+{
+ uint32_t primeBit = USB_GET_PRIMEBIT(ep);
+ uint8_t endpoint = USB_EP_GET_IDX(ep);
+ uint8_t direction = USB_EP_DIR_IS_IN(ep);
+ uint8_t index = USB_GET_INDEX(ep);
+
+ ehciState->qh[index].endpointStatusUnion.endpointStatusBitmap.isOpened = 0U;
+
+ /* Cancel the transfer of the endpoint */
+ (void)USB_DeviceEhciCancel(ehciState, ep);
+ if ((0U != (ehciState->registerBase->EPPRIME & primeBit)) || (0U != (ehciState->registerBase->EPSR & primeBit)))
+ {
+ return kStatus_USB_Busy;
+ }
+
+ /* Clear endpoint state */
+ ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristics = 0U;
+ /* Disable the endpoint */
+ if (0U == endpoint)
+ {
+ ehciState->registerBase->EPCR0 &=
+ ~((0U != direction) ? (USBHS_EPCR_TXE_MASK | USBHS_EPCR_TXT_MASK | USBHS_EPCR_TXS_MASK) :
+ (USBHS_EPCR_RXE_MASK | USBHS_EPCR_RXT_MASK | USBHS_EPCR_RXS_MASK));
+ }
+ else
+ {
+ ehciState->registerBase->EPCR[endpoint - 1U] &=
+ ~((0U != direction) ? (USBHS_EPCR_TXE_MASK | USBHS_EPCR_TXT_MASK | USBHS_EPCR_TXS_MASK) :
+ (USBHS_EPCR_RXE_MASK | USBHS_EPCR_RXT_MASK | USBHS_EPCR_RXS_MASK));
+ }
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief Stall a specified endpoint.
+ *
+ * The function is used to stall a specified endpoint.
+ * Current transfer of the endpoint will be cancelled and the specified endpoint will be stalled.
+ *
+ * @param ehciState Pointer of the device EHCI state structure.
+ * @param ep The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN.
+ *
+ * @return A USB error code or kStatus_USB_Success.
+ */
+static usb_status_t USB_DeviceEhciEndpointStall(usb_device_ehci_state_struct_t *ehciState, uint8_t ep)
+{
+ uint8_t endpoint = USB_EP_GET_IDX(ep);
+ uint8_t direction = USB_EP_DIR_IS_IN(ep);
+
+ if (0U == endpoint)
+ {
+ /* Cancel the transfer of the endpoint */
+ (void)USB_DeviceEhciCancel(ehciState, 0x00);
+ (void)USB_DeviceEhciCancel(ehciState, 0x80);
+ ehciState->registerBase->EPCR0 |= (USBHS_EPCR_TXS_MASK | USBHS_EPCR_RXS_MASK);
+ }
+ else
+ {
+ /* Cancel the transfer of the endpoint */
+ (void)USB_DeviceEhciCancel(ehciState, ep);
+
+ ehciState->registerBase->EPCR[endpoint - 1U] |= ((0U != direction) ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK);
+ }
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief Un-stall a specified endpoint.
+ *
+ * The function is used to un-stall a specified endpoint.
+ * Current transfer of the endpoint will be cancelled and the specified endpoint will be un-stalled.
+ *
+ * @param ehciState Pointer of the device EHCI state structure.
+ * @param ep The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN.
+ *
+ * @return A USB error code or kStatus_USB_Success.
+ */
+static usb_status_t USB_DeviceEhciEndpointUnstall(usb_device_ehci_state_struct_t *ehciState, uint8_t ep)
+{
+ uint8_t endpoint = USB_EP_GET_IDX(ep);
+ uint8_t direction = USB_EP_DIR_IS_IN(ep);
+
+ /* Clear the endpoint stall state */
+ if (0U == endpoint)
+ {
+ ehciState->registerBase->EPCR0 &= ~((0U != direction) ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK);
+ }
+ else
+ {
+ ehciState->registerBase->EPCR[endpoint - 1U] &=
+ ~((0U != direction) ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK);
+ ehciState->registerBase->EPCR[endpoint - 1U] |= ((0U != direction) ? USBHS_EPCR_TXR_MASK : USBHS_EPCR_RXR_MASK);
+ }
+ /* Cancel the transfer of the endpoint */
+ (void)USB_DeviceEhciCancel(ehciState, ep);
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief Set device controller state to default state.
+ *
+ * The function is used to set device controller state to default state.
+ * The function will be called when USB_DeviceEhciInit called or the control type kUSB_DeviceControlGetEndpointStatus
+ * received in USB_DeviceEhciControl.
+ *
+ * @param ehciState Pointer of the device EHCI state structure.
+ *
+ */
+static void USB_DeviceEhciSetDefaultState(usb_device_ehci_state_struct_t *ehciState)
+{
+ usb_device_ehci_dtd_struct_t *p;
+
+ for (uint8_t count = 0U; count < USB_DEVICE_ENDPOINTS; count++)
+ {
+ (void)USB_DeviceEhciEndpointDeinit(ehciState, (count | USB_EP_DIR_IN));
+ (void)USB_DeviceEhciEndpointDeinit(ehciState, (count | USB_EP_DIR_OUT));
+ }
+
+ /* Initialize the dtd free queue */
+ ehciState->dtdFree = ehciState->dtd;
+ p = ehciState->dtdFree;
+ for (uint32_t i = 1U; i < USB_DEVICE_MAX_DTD; i++)
+ {
+ p->nextDtdPointer = (uint32_t)&ehciState->dtd[i];
+ p = (usb_device_ehci_dtd_struct_t *)p->nextDtdPointer;
+ }
+ p->nextDtdPointer = 0U;
+ ehciState->dtdCount = USB_DEVICE_MAX_DTD;
+
+ /* Not use interrupt threshold. */
+ ehciState->registerBase->USBCMD &= ~USBHS_USBCMD_ITC_MASK;
+ ehciState->registerBase->USBCMD |= USBHS_USBCMD_ITC(0U);
+
+ /* Disable setup lockout, please refer to "Control Endpoint Operation" section in RM. */
+ ehciState->registerBase->USBMODE |= USBHS_USBMODE_SLOM_MASK;
+
+/* Set the endian by using CPU's endian */
+#if (ENDIANNESS == USB_BIG_ENDIAN)
+ ehciState->registerBase->USBMODE |= USBHS_USBMODE_ES_MASK;
+#else
+ ehciState->registerBase->USBMODE &= ~USBHS_USBMODE_ES_MASK;
+#endif
+ /* Initialize the QHs of endpoint. */
+ for (uint32_t i = 0U; i < (USB_DEVICE_ENDPOINTS * 2U); i++)
+ {
+ ehciState->qh[i].nextDtdPointer = USB_DEVICE_ECHI_DTD_TERMINATE_MASK;
+ ehciState->qh[i].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.maxPacketSize =
+ USB_CTRL_EP_MPS;
+ ehciState->dtdHead[i] = NULL;
+ ehciState->dtdTail[i] = NULL;
+ ehciState->qh[i].endpointStatusUnion.endpointStatusBitmap.isOpened = 0U;
+ }
+
+ /* Add QH buffer address to USBHS_EPLISTADDR_REG */
+ ehciState->registerBase->EPLISTADDR = (uint32_t)ehciState->qh;
+
+ /* Clear device address */
+ ehciState->registerBase->DEVICEADDR = 0U;
+
+#if defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U)
+ ehciState->registerBase->OTGSC = ehciState->registerBase->OTGSC & 0x0000FFFFU;
+ ehciState->registerBase->OTGSC |= USBHS_OTGSC_BSVIE_MASK;
+#endif /* USB_DEVICE_CONFIG_DETACH_ENABLE */
+
+ /* Enable USB Interrupt, USB Error Interrupt, Port Change detect Interrupt, USB-Reset Interrupt*/
+ ehciState->registerBase->USBINTR =
+ (USBHS_USBINTR_UE_MASK | USBHS_USBINTR_UEE_MASK | USBHS_USBINTR_PCE_MASK | USBHS_USBINTR_URE_MASK
+#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U))
+ | USBHS_USBINTR_SLE_MASK
+#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */
+ );
+
+ /* Clear reset flag */
+ ehciState->isResetting = 0U;
+}
+
+static void usb_device_set_prime(usb_device_ehci_state_struct_t *ehciState, uint8_t ep)
+{
+ uint32_t index = USB_GET_INDEX(ep);
+ uint32_t primeBit;
+ usb_device_ehci_dtd_struct_t *currentDtd;
+ /* Get the next in-used dtd */
+ currentDtd = (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHead[index] &
+ USB_DEVICE_ECHI_DTD_POINTER_MASK);
+
+ if ((NULL != currentDtd) && (0U != (currentDtd->dtdTokenUnion.dtdTokenBitmap.status &
+ USB_DEVICE_ECHI_DTD_STATUS_ACTIVE)))
+ {
+ primeBit = USB_GET_PRIMEBIT(ep);
+
+ /* Try to prime the next dtd. */
+ ehciState->registerBase->EPPRIME = primeBit;
+
+ /* Whether the endpoint transmit/receive buffer is ready or not. If not, wait for prime bit
+ * cleared and prime the next dtd. */
+ if (0U == (ehciState->registerBase->EPSR & primeBit))
+ {
+ /* Wait for the endpoint prime bit cleared by HW */
+ while (0U != (ehciState->registerBase->EPPRIME & primeBit))
+ {
+ }
+
+ /* If the endpoint transmit/receive buffer is not ready */
+ if (0U == (ehciState->registerBase->EPSR & primeBit))
+ {
+ /* Prime next dtd and prime the transfer */
+ ehciState->qh[index].nextDtdPointer = (uint32_t)currentDtd;
+ ehciState->qh[index].dtdTokenUnion.dtdToken = 0U;
+ ehciState->registerBase->EPPRIME = primeBit;
+ }
+ }
+ }
+}
+
+/***********************************usb dc func**********************************************/
+#if CONFIG_USB_HS
+/* pointer to high speed mode descriptor */
+uint8_t *USB_Descriptor_HS = 0;
+
+void usbd_desc_hs_register(uint8_t *descriptor)
+{
+ if(descriptor)
+ {
+ USB_Descriptor_HS = descriptor;
+ }
+}
+#endif
+
+int usb_dtd_buf_init(uint8_t instance)
+{
+ usb_dtd_buffer_t *ptr = g_UsbDtdBufList[instance];
+ for(int i = 0; i < USB_DEVICE_MAX_DTD; i++)
+ {
+ ptr[i].sta = 0;
+ ptr[i].pbuf = 0;
+ ptr[i].mps = 0;
+ }
+
+ return 0;
+}
+
+uint8_t usb_dtd_buf_set_manual(uint8_t ep)
+{
+ usb_dtd_buffer_t *ptr = g_UsbDtdBufList[0];
+ uint32_t index = USB_GET_INDEX(ep);
+
+ ptr[index].type = 2;
+
+ return 0;
+}
+
+int usb_transfer_data(uint8_t ep, uint8_t *data, uint16_t len)
+{
+ usb_dtd_buffer_t *ptr = g_UsbDtdBufList[0];
+ usb_device_ehci_state_struct_t *ehciState = &g_UsbDeviceEhciState[0];
+ uint32_t index = USB_GET_INDEX(ep);
+ uint8_t *pdata = data;
+
+ switch (ptr[index].type)
+ {
+ case 1:
+ if((ptr[index].sta != 1) || (len > ptr[index].mps))
+ {
+ return -1;
+ }
+
+ pdata = ptr[index].pbuf;
+ for(int i = 0; i < len; i++)
+ {
+ pdata[i] = data[i];
+ }
+ case 2:
+ if(USB_DeviceEhciTransfer(ehciState, ep, pdata, len) != kStatus_USB_Success)
+ {
+ return -1;
+ }
+ break;
+ default:
+ return -1;
+ }
+
+
+ return 0;
+}
+
+void usb_connect(uint8_t instance, uint8_t ctrl)
+{
+ IRQn_Type irqNum;
+ USB_Type *pdevice = g_UsbDeviceEhciState[instance].registerBase;
+
+ if(instance == 0)
+ {
+ irqNum = USB_OTG1_IRQn;
+ }
+ else
+ {
+ irqNum = USB_OTG2_IRQn;
+ }
+
+ if(ctrl)
+ {
+ /* Install isr, set priority, and enable IRQ. */
+ NVIC_SetPriority((IRQn_Type)irqNum, 3);
+ EnableIRQ((IRQn_Type)irqNum);
+
+ pdevice->USBCMD |= USBHS_USBCMD_RS_MASK;
+ }
+ else
+ {
+ pdevice->USBCMD &= ~USBHS_USBCMD_RS_MASK;
+ DisableIRQ((IRQn_Type)irqNum);
+ }
+}
+
+static uint8_t usb_device_init(uint8_t instance)
+{
+ USB_Type *pdevice;
+ usb_device_ehci_state_struct_t *ehciState = NULL;
+
+ if(instance == 0)
+ {
+ ehciState = &g_UsbDeviceEhciState[instance];
+ ehciState->controllerId = 1;
+ ehciState->qh = (usb_device_ehci_qh_struct_t *)&qh_buffer[instance * 2048];
+ ehciState->dtd = s_UsbDeviceEhciDtd[instance];
+ ehciState->registerBase = USB1;
+ #if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U))
+ ehciState->registerPhyBase = USBPHY1;
+ #if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U))
+ ehciState->registerNcBase = USBNC1;
+ #endif
+ #endif
+ }
+ else
+ {
+ return 1;
+ }
+
+ pdevice = ehciState->registerBase;
+
+ /* Reset the controller. */
+ pdevice->USBCMD |= USBHS_USBCMD_RST_MASK;
+ while (0U != (pdevice->USBCMD & USBHS_USBCMD_RST_MASK))
+ {
+ }
+ /* Get the HW's endpoint count */
+ ehciState->endpointCount =
+ (uint8_t)((pdevice->DCCPARAMS & USB_DCCPARAMS_DEN_MASK) >> USB_DCCPARAMS_DEN_SHIFT);
+ if(ehciState->endpointCount != USB_DEVICE_ENDPOINTS)
+ {
+ return 1;
+ }
+ /* Clear the controller mode field and set to device mode. */
+ pdevice->USBMODE &= ~USBHS_USBMODE_CM_MASK;
+ pdevice->USBMODE |= USBHS_USBMODE_CM(0x02U) | USB_USBMODE_SLOM(0x01);
+
+#ifndef CONFIG_USB_HS
+ pdevice->PORTSC1 |= (0x01u << 24); //fixed full-speed
+#endif // !CONFIG_USB_HS
+
+ /* Set the EHCI to default status. */
+ USB_DeviceEhciSetDefaultState(ehciState);
+
+ return 0;
+}
+
+static uint8_t usb_device_deinit(uint8_t instance)
+{
+ USB_Type *pdevice;
+ usb_device_ehci_state_struct_t *ehciState = NULL;
+ if(instance == 1)
+ {
+ ehciState = &g_UsbDeviceEhciState[instance];
+ pdevice = ehciState->registerBase;
+ }
+ else
+ {
+ return 1;
+ }
+
+ /* Disable all interrupt. */
+ pdevice->USBINTR = 0U;
+ /* Stop the device functionality. */
+ pdevice->USBCMD &= ~USBHS_USBCMD_RS_MASK;
+ /* Reset the controller. */
+ pdevice->USBCMD |= USBHS_USBCMD_RST_MASK;
+
+ usb_connect(instance, 0);
+
+ return 0;
+}
+
+int usb_dc_init(void)
+{
+ usb_device_ehci_state_struct_t *ehciState = &g_UsbDeviceEhciState[0];
+
+ memset(ehciState, 0, sizeof(usb_device_ehci_state_struct_t));
+
+ usb_clock_init(0);
+ usb_device_deinit(0);
+ usb_device_init(0);
+ usb_dtd_buf_init(0);
+
+ usb_connect(0, 1);
+ return 0;
+}
+
+int usbd_set_address(const uint8_t addr)
+{
+ usb_device_ehci_state_struct_t *ehciState = &g_UsbDeviceEhciState[0];
+ if(addr)
+ {
+ /* set address after IN transaction */
+ ehciState->registerBase->DEVICEADDR = (((uint32_t)addr << USB_DEVICEADDR_USBADR_SHIFT) | USB_DEVICEADDR_USBADRA_MASK);
+ }
+ else
+ {
+ /* immediately set address */
+ ehciState->registerBase->DEVICEADDR = (uint32_t)addr << USB_DEVICEADDR_USBADR_SHIFT;
+ }
+
+#if CONFIG_USB_HS
+ if((ehciState->speed == USB_SPEED_HIGH) && USB_Descriptor_HS)
+ {
+ /* set descriptor to high speed */
+ usbd_desc_register(USB_Descriptor_HS);
+ }
+#endif
+
+ return 0;
+}
+
+int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg)
+{
+ usb_device_ehci_state_struct_t *ehciState = &g_UsbDeviceEhciState[0];
+ usb_device_endpoint_init_struct_t epConfig;
+ usb_dtd_buffer_t *ptr = g_UsbDtdBufList[0];
+ uint32_t index = USB_GET_INDEX(ep_cfg->ep_addr);
+
+ epConfig.endpointAddress = ep_cfg->ep_addr;
+ epConfig.maxPacketSize = ep_cfg->ep_mps;
+ epConfig.transferType = ep_cfg->ep_type;
+ epConfig.zlt = 0;
+ epConfig.interval = 0;
+
+ if(kStatus_USB_Success != USB_DeviceEhciEndpointDeinit(ehciState, ep_cfg->ep_addr))
+ {
+ return -1;
+ }
+
+ if(USB_DeviceEhciEndpointInit(ehciState, &epConfig) != kStatus_USB_Success)
+ {
+ return -1;
+ }
+
+ if(ptr[index].type == 0)
+ {
+ if(ptr[index].pbuf == 0)
+ {
+ ptr[index].pbuf = malloc(ep_cfg->ep_mps);
+ if(ptr[index].pbuf == 0)
+ {
+ return -1;
+ }
+ ptr[index].mps = ep_cfg->ep_mps;
+ ptr[index].type = 1; /* set to auto mode */
+ ptr[index].sta = 1; /* ready */
+ }
+ }
+
+ if((ptr[index].type == 1) && (ep_cfg->ep_addr != USB_CONTROL_OUT_EP0))
+ {
+ /* is auto */
+ if(USB_EP_DIR_IS_OUT(ep_cfg->ep_addr))
+ {
+ if(USB_DeviceEhciTransfer(ehciState, ep_cfg->ep_addr, ptr[index].pbuf, ptr[index].mps) != kStatus_USB_Success)
+ {
+ return -1;
+ }
+ ptr[index].sta = 2; /* using */
+ }
+ }
+
+ return 0;
+}
+
+int usbd_ep_close(const uint8_t ep)
+{
+ usb_device_ehci_state_struct_t *ehciState = &g_UsbDeviceEhciState[0];
+
+ if(USB_DeviceEhciEndpointDeinit(ehciState, ep) != kStatus_USB_Success)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+int usbd_ep_set_stall(const uint8_t ep)
+{
+ usb_device_ehci_state_struct_t *ehciState = &g_UsbDeviceEhciState[0];
+
+ if(USB_DeviceEhciEndpointStall(ehciState, ep) != kStatus_USB_Success)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+int usbd_ep_clear_stall(const uint8_t ep)
+{
+ usb_device_ehci_state_struct_t *ehciState = &g_UsbDeviceEhciState[0];
+
+ if(USB_DeviceEhciEndpointUnstall(ehciState, ep) != kStatus_USB_Success)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled)
+{
+ uint8_t ep_idx = USB_EP_GET_IDX(ep);
+ uint8_t ep_dir = USB_EP_GET_DIR(ep);
+ usb_device_ehci_state_struct_t *ehciState = &g_UsbDeviceEhciState[0];
+
+ if(ep_idx == 0)
+ {
+ if(ep_dir)
+ {
+ *stalled = (ehciState->registerBase->ENDPTCTRL0 & 0x00000001) ? 1 : 0;
+ }
+ else
+ {
+ *stalled = (ehciState->registerBase->ENDPTCTRL0 & 0x00010000) ? 1 : 0;
+ }
+ }
+ else
+ {
+ if(ep_dir)
+ {
+ *stalled = (ehciState->registerBase->ENDPTCTRL[ep_idx - 1] & 0x00000001) ? 1 : 0;
+ }
+ else
+ {
+ *stalled = (ehciState->registerBase->ENDPTCTRL[ep_idx - 1] & 0x00010000) ? 1 : 0;
+ }
+ }
+ return 0;
+}
+
+int usbd_ep_write(const uint8_t ep, const uint8_t *data, uint32_t data_len, uint32_t *ret_bytes)
+{
+ uint8_t *txbuf = NULL;
+ uint8_t index = USB_GET_INDEX(ep);
+ usb_dtd_buffer_t *ptr = g_UsbDtdBufList[0];
+ usb_device_ehci_state_struct_t *ehciState = &g_UsbDeviceEhciState[0];
+
+ *ret_bytes = 0;
+
+ switch(ptr[index].type)
+ {
+ case 1:
+ txbuf = ptr[index].pbuf;
+ data_len = (data_len > ptr[index].mps) ? ptr[index].mps : data_len;
+ for(int i = 0; i < data_len; i++)
+ {
+ txbuf[i] = data[i];
+ }
+ break;
+ case 2:
+ data_len = (data_len > ptr[index].mps) ? ptr[index].mps : data_len;
+ txbuf = (uint8_t *)data;
+ break;
+ default:
+ return -1;
+ }
+
+ if(USB_DeviceEhciTransfer(ehciState, ep, txbuf, data_len) != kStatus_USB_Success)
+ {
+ return -1;
+ }
+
+ *ret_bytes = data_len;
+ return 0;
+}
+
+int usbd_ep_read(const uint8_t ep, uint8_t *data, uint32_t max_data_len, uint32_t *read_bytes)
+{
+ uint8_t index = USB_GET_INDEX(ep);
+ usb_dtd_buffer_t *ptr = g_UsbDtdBufList[0];
+ uint8_t *temp;
+ uint32_t count;
+ usb_device_ehci_dtd_struct_t *currentDtd;
+ usb_device_ehci_state_struct_t *ehciState = &g_UsbDeviceEhciState[0];
+
+ if (USB_EP_DIR_IS_IN(ep))
+ {
+ return -1;
+ }
+
+ if (!data && max_data_len) {
+ return -1;
+ }
+
+ if (!max_data_len) {
+ return 0;
+ }
+
+ if((ep == USB_CONTROL_OUT_EP0) && (max_data_len == 8) && !read_bytes) /* is read setup packet */
+ {
+ /* Cancel the data phase transfer */
+ USB_DeviceEhciCancelControlPipe(ehciState, index);
+ /* Cancel the status phase transfer */
+ USB_DeviceEhciCancelControlPipe(ehciState, index);
+ USB_DeviceEhciGetSetupData(ehciState, index, data);
+
+ struct usb_setup_packet *setup = (struct usb_setup_packet *)data;
+
+ if(setup->bmRequestType & USB_REQUEST_DIR_IN)
+ {
+ /* is in */
+ if(USB_DeviceEhciTransfer(ehciState, USB_CONTROL_OUT_EP0, ptr[index].pbuf, 0) != kStatus_USB_Success)
+ {
+ return -2;
+ }
+ }
+ else
+ {
+ /* is out */
+ if(setup->wLength)
+ {
+ if(setup->wLength > ptr[index].mps)
+ {
+ if(ptr[index].pbuf != NULL)
+ {
+ usb_free(ptr[index].pbuf);
+ }
+ ptr[index].mps = setup->wLength;
+ ptr[index].pbuf = usb_malloc(setup->wLength);
+ }
+ if(!ptr[index].pbuf)
+ {
+ return -3;
+ }
+ if(USB_DeviceEhciTransfer(ehciState, USB_CONTROL_OUT_EP0, ptr[index].pbuf, setup->wLength) != kStatus_USB_Success)
+ {
+ return -4;
+ }
+ ptr[index].sta = 2; /* using */
+ }
+ }
+ }
+ else
+ {
+ currentDtd = ehciState->dtdHead[index];
+ if (NULL != currentDtd)
+ {
+ /* Don't handle the active dtd. */
+ if ((0U == (currentDtd->dtdTokenUnion.dtdTokenBitmap.status & USB_DEVICE_ECHI_DTD_STATUS_ACTIVE)) &&
+ (0U != currentDtd->dtdTokenUnion.dtdTokenBitmap.ioc))
+ {
+ count = (currentDtd->reservedUnion.originalBufferInfo.originalBufferLength -
+ currentDtd->dtdTokenUnion.dtdTokenBitmap.totalBytes);
+ count = (count <= max_data_len) ? count : max_data_len;
+ temp = (uint8_t *)((currentDtd->bufferPointerPage[0] & USB_DEVICE_ECHI_DTD_PAGE_MASK) |
+ (currentDtd->reservedUnion.originalBufferInfo.originalBufferOffest));
+ /* Save the transfer buffer address */
+ if(data != NULL)
+ {
+ if(ptr[index].type == 1)
+ {
+ for(int i = 0; i < count; i++)
+ {
+ *data = temp[i];
+ data++;
+ }
+ }
+ else if(ptr[index].type == 2)
+ {
+ data = temp;
+ }
+ }
+ /* Save the transferred data length */
+ if (read_bytes)
+ {
+ *read_bytes = count;
+ }
+
+ /* Move the dtd queue head pointer to next */
+ if (ehciState->dtdHead[index] == ehciState->dtdTail[index])
+ {
+ ehciState->dtdHead[index] = NULL;
+ ehciState->dtdTail[index] = NULL;
+ ehciState->qh[index].nextDtdPointer = USB_DEVICE_ECHI_DTD_TERMINATE_MASK;
+ ehciState->qh[index].dtdTokenUnion.dtdToken = 0U;
+ }
+ else
+ {
+ ehciState->dtdHead[index] =
+ (usb_device_ehci_dtd_struct_t *)ehciState->dtdHead[index]->nextDtdPointer;
+ }
+
+ /* Clear the token field of the dtd */
+ currentDtd->dtdTokenUnion.dtdToken = 0U;
+ currentDtd->nextDtdPointer = (uint32_t)ehciState->dtdFree;
+ ehciState->dtdFree = currentDtd;
+ ehciState->dtdCount++;
+
+ if(USB_EP_GET_IDX(ep) && (ptr[index].type == 1)) /* if not ep0 */
+ {
+ if(USB_DeviceEhciTransfer(ehciState, ep, ptr[index].pbuf, ptr[index].mps) != kStatus_USB_Success)
+ {
+ return -5;
+ }
+ ptr[index].sta = 2; /* using */
+ }
+ }
+ else
+ {
+ *read_bytes = 0;
+ return 0;
+ }
+ }
+ else
+ {
+ return -6;
+ }
+ }
+
+ return 0;
+}
+
+void usb_device_isr_func(usb_device_ehci_state_struct_t *ehciState)
+{
+ USB_Type *device = ehciState->registerBase;
+ usb_device_ehci_dtd_struct_t *currentDtd;
+ uint8_t index = 0;
+ uint32_t int_stat;
+ uint32_t ep_setup_stat;
+ uint32_t ep_int_stat;
+ uint8_t endpoint;
+
+#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE)) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U))
+ USBNC_Type *usbnc = p->registerNcBase;
+ if (0U != (usbnc->USB_OTGn_CTRL & USBNC_USB_OTGn_CTRL_WIE_MASK))
+ {
+ if (0U != (usbnc->USB_OTGn_CTRL & USBNC_USB_OTGn_CTRL_WIR_MASK))
+ {
+ usbnc->PORTSC1 &= ~USBHS_PORTSC1_PHCD_MASK;
+ usbnc->USB_OTGn_CTRL &= ~USBNC_USB_OTGn_CTRL_WIE_MASK;
+ }
+ }
+ else
+ {
+ }
+#endif
+
+ int_stat = device->USBSTS;
+ int_stat &= device->USBINTR;
+
+ device->USBSTS = int_stat;
+
+#if defined(USB_DEVICE_CONFIG_ERROR_HANDLING) && (USB_DEVICE_CONFIG_ERROR_HANDLING > 0U)
+ if (0U != (status & USBHS_USBSTS_UEI_MASK))
+ {
+ /* Error interrupt */
+ // USB_DeviceEhciInterruptError(ehciState);
+ }
+#endif /* USB_DEVICE_CONFIG_ERROR_HANDLING */
+
+ if (0U != (int_stat & USBHS_USBSTS_URI_MASK))
+ {
+ /* Reset interrupt */
+ uint32_t status = 0U;
+
+ /* Clear the setup flag */
+ status = ehciState->registerBase->EPSETUPSR;
+ ehciState->registerBase->EPSETUPSR = status;
+ /* Clear the endpoint complete flag */
+ status = ehciState->registerBase->EPCOMPLETE;
+ ehciState->registerBase->EPCOMPLETE = status;
+
+ do
+ {
+ /* Flush the pending transfers */
+ ehciState->registerBase->EPFLUSH = USBHS_EPFLUSH_FERB_MASK | USBHS_EPFLUSH_FETB_MASK;
+ } while (0U != (ehciState->registerBase->EPPRIME & (USBHS_EPPRIME_PERB_MASK | USBHS_EPPRIME_PETB_MASK)));
+
+ /* Whether is the port reset. If yes, set the isResetting flag. Or, notify the up layer. */
+ if (0U != (ehciState->registerBase->PORTSC1 & USBHS_PORTSC1_PR_MASK))
+ {
+ ehciState->isResetting = 1U;
+ }
+ else
+ {
+ USB_DeviceEhciSetDefaultState(ehciState);
+ usbd_event_notify_handler(USBD_EVENT_RESET, NULL);
+ }
+ }
+
+ if (0U != (int_stat & USBHS_USBSTS_UI_MASK))
+ {
+ /* Token done interrupt */
+ /* Get the EPSETUPSR to check the setup packect received in which one endpoint. */
+ ep_setup_stat = device->ENDPTSETUPSTAT;
+
+ if(ep_setup_stat != 0)
+ {
+ /* read setup data */
+ for (endpoint = 0U; endpoint < USB_DEVICE_ENDPOINTS; endpoint++)
+ {
+ if (0U != (ep_setup_stat & (1UL << endpoint)))
+ {
+ usbd_event_notify_handler(USBD_EVENT_SETUP_NOTIFY, NULL);
+ }
+ }
+ }
+ /* Read the USBHS_EPCOMPLETE_REG to get the endpoint transfer done status */
+ ep_int_stat = device->ENDPTCOMPLETE;
+ /* Clear the endpoint transfer done status */
+ device->ENDPTCOMPLETE = ep_int_stat;
+ if (0U != ep_int_stat)
+ {
+ for (uint8_t endpoint = 0U; endpoint < 8; endpoint++)
+ {
+ volatile uint32_t tmp = (0x00010001UL << endpoint);
+ /* Check the transfer is done or not in the specified endpoint. */
+ if (ep_int_stat & tmp)
+ {
+ if(ep_int_stat & 0x0000FFFFu)
+ {
+ /* out int */
+ index = endpoint << 1;
+
+ if(endpoint == 0) /* is ep0 */
+ {
+ usbd_event_notify_handler(USBD_EVENT_EP0_OUT_NOTIFY, NULL);
+ }
+ else
+ {
+ usbd_event_notify_handler(USBD_EVENT_EP_OUT_NOTIFY, (void *)USB_ENDPOINT_OUT(endpoint));
+ }
+ }
+
+ if(ep_int_stat & 0xFFFF0000u)
+ {
+ /* in int */
+ index = (endpoint << 1) + 1;
+
+ /* Get the in-used dtd of the specified endpoint. */
+ currentDtd = (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHead[index] &
+ USB_DEVICE_ECHI_DTD_POINTER_MASK);
+
+ /* Don't handle the active dtd. */
+ if ((0U == (currentDtd->dtdTokenUnion.dtdTokenBitmap.status & USB_DEVICE_ECHI_DTD_STATUS_ACTIVE)) &&
+ (0U != currentDtd->dtdTokenUnion.dtdTokenBitmap.ioc))
+ {
+ /* Move the dtd queue head pointer to next */
+ if (ehciState->dtdHead[index] == ehciState->dtdTail[index])
+ {
+ ehciState->dtdHead[index] = NULL;
+ ehciState->dtdTail[index] = NULL;
+ ehciState->qh[index].nextDtdPointer = USB_DEVICE_ECHI_DTD_TERMINATE_MASK;
+ ehciState->qh[index].dtdTokenUnion.dtdToken = 0U;
+ }
+ else
+ {
+ ehciState->dtdHead[index] =
+ (usb_device_ehci_dtd_struct_t *)ehciState->dtdHead[index]->nextDtdPointer;
+ }
+
+ /* Clear the token field of the dtd */
+ currentDtd->dtdTokenUnion.dtdToken = 0U;
+ currentDtd->nextDtdPointer = (uint32_t)ehciState->dtdFree;
+ ehciState->dtdFree = currentDtd;
+ ehciState->dtdCount++;
+ }
+
+ if(endpoint == 0) /* is ep0 */
+ {
+ usbd_event_notify_handler(USBD_EVENT_EP0_IN_NOTIFY, NULL);
+ }
+ else
+ {
+ usbd_event_notify_handler(USBD_EVENT_EP_IN_NOTIFY, (void *)USB_ENDPOINT_IN(endpoint));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (0U != (int_stat & USBHS_USBSTS_PCI_MASK))
+ {
+ /* Port status change interrupt */
+ /* Whether the port is doing reset. */
+ if (0U == (device->PORTSC1 & USBHS_PORTSC1_PR_MASK))
+ {
+ /* If not, update the USB speed. */
+ if (0U != (device->PORTSC1 & USBHS_PORTSC1_HSP_MASK))
+ {
+ ehciState->speed = USB_SPEED_HIGH;
+ }
+ else
+ {
+ ehciState->speed = USB_SPEED_FULL;
+ }
+
+ /* If the device reset flag is non-zero, notify the up layer the device reset finished. */
+ if (0U != ehciState->isResetting)
+ {
+ USB_DeviceEhciSetDefaultState(ehciState);
+ usbd_event_notify_handler(USBD_EVENT_RESET, NULL);
+ ehciState->isResetting = 0U;
+ }
+ }
+
+#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U))
+ if ((0U != ehciState->isSuspending) && (0U == (device->PORTSC1 & USB_PORTSC1_SUSP_MASK)))
+ {
+ /* Set the resume flag */
+ ehciState->isSuspending = 0U;
+ usbd_event_notify_handler(USBD_EVENT_RESUME, NULL);
+ }
+#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */
+ }
+#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U))
+ if (0U != (int_stat & USBHS_USBSTS_SLI_MASK))
+ {
+ /* Suspend interrupt */
+ // USB_DeviceEhciInterruptSuspend(ehciState);
+ usbd_event_notify_handler(USBD_EVENT_SUSPEND, NULL);
+ }
+#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */
+
+ if (0U != (int_stat & USBHS_USBSTS_SRI_MASK))
+ {
+ /* Sof interrupt */
+ // USB_DeviceEhciInterruptSof(int_stat);
+ usbd_event_notify_handler(USBD_EVENT_SOF, NULL);
+ }
+}
+
+void USB_OTG1_IRQHandler(void)
+{
+ usb_device_isr_func(&g_UsbDeviceEhciState[0]);
+ /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
+ exception return operation might vector to incorrect interrupt */
+ __DSB();
+}
+
+void USB_OTG2_IRQHandler(void)
+{
+ usb_device_isr_func(&g_UsbDeviceEhciState[1]);
+ /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
+ exception return operation might vector to incorrect interrupt */
+ __DSB();
+}
diff --git a/port/imxrt/usb_dc_imxrt_port.h b/port/imxrt/usb_dc_imxrt_port.h
new file mode 100644
index 00000000..227a3dc4
--- /dev/null
+++ b/port/imxrt/usb_dc_imxrt_port.h
@@ -0,0 +1,42 @@
+#ifndef _USB_DC_IMXRT_PORT
+#define _USB_DC_IMXRT_PORT
+
+/* USB Device condfiguration */
+#define USB_DEVICE_USE_PORT (1U)
+#define USB_DEVICE_ENDPOINTS (8U)
+#define USB_DEVICE_MAX_DTD (USB_DEVICE_ENDPOINTS * 2)
+
+/*! @brief Whether the transfer buffer is cache-enabled or not. */
+#ifndef USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE
+#define USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE (0U)
+#endif
+/*! @brief Whether the low power mode is enabled or not. */
+#define USB_DEVICE_CONFIG_LOW_POWER_MODE (0U)
+/*! @brief Whether the device detached feature is enabled or not. */
+#define USB_DEVICE_CONFIG_DETACH_ENABLE (0U)
+/*! @brief Whether handle the USB bus error. */
+#define USB_DEVICE_CONFIG_ERROR_HANDLING (0U)
+
+/*! @brief Define big endian */
+#define USB_BIG_ENDIAN (0U)
+/*! @brief Define little endian */
+#define USB_LITTLE_ENDIAN (1U)
+
+/* USB PHY condfiguration */
+#define BOARD_USB_PHY_D_CAL (0x0CU)
+#define BOARD_USB_PHY_TXCAL45DP (0x06U)
+#define BOARD_USB_PHY_TXCAL45DM (0x06U)
+typedef struct
+{
+ uint8_t sta;
+ uint8_t type;
+ uint16_t mps;
+ uint8_t *pbuf;
+}usb_dtd_buffer_t;
+
+#if CONFIG_USB_HS
+void usbd_desc_hs_register(uint8_t *descriptor);
+#endif
+uint8_t usb_dtd_buf_node_register(uint8_t ep, uint32_t mps);
+int usb_transfer_data(uint8_t ep, uint8_t *data, uint16_t len);
+#endif // !_USB_DC_IMXRT_PORT \ No newline at end of file
diff --git a/port/imxrt/usb_imxrt_reg.h b/port/imxrt/usb_imxrt_reg.h
new file mode 100644
index 00000000..20d40c93
--- /dev/null
+++ b/port/imxrt/usb_imxrt_reg.h
@@ -0,0 +1,368 @@
+#ifndef __USB_IMXRT_REG_H__
+#define __USB_IMXRT_REG_H__
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#define __I volatile const /*!< Defines 'read only' permissions */
+#define __IO volatile /*!< Defines 'read / write' permissions */
+/* ----------------------------------------------------------------------------
+ -- USB Peripheral Access Layer
+ ---------------------------------------------------------------------------- */
+
+/*!
+ * @addtogroup USB_Peripheral_Access_Layer USB Peripheral Access Layer
+ * @{
+ */
+
+/** USB - Register Layout Typedef */
+// typedef struct {
+// __I uint32_t ID; /**< Identification register, offset: 0x0 */
+// __I uint32_t HWGENERAL; /**< Hardware General, offset: 0x4 */
+// __I uint32_t HWHOST; /**< Host Hardware Parameters, offset: 0x8 */
+// __I uint32_t HWDEVICE; /**< Device Hardware Parameters, offset: 0xC */
+// __I uint32_t HWTXBUF; /**< TX Buffer Hardware Parameters, offset: 0x10 */
+// __I uint32_t HWRXBUF; /**< RX Buffer Hardware Parameters, offset: 0x14 */
+// uint8_t RESERVED_0[104];
+// __IO uint32_t GPTIMER0LD; /**< General Purpose Timer #0 Load, offset: 0x80 */
+// __IO uint32_t GPTIMER0CTRL; /**< General Purpose Timer #0 Controller, offset: 0x84 */
+// __IO uint32_t GPTIMER1LD; /**< General Purpose Timer #1 Load, offset: 0x88 */
+// __IO uint32_t GPTIMER1CTRL; /**< General Purpose Timer #1 Controller, offset: 0x8C */
+// __IO uint32_t SBUSCFG; /**< System Bus Config, offset: 0x90 */
+// uint8_t RESERVED_1[108];
+// __I uint8_t CAPLENGTH; /**< Capability Registers Length, offset: 0x100 */
+// uint8_t RESERVED_2[1];
+// __I uint16_t HCIVERSION; /**< Host Controller Interface Version, offset: 0x102 */
+// __I uint32_t HCSPARAMS; /**< Host Controller Structural Parameters, offset: 0x104 */
+// __I uint32_t HCCPARAMS; /**< Host Controller Capability Parameters, offset: 0x108 */
+// uint8_t RESERVED_3[20];
+// __I uint16_t DCIVERSION; /**< Device Controller Interface Version, offset: 0x120 */
+// uint8_t RESERVED_4[2];
+// __I uint32_t DCCPARAMS; /**< Device Controller Capability Parameters, offset: 0x124 */
+// uint8_t RESERVED_5[24];
+// __IO uint32_t USBCMD; /**< USB Command Register, offset: 0x140 */
+// __IO uint32_t USBSTS; /**< USB Status Register, offset: 0x144 */
+// __IO uint32_t USBINTR; /**< Interrupt Enable Register, offset: 0x148 */
+// __IO uint32_t FRINDEX; /**< USB Frame Index, offset: 0x14C */
+// uint8_t RESERVED_6[4];
+// union { /* offset: 0x154 */
+// __IO uint32_t DEVICEADDR; /**< Device Address, offset: 0x154 */
+// __IO uint32_t PERIODICLISTBASE; /**< Frame List Base Address, offset: 0x154 */
+// };
+// union { /* offset: 0x158 */
+// __IO uint32_t ASYNCLISTADDR; /**< Next Asynch. Address, offset: 0x158 */
+// __IO uint32_t ENDPTLISTADDR; /**< Endpoint List Address, offset: 0x158 */
+// };
+// uint8_t RESERVED_7[4];
+// __IO uint32_t BURSTSIZE; /**< Programmable Burst Size, offset: 0x160 */
+// __IO uint32_t TXFILLTUNING; /**< TX FIFO Fill Tuning, offset: 0x164 */
+// uint8_t RESERVED_8[16];
+// __IO uint32_t ENDPTNAK; /**< Endpoint NAK, offset: 0x178 */
+// __IO uint32_t ENDPTNAKEN; /**< Endpoint NAK Enable, offset: 0x17C */
+// __I uint32_t CONFIGFLAG; /**< Configure Flag Register, offset: 0x180 */
+// __IO uint32_t PORTSC1; /**< Port Status & Control, offset: 0x184 */
+// uint8_t RESERVED_9[28];
+// __IO uint32_t OTGSC; /**< On-The-Go Status & control, offset: 0x1A4 */
+// __IO uint32_t USBMODE; /**< USB Device Mode, offset: 0x1A8 */
+// __IO uint32_t ENDPTSETUPSTAT; /**< Endpoint Setup Status, offset: 0x1AC */
+// __IO uint32_t ENDPTPRIME; /**< Endpoint Prime, offset: 0x1B0 */
+// __IO uint32_t ENDPTFLUSH; /**< Endpoint Flush, offset: 0x1B4 */
+// __I uint32_t ENDPTSTAT; /**< Endpoint Status, offset: 0x1B8 */
+// __IO uint32_t ENDPTCOMPLETE; /**< Endpoint Complete, offset: 0x1BC */
+// __IO uint32_t ENDPTCTRL0; /**< Endpoint Control0, offset: 0x1C0 */
+// __IO uint32_t ENDPTCTRL[7]; /**< Endpoint Control 1..Endpoint Control 7, array offset: 0x1C4, array step: 0x4 */
+// } USB_Type;
+
+
+/*! @brief The maximum value of ISO type maximum packet size for HS in USB specification 2.0 */
+#define USB_DEVICE_MAX_HS_ISO_MAX_PACKET_SIZE (1024U)
+/*! @brief The maximum value of interrupt type maximum packet size for HS in USB specification 2.0 */
+#define USB_DEVICE_MAX_HS_INTERUPT_MAX_PACKET_SIZE (1024U)
+/*! @brief The maximum value of bulk type maximum packet size for HS in USB specification 2.0 */
+#define USB_DEVICE_MAX_HS_BULK_MAX_PACKET_SIZE (512U)
+/*! @brief The maximum value of control type maximum packet size for HS in USB specification 2.0 */
+#define USB_DEVICE_MAX_HS_CONTROL_MAX_PACKET_SIZE (64U)
+#define USB_DEVICE_MAX_TRANSFER_PRIME_TIMES \
+ (10000000U) /* The max prime times of EPPRIME, if still doesn't take effect, means status has been reset*/
+
+/* Device QH */
+#define USB_DEVICE_EHCI_QH_POINTER_MASK (0xFFFFFFC0U)
+#define USB_DEVICE_EHCI_QH_MULT_MASK (0xC0000000U)
+#define USB_DEVICE_EHCI_QH_ZLT_MASK (0x20000000U)
+#define USB_DEVICE_EHCI_QH_MAX_PACKET_SIZE_MASK (0x07FF0000U)
+#define USB_DEVICE_EHCI_QH_MAX_PACKET_SIZE (0x00000800U)
+#define USB_DEVICE_EHCI_QH_IOS_MASK (0x00008000U)
+
+/* Device DTD */
+#define USB_DEVICE_ECHI_DTD_POINTER_MASK (0xFFFFFFE0U)
+#define USB_DEVICE_ECHI_DTD_TERMINATE_MASK (0x00000001U)
+#define USB_DEVICE_ECHI_DTD_PAGE_MASK (0xFFFFF000U)
+#define USB_DEVICE_ECHI_DTD_PAGE_OFFSET_MASK (0x00000FFFU)
+#define USB_DEVICE_ECHI_DTD_PAGE_BLOCK (0x00001000U)
+#define USB_DEVICE_ECHI_DTD_TOTAL_BYTES_MASK (0x7FFF0000U)
+#define USB_DEVICE_ECHI_DTD_TOTAL_BYTES (0x00004000U)
+#define USB_DEVICE_ECHI_DTD_IOC_MASK (0x00008000U)
+#define USB_DEVICE_ECHI_DTD_MULTIO_MASK (0x00000C00U)
+#define USB_DEVICE_ECHI_DTD_STATUS_MASK (0x000000FFU)
+#define USB_DEVICE_EHCI_DTD_STATUS_ERROR_MASK (0x00000068U)
+#define USB_DEVICE_ECHI_DTD_STATUS_ACTIVE (0x00000080U)
+#define USB_DEVICE_ECHI_DTD_STATUS_HALTED (0x00000040U)
+#define USB_DEVICE_ECHI_DTD_STATUS_DATA_BUFFER_ERROR (0x00000020U)
+#define USB_DEVICE_ECHI_DTD_STATUS_TRANSACTION_ERROR (0x00000008U)
+
+#define USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK (0x1800u)
+#define USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_SHFIT (11U)
+
+/*! @brief Define current endian */
+#ifndef ENDIANNESS
+#define ENDIANNESS USB_LITTLE_ENDIAN
+#endif
+
+/*
+ * The following MACROs (USB_GLOBAL, USB_BDT, USB_RAM_ADDRESS_ALIGNMENT, etc) are only used for USB device stack.
+ * The USB device global variables are put into the section m_usb_global and m_usb_bdt
+ * by using the MACRO USB_GLOBAL and USB_BDT. In this way, the USB device
+ * global variables can be linked into USB dedicated RAM by USB_STACK_USE_DEDICATED_RAM.
+ * The MACRO USB_STACK_USE_DEDICATED_RAM is used to decide the USB stack uses dedicated RAM or not. The value of
+ * the macro can be set as 0, USB_STACK_DEDICATED_RAM_TYPE_BDT_GLOBAL, or USB_STACK_DEDICATED_RAM_TYPE_BDT.
+ * The MACRO USB_STACK_DEDICATED_RAM_TYPE_BDT_GLOBAL means USB device global variables, including USB_BDT and
+ * USB_GLOBAL, are put into the USB dedicated RAM. This feature can only be enabled when the USB dedicated RAM
+ * is not less than 2K Bytes.
+ * The MACRO USB_STACK_DEDICATED_RAM_TYPE_BDT means USB device global variables, only including USB_BDT, are put
+ * into the USB dedicated RAM, the USB_GLOBAL will be put into .bss section. This feature is used for some SOCs,
+ * the USB dedicated RAM size is not more than 512 Bytes.
+ */
+#if defined(__ICCARM__)
+
+#define USB_WEAK_VAR __attribute__((weak))
+#define USB_WEAK_FUN __attribute__((weak))
+/* disable misra 19.13 */
+_Pragma("diag_suppress=Pm120")
+#define USB_ALIGN_PRAGMA(x) _Pragma(#x)
+ _Pragma("diag_default=Pm120")
+
+#define USB_RAM_ADDRESS_ALIGNMENT(n) USB_ALIGN_PRAGMA(data_alignment = n)
+ _Pragma("diag_suppress=Pm120")
+#define USB_LINK_SECTION_PART(str) _Pragma(#str)
+#define USB_LINK_DMA_INIT_DATA(sec) USB_LINK_SECTION_PART(location = #sec)
+#define USB_LINK_USB_GLOBAL _Pragma("location = \"m_usb_global\"")
+#define USB_LINK_USB_BDT _Pragma("location = \"m_usb_bdt\"")
+#define USB_LINK_USB_GLOBAL_BSS
+#define USB_LINK_USB_BDT_BSS
+ _Pragma("diag_default=Pm120")
+#define USB_LINK_DMA_NONINIT_DATA _Pragma("location = \"m_usb_dma_noninit_data\"")
+#define USB_LINK_NONCACHE_NONINIT_DATA _Pragma("location = \"NonCacheable\"")
+#elif defined(__CC_ARM) || (defined(__ARMCC_VERSION))
+
+#define USB_WEAK_VAR __attribute__((weak))
+#define USB_WEAK_FUN __attribute__((weak))
+#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n)))
+#define USB_LINK_DMA_INIT_DATA(sec) __attribute__((section(#sec)))
+#if defined(__CC_ARM)
+#define USB_LINK_USB_GLOBAL __attribute__((section("m_usb_global"))) __attribute__((zero_init))
+#else
+#define USB_LINK_USB_GLOBAL __attribute__((section(".bss.m_usb_global")))
+#endif
+#if defined(__CC_ARM)
+#define USB_LINK_USB_BDT __attribute__((section("m_usb_bdt"))) __attribute__((zero_init))
+#else
+#define USB_LINK_USB_BDT __attribute__((section(".bss.m_usb_bdt")))
+#endif
+#define USB_LINK_USB_GLOBAL_BSS
+#define USB_LINK_USB_BDT_BSS
+#if defined(__CC_ARM)
+#define USB_LINK_DMA_NONINIT_DATA __attribute__((section("m_usb_dma_noninit_data"))) __attribute__((zero_init))
+#else
+#define USB_LINK_DMA_NONINIT_DATA __attribute__((section(".bss.m_usb_dma_noninit_data")))
+#endif
+#if defined(__CC_ARM)
+#define USB_LINK_NONCACHE_NONINIT_DATA __attribute__((section("NonCacheable"))) __attribute__((zero_init))
+#else
+#define USB_LINK_NONCACHE_NONINIT_DATA __attribute__((section(".bss.NonCacheable")))
+#endif
+
+#elif defined(__GNUC__)
+
+#define USB_WEAK_VAR __attribute__((weak))
+#define USB_WEAK_FUN __attribute__((weak))
+#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n)))
+#define USB_LINK_DMA_INIT_DATA(sec) __attribute__((section(#sec)))
+#define USB_LINK_USB_GLOBAL __attribute__((section("m_usb_global, \"aw\", %nobits @")))
+#define USB_LINK_USB_BDT __attribute__((section("m_usb_bdt, \"aw\", %nobits @")))
+#define USB_LINK_USB_GLOBAL_BSS
+#define USB_LINK_USB_BDT_BSS
+#define USB_LINK_DMA_NONINIT_DATA __attribute__((section("m_usb_dma_noninit_data, \"aw\", %nobits @")))
+#define USB_LINK_NONCACHE_NONINIT_DATA __attribute__((section("NonCacheable, \"aw\", %nobits @")))
+
+#elif (defined(__DSC__) && defined(__CW__))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define USB_WEAK_VAR __attribute__((weak))
+#define USB_WEAK_FUN __attribute__((weak))
+#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n)))
+#define USB_LINK_USB_BDT_BSS
+#define USB_LINK_USB_GLOBAL_BSS
+#else
+#error The tool-chain is not supported.
+#endif
+
+#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE)) || \
+ (defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE))
+#define USB_DMA_DATA_NONINIT_SUB USB_LINK_DMA_NONINIT_DATA
+#define USB_DMA_DATA_INIT_SUB USB_LINK_DMA_INIT_DATA(m_usb_dma_init_data)
+#define USB_CONTROLLER_DATA USB_LINK_NONCACHE_NONINIT_DATA
+#else
+#if (defined(DATA_SECTION_IS_CACHEABLE) && (DATA_SECTION_IS_CACHEABLE))
+#define USB_DMA_DATA_NONINIT_SUB USB_LINK_NONCACHE_NONINIT_DATA
+#define USB_DMA_DATA_INIT_SUB USB_LINK_DMA_INIT_DATA(NonCacheable.init)
+#define USB_CONTROLLER_DATA USB_LINK_NONCACHE_NONINIT_DATA
+#else
+#define USB_DMA_DATA_NONINIT_SUB
+#define USB_DMA_DATA_INIT_SUB
+#define USB_CONTROLLER_DATA USB_LINK_USB_GLOBAL
+#endif
+#endif
+
+/*! @brief Endpoint initialization structure */
+typedef struct _usb_device_endpoint_init_struct
+{
+ uint16_t maxPacketSize; /*!< Endpoint maximum packet size */
+ uint8_t endpointAddress; /*!< Endpoint address*/
+ uint8_t transferType; /*!< Endpoint transfer type*/
+ uint8_t zlt; /*!< ZLT flag*/
+ uint8_t interval; /*!< Endpoint interval*/
+} usb_device_endpoint_init_struct_t;
+
+typedef struct _usb_device_ehci_qh_struct
+{
+ union
+ {
+ volatile uint32_t capabilttiesCharacteristics;
+ struct
+ {
+ volatile uint32_t reserved1 : 15;
+ volatile uint32_t ios : 1;
+ volatile uint32_t maxPacketSize : 11;
+ volatile uint32_t reserved2 : 2;
+ volatile uint32_t zlt : 1;
+ volatile uint32_t mult : 2;
+ } capabilttiesCharacteristicsBitmap;
+ } capabilttiesCharacteristicsUnion;
+ volatile uint32_t currentDtdPointer;
+ volatile uint32_t nextDtdPointer;
+ union
+ {
+ volatile uint32_t dtdToken;
+ struct
+ {
+ volatile uint32_t status : 8;
+ volatile uint32_t reserved1 : 2;
+ volatile uint32_t multiplierOverride : 2;
+ volatile uint32_t reserved2 : 3;
+ volatile uint32_t ioc : 1;
+ volatile uint32_t totalBytes : 15;
+ volatile uint32_t reserved3 : 1;
+ } dtdTokenBitmap;
+ } dtdTokenUnion;
+ volatile uint32_t bufferPointerPage[5];
+ volatile uint32_t reserved1;
+ uint32_t setupBuffer[2];
+ uint32_t setupBufferBack[2];
+ union
+ {
+ uint32_t endpointStatus;
+ struct
+ {
+ uint32_t isOpened : 1;
+ uint32_t zlt : 1;
+ uint32_t : 30;
+ } endpointStatusBitmap;
+ } endpointStatusUnion;
+ uint32_t reserved2;
+} usb_device_ehci_qh_struct_t;
+
+typedef struct _usb_device_ehci_dtd_struct
+{
+ volatile uint32_t nextDtdPointer;
+ union
+ {
+ volatile uint32_t dtdToken;
+ struct
+ {
+ volatile uint32_t status : 8;
+ volatile uint32_t reserved1 : 2;
+ volatile uint32_t multiplierOverride : 2;
+ volatile uint32_t reserved2 : 3;
+ volatile uint32_t ioc : 1;
+ volatile uint32_t totalBytes : 15;
+ volatile uint32_t reserved3 : 1;
+ } dtdTokenBitmap;
+ } dtdTokenUnion;
+ volatile uint32_t bufferPointerPage[5];
+ union
+ {
+ volatile uint32_t reserved;
+ struct
+ {
+ uint32_t originalBufferOffest : 12;
+ uint32_t originalBufferLength : 19;
+ uint32_t dtdInvalid : 1;
+ } originalBufferInfo;
+ } reservedUnion;
+} usb_device_ehci_dtd_struct_t;
+
+/*! @brief EHCI state structure */
+typedef struct _usb_device_ehci_state_struct
+{
+ USB_Type *registerBase; /*!< The base address of the register */
+#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U))
+ USBPHY_Type *registerPhyBase; /*!< The base address of the PHY register */
+#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U))
+ USBNC_Type *registerNcBase; /*!< The base address of the USBNC register */
+#endif
+#endif
+ usb_device_ehci_qh_struct_t *qh; /*!< The QH structure base address */
+ usb_device_ehci_dtd_struct_t *dtd; /*!< The DTD structure base address */
+ usb_device_ehci_dtd_struct_t *dtdFree; /*!< The idle DTD list head */
+ usb_device_ehci_dtd_struct_t
+ *dtdHead[USB_DEVICE_ENDPOINTS * 2]; /*!< The transferring DTD list head for each endpoint */
+ usb_device_ehci_dtd_struct_t
+ *dtdTail[USB_DEVICE_ENDPOINTS * 2]; /*!< The transferring DTD list tail for each endpoint */
+ uint8_t dtdCount; /*!< The idle DTD node count */
+ uint8_t endpointCount; /*!< The endpoint number of EHCI */
+ uint8_t isResetting; /*!< Whether a PORT reset is occurring or not */
+ uint8_t controllerId; /*!< Controller ID */
+ uint8_t speed; /*!< Current speed of EHCI */
+ uint8_t isSuspending; /*!< Is suspending of the PORT */
+} usb_device_ehci_state_struct_t;
+
+/*! @brief USB error code */
+typedef enum _usb_status
+{
+ kStatus_USB_Success = 0x00U, /*!< Success */
+ kStatus_USB_Error, /*!< Failed */
+
+ kStatus_USB_Busy, /*!< Busy */
+ kStatus_USB_InvalidHandle, /*!< Invalid handle */
+ kStatus_USB_InvalidParameter, /*!< Invalid parameter */
+ kStatus_USB_InvalidRequest, /*!< Invalid request */
+ kStatus_USB_ControllerNotFound, /*!< Controller cannot be found */
+ kStatus_USB_InvalidControllerInterface, /*!< Invalid controller interface */
+
+ kStatus_USB_NotSupported, /*!< Configuration is not supported */
+ kStatus_USB_Retry, /*!< Enumeration get configuration retry */
+ kStatus_USB_TransferStall, /*!< Transfer stalled */
+ kStatus_USB_TransferFailed, /*!< Transfer failed */
+ kStatus_USB_AllocFail, /*!< Allocation failed */
+ kStatus_USB_LackSwapBuffer, /*!< Insufficient swap buffer for KHCI */
+ kStatus_USB_TransferCancel, /*!< The transfer cancelled */
+ kStatus_USB_BandwidthFail, /*!< Allocate bandwidth failed */
+ kStatus_USB_MSDStatusFail, /*!< For MSD, the CSW status means fail */
+ kStatus_USB_EHCIAttached,
+ kStatus_USB_EHCIDetached,
+ kStatus_USB_DataOverRun, /*!< The amount of data returned by the endpoint exceeded
+ either the size of the maximum data packet allowed
+ from the endpoint or the remaining buffer size. */
+} usb_status_t;
+
+#endif /* __USB_IMXRT_REG_H__ */
+/* End of file ***************************************************************************/