From b300b42a471bfe02266577432fc077c3891fd136 Mon Sep 17 00:00:00 2001 From: zhouqiyusth Date: Thu, 14 Apr 2022 20:17:04 +0800 Subject: [PATCH] add imxrt usb device port --- port/imxrt/README.md | 12 + port/imxrt/usb_dc_imxrt.c | 1501 ++++++++++++++++++++++++++++++++ port/imxrt/usb_dc_imxrt_port.h | 42 + port/imxrt/usb_imxrt_reg.h | 368 ++++++++ 4 files changed, 1923 insertions(+) create mode 100644 port/imxrt/README.md create mode 100644 port/imxrt/usb_dc_imxrt.c create mode 100644 port/imxrt/usb_dc_imxrt_port.h create mode 100644 port/imxrt/usb_imxrt_reg.h 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 ***************************************************************************/