Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.
Upstream: https://github.com/ARMmbed/DAPLink
source/hic_hal/freescale/usbd_kinetis.c
- Committer:
- Pawel Zarembski
- Date:
- 2020-04-07
- Revision:
- 0:01f31e923fe2
File content as of revision 0:01f31e923fe2:
/** * @file usbd_kinetis.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 "fsl_device_registers.h" #include "cortex_m.h" #include "util.h" #include "string.h" #define __NO_USB_LIB_C #include "usb_config.c" typedef struct __BUF_DESC { uint8_t stat; uint8_t reserved; uint16_t bc; uint32_t buf_addr; } BUF_DESC; BUF_DESC __align(512) BD[(USBD_EP_NUM + 1) * 2 * 2]; uint8_t EPBuf[(USBD_EP_NUM + 1) * 2 * 2][64]; uint8_t OutEpSize[USBD_EP_NUM + 1]; uint8_t StatQueue[(USBD_EP_NUM + 1) * 2 * 2 + 1]; uint32_t StatQueueHead = 0; uint32_t StatQueueTail = 0; uint32_t LastIstat = 0; uint8_t UsbSuspended = 0; uint8_t Ep0ZlpOut = 0; uint32_t Data1 = 0x55555555; #define BD_OWN_MASK 0x80 #define BD_DATA01_MASK 0x40 #define BD_KEEP_MASK 0x20 #define BD_NINC_MASK 0x10 #define BD_DTS_MASK 0x08 #define BD_STALL_MASK 0x04 #define TX 1 #define RX 0 #define ODD 0 #define EVEN 1 #define IDX(Ep, dir, Ev_Odd) ((((Ep & 0x0F) * 4) + (2 * dir) + (1 * Ev_Odd))) #define SETUP_TOKEN 0x0D #define IN_TOKEN 0x09 #define OUT_TOKEN 0x01 #define TOK_PID(idx) ((BD[idx].stat >> 2) & 0x0F) inline static void protected_and(uint32_t *addr, uint32_t val) { cortex_int_state_t state; state = cortex_int_get_and_disable(); *addr = *addr & val; cortex_int_restore(state); } inline static void protected_or(uint32_t *addr, uint32_t val) { cortex_int_state_t state; state = cortex_int_get_and_disable(); *addr = *addr | val; cortex_int_restore(state); } inline static void protected_xor(uint32_t *addr, uint32_t val) { cortex_int_state_t state; state = cortex_int_get_and_disable(); *addr = *addr ^ val; cortex_int_restore(state); } inline static void stat_enque(uint32_t stat) { cortex_int_state_t state; state = cortex_int_get_and_disable(); StatQueue[StatQueueTail] = stat; StatQueueTail = (StatQueueTail + 1) % sizeof(StatQueue); cortex_int_restore(state); } inline static uint32_t stat_deque() { cortex_int_state_t state; uint32_t stat; state = cortex_int_get_and_disable(); stat = StatQueue[StatQueueHead]; StatQueueHead = (StatQueueHead + 1) % sizeof(StatQueue); cortex_int_restore(state); return stat; } inline static uint32_t stat_is_empty() { cortex_int_state_t state; uint32_t empty; state = cortex_int_get_and_disable(); empty = StatQueueHead == StatQueueTail; cortex_int_restore(state); return empty; } /* * USB Device Interrupt enable * Called by USBD_Init to enable the USB Interrupt * Return Value: None */ void USBD_IntrEna(void) { NVIC_EnableIRQ(USB0_IRQn); /* Enable OTG interrupt */ } /* * USB Device Initialize Function * Called by the User to initialize USB * Return Value: None */ void USBD_Init(void) { OutEpSize[0] = USBD_MAX_PACKET0; /* Enable all clocks needed for USB to function */ /* Set USB clock to 48 MHz */ SIM->SOPT2 |= SIM_SOPT2_USBSRC_MASK | /* MCGPLLCLK used as src */ SIM_SOPT2_PLLFLLSEL_MASK ; /* Select MCGPLLCLK as clock */ #if defined(TARGET_MK20D5) SIM->CLKDIV2 &= ~(SIM_CLKDIV2_USBFRAC_MASK | /* Clear CLKDIV2 FS values */ SIM_CLKDIV2_USBDIV_MASK); SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(0) ; /* USB clk = (PLL*1/2) */ /* = ( 48*1/1)=48 */ #endif // TARGET_MK20D5 SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK; /* Enable USBOTG clock */ USBD_IntrEna(); USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK; while (USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK); USB0->BDTPAGE1 = (uint8_t)((uint32_t) BD >> 8); USB0->BDTPAGE2 = (uint8_t)((uint32_t) BD >> 16); USB0->BDTPAGE3 = (uint8_t)((uint32_t) BD >> 24); USB0->ISTAT = 0xFF; /* clear interrupt flags */ /* enable interrupts */ USB0->INTEN = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK | USB_INTEN_SLEEPEN_MASK | #ifdef __RTX ((USBD_RTX_DevTask != 0) ? USB_INTEN_SOFTOKEN_MASK : 0) | ((USBD_RTX_DevTask != 0) ? USB_INTEN_ERROREN_MASK : 0) ; #else ((USBD_P_SOF_Event != 0) ? USB_INTEN_SOFTOKEN_MASK : 0) | ((USBD_P_Error_Event != 0) ? USB_INTEN_ERROREN_MASK : 0) ; #endif USB0->USBCTRL = USB_USBCTRL_PDE_MASK;/* pull dawn on D+ and D- */ USB0->USBTRC0 |= (1 << 6); /* bit 6 must be set to 1 */ } /* * USB Device Connect Function * Called by the User to Connect/Disconnect USB Device * Parameters: con: Connect/Disconnect * Return Value: None */ void USBD_Connect(uint32_t con) { if (con) { USB0->CTL |= USB_CTL_USBENSOFEN_MASK; /* enable USB */ USB0->CONTROL = USB_CONTROL_DPPULLUPNONOTG_MASK; /* pull up on D+ */ } else { USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK; /* disable USB */ USB0->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;/* pull down on D+ */ } } /* * USB Device Reset Function * Called automatically on USB Device Reset * Return Value: None */ void USBD_Reset(void) { uint32_t i; NVIC_DisableIRQ(USB0_IRQn); for (i = 1; i < 16; i++) { USB0->ENDPOINT[i].ENDPT = 0x00; } memset(StatQueue, 0, sizeof(StatQueue)); StatQueueHead = 0; StatQueueTail = 0; LastIstat = 0; UsbSuspended = 0; Ep0ZlpOut = 0; /* EP0 control endpoint */ BD[IDX(0, RX, ODD)].bc = USBD_MAX_PACKET0; BD[IDX(0, RX, ODD)].buf_addr = (uint32_t) & (EPBuf[IDX(0, RX, ODD)][0]); BD[IDX(0, RX, ODD)].stat = BD_OWN_MASK | BD_DTS_MASK | BD_DATA01_MASK; BD[IDX(0, RX, EVEN)].stat = 0; BD[IDX(0, TX, ODD)].buf_addr = (uint32_t) & (EPBuf[IDX(0, TX, ODD)][0]); BD[IDX(0, TX, EVEN)].buf_addr = 0; USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPHSHK_MASK | /* enable ep handshaking */ USB_ENDPT_EPTXEN_MASK | /* enable TX (IN) tran. */ USB_ENDPT_EPRXEN_MASK; /* enable RX (OUT) tran. */ Data1 = 0x55555555; USB0->CTL |= USB_CTL_ODDRST_MASK; USB0->ISTAT = 0xFF; /* clear all interrupt status flags */ USB0->ERRSTAT = 0xFF; /* clear all error flags */ USB0->ERREN = 0xFF; /* enable error interrupt sources */ USB0->ADDR = 0x00; /* set default address */ NVIC_EnableIRQ(USB0_IRQn); } /* * USB Device Suspend Function * Called automatically on USB Device Suspend * Return Value: None */ void USBD_Suspend(void) { USB0->INTEN |= USB_INTEN_RESUMEEN_MASK; } /* * USB Device Resume Function * Called automatically on USB Device Resume * Return Value: None */ void USBD_Resume(void) { USB0->INTEN &= ~USB_INTEN_RESUMEEN_MASK; } /* * USB Device Remote Wakeup Function * Called automatically on USB Device Remote Wakeup * Return Value: None */ void USBD_WakeUp(void) { uint32_t i = 50000; if (USBD_DeviceStatus & USB_GETSTATUS_REMOTE_WAKEUP) { USB0->CTL |= USB_CTL_RESUME_MASK; while (i--) { __nop(); } USB0->CTL &= ~USB_CTL_RESUME_MASK; } } /* * USB Device Remote Wakeup Configuration Function * Parameters: cfg: Device Enable/Disable * Return Value: None */ void USBD_WakeUpCfg(uint32_t cfg) { /* Not needed */ } /* * USB Device Set Address Function * Parameters: adr: USB Device Address * Return Value: None */ void USBD_SetAddress(uint32_t adr, uint32_t setup) { if (!setup) { USB0->ADDR = adr & 0x7F; } } /* * USB Device Configure Function * Parameters: cfg: Device Configure/Deconfigure * Return Value: None */ void USBD_Configure(uint32_t cfg) { } /* * Configure USB Device Endpoint according to Descriptor * Parameters: pEPD: Pointer to Device Endpoint Descriptor * Return Value: None */ void USBD_ConfigEP(USB_ENDPOINT_DESCRIPTOR *pEPD) { uint32_t num, val; num = pEPD->bEndpointAddress; val = pEPD->wMaxPacketSize; if (!(pEPD->bEndpointAddress & 0x80)) { OutEpSize[num] = val; } USBD_ResetEP(num); } /* * Set Direction for USB Device Control Endpoint * Parameters: dir: Out (dir == 0), In (dir <> 0) * Return Value: None */ void USBD_DirCtrlEP(uint32_t 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(uint32_t EPNum) { if (EPNum & 0x80) { EPNum &= 0x0F; USB0->ENDPOINT[EPNum].ENDPT |= USB_ENDPT_EPHSHK_MASK | /*en ep handshaking*/ USB_ENDPT_EPTXEN_MASK; /*en TX (IN) tran */ } else { USB0->ENDPOINT[EPNum].ENDPT |= USB_ENDPT_EPHSHK_MASK | /*en ep handshaking*/ USB_ENDPT_EPRXEN_MASK; /*en RX (OUT) tran.*/ } } /* * Disable USB Endpoint * Parameters: EPNum: Endpoint Number * EPNum.0..3: Address * EPNum.7: Dir * Return Value: None */ void USBD_DisableEP(uint32_t EPNum) { if (EPNum & 0x80) { EPNum &= 0x0F; USB0->ENDPOINT[EPNum].ENDPT &= ~(USB_ENDPT_EPHSHK_MASK |/*dis handshaking */ USB_ENDPT_EPTXEN_MASK);/*dis TX(IN) tran */ } else { USB0->ENDPOINT[EPNum].ENDPT &= ~(USB_ENDPT_EPHSHK_MASK |/*dis handshaking */ USB_ENDPT_EPRXEN_MASK);/*dis RX(OUT) tran*/ } } /* * Reset USB Device Endpoint * Parameters: EPNum: Device Endpoint Number * EPNum.0..3: Address * EPNum.7: Dir * Return Value: None */ void USBD_ResetEP(uint32_t EPNum) { if (EPNum & 0x80) { EPNum &= 0x0F; protected_or(&Data1, (1 << ((EPNum * 2) + 1))); BD[IDX(EPNum, TX, ODD)].buf_addr = (uint32_t) & (EPBuf[IDX(EPNum, TX, ODD)][0]); BD[IDX(EPNum, TX, EVEN)].buf_addr = 0; } else { protected_and(&Data1, ~(1 << (EPNum * 2))); BD[IDX(EPNum, RX, ODD)].bc = OutEpSize[EPNum]; BD[IDX(EPNum, RX, ODD)].buf_addr = (uint32_t) & (EPBuf[IDX(EPNum, RX, ODD)][0]); BD[IDX(EPNum, RX, ODD)].stat = BD_OWN_MASK | BD_DTS_MASK; BD[IDX(EPNum, RX, EVEN)].stat = 0; } } /* * Set Stall for USB Device Endpoint * Parameters: EPNum: Device Endpoint Number * EPNum.0..3: Address * EPNum.7: Dir * Return Value: None */ void USBD_SetStallEP(uint32_t EPNum) { EPNum &= 0x0F; USB0->ENDPOINT[EPNum].ENDPT |= USB_ENDPT_EPSTALL_MASK; } /* * Clear Stall for USB Device Endpoint * Parameters: EPNum: Device Endpoint Number * EPNum.0..3: Address * EPNum.7: Dir * Return Value: None */ void USBD_ClrStallEP(uint32_t EPNum) { USB0->ENDPOINT[EPNum & 0x0F].ENDPT &= ~USB_ENDPT_EPSTALL_MASK; 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(uint32_t EPNum) { } /* * 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 */ uint32_t USBD_ReadEP(uint32_t EPNum, uint8_t *pData, uint32_t size) { uint32_t n, sz, idx, setup = 0; idx = IDX(EPNum, RX, 0); sz = BD[idx].bc; if ((EPNum == 0) && Ep0ZlpOut) { // This packet was a zero length data out packet. It has already // been processed by USB0_IRQHandler. Only toggle the DATAx bit // and return a size of 0. protected_xor(&Data1, (1 << (idx / 2))); return 0; } if ((EPNum == 0) && (TOK_PID(idx) == SETUP_TOKEN)) { setup = 1; } if (size < sz) { util_assert(0); sz = size; } for (n = 0; n < sz; n++) { pData[n] = EPBuf[idx][n]; } BD[idx].bc = OutEpSize[EPNum]; if ((Data1 >> (idx / 2) & 1) == ((BD[idx].stat >> 6) & 1)) { uint32_t xfer_size = (pData[7] << 8) | (pData[6] << 0); if (setup && (0 == xfer_size)) { /* if no setup data stage, */ protected_and(&Data1, ~1); /* set DATA0 */ } else { protected_xor(&Data1, (1 << (idx / 2))); } } if ((Data1 >> (idx / 2)) & 1) { BD[idx].stat = BD_DTS_MASK | BD_DATA01_MASK; BD[idx].stat |= BD_OWN_MASK; } else { BD[idx].stat = BD_DTS_MASK; BD[idx].stat |= BD_OWN_MASK; } return (sz); } /* * Write USB Device Endpoint Data * Parameters: EPNum: Device 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 */ uint32_t USBD_WriteEP(uint32_t EPNum, uint8_t *pData, uint32_t cnt) { uint32_t idx, n; EPNum &= 0x0F; idx = IDX(EPNum, TX, 0); BD[idx].bc = cnt; for (n = 0; n < cnt; n++) { EPBuf[idx][n] = pData[n]; } if ((Data1 >> (idx / 2)) & 1) { BD[idx].stat = BD_OWN_MASK | BD_DTS_MASK; } else { BD[idx].stat = BD_OWN_MASK | BD_DTS_MASK | BD_DATA01_MASK; } protected_xor(&Data1, (1 << (idx / 2))); return (cnt); } /* * Get USB Device Last Frame Number * Parameters: None * Return Value: Frame Number */ uint32_t USBD_GetFrame(void) { return ((USB0->FRMNUML | (USB0->FRMNUMH << 8) & 0x07FF)); } #ifdef __RTX U32 LastError; /* Last Error */ /* * Get USB Device Last Error Code * Parameters: None * Return Value: Error Code */ U32 USBD_GetError(void) { return (LastError); } #endif /* * USB Device Interrupt Service Routine */ void USB0_IRQHandler(void) { uint32_t istat, num, dir, ev_odd; uint32_t new_istat; uint8_t suspended = 0; new_istat = istat = USB0->ISTAT; // Read all tokens if (istat & USB_ISTAT_TOKDNE_MASK) { while (istat & USB_ISTAT_TOKDNE_MASK) { uint8_t stat = USB0->STAT; num = (stat >> 4) & 0x0F; dir = (stat >> 3) & 0x01; ev_odd = (stat >> 2) & 0x01; // Consume all zero length OUT packets on endpoint 0 to prevent // a subsequent SETUP packet from being dropped if ((0 == num) && (RX == dir)) { uint32_t idx; idx = IDX(num, dir, ev_odd); if ((TOK_PID(idx) == OUT_TOKEN) && (BD[idx].bc == 0)) { BD[idx].bc = OutEpSize[num]; if (BD[idx].stat & BD_DATA01_MASK) { BD[idx].stat = BD_OWN_MASK | BD_DTS_MASK; } else { BD[idx].stat = BD_OWN_MASK | BD_DTS_MASK | BD_DATA01_MASK; } stat |= 1 << 0; } } stat_enque(stat); USB0->ISTAT = USB_ISTAT_TOKDNE_MASK; // Check if USB is suspending before checking istat suspended = suspended || USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK; istat = USB0->ISTAT; } } // Set global istat and suspended flags new_istat |= istat; protected_or(&LastIstat, new_istat); UsbSuspended |= suspended ? 1 : 0; USB0->ISTAT = istat; USBD_SignalHandler(); } /* * USB Device Service Routine */ void USBD_Handler(void) { uint32_t istr, num, dir, ev_odd; cortex_int_state_t state; uint8_t suspended = 0; // Get ISTAT state = cortex_int_get_and_disable(); istr = LastIstat; LastIstat = 0; suspended = UsbSuspended; UsbSuspended = 0; cortex_int_restore(state); /* reset interrupt */ if (istr & USB_ISTAT_USBRST_MASK) { 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 } /* suspend interrupt */ if (istr & USB_ISTAT_SLEEP_MASK) { 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 */ if (istr & USB_ISTAT_RESUME_MASK) { USBD_Resume(); #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 (istr & USB_ISTAT_SOFTOK_MASK) { #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 } /* Error interrupt */ if (istr == USB_ISTAT_ERROR_MASK) { #ifdef __RTX LastError = USB0->ERRSTAT; if (USBD_RTX_DevTask) { isr_evt_set(USBD_EVT_ERROR, USBD_RTX_DevTask); } #else if (USBD_P_Error_Event) { USBD_P_Error_Event(USB0->ERRSTAT); } #endif USB0->ERRSTAT = 0xFF; } /* token interrupt */ if (istr & USB_ISTAT_TOKDNE_MASK) { while (!stat_is_empty()) { uint32_t stat; stat = stat_deque(); num = (stat >> 4) & 0x0F; dir = (stat >> 3) & 0x01; ev_odd = (stat >> 2) & 0x01; /* setup packet */ if ((num == 0) && (TOK_PID((IDX(num, dir, ev_odd))) == SETUP_TOKEN)) { Data1 &= ~0x02; BD[IDX(0, TX, EVEN)].stat &= ~BD_OWN_MASK; BD[IDX(0, TX, ODD)].stat &= ~BD_OWN_MASK; Ep0ZlpOut = 0; #ifdef __RTX if (USBD_RTX_EPTask[num]) { isr_evt_set(USBD_EVT_SETUP, USBD_RTX_EPTask[num]); } #else if (USBD_P_EP[num]) { USBD_P_EP[num](USBD_EVT_SETUP); } #endif } else { /* OUT packet */ if (TOK_PID((IDX(num, dir, ev_odd))) == OUT_TOKEN) { if (0 == num) { Ep0ZlpOut = stat & (1 << 0); } #ifdef __RTX if (USBD_RTX_EPTask[num]) { isr_evt_set(USBD_EVT_OUT, USBD_RTX_EPTask[num]); } #else if (USBD_P_EP[num]) { USBD_P_EP[num](USBD_EVT_OUT); } #endif } /* IN packet */ if (TOK_PID((IDX(num, dir, ev_odd))) == IN_TOKEN) { #ifdef __RTX if (USBD_RTX_EPTask[num]) { isr_evt_set(USBD_EVT_IN, USBD_RTX_EPTask[num]); } #else if (USBD_P_EP[num]) { USBD_P_EP[num](USBD_EVT_IN); } #endif } } } } if (suspended) { USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; } }