Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.

Upstream: https://github.com/ARMmbed/DAPLink

Revision:
0:01f31e923fe2
diff -r 000000000000 -r 01f31e923fe2 source/hic_hal/maxim/max32625/usbd_max32625.c
--- /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);
+
+}