Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.
Upstream: https://github.com/ARMmbed/DAPLink
Diff: source/hic_hal/nxp/lpc11u35/usbd_LPC11Uxx.c
- Revision:
- 0:01f31e923fe2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/hic_hal/nxp/lpc11u35/usbd_LPC11Uxx.c Tue Apr 07 12:55:42 2020 +0200 @@ -0,0 +1,825 @@ +/** + * @file usbd_LPC11Uxx.c + * @brief + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rl_usb.h" +#include "LPC11Uxx.h" +#include "compiler.h" +#include "util.h" + +#define __NO_USB_LIB_C +#include "usb_config.c" + + +#define BUF_ACTIVE (1UL << 31) +#define EP_DISABLED (1UL << 30) +#define EP_STALL (1UL << 29) +#define TOOGLE_RESET (1UL << 28) +#define EP_TYPE (1UL << 26) + +#define N_BYTES(n) ((n & 0x3FF) << 16) +#define BUF_ADDR(addr) (((addr) >> 6) & 0xFFFF) + +#define EP_OUT_IDX(EPNum) (EPNum * 2 ) +#define EP_IN_IDX(EPNum) (EPNum * 2 + 1) + +#define EP_LIST_BASE 0x20004000 +#define EP_BUF_BASE (U32)(EP_LIST_BASE + 0x100) + +typedef struct BUF_INFO { + U32 buf_len; + U32 buf_ptr; +} EP_BUF_INFO; + +EP_BUF_INFO EPBufInfo[(USBD_EP_NUM + 1) * 2]; +volatile U32 EPList[(USBD_EP_NUM + 1) * 2] __at(EP_LIST_BASE); + +static U32 addr = 3 * 64 + EP_BUF_BASE; +static U32 ctrl_out_next = 0; + +/* + * Get EP CmdStat pointer + * Parameters: EPNum: endpoint number + * + */ + +U32 *GetEpCmdStatPtr(U32 EPNum) +{ + U32 ptr = 0; + + if (EPNum & 0x80) { + EPNum &= ~0x80; + ptr = 8; + } + + ptr += EP_LIST_BASE + EPNum * 16; + return ((U32 *)ptr); +} + + +/* + * Usb interrupt enable/disable + * Parameters: ena: enable/disable + * 0: disable interrupt + * 1: enable interrupt + */ + +#ifdef __RTX +void __svc(1) USBD_Intr(int ena); +void __SVC_1(int ena) +{ + if (ena) { + NVIC_EnableIRQ(USB_IRQn); /* Enable USB interrupt */ + } else { + NVIC_DisableIRQ(USB_IRQn); /* Disable USB interrupt */ + } +} +#endif + + + +/* + * USB Device Initialize Function + * Called by the User to initialize USB Device + * Return Value: None + */ + +void USBD_Init(void) +{ + LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 6); + LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 14) | + (1UL << 27); + LPC_USB->DEVCMDSTAT |= (1UL << 9); /* PLL ON */ + LPC_IOCON->PIO0_3 &= ~(0x1F); + LPC_IOCON->PIO0_3 |= (1UL << 0); /* Secondary function VBUS */ + LPC_IOCON->PIO0_6 &= ~7; + LPC_IOCON->PIO0_6 |= (1UL << 0); /* Secondary function USB CON */ + LPC_SYSCON->PDRUNCFG &= ~((1UL << 8) | /* USB PLL powered */ + (1UL << 10)); /* USB transceiver powered */ + LPC_USB->DATABUFSTART = EP_BUF_BASE & 0xFFC00000; + LPC_USB->EPLISTSTART = EP_LIST_BASE; + NVIC_EnableIRQ(USB_IRQn); + USBD_Reset(); +} + + +/* + * USB Device Connect Function + * Called by the User to Connect/Disconnect USB Device + * Parameters: con: Connect/Disconnect + * Return Value: None + */ + +void USBD_Connect(BOOL con) +{ + if (con) { + LPC_USB->DEVCMDSTAT |= (1UL << 16); /* Set device connect status */ + } else { + LPC_USB->DEVCMDSTAT &= ~(1UL << 16); /* Clear device connect status */ + } + + return; +} + + +/* + * USB Device Reset Function + * Called automatically on USB Device Reset + * Return Value: None + */ + +void USBD_Reset(void) +{ + U32 i; + U32 *ptr; + addr = 3 * 64 + EP_BUF_BASE; + + for (i = 2; i < (5 * 4); i++) { + EPList[i] = (1UL << 30); /* EPs disabled */ + } + + ctrl_out_next = 0; + EPBufInfo[0].buf_len = USBD_MAX_PACKET0; + EPBufInfo[0].buf_ptr = EP_BUF_BASE; + EPBufInfo[1].buf_len = USBD_MAX_PACKET0; + EPBufInfo[1].buf_ptr = EP_BUF_BASE + 2 * 64; + ptr = GetEpCmdStatPtr(0); + *ptr = N_BYTES(EPBufInfo[0].buf_len) | /* EP0 OUT */ + BUF_ADDR(EPBufInfo[0].buf_ptr) | + BUF_ACTIVE; + ptr++; + *ptr = BUF_ADDR(EPBufInfo[0].buf_ptr + 64);/* SETUP */ + LPC_USB->DEVCMDSTAT |= (1UL << 7); /*USB device enable */ + LPC_USB->INTSTAT = 0x2FC; /* clear EP interrupt flags */ + LPC_USB->INTEN = ((1UL << 30) | /* SOF intr enable */ + (1UL << 0) | /* EP0 OUT intr enable */ + (1UL << 1) | /* EP0 IN intr enable */ + (1UL << 31)); /* stat change int en */ +} + + +/* + * USB Device Suspend Function + * Called automatically on USB Device Suspend + * Return Value: None + */ + +void USBD_Suspend(void) +{ + /* Performed by Hardware */ +} + + +/* + * USB Device Resume Function + * Called automatically on USB Device Resume + * Return Value: None + */ + +void USBD_Resume(void) +{ + /* Performed by Hardware */ +} + + +/* + * USB Device Remote Wakeup Function + * Called automatically on USB Device Remote Wakeup + * Return Value: None + */ + +void USBD_WakeUp(void) +{ + LPC_SYSCON->USBCLKCTRL = 1; + LPC_USB->DEVCMDSTAT &= ~(1UL << 17); /*clear device suspend status */ + + while (LPC_USB->DEVCMDSTAT & (1UL << 17)); + + LPC_SYSCON->USBCLKCTRL = 0; +} + + +/* + * USB Device Remote Wakeup Configuration Function + * Parameters: cfg: Device Enable/Disable + * Return Value: None + */ + +void USBD_WakeUpCfg(BOOL cfg) +{ + if (cfg == __TRUE) { + LPC_USB->DEVCMDSTAT &= ~(1UL << 9); /*PPL_ON=0, in suspend clk is stoped */ + } else { + LPC_USB->DEVCMDSTAT |= (1UL << 9); /*PPL_ON=1, in suspend clk isnt stoped */ + LPC_SYSCON->USBCLKCTRL = 0; + } +} + + +/* + * USB Device Set Address Function + * Parameters: adr: USB Device Address + * Return Value: None + */ + +void USBD_SetAddress(U32 adr, U32 setup) +{ + if (!setup) { + LPC_USB->DEVCMDSTAT &= ~0x7F; + LPC_USB->DEVCMDSTAT |= adr | (1UL << 7); + } +} + + + +/* + * USB Device Configure Function + * Parameters: cfg: Device Configure/Deconfigure + * Return Value: None + */ + +void USBD_Configure(BOOL cfg) +{ + addr = 3 * 64 + EP_BUF_BASE; +} + + +/* + * Configure USB Device Endpoint according to Descriptor + * Parameters: pEPD: Pointer to Device Endpoint Descriptor + * Return Value: None + */ + +void USBD_ConfigEP(USB_ENDPOINT_DESCRIPTOR *pEPD) +{ + U32 num, val, type; + U32 *ptr; + num = pEPD->bEndpointAddress; + val = pEPD->wMaxPacketSize; + type = pEPD->bmAttributes & USB_ENDPOINT_TYPE_MASK; + + /* IN EPs */ + if (num & 0x80) { + num &= ~0x80; + EPBufInfo[EP_IN_IDX(num)].buf_len = val; + EPBufInfo[EP_IN_IDX(num)].buf_ptr = addr; + addr += ((val + 63) >> 6) * 64; /* calc new free buffer address */ + ptr = GetEpCmdStatPtr(num | 0x80); + *ptr = EP_DISABLED; + + if (type == USB_ENDPOINT_TYPE_ISOCHRONOUS) { + *ptr |= EP_TYPE; + } + } + + /* OUT EPs */ + else { + EPBufInfo[EP_OUT_IDX(num)].buf_len = val; + EPBufInfo[EP_OUT_IDX(num)].buf_ptr = addr; + ptr = GetEpCmdStatPtr(num); + *ptr = N_BYTES(EPBufInfo[EP_OUT_IDX(num)].buf_len) | + BUF_ADDR(EPBufInfo[EP_OUT_IDX(num)].buf_ptr) | + EP_DISABLED; + + if (type == USB_ENDPOINT_TYPE_ISOCHRONOUS) { + *ptr |= EP_TYPE; + } + + addr += ((val + 63) >> 6) * 64; /* calc new free buffer address */ + } +} + + +/* + * Set Direction for USB Device Control Endpoint + * Parameters: dir: Out (dir == 0), In (dir <> 0) + * Return Value: None + */ + +void USBD_DirCtrlEP(U32 dir) +{ + /* Not needed */ +} + + +/* + * Enable USB Device Endpoint + * Parameters: EPNum: Device Endpoint Number + * EPNum.0..3: Address + * EPNum.7: Dir + * Return Value: None + */ + +void USBD_EnableEP(U32 EPNum) +{ + U32 *ptr;; + ptr = GetEpCmdStatPtr(EPNum); + + /* IN EP */ + if (EPNum & 0x80) { + EPNum &= ~0x80; + *ptr &= ~EP_DISABLED; + LPC_USB->INTSTAT = (1 << EP_IN_IDX(EPNum)); + LPC_USB->INTEN |= (1 << EP_IN_IDX(EPNum)); + } + + /* OUT EP */ + else { + *ptr &= ~EP_DISABLED; + *ptr |= BUF_ACTIVE; + LPC_USB->INTSTAT = (1 << EP_OUT_IDX(EPNum)); + LPC_USB->INTEN |= (1 << EP_OUT_IDX(EPNum)); + } +} + + +/* + * Disable USB Device Endpoint + * Parameters: EPNum: Device Endpoint Number + * EPNum.0..3: Address + * EPNum.7: Dir + * Return Value: None + */ + +void USBD_DisableEP(U32 EPNum) +{ + U32 *ptr; + ptr = GetEpCmdStatPtr(EPNum); + *ptr = EP_DISABLED; + + if (EPNum & 0x80) { + EPNum &= ~0x80; + LPC_USB->INTEN &= ~(1 << EP_IN_IDX(EPNum)); + + } else { + LPC_USB->INTEN &= ~(1 << EP_OUT_IDX(EPNum)); + } +} + + +/* + * Reset USB Device Endpoint + * Parameters: EPNum: Device Endpoint Number + * EPNum.0..3: Address + * EPNum.7: Dir + * Return Value: None + */ + +void USBD_ResetEP(U32 EPNum) +{ + U32 *ptr; + ptr = GetEpCmdStatPtr(EPNum); + *ptr |= TOOGLE_RESET; +} + + +/* + * Set Stall for USB Device Endpoint + * Parameters: EPNum: Device Endpoint Number + * EPNum.0..3: Address + * EPNum.7: Dir + * Return Value: None + */ + +void USBD_SetStallEP(U32 EPNum) +{ + U32 *ptr; + ptr = GetEpCmdStatPtr(EPNum); + + if (EPNum & 0x7F) { + if (*ptr & BUF_ACTIVE) { + *ptr &= ~(BUF_ACTIVE); + } + + } else { + if (EPNum & 0x80) { + EPNum &= ~0x80; + LPC_USB->EPSKIP |= (1 << EP_IN_IDX(EPNum)); + + while (LPC_USB->EPSKIP & (1 << EP_IN_IDX(EPNum))); + + } else { + LPC_USB->EPSKIP |= (1 << EP_OUT_IDX(EPNum)); + + while (LPC_USB->EPSKIP & (1 << EP_OUT_IDX(EPNum))); + } + } + + if ((EPNum & 0x7F) == 0) { + /* Endpoint is stalled so control out won't be next */ + ctrl_out_next = 0; + } + + *ptr |= EP_STALL; +} + + +/* + * Clear Stall for USB Device Endpoint + * Parameters: EPNum: Device Endpoint Number + * EPNum.0..3: Address + * EPNum.7: Dir + * Return Value: None + */ + +void USBD_ClrStallEP(U32 EPNum) +{ + U32 *ptr; + ptr = GetEpCmdStatPtr(EPNum); + + if (EPNum & 0x80) { + *ptr &= ~EP_STALL; + + } else { + *ptr &= ~EP_STALL; + *ptr |= BUF_ACTIVE; + } + + USBD_ResetEP(EPNum); +} + + +/* + * Clear USB Device Endpoint Buffer + * Parameters: EPNum: Device Endpoint Number + * EPNum.0..3: Address + * EPNum.7: Dir + * Return Value: None + */ + +void USBD_ClearEPBuf(U32 EPNum) +{ + U32 cnt, i; + U8 *dataptr; + + if (EPNum & 0x80) { + EPNum &= ~0x80; + dataptr = (U8 *)EPBufInfo[EP_IN_IDX(EPNum)].buf_ptr; + cnt = EPBufInfo[EP_IN_IDX(EPNum)].buf_len; + + for (i = 0; i < cnt; i++) { + dataptr[i] = 0; + } + + } else { + dataptr = (U8 *)EPBufInfo[EP_OUT_IDX(EPNum)].buf_ptr; + cnt = EPBufInfo[EP_OUT_IDX(EPNum)].buf_len; + + for (i = 0; i < cnt; i++) { + dataptr[i] = 0; + } + } +} + + +/* + * Read USB Device Endpoint Data + * Parameters: EPNum: Device Endpoint Number + * EPNum.0..3: Address + * EPNum.7: Dir + * pData: Pointer to Data Buffer + * Return Value: Number of bytes read + */ + +U32 USBD_ReadEP(U32 EPNum, U8 *pData, U32 size) +{ + U32 cnt, i, xfer_size; + volatile U32 *ptr; + U8 *dataptr; + ptr = GetEpCmdStatPtr(EPNum); + int timeout = 256; + + /* Setup packet */ + if ((EPNum == 0) && !ctrl_out_next && (LPC_USB->DEVCMDSTAT & (1UL << 8))) { + cnt = USBD_MAX_PACKET0; + + if (size < cnt) { + util_assert(0); + cnt = size; + } + + dataptr = (U8 *)(EPBufInfo[EP_OUT_IDX(EPNum)].buf_ptr + 64); + + for (i = 0; i < cnt; i++) { + pData[i] = dataptr[i]; + } + + xfer_size = (pData[7] << 8) | (pData[6] << 0); + if ((xfer_size > 0) && (pData[0] & (1 << 7))) { + /* This control transfer has a data IN stage */ + /* and ends with a zero length data OUT transfer. */ + /* Ensure the data OUT token is not skipped even if */ + /* a SETUP token arrives before USBD_ReadEP has */ + /* been called. */ + ctrl_out_next = 1; + } + + LPC_USB->EPSKIP |= (1 << EP_IN_IDX(EPNum)); + + while (LPC_USB->EPSKIP & (1 << EP_IN_IDX(EPNum))); + + if (*(ptr + 2) & EP_STALL) { + *(ptr + 2) &= ~(EP_STALL); + } + + if (*ptr & EP_STALL) { + *ptr &= ~(EP_STALL); + } + + LPC_USB->DEVCMDSTAT |= (1UL << 8); + } + + /* OUT packet */ + else { + ptr = GetEpCmdStatPtr(EPNum); + cnt = EPBufInfo[EP_OUT_IDX(EPNum)].buf_len - ((*ptr >> 16) & 0x3FF); + dataptr = (U8 *)EPBufInfo[EP_OUT_IDX(EPNum)].buf_ptr; + + while ((timeout-- > 0) && (*ptr & BUF_ACTIVE)); //spin on the hardware until it's done + util_assert(!(*ptr & BUF_ACTIVE)); //check for timeout + + if (size < cnt) { + util_assert(0); + cnt = size; + } + + cnt = cnt < size ? cnt : size; + + for (i = 0; i < cnt; i++) { + pData[i] = dataptr[i]; + } + + *ptr = N_BYTES(EPBufInfo[EP_OUT_IDX(EPNum)].buf_len) | + BUF_ADDR(EPBufInfo[EP_OUT_IDX(EPNum)].buf_ptr) | + BUF_ACTIVE; + + if (EPNum == 0) { + /* If ctrl_out_next is set then this should be a zero length */ + /* data OUT packet. */ + util_assert(!ctrl_out_next || (cnt == 0)); + ctrl_out_next = 0; + if (LPC_USB->DEVCMDSTAT & (1UL << 8)) { + // A setup packet is still pending so trigger another interrupt + LPC_USB->INTSETSTAT |= (1 << 0); + } + } + } + + return (cnt); +} + + +/* + * Write USB Device Endpoint Data + * Parameters: EPNum: Endpoint Number + * EPNum.0..3: Address + * EPNum.7: Dir + * pData: Pointer to Data Buffer + * cnt: Number of bytes to write + * Return Value: Number of bytes written + */ + +U32 USBD_WriteEP(U32 EPNum, U8 *pData, U32 cnt) +{ + U32 i; + volatile U32 *ptr; + U32 *dataptr; + ptr = GetEpCmdStatPtr(EPNum); + EPNum &= ~0x80; + + while (*ptr & BUF_ACTIVE); + + *ptr &= ~(0x3FFFFFF); + *ptr |= BUF_ADDR(EPBufInfo[EP_IN_IDX(EPNum)].buf_ptr) | + N_BYTES(cnt); + dataptr = (U32 *)EPBufInfo[EP_IN_IDX(EPNum)].buf_ptr; + + for (i = 0; i < (cnt + 3) / 4; i++) { + dataptr[i] = * ((__packed U32 *)pData); + pData += 4; + } + + if (EPNum && (*ptr & EP_STALL)) { + return (0); + } + + *ptr |= BUF_ACTIVE; + return (cnt); +} + + +/* + * Get USB Device Last Frame Number + * Parameters: None + * Return Value: Frame Number + */ + +U32 USBD_GetFrame(void) +{ + return (LPC_USB->INFO & 0x7FF); +} + + +/* + * USB Device Interrupt Service Routine + */ + +void USB_IRQHandler(void) +{ + NVIC_DisableIRQ(USB_IRQn); + USBD_SignalHandler(); +} + +void USBD_Handler(void) +{ + U32 sts, val, num, i; + sts = LPC_USB->INTSTAT; + LPC_USB->INTSTAT = sts; + + /* Device Status Interrupt (Reset, Connect change, Suspend/Resume) */ + if (sts & (1UL << 31)) { + val = LPC_USB->DEVCMDSTAT; + + /* reset interrupt */ + if (val & (1UL << 26)) { + LPC_USB->DEVCMDSTAT |= (1UL << 26); + USBD_Reset(); + usbd_reset_core(); +#ifdef __RTX + + if (USBD_RTX_DevTask) { + isr_evt_set(USBD_EVT_RESET, USBD_RTX_DevTask); + } + +#else + + if (USBD_P_Reset_Event) { + USBD_P_Reset_Event(); + } + +#endif + } + + /* connect interrupt */ + if (val & (1UL << 24)) { + LPC_USB->DEVCMDSTAT |= (1UL << 24); +#ifdef __RTX + + if (USBD_RTX_DevTask) { + if (val & (1UL << 16)) { + isr_evt_set(USBD_EVT_POWER_ON, USBD_RTX_DevTask); + } else { + isr_evt_set(USBD_EVT_POWER_OFF, USBD_RTX_DevTask); + } + } + +#else + + if (USBD_P_Power_Event) { + USBD_P_Power_Event((val >> 16) & 1); + } + +#endif + } + + /* suspend/resume interrupt */ + if (val & (1 << 25)) { + LPC_USB->DEVCMDSTAT |= (1UL << 25); + + /* suspend interrupt */ + if (val & (1UL << 17)) { + USBD_Suspend(); +#ifdef __RTX + + if (USBD_RTX_DevTask) { + isr_evt_set(USBD_EVT_SUSPEND, USBD_RTX_DevTask); + } + +#else + + if (USBD_P_Suspend_Event) { + USBD_P_Suspend_Event(); + } + +#endif + } + + /* resume interrupt */ + else { +#ifdef __RTX + + if (USBD_RTX_DevTask) { + isr_evt_set(USBD_EVT_RESUME, USBD_RTX_DevTask); + } + +#else + + if (USBD_P_Resume_Event) { + USBD_P_Resume_Event(); + } + +#endif + } + } + } + + /* Start of Frame */ + if (sts & (1UL << 30)) { +#ifdef __RTX + + if (USBD_RTX_DevTask) { + isr_evt_set(USBD_EVT_SOF, USBD_RTX_DevTask); + } + +#else + + if (USBD_P_SOF_Event) { + USBD_P_SOF_Event(); + } + +#endif + } + + /* EndPoint Interrupt */ + if (sts & 0x3FF) { + const uint32_t endpoint_count = ((USBD_EP_NUM + 1) * 2); + + for (i = 0; i < endpoint_count; i++) { + // Iterate through endpoints in the reverse order so IN endpoints + // get processed before OUT endpoints if they are both pending. + num = endpoint_count - i - 1; + + if (sts & (1UL << num)) { + /* Setup */ + if ((num == 0) && !ctrl_out_next && (LPC_USB->DEVCMDSTAT & (1UL << 8))) { +#ifdef __RTX + + if (USBD_RTX_EPTask[num / 2]) { + isr_evt_set(USBD_EVT_SETUP, USBD_RTX_EPTask[num / 2]); + } + +#else + + if (USBD_P_EP[num / 2]) { + USBD_P_EP[num / 2](USBD_EVT_SETUP); + } + +#endif + } + + /* OUT */ + else if ((num % 2) == 0) { +#ifdef __RTX + + if (USBD_RTX_EPTask[num / 2]) { + isr_evt_set(USBD_EVT_OUT, USBD_RTX_EPTask[num / 2]); + } + +#else + + if (USBD_P_EP[num / 2]) { + USBD_P_EP[num / 2](USBD_EVT_OUT); + } + +#endif + } + + /* IN */ + else { +#ifdef __RTX + + if (USBD_RTX_EPTask[num / 2]) { + isr_evt_set(USBD_EVT_IN, USBD_RTX_EPTask[num / 2]); + } + +#else + + if (USBD_P_EP[num / 2]) { + USBD_P_EP[num / 2](USBD_EVT_IN); + } + +#endif + } + } + } + } + + NVIC_EnableIRQ(USB_IRQn); +}