Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.
Upstream: https://github.com/ARMmbed/DAPLink
Diff: source/hic_hal/maxim/max32625/usbd_max32625.c
- Revision:
- 0:01f31e923fe2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/hic_hal/maxim/max32625/usbd_max32625.c Tue Apr 07 12:55:42 2020 +0200 @@ -0,0 +1,647 @@ +/* CMSIS-DAP Interface Firmware + * Copyright (c) 2009-2013 ARM Limited + * + * 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 <string.h> +#include "rl_usb.h" +#include "util.h" + +#include "max32625.h" +#include "usb_regs.h" +#include "clkman_regs.h" +#include "pwrman_regs.h" +#include "tmr_regs.h" + +#define __NO_USB_LIB_C +#include "usb_config.c" + +#define EPNUM_MASK (~USB_ENDPOINT_DIRECTION_MASK) + +#define INIT_INTS (MXC_F_USB_DEV_INTEN_BRST | MXC_F_USB_DEV_INTFL_BRST_DN | MXC_F_USB_DEV_INTEN_VBUS | MXC_F_USB_DEV_INTFL_NO_VBUS) +#define CONNECT_INTS (MXC_F_USB_DEV_INTEN_SETUP | MXC_F_USB_DEV_INTEN_EP_IN | MXC_F_USB_DEV_INTEN_EP_OUT | MXC_F_USB_DEV_INTEN_DMA_ERR) + +typedef struct { + volatile uint32_t buf0_desc; + volatile uint32_t buf0_address; + volatile uint32_t buf1_desc; + volatile uint32_t buf1_address; +} ep_buffer_t; + +typedef struct { + ep_buffer_t out_buffer; + ep_buffer_t in_buffer; +} ep0_buffer_t; + +typedef struct { + ep0_buffer_t ep0; + ep_buffer_t ep[MXC_USB_NUM_EP - 1]; +} ep_buffer_descriptor_t; + +typedef struct { + U8 type; + U16 len; +} ep_info_t; + +/* static storage for endpoint buffer descriptor table, must be 512 byte aligned for DMA */ +__attribute__ ((aligned (512))) +ep_buffer_descriptor_t ep_buffer_descriptor; + +static uint32_t ep_buffer[MXC_USB_NUM_EP][MXC_USB_MAX_PACKET / sizeof(uint32_t)]; +static ep_info_t ep_info[MXC_USB_NUM_EP]; +static volatile int suspended; +static volatile int setup_waiting; +static volatile int ep0_expect_zlp; + +#if CDC_ENDPOINT +/* CDC-ACM class processes FIFOs in the SOF interrupt. The USB Device interface + * of Maxim's microcontrollers does not provide and SOF interrupt. A periodic + * timer interrupt is used instead. + */ +/******************************************************************************/ +void TMR0_IRQHandler(void) +{ + MXC_TMR0->intfl = MXC_TMR0->intfl; + + if (usbd_configured()) { + USBD_CDC_ACM_SOF_Event(); + } +} +#endif + +/******************************************************************************/ +static ep_buffer_t *get_desc(U32 EPNum) +{ + ep_buffer_t *desc; + + if (EPNum == 0x80) { + desc = &ep_buffer_descriptor.ep0.in_buffer; + } else if (EPNum == 0x00) { + desc = &ep_buffer_descriptor.ep0.out_buffer; + } else { + desc = &ep_buffer_descriptor.ep[(EPNum & EPNUM_MASK) - 1]; + } + + return desc; +} + +/* + * USB Device Interrupt enable + * Called by USBD_Init to enable the USB Interrupt + * Return Value: None + */ + +void USBD_IntrEna(void) +{ + NVIC_EnableIRQ(USB_IRQn); /* Enable OTG interrupt */ +} + +/******************************************************************************/ +/* + * 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 + +/******************************************************************************/ +static void reset_state(void) +{ + unsigned int ep; + + suspended = 0; + setup_waiting = 0; + ep0_expect_zlp = 0; + memset(ep_info, 0, sizeof(ep_info)); + + MXC_USB->ep[0] |= (MXC_S_USB_EP_DIR_CONTROL | MXC_F_USB_EP_INT_EN | MXC_F_USB_EP_DT); + for (ep = 1; ep < MXC_USB_NUM_EP; ep++) { + MXC_USB->ep[ep] = MXC_F_USB_EP_DT; + } +} + +/* + * USB Device Initialize Function + * Called by the User to initialize USB Device + * Return Value: None + */ +void USBD_Init (void) +{ + uint32_t reg; + + /* Enable USB power domain */ + MXC_PWRMAN->pwr_rst_ctrl |= MXC_F_PWRMAN_PWR_RST_CTRL_USB_POWERED; + /* Setup the USB clocking, select */ + MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_USB_CLOCK_ENABLE; + /* Force USB clock gater */ + reg = MXC_CLKMAN->clk_gate_ctrl0; + reg &= ~MXC_F_CLKMAN_CLK_GATE_CTRL0_USB_CLK_GATER; + reg |= (0x2 << MXC_F_CLKMAN_CLK_GATE_CTRL0_USB_CLK_GATER_POS); + MXC_CLKMAN->clk_gate_ctrl0 = reg; + + MXC_USB->cn = 0; + MXC_USB->cn = MXC_F_USB_CN_USB_EN; + MXC_USB->dev_inten = 0; + MXC_USB->dev_intfl = 0xFFFF; // clear interrupts + MXC_USB->dev_cn = 0; + MXC_USB->dev_cn |= MXC_F_USB_DEV_CN_URST; + MXC_USB->dev_cn = 0; + + reset_state(); + + /* set the descriptor location */ + MXC_USB->ep_base = (uint32_t)&ep_buffer_descriptor; + + /* enable some interrupts */ + MXC_USB->dev_inten = INIT_INTS; + NVIC_EnableIRQ(USB_IRQn); +} + +/* + * 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) { + MXC_USB->dev_intfl = 0xFFFF; // clear interrupts + MXC_USB->dev_inten |= CONNECT_INTS; + MXC_USB->ep[0] |= MXC_F_USB_EP_INT_EN; + MXC_USB->dev_cn |= (MXC_F_USB_DEV_CN_CONNECT | MXC_F_USB_DEV_CN_FIFO_MODE); + } else { + MXC_USB->dev_inten &= ~CONNECT_INTS; + MXC_USB->ep[0] &= ~MXC_F_USB_EP_INT_EN; + MXC_USB->dev_cn &= ~MXC_F_USB_DEV_CN_CONNECT; + } +} + +/* + * USB Device Remote Wakeup Configuration Function + * Parameters: cfg: Device Enable/Disable + * Return Value: None + */ +void USBD_WakeUpCfg (BOOL cfg) +{ +} + +/* + * USB Device Set Address Function + * Parameters: adr: USB Device Address + * Return Value: None + */ +void USBD_SetAddress (U32 adr, U32 setup) +{ + /* Performed by Hardware */ +} + +/* + * USB Device Configure Function + * Parameters: cfg: Device Configure/Deconfigure + * Return Value: None + */ +void USBD_Configure (BOOL cfg) +{ +#if CDC_ENDPOINT + /* CDC-ACM class processes FIFOs in the SOF interrupt. The USB Device interface + * of Maxim's microcontrollers does not provide and SOF interrupt. A periodic + * timer interrupt is used instead. + */ + + #define SOF_INT_US 1000 + + if (cfg) { + // Setup timer interrupt for SOF + MXC_TMR0->ctrl = MXC_S_TMR_CTRL_MODE_CONTINUOUS; + MXC_TMR0->count32 = 0; + MXC_TMR0->term_cnt32 = (SystemCoreClock / 1000000) * SOF_INT_US; + + // Enable the interrupt + MXC_TMR0->intfl = MXC_TMR0->intfl; + NVIC_EnableIRQ(TMR0_0_IRQn); + MXC_TMR0->inten = MXC_F_TMR_INTEN_TIMER0; + + // Start the timer + MXC_TMR0->ctrl |= MXC_F_TMR_CTRL_ENABLE0; + + } else { + // Disable tmr + MXC_TMR0->ctrl &= ~(MXC_F_TMR_CTRL_ENABLE0); + } +#endif +} + +/* + * 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 EPNum; + + EPNum = pEPD->bEndpointAddress & EPNUM_MASK; + + if (EPNum < MXC_USB_NUM_EP) { + + // Clear existing configurations + MXC_USB->ep[EPNum] = MXC_F_USB_EP_DT; + + if (pEPD->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) { + ep_info[EPNum].type = MXC_S_USB_EP_DIR_IN; + } else { + ep_info[EPNum].type = MXC_S_USB_EP_DIR_OUT; + } + + ep_info[EPNum].len = pEPD->wMaxPacketSize; + } +} + +/* + * 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) +{ + ep_buffer_t *desc = get_desc(EPNum); + + EPNum &= EPNUM_MASK; + MXC_USB->ep[EPNum] |= (MXC_F_USB_EP_INT_EN | ep_info[EPNum].type | MXC_F_USB_EP_DT); + + if (ep_info[EPNum].type == MXC_S_USB_EP_DIR_OUT) { + // This is an OUT endpoint. Go ahead and register a request. + desc = get_desc(EPNum); + desc->buf0_address = (uint32_t)ep_buffer[EPNum]; + desc->buf0_desc = sizeof(ep_buffer[EPNum]); + MXC_USB->out_owner = (1 << 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) +{ + EPNum &= EPNUM_MASK; + MXC_USB->ep[EPNum] = 0; +} + +/* + * Reset USB Device Endpoint + * Parameters: EPNum: Device Endpoint Number + * EPNum.0..3: Address + * EPNum.7: Dir + * Return Value: None + */ +void USBD_ResetEP (U32 EPNum) +{ + ep_buffer_t *desc = get_desc(EPNum); + + EPNum &= EPNUM_MASK; + MXC_USB->ep[EPNum] |= MXC_F_USB_EP_DT; + + if (ep_info[EPNum].type == MXC_S_USB_EP_DIR_OUT) { + // This is an OUT endpoint. Go ahead and register a request. + desc = get_desc(EPNum); + desc->buf0_address = (uint32_t)ep_buffer[EPNum]; + desc->buf0_desc = sizeof(ep_buffer[EPNum]); + MXC_USB->out_owner = (1 << EPNum); + } +} + +/* + * 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) +{ + EPNum &= EPNUM_MASK; + + if (EPNum == 0) { + MXC_USB->ep[0] |= (MXC_F_USB_EP_ST_STALL | MXC_F_USB_EP_STALL); + } else { + MXC_USB->ep[EPNum] |= MXC_F_USB_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) +{ + USBD_ResetEP(EPNum); + MXC_USB->ep[EPNum & EPNUM_MASK] &= ~MXC_F_USB_EP_STALL; +} + +/* + * 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; + ep_buffer_t *desc = get_desc(EPNum); + USB_SETUP_PACKET *sup; + + EPNum &= EPNUM_MASK; + + if ((EPNum == 0) && setup_waiting) { + cnt = USBD_MAX_PACKET0; + + if (size < cnt) { + cnt = size; + } + setup_waiting = 0; + memcpy(pData, (void*)&MXC_USB->setup0, cnt); + sup = (USB_SETUP_PACKET*)pData; + + if ( (sup->bmRequestType.Dir == REQUEST_HOST_TO_DEVICE) && (sup->wLength > 0) ) { + // There is an OUT stage for this setup packet. Register a request. + if (!(MXC_USB->out_owner & 1)) { + desc = &ep_buffer_descriptor.ep0.out_buffer; + desc->buf0_address = (uint32_t)ep_buffer[0]; + desc->buf0_desc = sup->wLength; + MXC_USB->out_owner = 1; + } + } + } else { + cnt = desc->buf0_desc; + + if (size < cnt) { + cnt = size; + } + memcpy(pData, ep_buffer[EPNum], cnt); + + // Register the next request. + desc->buf0_address = (uint32_t)ep_buffer[EPNum]; + desc->buf0_desc = sizeof(ep_buffer[EPNum]); + MXC_USB->out_owner = (1 << EPNum); + } + + 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) +{ + ep_buffer_t *desc = get_desc(EPNum); + uint32_t mask; + + EPNum &= EPNUM_MASK; + mask = (1 << EPNum); + + if (MXC_USB->in_owner & mask) { + return 0; + } + + if (EPNum == 0) { + // Prepare to ACK the status stage. + MXC_USB->ep[0] |= MXC_F_USB_EP_ST_ACK; + + if ((cnt == 0) && !ep0_expect_zlp) { + // This is a status stage ACK. Handled in hardware. + return 0; + } else if (cnt == USBD_MAX_PACKET0) { + ep0_expect_zlp = 1; + } else { + ep0_expect_zlp = 0; + } + } + + if (cnt > MXC_USB_MAX_PACKET) { + cnt = MXC_USB_MAX_PACKET; + } + + /* prepare data to be sent */ + memcpy(ep_buffer[EPNum], pData, cnt); + desc->buf0_address = (uint32_t)ep_buffer[EPNum]; + desc->buf0_desc = cnt; + + /* start the transaction */ + MXC_USB->in_owner = mask; + + return cnt; +} + +/* + * USB Device Interrupt Service Routine + */ +void USB_IRQHandler (void) +{ + NVIC_DisableIRQ(USB_IRQn); + USBD_SignalHandler(); +} + +void USBD_Handler(void) +{ + uint32_t irq_flags; + unsigned int ep; + uint32_t ep_int, mask; + + // Read and clear interrupts + irq_flags = MXC_USB->dev_intfl; + MXC_USB->dev_intfl = irq_flags; + + /* reset interrupt */ + if (irq_flags & MXC_F_USB_DEV_INTFL_BRST) { + if (suspended) { + suspended = 0; +#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 + } + + reset_state(); + 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 + + } + + /* reset done interrupt */ + if (irq_flags & MXC_F_USB_DEV_INTFL_BRST_DN) { + reset_state(); + } + + /* suspend interrupt */ + if (irq_flags & MXC_F_USB_DEV_INTFL_SUSP) { + suspended = 1; +#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 + } + + if (irq_flags & MXC_F_USB_DEV_INTFL_VBUS) { +#ifdef __RTX + if (USBD_RTX_DevTask) { + isr_evt_set(USBD_EVT_POWER_ON, USBD_RTX_DevTask); + } +#else + if (USBD_P_Power_Event) { + USBD_P_Power_Event(1); + } +#endif + } + + if (irq_flags & MXC_F_USB_DEV_INTFL_NO_VBUS) { +#ifdef __RTX + if (USBD_RTX_DevTask) { + isr_evt_set(USBD_EVT_POWER_OFF, USBD_RTX_DevTask); + } +#else + if (USBD_P_Power_Event) { + USBD_P_Power_Event(0); + } +#endif + } + + if (irq_flags & MXC_F_USB_DEV_INTFL_SETUP) { + setup_waiting = 1; +#ifdef __RTX + if (USBD_RTX_EPTask[0]) { + isr_evt_set(USBD_EVT_SETUP, USBD_RTX_EPTask[0]); + } +#else + if (USBD_P_EP[0]) { + USBD_P_EP[0](USBD_EVT_SETUP); + } +#endif + } + + if (irq_flags & MXC_F_USB_DEV_INTFL_EP_IN) { + + // Read and clear endpoint interrupts + ep_int = MXC_USB->in_int; + MXC_USB->in_int = ep_int; + + mask = 1; + for (ep = 0; ep < MXC_USB_NUM_EP; ep++) { + if (ep_int & mask) { +#ifdef __RTX + if (USBD_RTX_EPTask[ep]) { + isr_evt_set(USBD_EVT_IN, USBD_RTX_EPTask[ep]); + } +#else + if (USBD_P_EP[ep]) { + USBD_P_EP[ep](USBD_EVT_IN); + } +#endif + } + + mask <<= 1; + } + } + + if (irq_flags & MXC_F_USB_DEV_INTFL_EP_OUT) { + + // Read and clear endpoint interrupts + ep_int = MXC_USB->out_int; + MXC_USB->out_int = ep_int; + + mask = 1; + for (ep = 0; ep < MXC_USB_NUM_EP; ep++) { + if (ep_int & mask) { +#ifdef __RTX + if (USBD_RTX_EPTask[ep]) { + isr_evt_set(USBD_EVT_OUT, USBD_RTX_EPTask[ep]); + } +#else + if (USBD_P_EP[ep]) { + USBD_P_EP[ep](USBD_EVT_OUT); + } +#endif + } + + mask <<= 1; + } + } + + if (irq_flags & MXC_F_USB_DEV_INTFL_DMA_ERR) { + // Read and clear endpoint interrupts + ep_int = MXC_USB->dma_err_int; + MXC_USB->dma_err_int = ep_int; + while(1); // not recoverable + } + + NVIC_EnableIRQ(USB_IRQn); + +}