添加GD32H7的CMake工程
This commit is contained in:
@@ -0,0 +1,368 @@
|
||||
/*!
|
||||
\file drv_usb_core.h
|
||||
\brief USB core low level driver header file
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef DRV_USB_CORE_H
|
||||
#define DRV_USB_CORE_H
|
||||
|
||||
#include "drv_usb_regs.h"
|
||||
#include "usb_ch9_std.h"
|
||||
|
||||
#define USB_FS_EP0_MAX_LEN 64U /*!< maximum packet size of endpoint 0 */
|
||||
#define HC_MAX_PACKET_COUNT 140U /*!< maximum packet count */
|
||||
|
||||
#define EP_ID(x) ((uint8_t)((x) & 0x7FU)) /*!< endpoint number */
|
||||
#define EP_DIR(x) ((uint8_t)((x) >> 7)) /*!< endpoint direction */
|
||||
|
||||
enum _usb_eptype {
|
||||
USB_EPTYPE_CTRL = 0U, /*!< control endpoint type */
|
||||
USB_EPTYPE_ISOC = 1U, /*!< isochronous endpoint type */
|
||||
USB_EPTYPE_BULK = 2U, /*!< bulk endpoint type */
|
||||
USB_EPTYPE_INTR = 3U, /*!< interrupt endpoint type */
|
||||
USB_EPTYPE_MASK = 3U /*!< endpoint type mask */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
USB_OTG_OK = 0U, /*!< USB OTG status OK */
|
||||
USB_OTG_FAIL /*!< USB OTG status fail */
|
||||
} usb_otg_status;
|
||||
|
||||
typedef enum {
|
||||
USB_OK = 0U, /*!< USB status OK */
|
||||
USB_FAIL /*!< USB status fail */
|
||||
} usb_status;
|
||||
|
||||
typedef enum {
|
||||
USB_USE_FIFO, /*!< USB use FIFO transfer mode */
|
||||
USB_USE_DMA /*!< USB use DMA transfer mode */
|
||||
} usb_transfer_mode;
|
||||
|
||||
typedef enum {
|
||||
LPM_L0 = 0U, /*!< on */
|
||||
LPM_L1, /*!< LPM L1 sleep */
|
||||
LPM_L2, /*!< suspend */
|
||||
LPM_L3, /*!< off */
|
||||
}usb_lpm_state;
|
||||
|
||||
enum usb_ctl_status {
|
||||
USB_CTL_IDLE = 0U, /*!< USB control transfer idle state */
|
||||
USB_CTL_DATA_IN, /*!< USB control transfer data IN state */
|
||||
USB_CTL_LAST_DATA_IN, /*!< USB control transfer last data IN state */
|
||||
USB_CTL_DATA_OUT, /*!< USB control transfer data OUT state */
|
||||
USB_CTL_LAST_DATA_OUT, /*!< USB control transfer last data OUT state */
|
||||
USB_CTL_STATUS_IN, /*!< USB control transfer status IN state*/
|
||||
USB_CTL_STATUS_OUT /*!< USB control transfer status OUT state */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
LPM_L0_ACTIVE = 0U, /*!< on */
|
||||
LPM_L1_ACTIVE, /*!< LPM L1 sleep */
|
||||
}usb_lpm_type;
|
||||
|
||||
typedef struct {
|
||||
uint8_t core_enum; /*!< USB core type */
|
||||
uint8_t core_speed; /*!< USB core speed */
|
||||
uint8_t num_pipe; /*!< USB host channel numbers */
|
||||
uint8_t num_ep; /*!< USB device endpoint numbers */
|
||||
uint8_t transfer_mode; /*!< USB transfer mode */
|
||||
uint8_t phy_itf; /*!< USB core PHY interface */
|
||||
uint8_t sof_enable; /*!< USB SOF output */
|
||||
uint8_t low_power; /*!< USB low power */
|
||||
uint8_t lpm_enable; /*!< USB link power mode(LPM) */
|
||||
uint8_t vbus_sensing_enable; /*!< USB VBUS sensing feature */
|
||||
uint8_t use_dedicated_ep1; /*!< USB dedicated endpoint1 interrupt */
|
||||
uint8_t use_external_vbus; /*!< enable or disable the use of the external VBUS */
|
||||
uint32_t base_reg; /*!< base register address */
|
||||
} usb_core_basic;
|
||||
|
||||
#ifdef USE_DEVICE_MODE
|
||||
|
||||
/* USB descriptor */
|
||||
typedef struct _usb_desc {
|
||||
uint8_t *dev_desc; /*!< device descriptor */
|
||||
uint8_t *config_desc; /*!< configuration descriptor */
|
||||
uint8_t *bos_desc; /*!< BOS descriptor */
|
||||
|
||||
#ifdef USE_USB_HS
|
||||
uint8_t *other_speed_config_desc; /*!< other speed configuration descriptor */
|
||||
uint8_t *qualifier_desc; /*!< qualifier descriptor */
|
||||
#endif
|
||||
|
||||
void* const *strings; /*!< string descriptor */
|
||||
} usb_desc;
|
||||
|
||||
/* USB power management */
|
||||
typedef struct _usb_pm {
|
||||
uint8_t power_mode; /*!< power mode */
|
||||
uint8_t power_low; /*!< power low */
|
||||
uint8_t dev_remote_wakeup; /*!< remote wakeup */
|
||||
uint8_t remote_wakeup_on; /*!< remote wakeup on */
|
||||
usb_lpm_state lpm_state; /*!< LPM state */
|
||||
uint32_t BESL; /*!< BESL value */
|
||||
} usb_pm;
|
||||
|
||||
/* USB control information */
|
||||
typedef struct _usb_control {
|
||||
usb_req req; /*!< USB standard device request */
|
||||
|
||||
uint8_t ctl_state; /*!< USB control transfer state */
|
||||
uint8_t ctl_zlp; /*!< zero length package */
|
||||
} usb_control;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
uint8_t num: 4U; /*!< the endpoint number.it can be from 0 to 6 */
|
||||
uint8_t pad: 3U; /*!< padding between number and direction */
|
||||
uint8_t dir: 1U; /*!< the endpoint direction */
|
||||
} ep_addr;
|
||||
|
||||
uint8_t ep_type; /*!< USB endpoint type */
|
||||
uint8_t ep_stall; /*!< USB endpoint STALL status */
|
||||
|
||||
uint8_t frame_num; /*!< number of frame */
|
||||
uint16_t max_len; /*!< maximum packet length */
|
||||
|
||||
/* transaction level variables */
|
||||
uint8_t *xfer_buf; /*!< transmit buffer */
|
||||
uint32_t xfer_len; /*!< transmit buffer length */
|
||||
uint32_t xfer_count; /*!< transmit buffer count */
|
||||
|
||||
uint32_t remain_len; /*!< remain packet length */
|
||||
|
||||
uint32_t dma_addr; /*!< DMA address */
|
||||
} usb_transc;
|
||||
|
||||
typedef struct _usb_core_driver usb_dev;
|
||||
|
||||
typedef struct _usb_class_core {
|
||||
uint8_t alter_set; /*!< alternative set */
|
||||
uint8_t command; /*!< device class request command */
|
||||
|
||||
uint8_t (*init)(usb_dev *udev, uint8_t config_index); /*!< initialize handler */
|
||||
uint8_t (*deinit)(usb_dev *udev, uint8_t config_index); /*!< de-initialize handler */
|
||||
uint8_t (*req_proc)(usb_dev *udev, usb_req *req); /*!< device request handler */
|
||||
uint8_t (*set_intf)(usb_dev *udev, usb_req *req); /*!< device set interface callback */
|
||||
uint8_t (*ctlx_in)(usb_dev *udev); /*!< device control IN callback */
|
||||
uint8_t (*ctlx_out)(usb_dev *udev); /*!< device control OUT callback */
|
||||
uint8_t (*data_in)(usb_dev *udev, uint8_t ep_num); /*!< device data IN handler */
|
||||
uint8_t (*data_out)(usb_dev *udev, uint8_t ep_num); /*!< device data OUT handler */
|
||||
uint8_t (*SOF)(usb_dev *udev); /*!< start of frame handler */
|
||||
uint8_t (*incomplete_isoc_in)(usb_dev *udev); /*!< incomplete synchronization IN transfer handler */
|
||||
uint8_t (*incomplete_isoc_out)(usb_dev *udev); /*!< incomplete synchronization OUT transfer handler */
|
||||
} usb_class_core;
|
||||
|
||||
typedef struct _usb_perp_dev {
|
||||
uint8_t config; /*!< configuration */
|
||||
uint8_t dev_addr; /*!< device address */
|
||||
|
||||
__IO uint8_t cur_status; /*!< current status */
|
||||
__IO uint8_t backup_status; /*!< backup status */
|
||||
|
||||
usb_transc transc_in[USBHS_MAX_TX_FIFOS]; /*!< endpoint IN transaction */
|
||||
usb_transc transc_out[USBHS_MAX_TX_FIFOS]; /*!< endpoint OUT transaction */
|
||||
|
||||
usb_pm pm; /*!< power management */
|
||||
usb_control control; /*!< USB control information */
|
||||
usb_desc *desc; /*!< USB descriptors pointer */
|
||||
usb_class_core *class_core; /*!< class driver */
|
||||
void *class_data[4]; /*!< class data pointer */
|
||||
void *user_data; /*!< user data pointer */
|
||||
void *pdata; /*!< reserved data pointer */
|
||||
} usb_perp_dev;
|
||||
|
||||
#endif /* USE_DEVICE_MODE */
|
||||
|
||||
#ifdef USE_HOST_MODE
|
||||
|
||||
typedef enum _usb_pipe_status {
|
||||
PIPE_IDLE = 0U, /*!< host pipe IDLE status */
|
||||
PIPE_XF, /*!< host pipe transfer completed status */
|
||||
PIPE_HALTED, /*!< host pipe halted status */
|
||||
PIPE_NAK, /*!< host pipe NAK status */
|
||||
PIPE_NYET, /*!< host pipe NYET status */
|
||||
PIPE_STALL, /*!< host pipe STALL status */
|
||||
PIPE_TRACERR, /*!< host pipe transaction error status */
|
||||
PIPE_BBERR, /*!< host pipe babble error status */
|
||||
PIPE_REQOVR, /*!< host pipe frame overrun status */
|
||||
PIPE_DTGERR, /*!< host pipe data toggle error status */
|
||||
} usb_pipe_status;
|
||||
|
||||
typedef enum _usb_pipe_mode {
|
||||
PIPE_PERIOD = 0U, /*!< USB host pipe PERIOD mode */
|
||||
PIPE_NON_PERIOD = 1U /*!< USB host pipe NOT PERIOD mode */
|
||||
} usb_pipe_mode;
|
||||
|
||||
typedef enum _usb_urb_state {
|
||||
URB_IDLE = 0U, /*!< USB URB IDLE state */
|
||||
URB_DONE, /*!< USB URB DONE state */
|
||||
URB_NOTREADY, /*!< USB URB NOT READY state */
|
||||
URB_ERROR, /*!< USB URB ERROR state */
|
||||
URB_STALL, /*!< USB URB STALL state */
|
||||
URB_PING /*!< USB URB PING state */
|
||||
} usb_urb_state;
|
||||
|
||||
typedef struct _usb_pipe {
|
||||
uint8_t in_used; /*!< pipe used */
|
||||
uint8_t dev_addr; /*!< USB device address */
|
||||
uint32_t dev_speed; /*!< USB device speed */
|
||||
|
||||
struct {
|
||||
uint8_t num; /*!< endpoint numbers */
|
||||
uint8_t dir; /*!< endpoint direction */
|
||||
uint8_t type; /*!< endpoint transfer type */
|
||||
uint16_t mps; /*!< endpoint max packet size */
|
||||
} ep;
|
||||
|
||||
__IO uint8_t supp_ping; /*!< host pipe support PING */
|
||||
__IO uint8_t do_ping; /*!< host pipe do PING */
|
||||
__IO uint32_t DPID; /*!< data PID */
|
||||
|
||||
uint8_t *xfer_buf; /*!< USB transfer buffer */
|
||||
uint32_t xfer_len; /*!< USB transfer length */
|
||||
uint32_t xfer_count; /*!< USB transfer count */
|
||||
|
||||
uint8_t data_toggle_in; /*!< toggle DATA IN */
|
||||
uint8_t data_toggle_out; /*!< toggle DATA OUT */
|
||||
|
||||
__IO uint32_t err_count; /*!< error count */
|
||||
__IO usb_pipe_status pp_status; /*!< USB pipe status */
|
||||
__IO usb_urb_state urb_state; /*!< USB URB state */
|
||||
} usb_pipe;
|
||||
|
||||
typedef struct _usb_host_drv {
|
||||
__IO uint32_t connect_status; /*!< connect status */
|
||||
__IO uint32_t port_enabled; /*!< USB port enable */
|
||||
__IO uint32_t backup_xfercount[USBHS_MAX_TX_FIFOS]; /*!< USB backup transfer data count */
|
||||
|
||||
usb_pipe pipe[USBHS_MAX_TX_FIFOS]; /*!< USB host pipe handles */
|
||||
void *data; /*!< user data pointer */
|
||||
} usb_host_drv;
|
||||
|
||||
#endif /* USE_HOST_MODE */
|
||||
|
||||
typedef struct _usb_core_driver {
|
||||
usb_core_basic bp; /*!< USB basic parameters */
|
||||
usb_core_regs regs; /*!< USB registers */
|
||||
|
||||
#ifdef USE_DEVICE_MODE
|
||||
usb_perp_dev dev; /*!< USB peripheral device */
|
||||
#endif /* USE_DEVICE_MODE */
|
||||
|
||||
#ifdef USE_HOST_MODE
|
||||
usb_host_drv host; /*!< USB peripheral host */
|
||||
#endif /* USE_HOST_MODE */
|
||||
} usb_core_driver;
|
||||
|
||||
typedef enum {
|
||||
BCD_NONE = 0,
|
||||
BCD_SDP,
|
||||
BCD_DCP,
|
||||
BCD_CDP,
|
||||
BCD_PS2,
|
||||
BCD_ERROR
|
||||
} bcd_type;
|
||||
|
||||
/* static inline function definitions */
|
||||
|
||||
/*!
|
||||
\brief get the global interrupts
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval interrupt status
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_coreintr_get(usb_core_regs *usb_regs)
|
||||
{
|
||||
uint32_t reg_data = usb_regs->gr->GINTEN;
|
||||
|
||||
reg_data &= usb_regs->gr->GINTF;
|
||||
|
||||
return reg_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set USB RX FIFO size
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[in] size: assigned FIFO size
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_set_rxfifo(usb_core_regs *usb_regs, uint16_t size)
|
||||
{
|
||||
usb_regs->gr->GRFLEN = size;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable the global interrupts
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_globalint_enable(usb_core_regs *usb_regs)
|
||||
{
|
||||
/* enable USB global interrupt */
|
||||
usb_regs->gr->GAHBCS |= GAHBCS_GINTEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable the global interrupts
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_globalint_disable(usb_core_regs *usb_regs)
|
||||
{
|
||||
/* disable USB global interrupt */
|
||||
usb_regs->gr->GAHBCS &= ~GAHBCS_GINTEN;
|
||||
}
|
||||
|
||||
/* function declarations */
|
||||
/* configures USB parameters */
|
||||
void usb_para_init(usb_core_driver *core, uint32_t usb_periph, uint32_t usb_speed);
|
||||
/* configure core capabilities */
|
||||
usb_status usb_basic_init(usb_core_basic *usb_basic, usb_core_regs *usb_regs);
|
||||
/*initializes the USB controller registers and prepares the core device mode or host mode operation*/
|
||||
usb_status usb_core_init(usb_core_basic usb_basic, usb_core_regs *usb_regs);
|
||||
/* write a packet into the TX FIFO associated with the endpoint */
|
||||
usb_status usb_txfifo_write(usb_core_regs *usb_regs, uint8_t *src_buf, uint8_t fifo_num, uint16_t byte_count);
|
||||
/* read a packet from the RX FIFO associated with the endpoint */
|
||||
void *usb_rxfifo_read(usb_core_regs *usb_regs, uint8_t *dest_buf, uint16_t byte_count);
|
||||
/* flush a TX FIFO or all TX FIFOs */
|
||||
usb_status usb_txfifo_flush(usb_core_regs *usb_regs, uint8_t fifo_num);
|
||||
/* flush the entire RX FIFO */
|
||||
usb_status usb_rxfifo_flush(usb_core_regs *usb_regs);
|
||||
/* set endpoint or channel TX FIFO size */
|
||||
void usb_set_txfifo(usb_core_regs *usb_regs, uint8_t fifo, uint16_t size);
|
||||
/* set USB current mode */
|
||||
void usb_curmode_set(usb_core_regs *usb_regs, uint8_t mode);
|
||||
|
||||
#endif /* DRV_USB_CORE_H */
|
||||
@@ -0,0 +1,212 @@
|
||||
/*!
|
||||
\file drv_usb_dev.h
|
||||
\brief USB device low level driver header file
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef DRV_USB_DEV_H
|
||||
#define DRV_USB_DEV_H
|
||||
|
||||
#include "usbd_conf.h"
|
||||
#include "drv_usb_core.h"
|
||||
|
||||
#define EP_IN(x) ((uint8_t)(0x80U | (x))) /*!< device IN endpoint */
|
||||
#define EP_OUT(x) ((uint8_t)(x)) /*!< device OUT endpoint */
|
||||
#define EP_MAX_PACKET_SIZE_MASK 0x07FFU /*!< endpoint maximum packet size mask */
|
||||
|
||||
/* static inline function definitions */
|
||||
|
||||
/*!
|
||||
\brief configure the USB device to be disconnected
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_dev_disconnect(usb_core_driver *udev)
|
||||
{
|
||||
udev->regs.dr->DCTL |= DCTL_SD;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the USB device to be connected
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_dev_connect(usb_core_driver *udev)
|
||||
{
|
||||
udev->regs.dr->DCTL &= ~DCTL_SD;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set the USB device address
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] dev_addr: device address for setting
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_devaddr_set(usb_core_driver *udev, uint8_t dev_addr)
|
||||
{
|
||||
udev->regs.dr->DCFG &= ~DCFG_DAR;
|
||||
udev->regs.dr->DCFG |= (uint32_t)dev_addr << 4;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read device all OUT endpoint interrupt register
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval interrupt status
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_oepintnum_read(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t value = udev->regs.dr->DAEPINT;
|
||||
|
||||
value &= udev->regs.dr->DAEPINTEN;
|
||||
|
||||
return (value & DAEPINT_OEPITB) >> 16;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read device OUT endpoint interrupt flag register
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval interrupt status
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_oepintr_read(usb_core_driver *udev, uint8_t ep_num)
|
||||
{
|
||||
uint32_t value = udev->regs.er_out[ep_num]->DOEPINTF;
|
||||
|
||||
value &= udev->regs.dr->DOEPINTEN;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read device all IN endpoint interrupt register
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval interrupt status
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_iepintnum_read(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t value = udev->regs.dr->DAEPINT;
|
||||
|
||||
value &= udev->regs.dr->DAEPINTEN;
|
||||
|
||||
return value & DAEPINT_IEPITB;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set remote wakeup signaling
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_rwkup_set(usb_core_driver *udev)
|
||||
{
|
||||
if(udev->dev.pm.dev_remote_wakeup) {
|
||||
/* enable remote wakeup signaling */
|
||||
udev->regs.dr->DCTL |= DCTL_RWKUP;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reset remote wakeup signaling
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_rwkup_reset(usb_core_driver *udev)
|
||||
{
|
||||
if(udev->dev.pm.dev_remote_wakeup) {
|
||||
/* disable remote wakeup signaling */
|
||||
udev->regs.dr->DCTL &= ~DCTL_RWKUP;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable USB BCD function
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_bcd_enable(usb_core_driver *udev)
|
||||
{
|
||||
udev->regs.gr->GCCFG |= GCCFG_BCDEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable USB BCD function
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
__STATIC_INLINE void usb_bcd_disable(usb_core_driver *udev)
|
||||
{
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_BCDEN;
|
||||
}
|
||||
|
||||
/* function declarations */
|
||||
/* initialize USB core registers for device mode */
|
||||
usb_status usb_devcore_init(usb_core_driver *udev);
|
||||
/* enable the USB device mode interrupts */
|
||||
usb_status usb_devint_enable(usb_core_driver *udev);
|
||||
/* active the USB endpoint 0 transaction */
|
||||
usb_status usb_transc0_active(usb_core_driver *udev, usb_transc *transc);
|
||||
/* active the USB transaction */
|
||||
usb_status usb_transc_active(usb_core_driver *udev, usb_transc *transc);
|
||||
/* deactivate the USB transaction */
|
||||
usb_status usb_transc_deactivate(usb_core_driver *udev, usb_transc *transc);
|
||||
/* configure USB transaction to start IN transfer */
|
||||
usb_status usb_transc_inxfer(usb_core_driver *udev, usb_transc *transc);
|
||||
/* configure USB transaction to start OUT transfer */
|
||||
usb_status usb_transc_outxfer(usb_core_driver *udev, usb_transc *transc);
|
||||
/* set the USB transaction STALL status */
|
||||
usb_status usb_transc_stall(usb_core_driver *udev, usb_transc *transc);
|
||||
/* clear the USB transaction STALL status */
|
||||
usb_status usb_transc_clrstall(usb_core_driver *udev, usb_transc *transc);
|
||||
/* read device IN endpoint interrupt flag register */
|
||||
uint32_t usb_iepintr_read(usb_core_driver *udev, uint8_t ep_num);
|
||||
/* configures OUT endpoint 0 to receive SETUP packets */
|
||||
void usb_ctlep_startout(usb_core_driver *udev);
|
||||
/* active remote wakeup signaling */
|
||||
void usb_rwkup_active(usb_core_driver *udev);
|
||||
/* active USB core clock */
|
||||
void usb_clock_active(usb_core_driver *udev);
|
||||
/* USB device suspend */
|
||||
void usb_dev_suspend(usb_core_driver *udev);
|
||||
/* stop the device and clean up FIFOs */
|
||||
void usb_dev_stop(usb_core_driver *udev);
|
||||
/* USB battery charging detect operation */
|
||||
bcd_type usbd_bcd_detect(usb_core_driver *udev);
|
||||
|
||||
#endif /* DRV_USB_DEV_H */
|
||||
@@ -0,0 +1,102 @@
|
||||
/*!
|
||||
\file drv_usb_host.h
|
||||
\brief USB host mode low level driver header file
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef DRV_USB_HOST_H
|
||||
#define DRV_USB_HOST_H
|
||||
|
||||
#include "drv_usb_core.h"
|
||||
|
||||
/*!
|
||||
\brief get USB even frame
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval USB even frame state
|
||||
*/
|
||||
__STATIC_INLINE uint8_t usb_frame_even(usb_core_driver *udev)
|
||||
{
|
||||
return (uint8_t)!(udev->regs.hr->HFINFR & 0x01U);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read USB port
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval port status
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_port_read(usb_core_driver *udev)
|
||||
{
|
||||
return *udev->regs.HPCS & ~(HPCS_PE | HPCS_PCD | HPCS_PEDC);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get USB current speed
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval USB current speed
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_curspeed_get(usb_core_driver *udev)
|
||||
{
|
||||
return *udev->regs.HPCS & HPCS_PS;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get USB current frame
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval USB current frame
|
||||
*/
|
||||
__STATIC_INLINE uint32_t usb_curframe_get(usb_core_driver *udev)
|
||||
{
|
||||
return (udev->regs.hr->HFINFR & 0xFFFFU);
|
||||
}
|
||||
|
||||
/* function declarations */
|
||||
/* initializes USB core for host mode */
|
||||
usb_status usb_host_init(usb_core_driver *udev);
|
||||
/* control the VBUS to power */
|
||||
void usb_portvbus_switch(usb_core_driver *udev, uint8_t state);
|
||||
/* reset host port */
|
||||
uint32_t usb_port_reset(usb_core_driver *udev);
|
||||
/* initialize host pipe */
|
||||
usb_status usb_pipe_init(usb_core_driver *udev, uint8_t pipe_num);
|
||||
/* prepare host pipe for transferring packets */
|
||||
usb_status usb_pipe_xfer(usb_core_driver *udev, uint8_t pipe_num);
|
||||
/* halt host pipe */
|
||||
usb_status usb_pipe_halt(usb_core_driver *udev, uint8_t pipe_num);
|
||||
/* configure host pipe to do ping operation */
|
||||
usb_status usb_pipe_ping(usb_core_driver *udev, uint8_t pipe_num);
|
||||
/* stop the USB host and clean up FIFO */
|
||||
void usb_host_stop(usb_core_driver *udev);
|
||||
|
||||
#endif /* DRV_USB_HOST_H */
|
||||
@@ -0,0 +1,66 @@
|
||||
/*!
|
||||
\file drv_usb_hw.h
|
||||
\brief USB hardware configuration header file
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef DRV_USB_HW_H
|
||||
#define DRV_USB_HW_H
|
||||
|
||||
#include "drv_usb_core.h"
|
||||
|
||||
/* function declarations */
|
||||
/* configure USB clock */
|
||||
void usb_rcu_config(void);
|
||||
/* configure USB data line GPIO */
|
||||
void usb_gpio_config(void);
|
||||
/* configure USB interrupt */
|
||||
void usb_intr_config(void);
|
||||
/* initializes delay unit using Timer2 */
|
||||
void usb_timer_init(void);
|
||||
/* delay in microseconds */
|
||||
void usb_udelay(const uint32_t usec);
|
||||
/* delay in milliseconds */
|
||||
void usb_mdelay(const uint32_t msec);
|
||||
|
||||
/* configure USB clock */
|
||||
void pllusb_rcu_config(uint32_t usb_periph);
|
||||
|
||||
#ifdef USE_HOST_MODE
|
||||
/* configure systick */
|
||||
void systick_config(void);
|
||||
/* configure USB VBus */
|
||||
void usb_vbus_config(void);
|
||||
/* drive USB VBus */
|
||||
void usb_vbus_drive(uint8_t State);
|
||||
#endif /* USE_HOST_MODE */
|
||||
|
||||
#endif /* DRV_USB_HW_H */
|
||||
@@ -0,0 +1,750 @@
|
||||
/*!
|
||||
\file drv_usb_regs.h
|
||||
\brief USB cell registers definition and handle macros
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef DRV_USB_REGS_H
|
||||
#define DRV_USB_REGS_H
|
||||
|
||||
#include "usb_conf.h"
|
||||
|
||||
#define USBHS0 USBHS_BASE
|
||||
#define USBHS1 (USBHS_BASE + 0x00040000U)
|
||||
|
||||
#define USBHS0_REG_BASE USBHS0 /*!< base address of USBHS0 registers */
|
||||
#define USBHS1_REG_BASE USBHS1 /*!< base address of USBHS1 registers */
|
||||
|
||||
/* register definition */
|
||||
|
||||
#define USBHS_MAX_TX_FIFOS 16U /*!< FIFO number */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t GOTGCS; /*!< USB global OTG control and status register 000h */
|
||||
__IO uint32_t GOTGINTF; /*!< USB global OTG interrupt flag register 004h */
|
||||
__IO uint32_t GAHBCS; /*!< USB global AHB control and status register 008h */
|
||||
__IO uint32_t GUSBCS; /*!< USB global USB control and status register 00Ch */
|
||||
__IO uint32_t GRSTCTL; /*!< USB global reset control register 010h */
|
||||
__IO uint32_t GINTF; /*!< USB global interrupt flag register 014h */
|
||||
__IO uint32_t GINTEN; /*!< USB global interrupt enable register 018h */
|
||||
__IO uint32_t GRSTATR; /*!< USB receive status debug read register 01Ch */
|
||||
__IO uint32_t GRSTATP; /*!< USB receive status and pop register 020h */
|
||||
__IO uint32_t GRFLEN; /*!< USB global receive FIFO length register 024h */
|
||||
__IO uint32_t DIEP0TFLEN_HNPTFLEN; /*!< USB device IN endpoint 0/host non-periodic transmit FIFO length register 028h */
|
||||
__IO uint32_t HNPTFQSTAT; /*!< USB host non-periodic FIFO/queue status register 02Ch */
|
||||
uint32_t Reserved30[2]; /*!< Reserved 030h */
|
||||
__IO uint32_t GCCFG; /*!< USB global core configuration register 038h */
|
||||
__IO uint32_t CID; /*!< USB core ID register 03Ch */
|
||||
uint32_t Reserved40[5]; /*!< Reserved 040h-053h */
|
||||
__IO uint32_t GLPMCFG; /*!< LPM configuration register 54h */
|
||||
__IO uint32_t PWRD; /*!< power down register 58h */
|
||||
uint32_t Reserved5C; /*!< Reserved 5Ch */
|
||||
__IO uint32_t ADPCTL; /*!< ADP control and status register 60h */
|
||||
uint32_t Reserved64[3]; /*!< Reserved 64h-6Fh */
|
||||
__IO uint32_t PHYCTL; /*!< USBHS PHY control register 70h */
|
||||
uint32_t Reserved74[35]; /*!< Reserved 74h-FFh */
|
||||
__IO uint32_t HPTFLEN; /*!< USB host periodic transmit FIFO length register 100h */
|
||||
__IO uint32_t DIEPTFLEN[15]; /*!< USB device IN endpoint transmit FIFO length register 104h */
|
||||
} usb_gr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t HCTL; /*!< USB host control register 400h */
|
||||
__IO uint32_t HFT; /*!< USB host frame interval register 404h */
|
||||
__IO uint32_t HFINFR; /*!< USB host frame information remaining register 408h */
|
||||
uint32_t Reserved40C; /*!< Reserved 40Ch */
|
||||
__IO uint32_t HPTFQSTAT; /*!< USB host periodic transmit FIFO/queue status register 410h */
|
||||
__IO uint32_t HACHINT; /*!< USB host all channels interrupt register 414h */
|
||||
__IO uint32_t HACHINTEN; /*!< USB host all channels interrupt enable register 418h */
|
||||
} usb_hr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t HCHCTL; /*!< USB host channel control register 500h */
|
||||
__IO uint32_t HCHSTCTL; /*!< Reserved 504h */
|
||||
__IO uint32_t HCHINTF; /*!< USB host channel interrupt flag register 508h */
|
||||
__IO uint32_t HCHINTEN; /*!< USB host channel interrupt enable register 50Ch */
|
||||
__IO uint32_t HCHLEN; /*!< USB host channel transfer length register 510h */
|
||||
__IO uint32_t HCHDMAADDR; /*!< USB host channel-x DMA address register 514h*/
|
||||
uint32_t Reserved[2];
|
||||
} usb_pr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t DCFG; /*!< USB device configuration register 800h */
|
||||
__IO uint32_t DCTL; /*!< USB device control register 804h */
|
||||
__IO uint32_t DSTAT; /*!< USB device status register 808h */
|
||||
uint32_t Reserved0C; /*!< Reserved 80Ch */
|
||||
__IO uint32_t DIEPINTEN; /*!< USB device IN endpoint common interrupt enable register 810h */
|
||||
__IO uint32_t DOEPINTEN; /*!< USB device OUT endpoint common interrupt enable register 814h */
|
||||
__IO uint32_t DAEPINT; /*!< USB device all endpoints interrupt register 818h */
|
||||
__IO uint32_t DAEPINTEN; /*!< USB device all endpoints interrupt enable register 81Ch */
|
||||
uint32_t Reserved20; /*!< Reserved 820h */
|
||||
uint32_t Reserved24; /*!< Reserved 824h */
|
||||
__IO uint32_t DVBUSDT; /*!< USB device VBUS discharge time register 828h */
|
||||
__IO uint32_t DVBUSPT; /*!< USB device VBUS pulsing time register 82Ch */
|
||||
uint32_t Reserved30; /*!< Reserved 830h */
|
||||
__IO uint32_t DIEPFEINTEN; /*!< USB Device IN endpoint FIFO empty interrupt enable register 834h */
|
||||
__IO uint32_t DEP1INT; /*!< USB device endpoint 1 interrupt register 838h */
|
||||
__IO uint32_t DEP1INTEN; /*!< USB device endpoint 1 interrupt enable register 83Ch */
|
||||
uint32_t Reserved40; /*!< Reserved 840h */
|
||||
__IO uint32_t DIEP1INTEN; /*!< USB device IN endpoint-1 interrupt enable register 844h */
|
||||
uint32_t Reserved48[15]; /*!< Reserved 848-880h */
|
||||
__IO uint32_t DOEP1INTEN; /*!< USB device OUT endpoint-1 interrupt enable register 884h */
|
||||
} usb_dr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t DIEPCTL; /*!< USB device IN endpoint control register 900h + (EpNum * 20h) + 00h */
|
||||
uint32_t Reserved04; /*!< Reserved 900h + (EpNum * 20h) + 04h */
|
||||
__IO uint32_t DIEPINTF; /*!< USB device IN endpoint interrupt flag register 900h + (EpNum * 20h) + 08h */
|
||||
uint32_t Reserved0C; /*!< Reserved 900h + (EpNum * 20h) + 0Ch */
|
||||
__IO uint32_t DIEPLEN; /*!< USB device IN endpoint transfer length register 900h + (EpNum * 20h) + 10h */
|
||||
__IO uint32_t DIEPDMAADDR; /*!< Device IN endpoint-x DMA address register 900h + (EpNum * 20h) + 14h */
|
||||
__IO uint32_t DIEPTFSTAT; /*!< USB device IN endpoint transmit FIFO status register 900h + (EpNum * 20h) + 18h */
|
||||
} usb_erin;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t DOEPCTL; /*!< USB device IN endpoint control register B00h + (EpNum * 20h) + 00h */
|
||||
uint32_t Reserved04; /*!< Reserved B00h + (EpNum * 20h) + 04h */
|
||||
__IO uint32_t DOEPINTF; /*!< USB device IN endpoint interrupt flag register B00h + (EpNum * 20h) + 08h */
|
||||
uint32_t Reserved0C; /*!< Reserved B00h + (EpNum * 20h) + 0Ch */
|
||||
__IO uint32_t DOEPLEN; /*!< USB device IN endpoint transfer length register B00h + (EpNum * 20h) + 10h */
|
||||
__IO uint32_t DOEPDMAADDR; /*!< Device OUT endpoint-x DMA address register B00h + (EpNum * 20h) + 0Ch */
|
||||
} usb_erout;
|
||||
|
||||
typedef struct _usb_regs
|
||||
{
|
||||
usb_gr *gr; /*!< USBHS global registers */
|
||||
usb_dr *dr; /*!< device control and status registers */
|
||||
usb_hr *hr; /*!< host control and status registers */
|
||||
usb_erin *er_in[8]; /*!< USB device IN endpoint register */
|
||||
usb_erout *er_out[8]; /*!< USB device OUT endpoint register */
|
||||
usb_pr *pr[16]; /*!< USB Host channel-x control register */
|
||||
|
||||
__IO uint32_t *HPCS; /*!< USB host port control and status register */
|
||||
__IO uint32_t *DFIFO[USBHS_MAX_TX_FIFOS];
|
||||
__IO uint32_t *PWRCLKCTL; /*!< USB power and clock control register */
|
||||
} usb_core_regs;
|
||||
|
||||
/* global OTG control and status register bits definitions */
|
||||
#define GOTGCS_OV BIT(20) /*!< select OTG version */
|
||||
#define GOTGCS_BSV BIT(19) /*!< B-Session Valid */
|
||||
#define GOTGCS_ASV BIT(18) /*!< A-session valid */
|
||||
#define GOTGCS_DI BIT(17) /*!< debounce interval */
|
||||
#define GOTGCS_IDPS BIT(16) /*!< id pin status */
|
||||
#define GOTGCS_EHE BIT(12) /*!< embedded host enable */
|
||||
#define GOTGCS_DHNPEN BIT(11) /*!< device HNP enable */
|
||||
#define GOTGCS_HHNPEN BIT(10) /*!< host HNP enable */
|
||||
#define GOTGCS_HNPREQ BIT(9) /*!< HNP request */
|
||||
#define GOTGCS_HNPS BIT(8) /*!< HNP successes */
|
||||
#define GOTGCS_BVOV BIT(7) /*!< override value of B-peripheral session valid */
|
||||
#define GOTGCS_BVOE BIT(6) /*!< override enable of B-peripheral session valid */
|
||||
#define GOTGCS_AVOV BIT(5) /*!< override value of A-peripheral session valid */
|
||||
#define GOTGCS_AVOE BIT(4) /*!< override enable of A-peripheral session valid */
|
||||
#define GOTGCS_VOV BIT(3) /*!< override value of VBUS valid */
|
||||
#define GOTGCS_VOE BIT(2) /*!< override enable of VBUS valid */
|
||||
#define GOTGCS_SRPREQ BIT(1) /*!< SRP request */
|
||||
#define GOTGCS_SRPS BIT(0) /*!< SRP successes */
|
||||
|
||||
/* global OTG interrupt flag register bits definitions */
|
||||
#define GOTGINTF_IDCHG BIT(20) /*!< ID input change */
|
||||
#define GOTGINTF_DF BIT(19) /*!< debounce finish */
|
||||
#define GOTGINTF_ADTO BIT(18) /*!< A-device timeout */
|
||||
#define GOTGINTF_HNPDET BIT(17) /*!< host negotiation request detected */
|
||||
#define GOTGINTF_HNPEND BIT(9) /*!< HNP end */
|
||||
#define GOTGINTF_SRPEND BIT(8) /*!< SRP end */
|
||||
#define GOTGINTF_SESEND BIT(2) /*!< session end */
|
||||
|
||||
/* global AHB control and status register bits definitions */
|
||||
#define GAHBCS_PTXFTH BIT(8) /*!< periodic Tx FIFO threshold */
|
||||
#define GAHBCS_TXFTH BIT(7) /*!< tx FIFO threshold */
|
||||
#define GAHBCS_DMAEN BIT(5) /*!< DMA function Enable */
|
||||
#define GAHBCS_BURST BITS(1,4) /*!< the AHB burst type used by DMA */
|
||||
#define GAHBCS_GINTEN BIT(0) /*!< global interrupt enable */
|
||||
|
||||
/* global USB control and status register bits definitions */
|
||||
#define GUSBCS_FDM BIT(30) /*!< force device mode */
|
||||
#define GUSBCS_FHM BIT(29) /*!< force host mode */
|
||||
#define GUSBCS_ULPIEOI BIT(21) /*!< ULPI external over-current indicator */
|
||||
#define GUSBCS_ULPIEVD BIT(20) /*!< ULPI external VBUS driver */
|
||||
#define GUSBCS_UTT BITS(10,13) /*!< USB turnaround time */
|
||||
#define GUSBCS_HNPCEN BIT(9) /*!< HNP capability enable */
|
||||
#define GUSBCS_SRPCEN BIT(8) /*!< SRP capability enable */
|
||||
#define GUSBCS_EMBPHY_FS BIT(6) /*!< embedded FS PHY selected */
|
||||
#define GUSBCS_EMBPHY_HS BIT(5) /*!< embedded HS PHY selected */
|
||||
#define GUSBCS_HS_CUR_FE BIT(4) /*!< HS current software enable */
|
||||
#define GUSBCS_TOC BITS(0,2) /*!< timeout calibration */
|
||||
|
||||
/* global reset control register bits definitions */
|
||||
#define GRSTCTL_DMAIDL BIT(31) /*!< DMA idle state */
|
||||
#define GRSTCTL_DMABSY BIT(30) /*!< DMA busy */
|
||||
#define GRSTCTL_TXFNUM BITS(6,10) /*!< tx FIFO number */
|
||||
#define GRSTCTL_TXFF BIT(5) /*!< tx FIFO flush */
|
||||
#define GRSTCTL_RXFF BIT(4) /*!< rx FIFO flush */
|
||||
#define GRSTCTL_HFCRST BIT(2) /*!< host frame counter reset */
|
||||
#define GRSTCTL_HCSRST BIT(1) /*!< HCLK soft reset */
|
||||
#define GRSTCTL_CSRST BIT(0) /*!< core soft reset */
|
||||
|
||||
/* global interrupt flag register bits definitions */
|
||||
#define GINTF_WKUPIF BIT(31) /*!< wakeup interrupt flag */
|
||||
#define GINTF_SESIF BIT(30) /*!< session interrupt flag */
|
||||
#define GINTF_DISCIF BIT(29) /*!< disconnect interrupt flag */
|
||||
#define GINTF_IDPSC BIT(28) /*!< id pin status change */
|
||||
#define GINTF_LPMIF BIT(27) /*!< LPM interrupt flag */
|
||||
#define GINTF_PTXFEIF BIT(26) /*!< periodic tx FIFO empty interrupt flag */
|
||||
#define GINTF_HCIF BIT(25) /*!< host channels interrupt flag */
|
||||
#define GINTF_HPIF BIT(24) /*!< host port interrupt flag */
|
||||
#define GINTF_PXNCIF BIT(21) /*!< periodic transfer not complete interrupt flag */
|
||||
#define GINTF_ISOONCIF BIT(21) /*!< isochronous OUT transfer not complete interrupt flag */
|
||||
#define GINTF_ISOINCIF BIT(20) /*!< isochronous IN transfer not complete interrupt flag */
|
||||
#define GINTF_OEPIF BIT(19) /*!< OUT endpoint interrupt flag */
|
||||
#define GINTF_IEPIF BIT(18) /*!< IN endpoint interrupt flag */
|
||||
#define GINTF_EOPFIF BIT(15) /*!< end of periodic frame interrupt flag */
|
||||
#define GINTF_ISOOPDIF BIT(14) /*!< isochronous OUT packet dropped interrupt flag */
|
||||
#define GINTF_ENUMFIF BIT(13) /*!< enumeration finished */
|
||||
#define GINTF_RST BIT(12) /*!< USB reset */
|
||||
#define GINTF_SP BIT(11) /*!< USB suspend */
|
||||
#define GINTF_ESP BIT(10) /*!< early suspend */
|
||||
#define GINTF_GONAK BIT(7) /*!< global OUT NAK effective */
|
||||
#define GINTF_GNPINAK BIT(6) /*!< global IN non-periodic NAK effective */
|
||||
#define GINTF_NPTXFEIF BIT(5) /*!< non-periodic tx FIFO empty interrupt flag */
|
||||
#define GINTF_RXFNEIF BIT(4) /*!< rx FIFO non-empty interrupt flag */
|
||||
#define GINTF_SOF BIT(3) /*!< start of frame */
|
||||
#define GINTF_OTGIF BIT(2) /*!< OTG interrupt flag */
|
||||
#define GINTF_MFIF BIT(1) /*!< mode fault interrupt flag */
|
||||
#define GINTF_COPM BIT(0) /*!< current operation mode */
|
||||
|
||||
/* global interrupt enable register bits definitions */
|
||||
#define GINTEN_WKUPIE BIT(31) /*!< wakeup interrupt enable */
|
||||
#define GINTEN_SESIE BIT(30) /*!< session interrupt enable */
|
||||
#define GINTEN_DISCIE BIT(29) /*!< disconnect interrupt enable */
|
||||
#define GINTEN_IDPSCIE BIT(28) /*!< id pin status change interrupt enable */
|
||||
#define GINTEN_LPMIE BIT(27) /*!< LPM interrupt enable */
|
||||
#define GINTEN_PTXFEIE BIT(26) /*!< periodic tx FIFO empty interrupt enable */
|
||||
#define GINTEN_HCIE BIT(25) /*!< host channels interrupt enable */
|
||||
#define GINTEN_HPIE BIT(24) /*!< host port interrupt enable */
|
||||
#define GINTEN_IPXIE BIT(21) /*!< periodic transfer not complete interrupt enable */
|
||||
#define GINTEN_ISOONCIE BIT(21) /*!< isochronous OUT transfer not complete interrupt enable */
|
||||
#define GINTEN_ISOINCIE BIT(20) /*!< isochronous IN transfer not complete interrupt enable */
|
||||
#define GINTEN_OEPIE BIT(19) /*!< OUT endpoints interrupt enable */
|
||||
#define GINTEN_IEPIE BIT(18) /*!< IN endpoints interrupt enable */
|
||||
#define GINTEN_EOPFIE BIT(15) /*!< end of periodic frame interrupt enable */
|
||||
#define GINTEN_ISOOPDIE BIT(14) /*!< isochronous OUT packet dropped interrupt enable */
|
||||
#define GINTEN_ENUMFIE BIT(13) /*!< enumeration finish enable */
|
||||
#define GINTEN_RSTIE BIT(12) /*!< USB reset interrupt enable */
|
||||
#define GINTEN_SPIE BIT(11) /*!< USB suspend interrupt enable */
|
||||
#define GINTEN_ESPIE BIT(10) /*!< early suspend interrupt enable */
|
||||
#define GINTEN_GONAKIE BIT(7) /*!< global OUT NAK effective interrupt enable */
|
||||
#define GINTEN_GNPINAKIE BIT(6) /*!< global non-periodic IN NAK effective interrupt enable */
|
||||
#define GINTEN_NPTXFEIE BIT(5) /*!< non-periodic Tx FIFO empty interrupt enable */
|
||||
#define GINTEN_RXFNEIE BIT(4) /*!< receive FIFO non-empty interrupt enable */
|
||||
#define GINTEN_SOFIE BIT(3) /*!< start of frame interrupt enable */
|
||||
#define GINTEN_OTGIE BIT(2) /*!< OTG interrupt enable */
|
||||
#define GINTEN_MFIE BIT(1) /*!< mode fault interrupt enable */
|
||||
|
||||
/* global receive status read and pop register bits definitions */
|
||||
#define GRSTATRP_RPCKST BITS(17,20) /*!< received packet status */
|
||||
#define GRSTATRP_DPID BITS(15,16) /*!< data PID */
|
||||
#define GRSTATRP_BCOUNT BITS(4,14) /*!< byte count */
|
||||
#define GRSTATRP_CNUM BITS(0,3) /*!< channel number */
|
||||
#define GRSTATRP_EPNUM BITS(0,3) /*!< endpoint number */
|
||||
|
||||
/* global receive FIFO length register bits definitions */
|
||||
#define GRFLEN_RXFD BITS(0,15) /*!< rx FIFO depth */
|
||||
|
||||
/* host non-periodic transmit FIFO length register bits definitions */
|
||||
#define HNPTFLEN_HNPTXFD BITS(16,31) /*!< non-periodic Tx FIFO depth */
|
||||
#define HNPTFLEN_HNPTXRSAR BITS(0,15) /*!< non-periodic Tx RAM start address */
|
||||
|
||||
/* USB IN endpoint 0 transmit FIFO length register bits definitions */
|
||||
#define DIEP0TFLEN_IEP0TXFD BITS(16,31) /*!< IN Endpoint 0 Tx FIFO depth */
|
||||
#define DIEP0TFLEN_IEP0TXRSAR BITS(0,15) /*!< IN Endpoint 0 TX RAM start address */
|
||||
|
||||
/* host non-periodic transmit FIFO/queue status register bits definitions */
|
||||
#define HNPTFQSTAT_NPTXRQTOP BITS(24,30) /*!< top entry of the non-periodic Tx request queue */
|
||||
#define HNPTFQSTAT_NPTXRQS BITS(16,23) /*!< non-periodic Tx request queue space */
|
||||
#define HNPTFQSTAT_NPTXFS BITS(0,15) /*!< non-periodic Tx FIFO space */
|
||||
#define HNPTFQSTAT_CNUM BITS(27,30) /*!< channel number*/
|
||||
#define HNPTFQSTAT_EPNUM BITS(27,30) /*!< endpoint number */
|
||||
#define HNPTFQSTAT_TYPE BITS(25,26) /*!< token type */
|
||||
#define HNPTFQSTAT_TMF BIT(24) /*!< terminate flag */
|
||||
|
||||
/* global core configuration register bits definitions */
|
||||
#define GCCFG_VDEN BIT(21) /*!< enable of VBUS sensing comparator to detect VBUS valid */
|
||||
#define GCCFG_SOFOEN BIT(20) /*!< SOF output enable */
|
||||
#define GCCFG_PWRON BIT(16) /*!< power on */
|
||||
#define GCCFG_SDMEN BIT(15) /*!< secondary detection mode enable */
|
||||
#define GCCFG_PEMEN BIT(14) /*!< primary detection mode enable */
|
||||
#define GCCFG_DCDEN BIT(13) /*!< data connect detection mode enable */
|
||||
#define GCCFG_BCDEN BIT(12) /*!< battery charging detection enable */
|
||||
#define GCCFG_PS2F BIT(3) /*!< PS2 detection status */
|
||||
#define GCCFG_SDF BIT(2) /*!< secondary detection status */
|
||||
#define GCCFG_PDF BIT(1) /*!< primary detection status */
|
||||
#define GCCFG_DCDF BIT(0) /*!< battery connect detection status */
|
||||
|
||||
/* core ID register bits definitions */
|
||||
#define CID_CID BITS(0,31) /*!< core ID */
|
||||
|
||||
/* global core LPM configuration register bits definitions */
|
||||
#define GLPMCFG_BESLEN BIT(28) /*!< LPM Errata selection enable */
|
||||
#define GLPMCFG_LPMRCS BITS(25,27) /*!< LPM retry count status */
|
||||
#define GLPMCFG_LPMSND BIT(24) /*!< send LPM transaction */
|
||||
#define GLPMCFG_LPMRC BITS(21,23) /*!< LPM retry count */
|
||||
#define GLPMCFG_LPMCHI BITS(17,20) /*!< channel number index */
|
||||
#define GLPMCFG_RSOK BIT(16) /*!< Resume can be sent after sleep state */
|
||||
#define GLPMCFG_LPMSLPS BIT(15) /*!< sleep status */
|
||||
#define GLPMCFG_LPMRSP BITS(13,14) /*!< response of LPM */
|
||||
#define GLPMCFG_DSEN BIT(12) /*!< deep sleep enable */
|
||||
#define GLPMCFG_BESLTH BITS(8,11) /*!< BESL threshold */
|
||||
#define GLPMCFG_SSEN BIT(7) /*!< shallow sleep enable */
|
||||
#define GLPMCFG_REW BIT(6) /*!< bRemoteWake value */
|
||||
#define GLPMCFG_BESL BITS(2,5) /*!< best effort service latency */
|
||||
#define GLPMCFG_ACKLPM BIT(1) /*!< ACK in LPM transaction enable */
|
||||
#define GLPMCFG_LPMEN BIT(0) /*!< LPM enable */
|
||||
|
||||
/* power down register bits definition */
|
||||
#define PWRD_ADPF BIT(23) /*!< ADP event interrupt flag */
|
||||
#define PWRD_ADPMEN BIT(0) /*!< ADP module enable */
|
||||
|
||||
/* ADP control and status register bits definition */
|
||||
#define ADPCTL_RWR BITS(27,28) /*!< read and write request */
|
||||
#define ADPCTL_ADPTFM BIT(26) /*!< the mask of ADP timeout interrupt flag */
|
||||
#define ADPCTL_ADPSNFM BIT(25) /*!< the mask of ADP sense interrupt flag */
|
||||
#define ADPCTL_ADPPRFM BIT(24) /*!< the mask of ADP probe interrupt flag */
|
||||
#define ADPCTL_ADPTF BIT(23) /*!< ADP timeout interrupt flag */
|
||||
#define ADPCTL_ADPSNF BIT(22) /*!< ADP sense interrupt flag */
|
||||
#define ADPCTL_ADPPRF BIT(21) /*!< ADP probe interrupt flag */
|
||||
#define ADPCTL_ADPEN BIT(20) /*!< ADP enable */
|
||||
#define ADPCTL_ADPRST BIT(19) /*!< ADP reset */
|
||||
#define ADPCTL_SNEN BIT(18) /*!< ADP sense enable */
|
||||
#define ADPCTL_PREN BIT(17) /*!< ADP probe enable */
|
||||
#define ADPCTL_CHGT BITS(6,16) /*!< the latest time that VBUS ramps from VADPSINK to VADPPRB */
|
||||
#define ADPCTL_PERPR BITS(4,5) /*!< period of probe */
|
||||
#define ADPCTL_RESOPR BITS(2,3) /*!< the resolution of CHGT value */
|
||||
#define ADPCTL_DSCHGPR BITS(0,1) /*!< Time of probe discharge */
|
||||
|
||||
/* USBHS PHY control register bits definitions */
|
||||
#define PHYCTL_HS_CALEN BIT(31) /*!< HS PHY calibration enable */
|
||||
#define PHYCTL_HS_CALR BITS(25,30) /*!< HS PHY calibration value */
|
||||
#define PHYCTL_HS_RCALR BITS(21,24) /*!< HS PHY R calibration value */
|
||||
#define PHYCTL_SQUECH BIT(16) /*!< HS PHY squech flag */
|
||||
#define PHYCTL_HS_BIST_DONE BIT(15) /*!< HS PHY bist finished flag */
|
||||
#define PHYCTL_HS_BIST_SUCCESS BIT(14) /*!< HS PHY bist success flag */
|
||||
#define PHYCTL_HS_BIST_FAIL BIT(13) /*!< HS PHY bist fail flag */
|
||||
#define PHYCTL_HS_BIST_PKT_SEL BITS(11,12) /*!< HS PHY bist packet select */
|
||||
#define PHYCTL_HS_BIST_SEED BITS(3,10) /*!< HS PHY bist seed */
|
||||
#define PHYCTL_HS_BIST_EN BIT(2) /*!< HS PHY bist enable */
|
||||
#define PHYCTL_HS_BIST_RESET BIT(1) /*!< HS PHY bist logic reset */
|
||||
#define PHYCTL_HS_BIST_START BIT(0) /*!< HS PHY bist start */
|
||||
|
||||
/* host periodic transmit FIFO length register bits definitions */
|
||||
#define HPTFLEN_HPTXFD BITS(16,31) /*!< host periodic Tx FIFO depth */
|
||||
#define HPTFLEN_HPTXFSAR BITS(0,15) /*!< host periodic Tx RAM start address */
|
||||
|
||||
/* device IN endpoint transmit FIFO length register bits definitions */
|
||||
#define DIEPTFLEN_IEPTXFD BITS(16,31) /*!< IN endpoint Tx FIFO x depth */
|
||||
#define DIEPTFLEN_IEPTXRSAR BITS(0,15) /*!< IN endpoint FIFOx Tx x RAM start address */
|
||||
|
||||
/* host control register bits definitions */
|
||||
#define HCTL_SPDFSLS BIT(2) /*!< speed limited to FS and LS */
|
||||
|
||||
/* host frame interval register bits definitions */
|
||||
#define HFT_FRI BITS(0,15) /*!< frame interval */
|
||||
|
||||
/* host frame information remaining register bits definitions */
|
||||
#define HFINFR_FRT BITS(16,31) /*!< frame remaining time */
|
||||
#define HFINFR_FRNUM BITS(0,15) /*!< frame number */
|
||||
|
||||
/* host periodic transmit FIFO/queue status register bits definitions */
|
||||
#define HPTFQSTAT_PTXREQT BITS(24,31) /*!< top entry of the periodic Tx request queue */
|
||||
#define HPTFQSTAT_PTXREQS BITS(16,23) /*!< periodic Tx request queue space */
|
||||
#define HPTFQSTAT_PTXFS BITS(0,15) /*!< periodic Tx FIFO space */
|
||||
#define HPTFQSTAT_OEFRM BIT(31) /*!< odd/eveb frame */
|
||||
#define HPTFQSTAT_CNUM BITS(27,30) /*!< channel number */
|
||||
#define HPTFQSTAT_EPNUM BITS(27,30) /*!< endpoint number */
|
||||
#define HPTFQSTAT_TYPE BITS(25,26) /*!< token type */
|
||||
#define HPTFQSTAT_TMF BIT(24) /*!< terminate flag */
|
||||
|
||||
#define TFQSTAT_TXFS BITS(0,15)
|
||||
#define TFQSTAT_CNUM BITS(27,30)
|
||||
|
||||
/* host all channels interrupt register bits definitions */
|
||||
#define HACHINT_HACHINT BITS(0,15) /*!< host all channel interrupts */
|
||||
|
||||
/* host all channels interrupt enable register bits definitions */
|
||||
#define HACHINTEN_CINTEN BITS(0,15) /*!< channel interrupt enable */
|
||||
|
||||
/* host port control and status register bits definitions */
|
||||
#define HPCS_PS BITS(17,18) /*!< port speed */
|
||||
#define HPCS_PTEST BITS(13,16) /*!< port test control */
|
||||
#define HPCS_PP BIT(12) /*!< port power */
|
||||
#define HPCS_PLST BITS(10,11) /*!< port line status */
|
||||
#define HPCS_PRST BIT(8) /*!< port reset */
|
||||
#define HPCS_PSP BIT(7) /*!< port suspend */
|
||||
#define HPCS_PREM BIT(6) /*!< port resume */
|
||||
#define HPCS_PEDC BIT(3) /*!< port enable/disable change */
|
||||
#define HPCS_PE BIT(2) /*!< port enable */
|
||||
#define HPCS_PCD BIT(1) /*!< port connect detected */
|
||||
#define HPCS_PCST BIT(0) /*!< port connect status */
|
||||
|
||||
/* host channel-x control register bits definitions */
|
||||
#define HCHCTL_CEN BIT(31) /*!< channel enable */
|
||||
#define HCHCTL_CDIS BIT(30) /*!< channel disable */
|
||||
#define HCHCTL_ODDFRM BIT(29) /*!< odd frame */
|
||||
#define HCHCTL_DAR BITS(22,28) /*!< device address */
|
||||
#define HCHCTL_MPC BITS(20,21) /*!< multiple packet count */
|
||||
#define HCHCTL_EPTYPE BITS(18,19) /*!< endpoint type */
|
||||
#define HCHCTL_LSD BIT(17) /*!< low-speed device */
|
||||
#define HCHCTL_EPDIR BIT(15) /*!< endpoint direction */
|
||||
#define HCHCTL_EPNUM BITS(11,14) /*!< endpoint number */
|
||||
#define HCHCTL_MPL BITS(0,10) /*!< maximum packet length */
|
||||
|
||||
/* host channel-x split transaction register bits definitions */
|
||||
#define HCHSTCTL_SPLEN BIT(31) /*!< enable high-speed split transaction */
|
||||
#define HCHSTCTL_CSPLT BIT(16) /*!< complete-split enable */
|
||||
#define HCHSTCTL_ISOPCE BITS(14,15) /*!< isochronous OUT payload continuation encoding */
|
||||
#define HCHSTCTL_HADDR BITS(7,13) /*!< HUB address */
|
||||
#define HCHSTCTL_PADDR BITS(0,6) /*!< port address */
|
||||
|
||||
/* host channel-x interrupt flag register bits definitions */
|
||||
#define HCHINTF_DTER BIT(10) /*!< data toggle error */
|
||||
#define HCHINTF_REQOVR BIT(9) /*!< request queue overrun */
|
||||
#define HCHINTF_BBER BIT(8) /*!< babble error */
|
||||
#define HCHINTF_USBER BIT(7) /*!< USB bus Error */
|
||||
#define HCHINTF_NYET BIT(6) /*!< NYET */
|
||||
#define HCHINTF_ACK BIT(5) /*!< ACK */
|
||||
#define HCHINTF_NAK BIT(4) /*!< NAK */
|
||||
#define HCHINTF_STALL BIT(3) /*!< STALL */
|
||||
#define HCHINTF_DMAER BIT(2) /*!< DMA error */
|
||||
#define HCHINTF_CH BIT(1) /*!< channel halted */
|
||||
#define HCHINTF_TF BIT(0) /*!< transfer finished */
|
||||
|
||||
/* host channel-x interrupt enable register bits definitions */
|
||||
#define HCHINTEN_DTERIE BIT(10) /*!< data toggle error interrupt enable */
|
||||
#define HCHINTEN_REQOVRIE BIT(9) /*!< request queue overrun interrupt enable */
|
||||
#define HCHINTEN_BBERIE BIT(8) /*!< babble error interrupt enable */
|
||||
#define HCHINTEN_USBERIE BIT(7) /*!< USB bus error interrupt enable */
|
||||
#define HCHINTEN_NYETIE BIT(6) /*!< NYET interrupt enable */
|
||||
#define HCHINTEN_ACKIE BIT(5) /*!< ACK interrupt enable */
|
||||
#define HCHINTEN_NAKIE BIT(4) /*!< NAK interrupt enable */
|
||||
#define HCHINTEN_STALLIE BIT(3) /*!< STALL interrupt enable */
|
||||
#define HCHINTEN_DMAERIE BIT(2) /*!< DMA error interrupt enable */
|
||||
#define HCHINTEN_CHIE BIT(1) /*!< channel halted interrupt enable */
|
||||
#define HCHINTEN_TFIE BIT(0) /*!< transfer finished interrupt enable */
|
||||
|
||||
/* host channel-x transfer length register bits definitions */
|
||||
#define HCHLEN_PING BIT(31) /*!< PING token request */
|
||||
#define HCHLEN_DPID BITS(29,30) /*!< data PID */
|
||||
#define HCHLEN_PCNT BITS(19,28) /*!< packet count */
|
||||
#define HCHLEN_TLEN BITS(0,18) /*!< transfer length */
|
||||
|
||||
/* host channel-x DMA address register bits definitions */
|
||||
#define HCHDMAADDR_DMAADDR BITS(0,31) /*!< DMA address */
|
||||
|
||||
#define PORT_SPEED(x) (((uint32_t)(x) << 17U) & HPCS_PS) /*!< Port speed */
|
||||
|
||||
#define PORT_SPEED_HIGH PORT_SPEED(0U) /*!< high speed */
|
||||
#define PORT_SPEED_FULL PORT_SPEED(1U) /*!< full speed */
|
||||
#define PORT_SPEED_LOW PORT_SPEED(2U) /*!< low speed */
|
||||
|
||||
#define PIPE_CTL_DAR(x) (((uint32_t)(x) << 22U) & HCHCTL_DAR) /*!< device address */
|
||||
#define PIPE_CTL_EPTYPE(x) (((uint32_t)(x) << 18U) & HCHCTL_EPTYPE) /*!< endpoint type */
|
||||
#define PIPE_CTL_EPNUM(x) (((uint32_t)(x) << 11U) & HCHCTL_EPNUM) /*!< endpoint number */
|
||||
#define PIPE_CTL_EPDIR(x) (((uint32_t)(x) << 15U) & HCHCTL_EPDIR) /*!< endpoint direction */
|
||||
#define PIPE_CTL_EPMPL(x) (((uint32_t)(x) << 0U) & HCHCTL_MPL) /*!< maximum packet length */
|
||||
#define PIPE_CTL_LSD(x) (((uint32_t)(x) << 17U) & HCHCTL_LSD) /*!< low-Speed device */
|
||||
|
||||
#define PIPE_XFER_PCNT(x) (((uint32_t)(x) << 19U) & HCHLEN_PCNT) /*!< packet count */
|
||||
#define PIPE_XFER_DPID(x) (((uint32_t)(x) << 29U) & HCHLEN_DPID) /*!< data PID */
|
||||
|
||||
#define PIPE_DPID_DATA0 PIPE_XFER_DPID(0) /*!< DATA0 */
|
||||
#define PIPE_DPID_DATA1 PIPE_XFER_DPID(2) /*!< DATA1 */
|
||||
#define PIPE_DPID_DATA2 PIPE_XFER_DPID(1) /*!< DATA2 */
|
||||
#define PIPE_DPID_SETUP PIPE_XFER_DPID(3) /*!< MDATA (non-control)/SETUP (control) */
|
||||
|
||||
extern const uint32_t PIPE_DPID[2];
|
||||
|
||||
/* device configuration registers bits definitions */
|
||||
#define DCFG_EOPFT BITS(11,12) /*!< end of periodic frame time */
|
||||
#define DCFG_DAR BITS(4,10) /*!< device address */
|
||||
#define DCFG_NZLSOH BIT(2) /*!< non-zero-length status OUT handshake */
|
||||
#define DCFG_DS BITS(0,1) /*!< device speed */
|
||||
|
||||
/* device control registers bits definitions */
|
||||
#define DCTL_L1RJCT BIT(18) /*!< deep sleep reject */
|
||||
#define DCTL_POIF BIT(11) /*!< power-on initialization finished */
|
||||
#define DCTL_CGONAK BIT(10) /*!< clear global OUT NAK */
|
||||
#define DCTL_SGONAK BIT(9) /*!< set global OUT NAK */
|
||||
#define DCTL_CGINAK BIT(8) /*!< clear global IN NAK */
|
||||
#define DCTL_SGINAK BIT(7) /*!< set global IN NAK */
|
||||
#define DCTL_DTEST BITS(4,6) /*!< device test control */
|
||||
#define DCTL_GONS BIT(3) /*!< global OUT NAK status */
|
||||
#define DCTL_GINS BIT(2) /*!< global IN NAK status */
|
||||
#define DCTL_SD BIT(1) /*!< soft disconnect */
|
||||
#define DCTL_RWKUP BIT(0) /*!< remote wakeup */
|
||||
|
||||
/* device status registers bits definitions */
|
||||
#define DSTAT_FNRSOF BITS(8,21) /*!< the frame number of the received SOF. */
|
||||
#define DSTAT_ES BITS(1,2) /*!< enumerated speed */
|
||||
#define DSTAT_SPST BIT(0) /*!< suspend status */
|
||||
|
||||
/* device IN endpoint common interrupt enable registers bits definitions */
|
||||
#define DIEPINTEN_NAKEN BIT(13) /*!< NAK handshake sent by USBHS interrupt enable bit */
|
||||
#define DIEPINTEN_TXFEEN BIT(7) /*!< transmit FIFO empty interrupt enable bit */
|
||||
#define DIEPINTEN_IEPNEEN BIT(6) /*!< IN endpoint NAK effective interrupt enable bit */
|
||||
#define DIEPINTEN_EPTXFUDEN BIT(4) /*!< endpoint Tx FIFO underrun interrupt enable bit */
|
||||
#define DIEPINTEN_CITOEN BIT(3) /*!< control In Timeout interrupt enable bit */
|
||||
#define DIEPINTEN_EPDISEN BIT(1) /*!< endpoint disabled interrupt enable bit */
|
||||
#define DIEPINTEN_TFEN BIT(0) /*!< transfer finished interrupt enable bit */
|
||||
|
||||
/* device OUT endpoint common interrupt enable registers bits definitions */
|
||||
#define DOEPINTEN_NYETEN BIT(14) /*!< NYET handshake is sent interrupt enable bit */
|
||||
#define DOEPINTEN_BTBSTPEN BIT(6) /*!< back-to-back SETUP packets interrupt enable bit */
|
||||
#define DOEPINTEN_EPRXFOVREN BIT(4) /*!< endpoint Rx FIFO overrun interrupt enable bit */
|
||||
#define DOEPINTEN_STPFEN BIT(3) /*!< SETUP phase finished interrupt enable bit */
|
||||
#define DOEPINTEN_EPDISEN BIT(1) /*!< endpoint disabled interrupt enable bit */
|
||||
#define DOEPINTEN_TFEN BIT(0) /*!< transfer finished interrupt enable bit */
|
||||
|
||||
/* device all endpoints interrupt registers bits definitions */
|
||||
#define DAEPINT_OEPITB BITS(16,23) /*!< device all OUT endpoint interrupt bits */
|
||||
#define DAEPINT_IEPITB BITS(0,7) /*!< device all IN endpoint interrupt bits */
|
||||
|
||||
/* device all endpoints interrupt enable registers bits definitions */
|
||||
#define DAEPINTEN_OEPIE BITS(16,23) /*!< OUT endpoint interrupt enable */
|
||||
#define DAEPINTEN_IEPIE BITS(0,7) /*!< IN endpoint interrupt enable */
|
||||
|
||||
/* device VBUS discharge time registers bits definitions */
|
||||
#define DVBUSDT_DVBUSDT BITS(0,15) /*!< device VBUS discharge time */
|
||||
|
||||
/* device VBUS pulsing time registers bits definitions */
|
||||
#define DVBUSPT_DVBUSPT BITS(0,11) /*!< device VBUS pulsing time */
|
||||
|
||||
/* device IN endpoint FIFO empty interrupt enable register bits definitions */
|
||||
#define DIEPFEINTEN_IEPTXFEIE BITS(0,5) /*!< IN endpoint Tx FIFO empty interrupt enable bits */
|
||||
|
||||
/* device endpoint 0 control register bits definitions */
|
||||
#define DEP0CTL_EPEN BIT(31) /*!< endpoint enable */
|
||||
#define DEP0CTL_EPD BIT(30) /*!< endpoint disable */
|
||||
#define DEP0CTL_SNAK BIT(27) /*!< set NAK */
|
||||
#define DEP0CTL_CNAK BIT(26) /*!< clear NAK */
|
||||
#define DIEP0CTL_TXFNUM BITS(22,25) /*!< tx FIFO number */
|
||||
#define DEP0CTL_STALL BIT(21) /*!< STALL handshake */
|
||||
#define DOEP0CTL_SNOOP BIT(20) /*!< snoop mode */
|
||||
#define DEP0CTL_EPTYPE BITS(18,19) /*!< endpoint type */
|
||||
#define DEP0CTL_NAKS BIT(17) /*!< NAK status */
|
||||
#define DEP0CTL_EPACT BIT(15) /*!< endpoint active */
|
||||
#define DEP0CTL_MPL BITS(0,1) /*!< maximum packet length */
|
||||
|
||||
/* device endpoint x control register bits definitions */
|
||||
#define DEPCTL_EPEN BIT(31) /*!< endpoint enable */
|
||||
#define DEPCTL_EPD BIT(30) /*!< endpoint disable */
|
||||
#define DEPCTL_SODDFRM BIT(29) /*!< set odd frame */
|
||||
#define DEPCTL_SD1PID BIT(29) /*!< set DATA1 PID */
|
||||
#define DEPCTL_SEVNFRM BIT(28) /*!< set even frame */
|
||||
#define DEPCTL_SD0PID BIT(28) /*!< set DATA0 PID */
|
||||
#define DEPCTL_SNAK BIT(27) /*!< set NAK */
|
||||
#define DEPCTL_CNAK BIT(26) /*!< clear NAK */
|
||||
#define DIEPCTL_TXFNUM BITS(22,25) /*!< tx FIFO number */
|
||||
#define DEPCTL_STALL BIT(21) /*!< STALL handshake */
|
||||
#define DOEPCTL_SNOOP BIT(20) /*!< snoop mode */
|
||||
#define DEPCTL_EPTYPE BITS(18,19) /*!< endpoint type */
|
||||
#define DEPCTL_NAKS BIT(17) /*!< NAK status */
|
||||
#define DEPCTL_EOFRM BIT(16) /*!< even/odd frame */
|
||||
#define DEPCTL_DPID BIT(16) /*!< endpoint data PID */
|
||||
#define DEPCTL_EPACT BIT(15) /*!< endpoint active */
|
||||
#define DEPCTL_MPL BITS(0,10) /*!< maximum packet length */
|
||||
|
||||
/* device IN endpoint-x interrupt flag register bits definitions */
|
||||
#define DIEPINTF_NAK BIT(13) /*!< NAK handshake sent by USBHS */
|
||||
#define DIEPINTF_TXFE BIT(7) /*!< transmit FIFO empty */
|
||||
#define DIEPINTF_IEPNE BIT(6) /*!< IN endpoint NAK effective */
|
||||
#define DIEPINTF_EPTXFUD BIT(4) /*!< endpoint Tx FIFO underrun */
|
||||
#define DIEPINTF_CITO BIT(3) /*!< control In Timeout interrupt */
|
||||
#define DIEPINTF_EPDIS BIT(1) /*!< endpoint disabled */
|
||||
#define DIEPINTF_TF BIT(0) /*!< transfer finished */
|
||||
|
||||
/* device OUT endpoint-x interrupt flag register bits definitions */
|
||||
#define DOEPINTF_NYET BIT(14) /*!< NYET handshake is sent */
|
||||
#define DOEPINTF_BTBSTP BIT(6) /*!< back-to-back SETUP packets */
|
||||
#define DOEPINTF_EPRXFOVR BIT(4) /*!< endpoint Rx FIFO overrun */
|
||||
#define DOEPINTF_STPF BIT(3) /*!< SETUP phase finished */
|
||||
#define DOEPINTF_EPDIS BIT(1) /*!< endpoint disabled */
|
||||
#define DOEPINTF_TF BIT(0) /*!< transfer finished */
|
||||
|
||||
/* device IN endpoint 0 transfer length register bits definitions */
|
||||
#define DIEP0LEN_PCNT BITS(19,20) /*!< packet count */
|
||||
#define DIEP0LEN_TLEN BITS(0,6) /*!< transfer length */
|
||||
|
||||
/* device OUT endpoint 0 transfer length register bits definitions */
|
||||
#define DOEP0LEN_STPCNT BITS(29,30) /*!< SETUP packet count */
|
||||
#define DOEP0LEN_PCNT BIT(19) /*!< packet count */
|
||||
#define DOEP0LEN_TLEN BITS(0,6) /*!< transfer length */
|
||||
|
||||
/* device OUT endpoint-x transfer length register bits definitions */
|
||||
#define DOEPLEN_RXDPID BITS(29,30) /*!< received data PID */
|
||||
#define DOEPLEN_STPCNT BITS(29,30) /*!< SETUP packet count */
|
||||
#define DIEPLEN_MCNT BITS(29,30) /*!< multi count */
|
||||
#define DEPLEN_PCNT BITS(19,28) /*!< packet count */
|
||||
#define DEPLEN_TLEN BITS(0,18) /*!< transfer length */
|
||||
|
||||
/* device IN endpoint-x DMA address register bits definitions */
|
||||
#define DIEPDMAADDR_DMAADDR BITS(0,31) /*!< DMA address */
|
||||
|
||||
/* device OUT endpoint-x DMA address register bits definitions */
|
||||
#define DOEPDMAADDR_DMAADDR BITS(0,31) /*!< DMA address */
|
||||
|
||||
/* device IN endpoint-x transmit FIFO status register bits definitions */
|
||||
#define DIEPTFSTAT_IEPTFS BITS(0,15) /*!< IN endpoint Tx FIFO space remaining */
|
||||
|
||||
/* USB power and clock registers bits definition */
|
||||
#define PWRCLKCTL_DSLEEP BIT(7) /*!< PHY is in deep sleep status */
|
||||
#define PWRCLKCTL_SSLEEP BIT(6) /*!< PHY is in shallow sleep status */
|
||||
#define PWRCLKCTL_SCGEN BIT(5) /*!< When this bit is set, the internal clock gating is enabled */
|
||||
#define PWRCLKCTL_SUSP BIT(4) /*!< PHY is in suspend status */
|
||||
#define PWRCLKCTL_SHCLK BIT(1) /*!< stop HCLK */
|
||||
#define PWRCLKCTL_SUCLK BIT(0) /*!< stop the USB clock */
|
||||
|
||||
#define RSTAT_GOUT_NAK 1U /*!< global OUT NAK (triggers an interrupt) */
|
||||
#define RSTAT_DATA_UPDT 2U /*!< OUT data packet received */
|
||||
#define RSTAT_XFER_COMP 3U /*!< OUT transfer completed (triggers an interrupt) */
|
||||
#define RSTAT_SETUP_COMP 4U /*!< SETUP transaction completed (triggers an interrupt) */
|
||||
#define RSTAT_SETUP_UPDT 6U /*!< SETUP data packet received */
|
||||
|
||||
#define DSTAT_EM_HS_PHY_30MHZ_60MHZ 0U /*!< USB enumerate speed use high-speed PHY clock in 30MHz or 60MHz */
|
||||
#define DSTAT_EM_FS_PHY_30MHZ_60MHZ 1U /*!< USB enumerate speed use full-speed PHY clock in 30MHz or 60MHz */
|
||||
#define DSTAT_EM_LS_PHY_6MHZ 2U /*!< USB enumerate speed use low-speed PHY clock in 6MHz */
|
||||
#define DSTAT_EM_FS_PHY_48MHZ 3U /*!< USB enumerate speed use full-speed PHY clock in 48MHz */
|
||||
|
||||
#define DPID_DATA0 0U /*!< device endpoint data PID is DATA0 */
|
||||
#define DPID_DATA1 2U /*!< device endpoint data PID is DATA1 */
|
||||
#define DPID_DATA2 1U /*!< device endpoint data PID is DATA2 */
|
||||
#define DPID_MDATA 3U /*!< device endpoint data PID is MDATA */
|
||||
|
||||
#define GAHBCS_DMAINCR(regval) (GAHBCS_BURST & ((regval) << 1U)) /*!< AHB burst type used by DMA */
|
||||
|
||||
#define DMA_INCR0 GAHBCS_DMAINCR(0U) /*!< single burst type used by DMA*/
|
||||
#define DMA_INCR1 GAHBCS_DMAINCR(1U) /*!< 4-beat incrementing burst type used by DMA */
|
||||
#define DMA_INCR4 GAHBCS_DMAINCR(3U) /*!< 8-beat incrementing burst type used by DMA */
|
||||
#define DMA_INCR8 GAHBCS_DMAINCR(5U) /*!< 16-beat incrementing burst type used by DMA */
|
||||
#define DMA_INCR16 GAHBCS_DMAINCR(7U) /*!< 32-beat incrementing burst type used by DMA */
|
||||
|
||||
#define DCFG_PFRI(regval) (DCFG_EOPFT & ((regval) << 11U)) /*!< end of periodic frame time configuration */
|
||||
|
||||
#define FRAME_INTERVAL_80 DCFG_PFRI(0U) /*!< 80% of the frame time */
|
||||
#define FRAME_INTERVAL_85 DCFG_PFRI(1U) /*!< 85% of the frame time */
|
||||
#define FRAME_INTERVAL_90 DCFG_PFRI(2U) /*!< 90% of the frame time */
|
||||
#define FRAME_INTERVAL_95 DCFG_PFRI(3U) /*!< 95% of the frame time */
|
||||
|
||||
#define DCFG_DEVSPEED(regval) (DCFG_DS & ((regval) << 0U)) /*!< device speed configuration */
|
||||
|
||||
#define USB_SPEED_INP_HIGH DCFG_DEVSPEED(0U) /*!< device internal PHY high speed */
|
||||
#define USB_SPEED_INP_FULL DCFG_DEVSPEED(1U) /*!< device internal PHY full speed */
|
||||
|
||||
#define DEP0_MPL(regval) (DEP0CTL_MPL & ((regval) << 0U)) /*!< maximum packet length configuration */
|
||||
|
||||
#define EP0MPL_64 DEP0_MPL(0U) /*!< maximum packet length 64 bytes */
|
||||
#define EP0MPL_32 DEP0_MPL(1U) /*!< maximum packet length 32 bytes */
|
||||
#define EP0MPL_16 DEP0_MPL(2U) /*!< maximum packet length 16 bytes */
|
||||
#define EP0MPL_8 DEP0_MPL(3U) /*!< maximum packet length 8 bytes */
|
||||
|
||||
#define DOEP0_TLEN(regval) (DOEP0LEN_TLEN & ((regval) << 0U)) /*!< Transfer length */
|
||||
#define DOEP0_PCNT(regval) (DOEP0LEN_PCNT & ((regval) << 19U)) /*!< Packet count */
|
||||
#define DOEP0_STPCNT(regval) (DOEP0LEN_STPCNT & ((regval) << 29U)) /*!< SETUP packet count */
|
||||
|
||||
#define GRXSTS_PKTSTS_IN 2U
|
||||
#define GRXSTS_PKTSTS_IN_XFER_COMP 3U
|
||||
#define GRXSTS_PKTSTS_DATA_TOGGLE_ERR 5U
|
||||
#define GRXSTS_PKTSTS_CH_HALTED 7U
|
||||
|
||||
#define DEVICE_MODE 0U /*!< device mode */
|
||||
#define HOST_MODE 1U /*!< host mode */
|
||||
#define OTG_MODE 2U /*!< OTG mode */
|
||||
|
||||
#define HCTL_30_60MHZ 0U /*!< USB clock 30-60MHZ */
|
||||
#define HCTL_48MHZ 1U /*!< USB clock 48MHZ */
|
||||
#define HCTL_6MHZ 2U /*!< USB clock 6MHZ */
|
||||
|
||||
#define USBHS_MAX_PACKET_SIZE 512U /*!< USBHS max packet size */
|
||||
#define USBHS_MAX_CHANNEL_COUNT 16U /*!< USBHS host channel count */
|
||||
#define USBHS_MAX_EP_COUNT 8U /*!< USBHS device endpoint count */
|
||||
#define USBHS_MAX_FIFO_WORDLEN 1280U /*!< USBHS max fifo size in words */
|
||||
|
||||
#define USB_DATA_FIFO_OFFSET 0x1000U /*!< USB data fifo offset */
|
||||
#define USB_DATA_FIFO_SIZE 0x1000U /*!< USB data fifo size */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USB_EMBEDDED_PHY_FS = 0U, /*!< USB embedded FS PHY */
|
||||
USB_EMBEDDED_PHY_HS, /*!< USB embedded HS PHY */
|
||||
USB_ULPI_PHY_EXTERNAL /*!< USB external ULPI PHY */
|
||||
} usb_phy_enum;
|
||||
|
||||
enum usb_reg_offset {
|
||||
USB_REG_OFFSET_CORE = 0x0000U, /*!< global OTG control and status register */
|
||||
USB_REG_OFFSET_DEV = 0x0800U, /*!< device mode control and status registers */
|
||||
USB_REG_OFFSET_EP = 0x0020U, /*!< offset of each endpoint */
|
||||
USB_REG_OFFSET_EP_IN = 0x0900U, /*!< device IN endpoint 0 control register */
|
||||
USB_REG_OFFSET_EP_OUT = 0x0B00U, /*!< device OUT endpoint 0 control register */
|
||||
USB_REG_OFFSET_HOST = 0x0400U, /*!< host control register */
|
||||
USB_REG_OFFSET_CH = 0x0020U, /*!< offset of each channel */
|
||||
USB_REG_OFFSET_PORT = 0x0440U, /*!< host port control and status register */
|
||||
USB_REG_OFFSET_CH_INOUT = 0x0500U, /*!< host channel-x control registers */
|
||||
USB_REG_OFFSET_PWRCLKCTL = 0x0E00U /*!< power and clock register */
|
||||
};
|
||||
|
||||
enum USB_SPEED {
|
||||
USB_SPEED_UNKNOWN = 0, /*!< USB speed unknown */
|
||||
USB_SPEED_LOW, /*!< USB speed low */
|
||||
USB_SPEED_FULL, /*!< USB speed full */
|
||||
USB_SPEED_HIGH /*!< USB speed high */
|
||||
};
|
||||
|
||||
#define EP0_OUT ((uint8_t)0x00U) /*!< endpoint out 0 */
|
||||
#define EP0_IN ((uint8_t)0x80U) /*!< endpoint in 0 */
|
||||
#define EP1_OUT ((uint8_t)0x01U) /*!< endpoint out 1 */
|
||||
#define EP1_IN ((uint8_t)0x81U) /*!< endpoint in 1 */
|
||||
#define EP2_OUT ((uint8_t)0x02U) /*!< endpoint out 2 */
|
||||
#define EP2_IN ((uint8_t)0x82U) /*!< endpoint in 2 */
|
||||
#define EP3_OUT ((uint8_t)0x03U) /*!< endpoint out 3 */
|
||||
#define EP3_IN ((uint8_t)0x83U) /*!< endpoint in 3 */
|
||||
#define EP4_OUT ((uint8_t)0x04U) /*!< endpoint out 4 */
|
||||
#define EP4_IN ((uint8_t)0x84U) /*!< endpoint in 4 */
|
||||
#define EP5_OUT ((uint8_t)0x05U) /*!< endpoint out 5 */
|
||||
#define EP5_IN ((uint8_t)0x85U) /*!< endpoint in 5 */
|
||||
#define EP6_OUT ((uint8_t)0x06U) /*!< endpoint out 6 */
|
||||
#define EP6_IN ((uint8_t)0x86U) /*!< endpoint in 6 */
|
||||
#define EP7_OUT ((uint8_t)0x06U) /*!< endpoint out 7 */
|
||||
#define EP7_IN ((uint8_t)0x86U) /*!< endpoint in 7 */
|
||||
|
||||
#endif /* DRV_USB_REGS_H */
|
||||
@@ -0,0 +1,52 @@
|
||||
/*!
|
||||
\file drv_usbd_int.h
|
||||
\brief USB device mode interrupt header file
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef DRV_USBD_INT_H
|
||||
#define DRV_USBD_INT_H
|
||||
|
||||
#include "drv_usb_core.h"
|
||||
#include "drv_usb_dev.h"
|
||||
|
||||
/* function declarations */
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
/* USB dedicated OUT endpoint 1 interrupt service routine handler */
|
||||
uint32_t usbd_int_dedicated_ep1out(usb_core_driver *udev);
|
||||
/* USB dedicated IN endpoint 1 interrupt service routine handler */
|
||||
uint32_t usbd_int_dedicated_ep1in(usb_core_driver *udev);
|
||||
#endif /* USB_DEDICATED_EP1_ENABLED */
|
||||
|
||||
/* USB device-mode interrupts global service routine handler */
|
||||
void usbd_isr(usb_core_driver *udev);
|
||||
|
||||
#endif /* DRV_USBD_INT_H */
|
||||
@@ -0,0 +1,55 @@
|
||||
/*!
|
||||
\file drv_usbh_int.h.h
|
||||
\brief USB host mode interrupt management header file
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef DRV_USBH_INT_H
|
||||
#define DRV_USBH_INT_H
|
||||
|
||||
#include "drv_usb_host.h"
|
||||
#include "usbh_core.h"
|
||||
|
||||
typedef struct _usbh_ev_cb {
|
||||
uint8_t (*connect)(usbh_host *uhost);
|
||||
uint8_t (*disconnect)(usbh_host *uhost);
|
||||
uint8_t (*port_enabled)(usbh_host *uhost);
|
||||
uint8_t (*port_disabled)(usbh_host *uhost);
|
||||
uint8_t (*SOF)(usbh_host *uhost);
|
||||
} usbh_ev_cb;
|
||||
|
||||
extern usbh_ev_cb *usbh_int_fop;
|
||||
|
||||
/* function declarations */
|
||||
/* handle global host interrupt */
|
||||
uint32_t usbh_isr(usb_core_driver *udev);
|
||||
|
||||
#endif /* DRV_USBH_INT_H */
|
||||
@@ -0,0 +1,414 @@
|
||||
/*!
|
||||
\file drv_usb_core.c
|
||||
\brief USB core driver which can operate in host and device mode
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "drv_usb_hw.h"
|
||||
#include "drv_usb_core.h"
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static void usb_core_reset(usb_core_regs *usb_regs);
|
||||
|
||||
/*!
|
||||
\brief configures USB parameters
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] usb_periph: USBHSx(x=0,1)
|
||||
\param[in] usb_speed: USB speed type (full-speed or high-speed)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_para_init(usb_core_driver *udev, uint32_t usb_periph, uint32_t usb_speed)
|
||||
{
|
||||
usb_core_basic *usb_basic = &udev->bp;
|
||||
|
||||
/* configure USB default transfer mode as FIFO mode */
|
||||
usb_basic->transfer_mode = (uint8_t)USB_USE_FIFO;
|
||||
|
||||
/* USB default speed is full-speed */
|
||||
usb_basic->core_speed = (uint8_t)USB_SPEED_FULL;
|
||||
|
||||
/* USB basic register address setting */
|
||||
switch(usb_periph){
|
||||
case USBHS0:
|
||||
usb_basic->base_reg = (uint32_t)USBHS0_REG_BASE;
|
||||
break;
|
||||
case USBHS1:
|
||||
usb_basic->base_reg = (uint32_t)USBHS1_REG_BASE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* set the host channel numbers */
|
||||
usb_basic->num_pipe = USBHS_MAX_CHANNEL_COUNT;
|
||||
|
||||
/* set the device endpoint numbers */
|
||||
usb_basic->num_ep = USBHS_MAX_EP_COUNT;
|
||||
|
||||
if (USB_SPEED_HIGH == usb_speed) {
|
||||
#ifdef USB_EXTERNAL_ULPI_PHY_ENABLED
|
||||
usb_basic->phy_itf = USB_ULPI_PHY_EXTERNAL;
|
||||
#endif /* USB_EXTERNAL_ULPI_PHY_ENABLED */
|
||||
|
||||
#ifdef USB_EMBEDDED_HS_PHY_ENABLED
|
||||
usb_basic->phy_itf = USB_EMBEDDED_PHY_HS;
|
||||
#endif /* USB_EMBEDDED_HS_PHY_ENABLED */
|
||||
} else if(USB_SPEED_FULL == usb_speed) {
|
||||
#ifdef USB_EMBEDDED_FS_PHY_ENABLED
|
||||
usb_basic->phy_itf = USB_EMBEDDED_PHY_FS;
|
||||
#endif /* USB_EMBEDDED_FS_PHY_ENABLED */
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
#ifdef USB_INTERNAL_DMA_ENABLED
|
||||
usb_basic->transfer_mode = USB_USE_DMA;
|
||||
#endif /* USB_INTERNAL_DMA_ENABLED */
|
||||
|
||||
usb_basic->sof_enable = (uint8_t)USB_SOF_OUTPUT;
|
||||
usb_basic->low_power = (uint8_t)USB_LOW_POWER;
|
||||
|
||||
#if (1U == LPM_ENABLED)
|
||||
usb_basic->lpm_enable = 1U;
|
||||
#endif /* LPM_ENABLED */
|
||||
}
|
||||
/*!
|
||||
\brief configure USB core basic
|
||||
\param[in] usb_basic: pointer to USB capabilities
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_basic_init (usb_core_basic *usb_basic, usb_core_regs *usb_regs)
|
||||
{
|
||||
/* assign main registers address */
|
||||
*usb_regs = (usb_core_regs) {
|
||||
.gr = (usb_gr*)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_CORE),
|
||||
.hr = (usb_hr*)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_HOST),
|
||||
.dr = (usb_dr*)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_DEV),
|
||||
|
||||
.HPCS = (uint32_t*)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_PORT),
|
||||
.PWRCLKCTL = (uint32_t*)(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_PWRCLKCTL)
|
||||
};
|
||||
|
||||
/* assign device endpoint registers address */
|
||||
for(uint8_t i = 0U; i < usb_basic->num_ep; i++) {
|
||||
usb_regs->er_in[i] = (usb_erin *) \
|
||||
(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_EP_IN + (i * (uint32_t)USB_REG_OFFSET_EP));
|
||||
|
||||
usb_regs->er_out[i] = (usb_erout *)\
|
||||
(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_EP_OUT + (i * (uint32_t)USB_REG_OFFSET_EP));
|
||||
}
|
||||
|
||||
/* assign host pipe registers address */
|
||||
for(uint8_t i = 0U; i < usb_basic->num_pipe; i++) {
|
||||
usb_regs->pr[i] = (usb_pr *) \
|
||||
(usb_basic->base_reg + (uint32_t)USB_REG_OFFSET_CH_INOUT + (i * (uint32_t)USB_REG_OFFSET_CH));
|
||||
|
||||
usb_regs->DFIFO[i] = (uint32_t *) \
|
||||
(usb_basic->base_reg + (uint32_t)USB_DATA_FIFO_OFFSET + (i * (uint32_t)USB_DATA_FIFO_SIZE));
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initializes the USB controller registers and
|
||||
prepares the core device mode or host mode operation
|
||||
\param[in] usb_basic: pointer to USB capabilities
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_core_init(usb_core_basic usb_basic, usb_core_regs *usb_regs)
|
||||
{
|
||||
if(USB_ULPI_PHY_EXTERNAL == usb_basic.phy_itf) {
|
||||
usb_regs->gr->GCCFG &= ~GCCFG_PWRON;
|
||||
|
||||
usb_regs->gr->GUSBCS &= ~(GUSBCS_EMBPHY_HS | GUSBCS_EMBPHY_FS);
|
||||
|
||||
if(usb_basic.sof_enable) {
|
||||
usb_regs->gr->GCCFG |= GCCFG_SOFOEN;
|
||||
}
|
||||
|
||||
/* initialize the ULPI interface */
|
||||
usb_regs->gr->GUSBCS &= ~GUSBCS_ULPIEOI;
|
||||
|
||||
#ifdef USBHS_EXTERNAL_VBUS_ENABLED
|
||||
/* use external VBUS driver */
|
||||
usb_regs->gr->GUSBCS |= GUSBCS_ULPIEVD;
|
||||
#else
|
||||
/* use internal VBUS driver */
|
||||
usb_regs->gr->GUSBCS &= ~GUSBCS_ULPIEVD;
|
||||
#endif /* USBHS_EXTERNAL_VBUS_ENABLED */
|
||||
|
||||
/* soft reset the core */
|
||||
usb_core_reset(usb_regs);
|
||||
} else if(USB_EMBEDDED_PHY_HS == usb_basic.phy_itf) {
|
||||
usb_regs->gr->GUSBCS |= GUSBCS_EMBPHY_HS;
|
||||
|
||||
/* soft reset the core */
|
||||
usb_core_reset(usb_regs);
|
||||
|
||||
usb_regs->gr->GCCFG = 0U;
|
||||
|
||||
#ifdef VBUS_SENSING_ENABLED
|
||||
/* active the transceiver and enable VBUS sensing */
|
||||
usb_regs->gr->GCCFG |= GCCFG_VDEN | GCCFG_PWRON;
|
||||
#else
|
||||
#ifdef USE_HOST_MODE
|
||||
usb_regs->gr->GOTGCS |= GOTGCS_AVOV | GOTGCS_AVOE;
|
||||
#endif /* USE_HOST_MODE */
|
||||
|
||||
#ifdef USE_DEVICE_MODE
|
||||
usb_regs->gr->GOTGCS |= GOTGCS_BVOV | GOTGCS_BVOE;
|
||||
#endif /* USE_DEVICE_MODE */
|
||||
|
||||
/* active the transceiver */
|
||||
usb_regs->gr->GCCFG |= GCCFG_PWRON;
|
||||
#endif /* VBUS_SENSING_ENABLED */
|
||||
|
||||
if(usb_basic.sof_enable) {
|
||||
usb_regs->gr->GCCFG |= GCCFG_SOFOEN;
|
||||
}
|
||||
|
||||
usb_mdelay(20U);
|
||||
} else if(USB_EMBEDDED_PHY_FS == usb_basic.phy_itf) {
|
||||
usb_regs->gr->GUSBCS |= GUSBCS_EMBPHY_FS;
|
||||
|
||||
/* soft reset the core */
|
||||
usb_core_reset(usb_regs);
|
||||
|
||||
#ifdef VBUS_SENSING_ENABLED
|
||||
/* active the transceiver and enable VBUS sensing */
|
||||
usb_regs->gr->GCCFG |= GCCFG_VDEN | GCCFG_PWRON;
|
||||
#else
|
||||
#ifdef USE_HOST_MODE
|
||||
usb_regs->gr->GOTGCS |= GOTGCS_AVOV | GOTGCS_AVOE;
|
||||
#endif /* USE_HOST_MODE */
|
||||
|
||||
#ifdef USE_DEVICE_MODE
|
||||
usb_regs->gr->GOTGCS |= GOTGCS_BVOV | GOTGCS_BVOE;
|
||||
#endif /* USE_DEVICE_MODE */
|
||||
|
||||
/* active the transceiver */
|
||||
usb_regs->gr->GCCFG |= GCCFG_PWRON;
|
||||
#endif /* VBUS_SENSING_ENABLED */
|
||||
|
||||
/* enable SOF output */
|
||||
if(usb_basic.sof_enable) {
|
||||
usb_regs->gr->GCCFG |= GCCFG_SOFOEN;
|
||||
}
|
||||
|
||||
usb_mdelay(20U);
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
if((uint8_t)USB_USE_DMA == usb_basic.transfer_mode) {
|
||||
usb_regs->gr->GAHBCS &= ~GAHBCS_BURST;
|
||||
usb_regs->gr->GAHBCS |= DMA_INCR8 | GAHBCS_DMAEN;
|
||||
}
|
||||
|
||||
#ifdef USE_OTG_MODE
|
||||
|
||||
/* enable USB OTG features */
|
||||
usb_regs->gr->GUSBCS |= GUSBCS_HNPCEN | GUSBCS_SRPCEN;
|
||||
|
||||
/* enable the USB wakeup and suspend interrupts */
|
||||
usb_regs->gr->GINTF = 0xBFFFFFFFU;
|
||||
|
||||
usb_regs->gr->GINTEN = GINTEN_WKUPIE | GINTEN_SPIE | \
|
||||
GINTEN_OTGIE | GINTEN_SESIE | GINTEN_IDPSCIE;
|
||||
|
||||
#endif /* USE_OTG_MODE */
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief write a packet into the TX FIFO associated with the endpoint
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[in] src_buf: pointer to source buffer
|
||||
\param[in] fifo_num: FIFO number which is in (0..5)
|
||||
\param[in] byte_count: packet byte count
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_txfifo_write(usb_core_regs *usb_regs, \
|
||||
uint8_t *src_buf, \
|
||||
uint8_t fifo_num, \
|
||||
uint16_t byte_count)
|
||||
{
|
||||
uint32_t word_count = (byte_count + 3U) / 4U;
|
||||
|
||||
__IO uint32_t *fifo = usb_regs->DFIFO[fifo_num];
|
||||
|
||||
while(word_count-- > 0U) {
|
||||
*fifo = *((__IO uint32_t *)src_buf);
|
||||
|
||||
src_buf += 4U;
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read a packet from the Rx FIFO associated with the endpoint
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[in] dest_buf: pointer to destination buffer
|
||||
\param[in] byte_count: packet byte count
|
||||
\param[out] none
|
||||
\retval void type pointer
|
||||
*/
|
||||
void *usb_rxfifo_read(usb_core_regs *usb_regs, uint8_t *dest_buf, uint16_t byte_count)
|
||||
{
|
||||
__IO uint32_t word_count = (byte_count + 3U) / 4U;
|
||||
__IO uint32_t *fifo = usb_regs->DFIFO[0];
|
||||
|
||||
while(word_count-- > 0U) {
|
||||
*(__IO uint32_t *)dest_buf = *fifo;
|
||||
|
||||
dest_buf += 4U;
|
||||
}
|
||||
|
||||
return ((void *)dest_buf);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief flush a TX FIFO or all TX FIFOs
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[in] fifo_num: FIFO number which is in (0..5)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_txfifo_flush(usb_core_regs *usb_regs, uint8_t fifo_num)
|
||||
{
|
||||
usb_regs->gr->GRSTCTL = ((uint32_t)fifo_num << 6) | GRSTCTL_TXFF;
|
||||
|
||||
/* wait for TX FIFO flush bit is set */
|
||||
while(usb_regs->gr->GRSTCTL & GRSTCTL_TXFF) {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
/* wait for 3 PHY clocks*/
|
||||
usb_udelay(3U);
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief flush the entire RX FIFO
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_rxfifo_flush(usb_core_regs *usb_regs)
|
||||
{
|
||||
usb_regs->gr->GRSTCTL = GRSTCTL_RXFF;
|
||||
|
||||
/* wait for RX FIFO flush bit is set */
|
||||
while(usb_regs->gr->GRSTCTL & GRSTCTL_RXFF) {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
/* wait for 3 PHY clocks */
|
||||
usb_udelay(3U);
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set endpoint or channel TX FIFO size
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[in] fifo: TX FIFO number
|
||||
\param[in] size: assigned TX FIFO size
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_set_txfifo(usb_core_regs *usb_regs, uint8_t fifo, uint16_t size)
|
||||
{
|
||||
uint32_t tx_offset = usb_regs->gr->GRFLEN;
|
||||
|
||||
if(0U == fifo) {
|
||||
usb_regs->gr->DIEP0TFLEN_HNPTFLEN = ((uint32_t)size << 16) | tx_offset;
|
||||
} else {
|
||||
tx_offset += (usb_regs->gr->DIEP0TFLEN_HNPTFLEN) >> 16;
|
||||
|
||||
for(uint8_t i = 0U; i < (fifo - 1U); i++) {
|
||||
tx_offset += (usb_regs->gr->DIEPTFLEN[i] >> 16);
|
||||
}
|
||||
|
||||
usb_regs->gr->DIEPTFLEN[fifo - 1U] = ((uint32_t)size << 16) | tx_offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set USB current mode
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[in] mode: USB current mode
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_curmode_set(usb_core_regs *usb_regs, uint8_t mode)
|
||||
{
|
||||
usb_regs->gr->GUSBCS &= ~(GUSBCS_FDM | GUSBCS_FHM);
|
||||
|
||||
if(DEVICE_MODE == mode) {
|
||||
usb_regs->gr->GUSBCS |= GUSBCS_FDM;
|
||||
} else if(HOST_MODE == mode) {
|
||||
usb_regs->gr->GUSBCS |= GUSBCS_FHM;
|
||||
} else {
|
||||
/* OTG mode and other mode can not be here! */
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure USB core to soft reset
|
||||
\param[in] usb_regs: pointer to USB core registers
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void usb_core_reset(usb_core_regs *usb_regs)
|
||||
{
|
||||
/* enable core soft reset */
|
||||
usb_regs->gr->GRSTCTL |= GRSTCTL_CSRST;
|
||||
|
||||
/* wait for the core to be soft reset */
|
||||
while(usb_regs->gr->GRSTCTL & GRSTCTL_CSRST) {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
/* wait for additional 3 PHY clocks */
|
||||
usb_udelay(3U);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,688 @@
|
||||
/*!
|
||||
\file drv_usb_dev.c
|
||||
\brief USB device mode low level driver
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "drv_usb_hw.h"
|
||||
#include "drv_usb_dev.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* endpoint 0 max packet length */
|
||||
static const uint8_t EP0_MAXLEN[4] = {
|
||||
[DSTAT_EM_HS_PHY_30MHZ_60MHZ] = EP0MPL_64,
|
||||
[DSTAT_EM_FS_PHY_30MHZ_60MHZ] = EP0MPL_64,
|
||||
[DSTAT_EM_FS_PHY_48MHZ] = EP0MPL_64,
|
||||
[DSTAT_EM_LS_PHY_6MHZ] = EP0MPL_8
|
||||
};
|
||||
|
||||
/* USB endpoint TX FIFO size */
|
||||
static uint16_t USBHS_TX_FIFO_SIZE[USBHS_MAX_EP_COUNT] = {
|
||||
(uint16_t)TX0_FIFO_SIZE,
|
||||
(uint16_t)TX1_FIFO_SIZE,
|
||||
(uint16_t)TX2_FIFO_SIZE,
|
||||
(uint16_t)TX3_FIFO_SIZE,
|
||||
(uint16_t)TX4_FIFO_SIZE,
|
||||
(uint16_t)TX5_FIFO_SIZE,
|
||||
(uint16_t)TX6_FIFO_SIZE,
|
||||
(uint16_t)TX7_FIFO_SIZE,
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief initialize USB core registers for device mode
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_devcore_init(usb_core_driver *udev)
|
||||
{
|
||||
uint8_t i = 0U;
|
||||
|
||||
/* restart the PHY clock (maybe don't need to...) */
|
||||
*udev->regs.PWRCLKCTL = 0U;
|
||||
|
||||
/* configure periodic frame interval to default value */
|
||||
udev->regs.dr->DCFG &= ~DCFG_EOPFT;
|
||||
udev->regs.dr->DCFG |= FRAME_INTERVAL_80;
|
||||
|
||||
udev->regs.dr->DCFG &= ~DCFG_DS;
|
||||
|
||||
if(USB_EMBEDDED_PHY_HS == udev->bp.phy_itf) {
|
||||
udev->regs.dr->DCFG |= USB_SPEED_INP_HIGH;
|
||||
} else if(USB_EMBEDDED_PHY_FS == udev->bp.phy_itf) {
|
||||
udev->regs.dr->DCFG |= USB_SPEED_INP_FULL;
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
/* set RX FIFO size */
|
||||
usb_set_rxfifo(&udev->regs, (uint16_t)RX_FIFO_SIZE);
|
||||
|
||||
/* set endpoint 0 to 3's TX FIFO length and RAM address */
|
||||
for(i = 0U; i < USBHS_MAX_EP_COUNT; i++) {
|
||||
usb_set_txfifo(&udev->regs, i, USBHS_TX_FIFO_SIZE[i]);
|
||||
}
|
||||
|
||||
/* make sure all FIFOs are flushed */
|
||||
|
||||
/* flush all TX FIFOs */
|
||||
(void)usb_txfifo_flush(&udev->regs, 0x10U);
|
||||
|
||||
/* flush entire RX FIFO */
|
||||
(void)usb_rxfifo_flush(&udev->regs);
|
||||
|
||||
/* clear all pending device interrupts */
|
||||
udev->regs.dr->DIEPINTEN = 0U;
|
||||
udev->regs.dr->DOEPINTEN = 0U;
|
||||
udev->regs.dr->DAEPINT = 0xFFFFFFFFU;
|
||||
udev->regs.dr->DAEPINTEN = 0U;
|
||||
|
||||
/* configure all IN/OUT endpoints */
|
||||
for(i = 0U; i < udev->bp.num_ep; i++) {
|
||||
if(udev->regs.er_in[i]->DIEPCTL & DEPCTL_EPEN) {
|
||||
udev->regs.er_in[i]->DIEPCTL |= DEPCTL_EPD | DEPCTL_SNAK;
|
||||
} else {
|
||||
udev->regs.er_in[i]->DIEPCTL = 0U;
|
||||
}
|
||||
|
||||
/* set IN endpoint transfer length to 0 */
|
||||
udev->regs.er_in[i]->DIEPLEN = 0U;
|
||||
|
||||
/* clear all pending IN endpoint interrupts */
|
||||
udev->regs.er_in[i]->DIEPINTF = 0xFFU;
|
||||
|
||||
if(udev->regs.er_out[i]->DOEPCTL & DEPCTL_EPEN) {
|
||||
udev->regs.er_out[i]->DOEPCTL |= DEPCTL_EPD | DEPCTL_SNAK;
|
||||
} else {
|
||||
udev->regs.er_out[i]->DOEPCTL = 0U;
|
||||
}
|
||||
|
||||
/* set OUT endpoint transfer length to 0 */
|
||||
udev->regs.er_out[i]->DOEPLEN = 0U;
|
||||
|
||||
/* clear all pending OUT endpoint interrupts */
|
||||
udev->regs.er_out[i]->DOEPINTF = 0xFFU;
|
||||
}
|
||||
|
||||
udev->regs.dr->DIEPINTEN |= DIEPINTEN_EPTXFUDEN;
|
||||
|
||||
(void)usb_devint_enable(udev);
|
||||
|
||||
/* configure LPM function */
|
||||
if(1U == udev->bp.lpm_enable) {
|
||||
udev->dev.pm.lpm_state = LPM_L0;
|
||||
udev->regs.gr->GLPMCFG = GLPMCFG_LPMEN | GLPMCFG_ACKLPM | GLPMCFG_BESLEN;
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable the USB device mode interrupts
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_devint_enable(usb_core_driver *udev)
|
||||
{
|
||||
/* clear any pending USB OTG interrupts */
|
||||
udev->regs.gr->GOTGINTF = 0xFFFFFFFFU;
|
||||
|
||||
/* clear any pending interrupts */
|
||||
udev->regs.gr->GINTF = 0xBFFFFFFFU;
|
||||
|
||||
/* enable the USB wakeup and suspend interrupts */
|
||||
udev->regs.gr->GINTEN = GINTEN_WKUPIE | GINTEN_SPIE;
|
||||
|
||||
/* enable device_mode-related interrupts */
|
||||
if((uint8_t)USB_USE_FIFO == udev->bp.transfer_mode) {
|
||||
udev->regs.gr->GINTEN |= GINTEN_RXFNEIE;
|
||||
}
|
||||
|
||||
udev->regs.gr->GINTEN |= GINTEN_RSTIE | GINTEN_ENUMFIE | GINTEN_IEPIE |\
|
||||
GINTEN_OEPIE | GINTEN_SOFIE | GINTEN_ISOONCIE | GINTEN_ISOINCIE;
|
||||
|
||||
#ifdef VBUS_SENSING_ENABLED
|
||||
udev->regs.gr->GINTEN |= GINTEN_SESIE | GINTEN_OTGIE;
|
||||
#endif /* VBUS_SENSING_ENABLED */
|
||||
|
||||
if(1U == udev->bp.lpm_enable) {
|
||||
udev->regs.gr->GINTEN |= GINTEN_LPMIE;
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief active the USB endpoint0 transaction
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB endpoint0 transaction
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_transc0_active(usb_core_driver *udev, usb_transc *transc)
|
||||
{
|
||||
__IO uint32_t *reg_addr = NULL;
|
||||
|
||||
uint32_t enum_speed = udev->regs.dr->DSTAT & DSTAT_ES;
|
||||
|
||||
/* get the endpoint number */
|
||||
uint8_t ep_num = transc->ep_addr.num;
|
||||
|
||||
if(ep_num) {
|
||||
/* not endpoint 0 */
|
||||
return USB_FAIL;
|
||||
}
|
||||
|
||||
if(transc->ep_addr.dir) {
|
||||
reg_addr = &udev->regs.er_in[0]->DIEPCTL;
|
||||
} else {
|
||||
reg_addr = &udev->regs.er_out[0]->DOEPCTL;
|
||||
}
|
||||
|
||||
/* endpoint 0 is activated after USB clock is enabled */
|
||||
*reg_addr &= ~(DEPCTL_MPL | DEPCTL_EPTYPE | DIEPCTL_TXFNUM);
|
||||
|
||||
/* set endpoint 0 maximum packet length */
|
||||
*reg_addr |= EP0_MAXLEN[enum_speed];
|
||||
|
||||
/* activate endpoint */
|
||||
*reg_addr |= ((uint32_t)transc->ep_type << 18) | ((uint32_t)ep_num << 22) | DEPCTL_SD0PID | DEPCTL_EPACT;
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief active the USB transaction
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB transaction
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
usb_status usb_transc_active(usb_core_driver *udev, usb_transc *transc)
|
||||
{
|
||||
__IO uint32_t *reg_addr = NULL;
|
||||
uint32_t epinten = 0U;
|
||||
uint32_t enum_speed = udev->regs.dr->DSTAT & DSTAT_ES;
|
||||
|
||||
/* get the endpoint number */
|
||||
uint8_t ep_num = transc->ep_addr.num;
|
||||
|
||||
/* enable endpoint interrupt number */
|
||||
if(transc->ep_addr.dir) {
|
||||
reg_addr = &udev->regs.er_in[ep_num]->DIEPCTL;
|
||||
|
||||
epinten = 1U << ep_num;
|
||||
} else {
|
||||
reg_addr = &udev->regs.er_out[ep_num]->DOEPCTL;
|
||||
|
||||
epinten = 1U << (16U + ep_num);
|
||||
}
|
||||
|
||||
/* if the endpoint is not active, need change the endpoint control register */
|
||||
if(!(*reg_addr & DEPCTL_EPACT)) {
|
||||
*reg_addr &= ~(DEPCTL_MPL | DEPCTL_EPTYPE | DIEPCTL_TXFNUM);
|
||||
|
||||
/* set endpoint maximum packet length */
|
||||
if(0U == ep_num) {
|
||||
*reg_addr |= EP0_MAXLEN[enum_speed];
|
||||
} else {
|
||||
*reg_addr |= transc->max_len;
|
||||
}
|
||||
|
||||
/* activate endpoint */
|
||||
*reg_addr |= ((uint32_t)transc->ep_type << 18) | ((uint32_t)ep_num << 22) | DEPCTL_SD0PID | DEPCTL_EPACT;
|
||||
}
|
||||
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
if (1U == ep_num) {
|
||||
udev->regs.dr->DEP1INTEN |= epinten;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* enable the interrupts for this endpoint */
|
||||
udev->regs.dr->DAEPINTEN |= epinten;
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief deactivate the USB transaction
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB transaction
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
usb_status usb_transc_deactivate(usb_core_driver *udev, usb_transc *transc)
|
||||
{
|
||||
uint32_t epinten = 0U;
|
||||
|
||||
uint8_t ep_num = transc->ep_addr.num;
|
||||
|
||||
/* disable endpoint interrupt number */
|
||||
if(transc->ep_addr.dir) {
|
||||
epinten = 1U << ep_num;
|
||||
|
||||
udev->regs.er_in[ep_num]->DIEPCTL &= ~DEPCTL_EPACT;
|
||||
} else {
|
||||
epinten = 1U << (ep_num + 16U);
|
||||
|
||||
udev->regs.er_out[ep_num]->DOEPCTL &= ~DEPCTL_EPACT;
|
||||
}
|
||||
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
if (1U == ep_num) {
|
||||
udev->regs.dr->DEP1INTEN &= ~epinten;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* disable the interrupts for this endpoint */
|
||||
udev->regs.dr->DAEPINTEN &= ~epinten;
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure USB transaction to start IN transfer
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB IN transaction
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_transc_inxfer(usb_core_driver *udev, usb_transc *transc)
|
||||
{
|
||||
usb_status status = USB_OK;
|
||||
uint8_t ep_num = transc->ep_addr.num;
|
||||
|
||||
uint32_t epctl = udev->regs.er_in[ep_num]->DIEPCTL;
|
||||
uint32_t eplen = udev->regs.er_in[ep_num]->DIEPLEN;
|
||||
|
||||
eplen &= ~(DEPLEN_TLEN | DEPLEN_PCNT);
|
||||
|
||||
/* zero length packet or endpoint 0 */
|
||||
if(0U == transc->xfer_len) {
|
||||
/* set transfer packet count to 1 */
|
||||
eplen |= 1U << 19;
|
||||
} else {
|
||||
/* set transfer packet count */
|
||||
if(0U == ep_num) {
|
||||
transc->xfer_len = USB_MIN(transc->xfer_len, transc->max_len);
|
||||
|
||||
eplen |= 1U << 19;
|
||||
} else {
|
||||
eplen |= (((transc->xfer_len - 1U) + transc->max_len) / transc->max_len) << 19;
|
||||
}
|
||||
|
||||
/* set endpoint transfer length */
|
||||
eplen |= transc->xfer_len;
|
||||
|
||||
if((uint8_t)USB_EPTYPE_ISOC == transc->ep_type) {
|
||||
eplen |= DIEPLEN_MCNT & (1U << 29);
|
||||
}
|
||||
}
|
||||
|
||||
udev->regs.er_in[ep_num]->DIEPLEN = eplen;
|
||||
|
||||
if((uint8_t)USB_EPTYPE_ISOC == transc->ep_type) {
|
||||
if(((udev->regs.dr->DSTAT & DSTAT_FNRSOF) >> 8) & 0x01U) {
|
||||
epctl |= DEPCTL_SEVNFRM;
|
||||
} else {
|
||||
epctl |= DEPCTL_SODDFRM;
|
||||
}
|
||||
}
|
||||
|
||||
if((uint8_t)USB_USE_DMA == udev->bp.transfer_mode) {
|
||||
udev->regs.er_in[ep_num]->DIEPDMAADDR = transc->dma_addr;
|
||||
}
|
||||
|
||||
/* enable the endpoint and clear the NAK */
|
||||
epctl |= DEPCTL_CNAK | DEPCTL_EPEN;
|
||||
|
||||
udev->regs.er_in[ep_num]->DIEPCTL = epctl;
|
||||
|
||||
if((uint8_t)USB_USE_FIFO == udev->bp.transfer_mode) {
|
||||
if((uint8_t)USB_EPTYPE_ISOC != transc->ep_type) {
|
||||
/* enable the TX FIFO empty interrupt for this endpoint */
|
||||
if(transc->xfer_len > 0U) {
|
||||
udev->regs.dr->DIEPFEINTEN |= 1U << ep_num;
|
||||
}
|
||||
} else {
|
||||
(void)usb_txfifo_write(&udev->regs, transc->xfer_buf, ep_num, (uint16_t)transc->xfer_len);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure USB transaction to start OUT transfer
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB OUT transaction
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
usb_status usb_transc_outxfer(usb_core_driver *udev, usb_transc *transc)
|
||||
{
|
||||
usb_status status = USB_OK;
|
||||
|
||||
__IO uint8_t ep_num = transc->ep_addr.num;
|
||||
|
||||
uint32_t epctl = udev->regs.er_out[ep_num]->DOEPCTL;
|
||||
uint32_t eplen = udev->regs.er_out[ep_num]->DOEPLEN;
|
||||
|
||||
eplen &= ~(DEPLEN_TLEN | DEPLEN_PCNT);
|
||||
|
||||
/* zero length packet or endpoint 0 */
|
||||
if((0U == transc->xfer_len) || (0U == ep_num)) {
|
||||
/* set the transfer length to max packet size */
|
||||
eplen |= transc->max_len;
|
||||
|
||||
/* set the transfer packet count to 1 */
|
||||
eplen |= 1U << 19;
|
||||
} else {
|
||||
/* configure the transfer size and packet count as follows:
|
||||
* pktcnt = N
|
||||
* xfersize = N * maxpacket
|
||||
*/
|
||||
uint32_t packet_count = (transc->xfer_len + transc->max_len - 1U) / transc->max_len;
|
||||
|
||||
eplen |= packet_count << 19;
|
||||
eplen |= packet_count * transc->max_len;
|
||||
}
|
||||
|
||||
udev->regs.er_out[ep_num]->DOEPLEN = eplen;
|
||||
|
||||
if((uint8_t)USB_USE_DMA == udev->bp.transfer_mode) {
|
||||
udev->regs.er_out[ep_num]->DOEPDMAADDR = transc->dma_addr;
|
||||
}
|
||||
|
||||
if((uint8_t)USB_EPTYPE_ISOC == transc->ep_type) {
|
||||
if(transc->frame_num) {
|
||||
epctl |= DEPCTL_SD1PID;
|
||||
} else {
|
||||
epctl |= DEPCTL_SD0PID;
|
||||
}
|
||||
}
|
||||
|
||||
/* enable the endpoint and clear the NAK */
|
||||
epctl |= DEPCTL_EPEN | DEPCTL_CNAK;
|
||||
|
||||
udev->regs.er_out[ep_num]->DOEPCTL = epctl;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set the USB transaction STALL status
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB transaction
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
usb_status usb_transc_stall(usb_core_driver *udev, usb_transc *transc)
|
||||
{
|
||||
__IO uint32_t *reg_addr = NULL;
|
||||
|
||||
uint8_t ep_num = transc->ep_addr.num;
|
||||
|
||||
if(transc->ep_addr.dir) {
|
||||
reg_addr = &(udev->regs.er_in[ep_num]->DIEPCTL);
|
||||
|
||||
/* set the endpoint disable bit */
|
||||
if(*reg_addr & DEPCTL_EPEN) {
|
||||
*reg_addr |= DEPCTL_EPD;
|
||||
}
|
||||
} else {
|
||||
/* set the endpoint STALL bit */
|
||||
reg_addr = &(udev->regs.er_out[ep_num]->DOEPCTL);
|
||||
}
|
||||
|
||||
/* set the endpoint STALL bit */
|
||||
*reg_addr |= DEPCTL_STALL;
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear the USB transaction STALL status
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] transc: the USB transaction
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_transc_clrstall(usb_core_driver *udev, usb_transc *transc)
|
||||
{
|
||||
__IO uint32_t *reg_addr = NULL;
|
||||
|
||||
uint8_t ep_num = transc->ep_addr.num;
|
||||
|
||||
if(transc->ep_addr.dir) {
|
||||
reg_addr = &(udev->regs.er_in[ep_num]->DIEPCTL);
|
||||
} else {
|
||||
reg_addr = &(udev->regs.er_out[ep_num]->DOEPCTL);
|
||||
}
|
||||
|
||||
/* clear the endpoint STALL bit */
|
||||
*reg_addr &= ~DEPCTL_STALL;
|
||||
|
||||
/* reset data PID of the periodic endpoints */
|
||||
if(((uint8_t)USB_EPTYPE_INTR == transc->ep_type) || ((uint8_t)USB_EPTYPE_BULK == transc->ep_type)) {
|
||||
*reg_addr |= DEPCTL_SD0PID;
|
||||
}
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read device IN endpoint interrupt flag register
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] ep_num: endpoint number
|
||||
\param[out] none
|
||||
\retval interrupt value
|
||||
*/
|
||||
uint32_t usb_iepintr_read(usb_core_driver *udev, uint8_t ep_num)
|
||||
{
|
||||
__IO uint32_t value = 0U;
|
||||
uint32_t fifoemptymask, commonintmask;
|
||||
|
||||
commonintmask = udev->regs.dr->DIEPINTEN;
|
||||
fifoemptymask = udev->regs.dr->DIEPFEINTEN;
|
||||
|
||||
/* check FIFO empty interrupt enable bit */
|
||||
commonintmask |= ((fifoemptymask >> ep_num) & 0x1U) << 7;
|
||||
|
||||
value = udev->regs.er_in[ep_num]->DIEPINTF & commonintmask;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configures OUT endpoint 0 to receive SETUP packets
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_ctlep_startout(usb_core_driver *udev)
|
||||
{
|
||||
/* set OUT endpoint 0 receive length to 24 bytes, 1 packet and 3 SETUP packets */
|
||||
udev->regs.er_out[0]->DOEPLEN = DOEP0_TLEN(8U * 3U) | DOEP0_PCNT(1U) | DOEP0_STPCNT(3U);
|
||||
|
||||
if((uint8_t)USB_USE_DMA == udev->bp.transfer_mode) {
|
||||
udev->regs.er_out[0]->DOEPDMAADDR = (uint32_t)&udev->dev.control.req;
|
||||
|
||||
/* endpoint enable */
|
||||
udev->regs.er_out[0]->DOEPCTL |= DEPCTL_EPACT | DEPCTL_EPEN;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief active remote wakeup signaling
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_rwkup_active(usb_core_driver *udev)
|
||||
{
|
||||
if(udev->dev.pm.dev_remote_wakeup) {
|
||||
if(udev->regs.dr->DSTAT & DSTAT_SPST) {
|
||||
if(udev->bp.low_power) {
|
||||
/* ungate USB core clock */
|
||||
*udev->regs.PWRCLKCTL &= ~(PWRCLKCTL_SHCLK | PWRCLKCTL_SUCLK);
|
||||
}
|
||||
|
||||
/* active remote wakeup signaling */
|
||||
udev->regs.dr->DCTL |= DCTL_RWKUP;
|
||||
|
||||
usb_mdelay(5U);
|
||||
|
||||
udev->regs.dr->DCTL &= ~DCTL_RWKUP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief active USB core clock
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_clock_active(usb_core_driver *udev)
|
||||
{
|
||||
if(udev->bp.low_power) {
|
||||
if(udev->regs.dr->DSTAT & DSTAT_SPST) {
|
||||
/* un-gate USB Core clock */
|
||||
*udev->regs.PWRCLKCTL &= ~(PWRCLKCTL_SHCLK | PWRCLKCTL_SUCLK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB device suspend
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_dev_suspend(usb_core_driver *udev)
|
||||
{
|
||||
__IO uint32_t devstat = udev->regs.dr->DSTAT;
|
||||
|
||||
if((devstat & DSTAT_SPST) && (udev->bp.low_power)) {
|
||||
/* switch-off the USB clocks */
|
||||
*udev->regs.PWRCLKCTL |= PWRCLKCTL_SHCLK;
|
||||
|
||||
/* enter DEEP_SLEEP mode with LDO in low power mode */
|
||||
pmu_to_deepsleepmode(WFI_CMD);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief stop the device and clean up FIFOs
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_dev_stop(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
udev->dev.cur_status = 1U;
|
||||
|
||||
/* clear all interrupt flag and enable bits */
|
||||
for(i = 0U; i < udev->bp.num_ep; i++) {
|
||||
udev->regs.er_in[i]->DIEPINTF = 0xFFU;
|
||||
udev->regs.er_out[i]->DOEPINTF = 0xFFU;
|
||||
}
|
||||
|
||||
udev->regs.dr->DIEPINTEN = 0U;
|
||||
udev->regs.dr->DOEPINTEN = 0U;
|
||||
udev->regs.dr->DAEPINTEN = 0U;
|
||||
udev->regs.dr->DAEPINT = 0xFFFFFFFFU;
|
||||
|
||||
/* flush the FIFO */
|
||||
(void)usb_rxfifo_flush(&udev->regs);
|
||||
(void)usb_txfifo_flush(&udev->regs, 0x10U);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief usb battery charging detect operation
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval bcd type
|
||||
*/
|
||||
bcd_type usbd_bcd_detect(usb_core_driver *udev)
|
||||
{
|
||||
udev->regs.gr->GCCFG |= GCCFG_DCDEN;
|
||||
|
||||
usb_mdelay(1000U);
|
||||
|
||||
if(0U == (udev->regs.gr->GCCFG & GCCFG_DCDF)) {
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_DCDEN;
|
||||
|
||||
return BCD_ERROR;
|
||||
}
|
||||
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_DCDEN;
|
||||
usb_mdelay(20U);
|
||||
udev->regs.gr->GCCFG |= GCCFG_PEMEN;
|
||||
usb_mdelay(50U);
|
||||
|
||||
if(udev->regs.gr->GCCFG & GCCFG_PDF) {
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_PEMEN;
|
||||
usb_mdelay(20U);
|
||||
udev->regs.gr->GCCFG |= GCCFG_SDMEN;
|
||||
usb_mdelay(50U);
|
||||
|
||||
if(udev->regs.gr->GCCFG & GCCFG_SDF) {
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_SDMEN;
|
||||
usb_mdelay(20U);
|
||||
|
||||
return BCD_DCP;
|
||||
} else {
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_SDMEN;
|
||||
usb_mdelay(20U);
|
||||
|
||||
return BCD_CDP;
|
||||
}
|
||||
} else if(udev->regs.gr->GCCFG & GCCFG_PS2F) {
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_PEMEN;
|
||||
usb_mdelay(20U);
|
||||
|
||||
return BCD_PS2;
|
||||
} else {
|
||||
udev->regs.gr->GCCFG &= ~GCCFG_PEMEN;
|
||||
usb_mdelay(20U);
|
||||
|
||||
return BCD_SDP;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
/*!
|
||||
\file drv_usb_host.c
|
||||
\brief USB host mode low level driver
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "drv_usb_hw.h"
|
||||
#include "drv_usb_host.h"
|
||||
|
||||
const uint32_t PIPE_DPID[2] = {
|
||||
PIPE_DPID_DATA0,
|
||||
PIPE_DPID_DATA1
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief initializes USB core for host mode
|
||||
\param[in] udev: pointer to selected USB host
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_host_init(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t i = 0U, inten = 0U;
|
||||
|
||||
uint32_t nptxfifolen = 0U;
|
||||
uint32_t ptxfifolen = 0U;
|
||||
|
||||
/* restart the PHY Clock */
|
||||
*udev->regs.PWRCLKCTL = 0U;
|
||||
|
||||
/* support HS, FS and LS */
|
||||
udev->regs.hr->HCTL &= ~HCTL_SPDFSLS;
|
||||
|
||||
/* set RX FIFO size */
|
||||
udev->regs.gr->GRFLEN = USB_RX_FIFO_SIZE;
|
||||
|
||||
/* set non-periodic TX FIFO size and address */
|
||||
nptxfifolen |= USB_RX_FIFO_SIZE;
|
||||
nptxfifolen |= USB_HTX_NPFIFO_SIZE << 16;
|
||||
udev->regs.gr->DIEP0TFLEN_HNPTFLEN = nptxfifolen;
|
||||
|
||||
/* set periodic TX FIFO size and address */
|
||||
ptxfifolen |= USB_RX_FIFO_SIZE + USB_HTX_PFIFO_SIZE;
|
||||
ptxfifolen |= USB_HTX_PFIFO_SIZE << 16;
|
||||
udev->regs.gr->HPTFLEN = ptxfifolen;
|
||||
|
||||
#ifdef USE_OTG_MODE
|
||||
/* clear host set HNP enable in the usb_otg control register */
|
||||
udev->regs.gr->GOTGCS &= ~GOTGCS_HHNPEN;
|
||||
#endif /* USE_OTG_MODE */
|
||||
|
||||
/* make sure the FIFOs are flushed */
|
||||
|
||||
/* flush all TX FIFOs in device or host mode */
|
||||
usb_txfifo_flush(&udev->regs, 0x10U);
|
||||
|
||||
/* flush the entire RX FIFO */
|
||||
usb_rxfifo_flush(&udev->regs);
|
||||
|
||||
/* disable all interrupts */
|
||||
udev->regs.gr->GINTEN = 0U;
|
||||
|
||||
/* clear any pending USB OTG interrupts */
|
||||
udev->regs.gr->GOTGINTF = 0xFFFFFFFFU;
|
||||
|
||||
/* enable the USB wakeup and suspend interrupts */
|
||||
udev->regs.gr->GINTF = 0xBFFFFFFFU;
|
||||
|
||||
/* clear all pending host channel interrupts */
|
||||
for(i = 0U; i < udev->bp.num_pipe; i++) {
|
||||
udev->regs.pr[i]->HCHINTF = 0xFFFFFFFFU;
|
||||
udev->regs.pr[i]->HCHINTEN = 0U;
|
||||
}
|
||||
|
||||
#ifndef USE_OTG_MODE
|
||||
usb_portvbus_switch(udev, 1U);
|
||||
#endif /* USE_OTG_MODE */
|
||||
|
||||
udev->regs.gr->GINTEN = GINTEN_WKUPIE | GINTEN_SPIE;
|
||||
|
||||
/* enable host_mode-related interrupts */
|
||||
if(USB_USE_FIFO == udev->bp.transfer_mode) {
|
||||
inten = GINTEN_RXFNEIE;
|
||||
}
|
||||
|
||||
/* configure USBHS interrupts */
|
||||
inten |= GINTEN_HPIE | GINTEN_HCIE | GINTEN_ISOINCIE;
|
||||
udev->regs.gr->GINTEN |= inten;
|
||||
|
||||
inten = GINTEN_DISCIE | GINTEN_SOFIE;
|
||||
udev->regs.gr->GINTEN &= ~inten;
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief control the VBUS to power
|
||||
\param[in] udev: pointer to selected USB host
|
||||
\param[in] state: VBUS state
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_portvbus_switch(usb_core_driver *udev, uint8_t state)
|
||||
{
|
||||
uint32_t port = 0U;
|
||||
|
||||
/* enable or disable the external charge pump */
|
||||
usb_vbus_drive(state);
|
||||
|
||||
/* turn on the host port power. */
|
||||
port = usb_port_read(udev);
|
||||
|
||||
if((!(port & HPCS_PP)) && (1U == state)) {
|
||||
port |= HPCS_PP;
|
||||
}
|
||||
|
||||
if((port & HPCS_PP) && (0U == state)) {
|
||||
port &= ~HPCS_PP;
|
||||
}
|
||||
|
||||
*udev->regs.HPCS = port;
|
||||
|
||||
usb_mdelay(200U);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reset host port
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint32_t usb_port_reset(usb_core_driver *udev)
|
||||
{
|
||||
__IO uint32_t port = usb_port_read(udev);
|
||||
|
||||
*udev->regs.HPCS = port | HPCS_PRST;
|
||||
|
||||
usb_mdelay(20U); /* see note */
|
||||
|
||||
*udev->regs.HPCS = port & ~HPCS_PRST;
|
||||
|
||||
usb_mdelay(20U);
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize host pipe
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] pipe_num: host pipe number which is in (0..7)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_pipe_init(usb_core_driver *udev, uint8_t pipe_num)
|
||||
{
|
||||
usb_status status = USB_OK;
|
||||
|
||||
__IO uint32_t pp_ctl = 0U;
|
||||
__IO uint32_t pp_inten = HCHINTEN_TFIE;
|
||||
|
||||
usb_pipe *pp = &udev->host.pipe[pipe_num];
|
||||
|
||||
/* clear old interrupt conditions for this host channel */
|
||||
udev->regs.pr[pipe_num]->HCHINTF = 0xFFFFFFFFU;
|
||||
|
||||
if(USB_USE_DMA == udev->bp.transfer_mode) {
|
||||
pp_inten |= HCHINTEN_DMAERIE;
|
||||
}
|
||||
|
||||
if(pp->ep.dir) {
|
||||
pp_inten |= HCHINTEN_BBERIE;
|
||||
}
|
||||
|
||||
/* enable channel interrupts required for this transfer */
|
||||
switch(pp->ep.type) {
|
||||
case USB_EPTYPE_CTRL:
|
||||
case USB_EPTYPE_BULK:
|
||||
pp_inten |= HCHINTEN_STALLIE | HCHINTEN_USBERIE \
|
||||
| HCHINTEN_DTERIE | HCHINTEN_NAKIE;
|
||||
|
||||
if(!pp->ep.dir) {
|
||||
if(PORT_SPEED_HIGH == pp->dev_speed) {
|
||||
pp_inten |= HCHINTEN_NYETIE;
|
||||
pp_inten |= HCHINTEN_ACKIE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_INTR:
|
||||
pp_inten |= HCHINTEN_STALLIE | HCHINTEN_USBERIE | HCHINTEN_DTERIE \
|
||||
| HCHINTEN_NAKIE | HCHINTEN_REQOVRIE;
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_ISOC:
|
||||
pp_inten |= HCHINTEN_REQOVRIE | HCHINTEN_ACKIE;
|
||||
|
||||
if(pp->ep.dir) {
|
||||
pp_inten |= HCHINTEN_USBERIE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
udev->regs.pr[pipe_num]->HCHINTEN = pp_inten;
|
||||
|
||||
/* enable the top level host channel interrupt */
|
||||
udev->regs.hr->HACHINTEN |= 1U << pipe_num;
|
||||
|
||||
/* make sure host channel interrupts are enabled */
|
||||
udev->regs.gr->GINTEN |= GINTEN_HCIE;
|
||||
|
||||
/* program the host channel control register */
|
||||
pp_ctl |= PIPE_CTL_DAR(pp->dev_addr);
|
||||
pp_ctl |= PIPE_CTL_EPNUM(pp->ep.num);
|
||||
pp_ctl |= PIPE_CTL_EPDIR(pp->ep.dir);
|
||||
pp_ctl |= PIPE_CTL_EPTYPE(pp->ep.type);
|
||||
pp_ctl |= PIPE_CTL_LSD(PORT_SPEED_LOW == pp->dev_speed);
|
||||
|
||||
pp_ctl |= pp->ep.mps;
|
||||
pp_ctl |= ((uint32_t)(USB_EPTYPE_INTR == pp->ep.type) << 29) & HCHCTL_ODDFRM;
|
||||
|
||||
udev->regs.pr[pipe_num]->HCHCTL = pp_ctl;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief prepare host channel for transferring packets
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] pipe_num: host pipe number which is in (0..7)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_pipe_xfer(usb_core_driver *udev, uint8_t pipe_num)
|
||||
{
|
||||
usb_status status = USB_OK;
|
||||
|
||||
uint16_t dword_len = 0U;
|
||||
uint16_t packet_count = 0U;
|
||||
|
||||
__IO uint32_t pp_ctl = 0U;
|
||||
|
||||
usb_pipe *pp = &udev->host.pipe[pipe_num];
|
||||
|
||||
uint16_t max_packet_len = pp->ep.mps;
|
||||
|
||||
/* compute the expected number of packets associated to the transfer */
|
||||
if(pp->xfer_len > 0U) {
|
||||
packet_count = (uint16_t)((pp->xfer_len + max_packet_len - 1U) / max_packet_len);
|
||||
|
||||
if(packet_count > HC_MAX_PACKET_COUNT) {
|
||||
packet_count = HC_MAX_PACKET_COUNT;
|
||||
pp->xfer_len = (uint16_t)(packet_count * max_packet_len);
|
||||
}
|
||||
} else {
|
||||
packet_count = 1U;
|
||||
}
|
||||
|
||||
if(pp->ep.dir) {
|
||||
pp->xfer_len = (uint16_t)(packet_count * max_packet_len);
|
||||
}
|
||||
|
||||
/* initialize the host channel transfer information */
|
||||
udev->regs.pr[pipe_num]->HCHLEN = pp->xfer_len | pp->DPID | PIPE_XFER_PCNT(packet_count);
|
||||
|
||||
if(USB_USE_DMA == udev->bp.transfer_mode) {
|
||||
udev->regs.pr[pipe_num]->HCHDMAADDR = (unsigned int)pp->xfer_buf;
|
||||
}
|
||||
|
||||
pp_ctl = udev->regs.pr[pipe_num]->HCHCTL;
|
||||
|
||||
if(usb_frame_even(udev)) {
|
||||
pp_ctl |= HCHCTL_ODDFRM;
|
||||
} else {
|
||||
pp_ctl &= ~HCHCTL_ODDFRM;
|
||||
}
|
||||
|
||||
/* set host channel enabled */
|
||||
pp_ctl |= HCHCTL_CEN;
|
||||
pp_ctl &= ~HCHCTL_CDIS;
|
||||
|
||||
udev->regs.pr[pipe_num]->HCHCTL = pp_ctl;
|
||||
|
||||
if(USB_USE_FIFO == udev->bp.transfer_mode) {
|
||||
if((0U == pp->ep.dir) && (pp->xfer_len > 0U)) {
|
||||
switch(pp->ep.type) {
|
||||
/* non-periodic transfer */
|
||||
case USB_EPTYPE_CTRL:
|
||||
case USB_EPTYPE_BULK:
|
||||
dword_len = (uint16_t)((pp->xfer_len + 3U) / 4U);
|
||||
|
||||
/* check if there is enough space in FIFO space */
|
||||
if(dword_len > (udev->regs.gr->HNPTFQSTAT & HNPTFQSTAT_NPTXFS)) {
|
||||
/* need to process data in nptxfempty interrupt */
|
||||
udev->regs.gr->GINTEN |= GINTEN_NPTXFEIE;
|
||||
}
|
||||
break;
|
||||
|
||||
/* periodic transfer */
|
||||
case USB_EPTYPE_INTR:
|
||||
case USB_EPTYPE_ISOC:
|
||||
dword_len = (uint16_t)((pp->xfer_len + 3U) / 4U);
|
||||
|
||||
/* check if there is enough space in FIFO space */
|
||||
if(dword_len > (udev->regs.hr->HPTFQSTAT & HPTFQSTAT_PTXFS)) {
|
||||
/* need to process data in ptxfempty interrupt */
|
||||
udev->regs.gr->GINTEN |= GINTEN_PTXFEIE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* write packet into the TX FIFO */
|
||||
usb_txfifo_write(&udev->regs, pp->xfer_buf, pipe_num, (uint16_t)pp->xfer_len);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief halt pipe
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] pipe_num: host pipe number which is in (0..7)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_pipe_halt(usb_core_driver *udev, uint8_t pipe_num)
|
||||
{
|
||||
__IO uint32_t pp_ctl = udev->regs.pr[pipe_num]->HCHCTL;
|
||||
|
||||
uint8_t ep_type = (uint8_t)((pp_ctl & HCHCTL_EPTYPE) >> 18U);
|
||||
|
||||
pp_ctl |= HCHCTL_CEN | HCHCTL_CDIS;
|
||||
|
||||
switch(ep_type) {
|
||||
case USB_EPTYPE_CTRL:
|
||||
case USB_EPTYPE_BULK:
|
||||
if(0U == (udev->regs.gr->HNPTFQSTAT & HNPTFQSTAT_NPTXFS)) {
|
||||
pp_ctl &= ~HCHCTL_CEN;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_INTR:
|
||||
case USB_EPTYPE_ISOC:
|
||||
if(0U == (udev->regs.hr->HPTFQSTAT & HPTFQSTAT_PTXFS)) {
|
||||
pp_ctl &= ~HCHCTL_CEN;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
udev->regs.pr[pipe_num]->HCHCTL = pp_ctl;
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure host pipe to do ping operation
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[in] pipe_num: host pipe number which is in (0..7)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
usb_status usb_pipe_ping(usb_core_driver *udev, uint8_t pipe_num)
|
||||
{
|
||||
uint32_t pp_ctl = 0U;
|
||||
|
||||
udev->regs.pr[pipe_num]->HCHLEN = HCHLEN_PING;
|
||||
|
||||
pp_ctl = udev->regs.pr[pipe_num]->HCHCTL;
|
||||
|
||||
pp_ctl |= HCHCTL_CEN;
|
||||
pp_ctl &= ~HCHCTL_CDIS;
|
||||
|
||||
udev->regs.pr[pipe_num]->HCHCTL = pp_ctl;
|
||||
|
||||
return USB_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief stop the USB host and clean up FIFO
|
||||
\param[in] udev: pointer to USB device
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usb_host_stop(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t i;
|
||||
__IO uint32_t pp_ctl = 0U;
|
||||
|
||||
udev->regs.hr->HACHINTEN = 0x0U;
|
||||
udev->regs.hr->HACHINT = 0xFFFFFFFFU;
|
||||
|
||||
/* flush out any leftover queued requests. */
|
||||
for(i = 0U; i < udev->bp.num_pipe; i++) {
|
||||
pp_ctl = udev->regs.pr[i]->HCHCTL;
|
||||
|
||||
pp_ctl &= ~(HCHCTL_CEN | HCHCTL_EPDIR);
|
||||
pp_ctl |= HCHCTL_CDIS;
|
||||
|
||||
udev->regs.pr[i]->HCHCTL = pp_ctl;
|
||||
}
|
||||
|
||||
/* flush the FIFO */
|
||||
usb_rxfifo_flush(&udev->regs);
|
||||
usb_txfifo_flush(&udev->regs, 0x10U);
|
||||
}
|
||||
@@ -0,0 +1,694 @@
|
||||
/*!
|
||||
\file drv_usbd_int.c
|
||||
\brief USB device mode interrupt routines
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "drv_usbd_int.h"
|
||||
#include "usbd_transc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const uint8_t USB_SPEED[4] = {
|
||||
[DSTAT_EM_HS_PHY_30MHZ_60MHZ] = (uint8_t)USB_SPEED_HIGH,
|
||||
[DSTAT_EM_FS_PHY_30MHZ_60MHZ] = (uint8_t)USB_SPEED_FULL,
|
||||
[DSTAT_EM_FS_PHY_48MHZ] = (uint8_t)USB_SPEED_FULL,
|
||||
[DSTAT_EM_LS_PHY_6MHZ] = (uint8_t)USB_SPEED_LOW
|
||||
};
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint32_t usbd_int_epout(usb_core_driver *udev);
|
||||
static uint32_t usbd_int_epin(usb_core_driver *udev);
|
||||
static uint32_t usbd_int_rxfifo(usb_core_driver *udev);
|
||||
static uint32_t usbd_int_reset(usb_core_driver *udev);
|
||||
static uint32_t usbd_int_enumfinish(usb_core_driver *udev);
|
||||
static uint32_t usbd_int_suspend(usb_core_driver *udev);
|
||||
static uint32_t usbd_int_wakeup(usb_core_driver *udev);
|
||||
|
||||
#if (1U == LPM_ENABLED)
|
||||
static uint32_t usbd_int_lpm(usb_core_driver *udev, usb_lpm_type active_type);
|
||||
#endif /* LPM_ENABLED */
|
||||
|
||||
static uint32_t usbd_emptytxfifo_write(usb_core_driver *udev, uint32_t ep_num);
|
||||
|
||||
/*!
|
||||
\brief USB device-mode interrupts global service routine handler
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void usbd_isr(usb_core_driver *udev)
|
||||
{
|
||||
if(HOST_MODE != (udev->regs.gr->GINTF & GINTF_COPM)) {
|
||||
uint32_t intr = udev->regs.gr->GINTF;
|
||||
intr &= udev->regs.gr->GINTEN;
|
||||
|
||||
/* there are no interrupts, avoid spurious interrupt */
|
||||
if(!intr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* OUT endpoints interrupts */
|
||||
if(intr & GINTF_OEPIF) {
|
||||
(void)usbd_int_epout(udev);
|
||||
}
|
||||
|
||||
/* IN endpoints interrupts */
|
||||
if(intr & GINTF_IEPIF) {
|
||||
(void)usbd_int_epin(udev);
|
||||
}
|
||||
|
||||
/* suspend interrupt */
|
||||
if(intr & GINTF_SP) {
|
||||
(void)usbd_int_suspend(udev);
|
||||
}
|
||||
|
||||
/* wakeup interrupt */
|
||||
if(intr & GINTF_WKUPIF) {
|
||||
(void)usbd_int_wakeup(udev);
|
||||
}
|
||||
|
||||
/* start of frame interrupt */
|
||||
if(intr & GINTF_SOF) {
|
||||
if(udev->dev.class_core->SOF) {
|
||||
(void)udev->dev.class_core->SOF(udev);
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_SOF;
|
||||
}
|
||||
|
||||
/* receive FIFO not empty interrupt */
|
||||
if(intr & GINTF_RXFNEIF) {
|
||||
(void)usbd_int_rxfifo(udev);
|
||||
}
|
||||
|
||||
/* USB reset interrupt */
|
||||
if(intr & GINTF_RST) {
|
||||
(void)usbd_int_reset(udev);
|
||||
}
|
||||
|
||||
/* enumeration has been done interrupt */
|
||||
if(intr & GINTF_ENUMFIF) {
|
||||
(void)usbd_int_enumfinish(udev);
|
||||
}
|
||||
|
||||
/* incomplete synchronization IN transfer interrupt*/
|
||||
if(intr & GINTF_ISOINCIF) {
|
||||
if(NULL != udev->dev.class_core->incomplete_isoc_in) {
|
||||
(void)udev->dev.class_core->incomplete_isoc_in(udev);
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_ISOINCIF;
|
||||
}
|
||||
|
||||
/* incomplete synchronization OUT transfer interrupt*/
|
||||
if(intr & GINTF_ISOONCIF) {
|
||||
if(NULL != udev->dev.class_core->incomplete_isoc_out) {
|
||||
(void)udev->dev.class_core->incomplete_isoc_out(udev);
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_ISOONCIF;
|
||||
}
|
||||
|
||||
#if (1U == LPM_ENABLED)
|
||||
if(intr & GINTF_LPMIF) {
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_LPMIF;
|
||||
|
||||
udev->dev.pm.BESL = (udev->regs.gr->GLPMCFG & GLPMCFG_BESL) >> 2U;
|
||||
udev->dev.pm.dev_remote_wakeup = (udev->regs.gr->GLPMCFG & GLPMCFG_REW) >> 6U;
|
||||
|
||||
if(LPM_L0 == udev->dev.pm.lpm_state) {
|
||||
udev->dev.pm.lpm_state = LPM_L1;
|
||||
usbd_int_lpm(udev, LPM_L1_ACTIVE);
|
||||
} else {
|
||||
udev->dev.pm.lpm_state = LPM_L0;
|
||||
usbd_int_lpm(udev, LPM_L0_ACTIVE);
|
||||
}
|
||||
}
|
||||
#endif /* LPM_ENABLED */
|
||||
|
||||
#ifdef VBUS_SENSING_ENABLED
|
||||
|
||||
/* session request interrupt */
|
||||
if(intr & GINTF_SESIF) {
|
||||
udev->regs.gr->GINTF = GINTF_SESIF;
|
||||
}
|
||||
|
||||
/* OTG mode interrupt */
|
||||
if(intr & GINTF_OTGIF) {
|
||||
if(udev->regs.gr->GOTGINTF & GOTGINTF_SESEND) {
|
||||
|
||||
}
|
||||
|
||||
/* clear OTG interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_OTGIF;
|
||||
}
|
||||
#endif /* VBUS_SENSING_ENABLED */
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief indicates that an OUT endpoint has a pending interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbd_int_epout(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t epintnum = 0U;
|
||||
uint8_t ep_num = 0U;
|
||||
|
||||
for(epintnum = usb_oepintnum_read(udev); epintnum; epintnum >>= 1) {
|
||||
if(epintnum & 0x01U) {
|
||||
__IO uint32_t oepintr = usb_oepintr_read(udev, ep_num);
|
||||
|
||||
/* transfer complete interrupt */
|
||||
if(oepintr & DOEPINTF_TF) {
|
||||
/* clear the bit in DOEPINTF for this interrupt */
|
||||
udev->regs.er_out[ep_num]->DOEPINTF = DOEPINTF_TF;
|
||||
|
||||
if((uint8_t)USB_USE_DMA == udev->bp.transfer_mode) {
|
||||
__IO uint32_t eplen = udev->regs.er_out[ep_num]->DOEPLEN;
|
||||
|
||||
udev->dev.transc_out[ep_num].xfer_count = udev->dev.transc_out[ep_num].max_len - \
|
||||
(eplen & DEPLEN_TLEN);
|
||||
}
|
||||
|
||||
/* inform upper layer: data ready */
|
||||
(void)usbd_out_transc(udev, ep_num);
|
||||
|
||||
if((uint8_t)USB_USE_DMA == udev->bp.transfer_mode) {
|
||||
if((0U == ep_num) && ((uint8_t)USB_CTL_STATUS_OUT == udev->dev.control.ctl_state)) {
|
||||
usb_ctlep_startout(udev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* SETUP phase finished interrupt (control endpoints) */
|
||||
if(oepintr & DOEPINTF_STPF) {
|
||||
/* inform the upper layer that a SETUP packet is available */
|
||||
(void)usbd_setup_transc(udev);
|
||||
|
||||
udev->regs.er_out[ep_num]->DOEPINTF = DOEPINTF_STPF;
|
||||
}
|
||||
}
|
||||
|
||||
ep_num++;
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief indicates that an IN endpoint has a pending interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbd_int_epin(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t epintnum = 0U;
|
||||
uint8_t ep_num = 0U;
|
||||
|
||||
for(epintnum = usb_iepintnum_read(udev); epintnum; epintnum >>= 1) {
|
||||
if(epintnum & 0x1U) {
|
||||
__IO uint32_t iepintr = usb_iepintr_read(udev, ep_num);
|
||||
|
||||
if(iepintr & DIEPINTF_TF) {
|
||||
udev->regs.er_in[ep_num]->DIEPINTF = DIEPINTF_TF;
|
||||
|
||||
/* data transmission is completed */
|
||||
(void)usbd_in_transc(udev, ep_num);
|
||||
|
||||
if((uint8_t)USB_USE_DMA == udev->bp.transfer_mode) {
|
||||
if((0U == ep_num) && ((uint8_t)USB_CTL_STATUS_IN == udev->dev.control.ctl_state)) {
|
||||
usb_ctlep_startout(udev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(iepintr & DIEPINTF_TXFE) {
|
||||
usbd_emptytxfifo_write(udev, (uint32_t)ep_num);
|
||||
|
||||
udev->regs.er_in[ep_num]->DIEPINTF = DIEPINTF_TXFE;
|
||||
}
|
||||
}
|
||||
|
||||
ep_num++;
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the RX status queue level interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbd_int_rxfifo(usb_core_driver *udev)
|
||||
{
|
||||
usb_transc *transc = NULL;
|
||||
|
||||
uint8_t data_PID = 0U;
|
||||
uint32_t bcount = 0U;
|
||||
|
||||
__IO uint32_t devrxstat = 0U;
|
||||
|
||||
/* disable the RX status queue non-empty interrupt */
|
||||
udev->regs.gr->GINTEN &= ~GINTEN_RXFNEIE;
|
||||
|
||||
/* get the status from the top of the FIFO */
|
||||
devrxstat = udev->regs.gr->GRSTATP;
|
||||
|
||||
uint8_t ep_num = (uint8_t)(devrxstat & GRSTATRP_EPNUM);
|
||||
|
||||
transc = &udev->dev.transc_out[ep_num];
|
||||
|
||||
bcount = (devrxstat & GRSTATRP_BCOUNT) >> 4;
|
||||
data_PID = (uint8_t)((devrxstat & GRSTATRP_DPID) >> 15);
|
||||
|
||||
switch((devrxstat & GRSTATRP_RPCKST) >> 17) {
|
||||
case RSTAT_GOUT_NAK:
|
||||
break;
|
||||
|
||||
case RSTAT_DATA_UPDT:
|
||||
if(bcount > 0U) {
|
||||
(void)usb_rxfifo_read(&udev->regs, transc->xfer_buf, (uint16_t)bcount);
|
||||
|
||||
transc->xfer_buf += bcount;
|
||||
transc->xfer_count += bcount;
|
||||
}
|
||||
break;
|
||||
|
||||
case RSTAT_XFER_COMP:
|
||||
/* trigger the OUT endpoint interrupt */
|
||||
break;
|
||||
|
||||
case RSTAT_SETUP_COMP:
|
||||
/* trigger the OUT endpoint interrupt */
|
||||
break;
|
||||
|
||||
case RSTAT_SETUP_UPDT:
|
||||
if((0U == transc->ep_addr.num) && (8U == bcount) && (DPID_DATA0 == data_PID)) {
|
||||
/* copy the SETUP packet received in FIFO into the setup buffer in RAM */
|
||||
(void)usb_rxfifo_read(&udev->regs, (uint8_t *)&udev->dev.control.req, (uint16_t)bcount);
|
||||
|
||||
transc->xfer_count += bcount;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* enable the RX status queue level interrupt */
|
||||
udev->regs.gr->GINTEN |= GINTEN_RXFNEIE;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB reset interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static uint32_t usbd_int_reset(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
/* clear the remote wakeup signaling */
|
||||
udev->regs.dr->DCTL &= ~DCTL_RWKUP;
|
||||
|
||||
/* flush the TX FIFO */
|
||||
(void)usb_txfifo_flush(&udev->regs, 0U);
|
||||
|
||||
for(i = 0U; i < udev->bp.num_ep; i++) {
|
||||
udev->regs.er_in[i]->DIEPINTF = 0xFFU;
|
||||
udev->regs.er_out[i]->DOEPINTF = 0xFFU;
|
||||
}
|
||||
|
||||
/* clear all pending device endpoint interrupts */
|
||||
udev->regs.dr->DAEPINT = 0xFFFFFFFFU;
|
||||
|
||||
/* enable endpoint 0 interrupts */
|
||||
udev->regs.dr->DAEPINTEN = 1U | (1U << 16U);
|
||||
|
||||
/* enable OUT endpoint interrupts */
|
||||
udev->regs.dr->DOEPINTEN = DOEPINTEN_STPFEN | DOEPINTEN_TFEN;
|
||||
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
udev->regs.dr->DOEP1INTEN = DOEPINTEN_STPFEN | DOEPINTEN_TFEN;
|
||||
#endif
|
||||
|
||||
/* enable IN endpoint interrupts */
|
||||
udev->regs.dr->DIEPINTEN = DIEPINTEN_TFEN;
|
||||
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
udev->regs.dr->DIEP1INTEN = DIEPINTEN_TFEN;
|
||||
#endif
|
||||
|
||||
/* reset device address */
|
||||
udev->regs.dr->DCFG &= ~DCFG_DAR;
|
||||
|
||||
/* configure endpoint 0 to receive SETUP packets */
|
||||
usb_ctlep_startout(udev);
|
||||
|
||||
/* clear USB reset interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_RST;
|
||||
|
||||
udev->dev.transc_out[0] = (usb_transc) {
|
||||
.ep_type = USB_EPTYPE_CTRL,
|
||||
.max_len = USB_FS_EP0_MAX_LEN
|
||||
};
|
||||
|
||||
(void)usb_transc_active(udev, &udev->dev.transc_out[0]);
|
||||
|
||||
udev->dev.transc_in[0] = (usb_transc) {
|
||||
.ep_addr = {
|
||||
.dir = 1U
|
||||
},
|
||||
|
||||
.ep_type = USB_EPTYPE_CTRL,
|
||||
.max_len = USB_FS_EP0_MAX_LEN
|
||||
};
|
||||
|
||||
(void)usb_transc_active(udev, &udev->dev.transc_in[0]);
|
||||
|
||||
/* upon reset call user call back */
|
||||
udev->dev.cur_status = (uint8_t)USBD_DEFAULT;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB speed enumeration finish interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static uint32_t usbd_int_enumfinish(usb_core_driver *udev)
|
||||
{
|
||||
uint8_t enum_speed = (uint8_t)((udev->regs.dr->DSTAT & DSTAT_ES) >> 1);
|
||||
|
||||
udev->regs.dr->DCTL &= ~DCTL_CGINAK;
|
||||
udev->regs.dr->DCTL |= DCTL_CGINAK;
|
||||
|
||||
udev->regs.gr->GUSBCS &= ~GUSBCS_UTT;
|
||||
|
||||
/* set USB turn-around time based on device speed and PHY interface */
|
||||
if((uint8_t)USB_SPEED_HIGH == USB_SPEED[enum_speed]) {
|
||||
udev->bp.core_speed = (uint8_t)USB_SPEED_HIGH;
|
||||
|
||||
udev->regs.gr->GUSBCS |= 0x09U << 10;
|
||||
} else {
|
||||
udev->bp.core_speed = (uint8_t)USB_SPEED_FULL;
|
||||
|
||||
udev->regs.gr->GUSBCS |= 0x05U << 10;
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_ENUMFIF;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB suspend interrupt handler
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbd_int_suspend(usb_core_driver *udev)
|
||||
{
|
||||
__IO uint8_t low_power = udev->bp.low_power;
|
||||
__IO uint8_t suspend = (uint8_t)(udev->regs.dr->DSTAT & DSTAT_SPST);
|
||||
__IO uint8_t is_configured = ((uint8_t)USBD_CONFIGURED == udev->dev.cur_status) ? 1U : 0U;
|
||||
|
||||
udev->dev.backup_status = udev->dev.cur_status;
|
||||
udev->dev.cur_status = (uint8_t)USBD_SUSPENDED;
|
||||
|
||||
if(low_power && suspend && is_configured) {
|
||||
/* switch-off the USB clocks */
|
||||
*udev->regs.PWRCLKCTL |= PWRCLKCTL_SUCLK | PWRCLKCTL_SHCLK;
|
||||
|
||||
/* enter DEEP_SLEEP mode with LDO in low power mode */
|
||||
pmu_to_deepsleepmode(WFI_CMD);
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_SP;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB wakeup interrupt handler
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbd_int_wakeup(usb_core_driver *udev)
|
||||
{
|
||||
__IO uint8_t low_power = udev->bp.low_power;
|
||||
__IO uint8_t remote_wakeup = udev->dev.pm.dev_remote_wakeup;
|
||||
|
||||
#if (1U == LPM_ENABLED)
|
||||
if(LPM_L1 == udev->dev.pm.lpm_state) {
|
||||
udev->dev.pm.lpm_state = LPM_L0;
|
||||
usbd_int_lpm(udev, LPM_L0_ACTIVE);
|
||||
} else
|
||||
#endif /* LPM_ENABLED */
|
||||
{
|
||||
if(remote_wakeup && low_power) {
|
||||
/* resume MCU CLK */
|
||||
|
||||
/* reset SLEEPDEEP bit of Cortex-M33 system control register */
|
||||
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
|
||||
}
|
||||
|
||||
usb_clock_active(udev);
|
||||
|
||||
if(USBD_SUSPENDED == udev->dev.cur_status) {
|
||||
/* inform upper layer by the resume event */
|
||||
udev->dev.cur_status = udev->dev.backup_status;
|
||||
}
|
||||
|
||||
udev->dev.cur_status = USBD_CONFIGURED;
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_WKUPIF;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
#ifdef USB_DEDICATED_EP1_ENABLED
|
||||
|
||||
/*!
|
||||
\brief USB dedicated OUT endpoint 1 interrupt service routine handler
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint32_t usbd_int_dedicated_ep1out(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t oepintr = 0U;
|
||||
uint32_t oeplen = 0U;
|
||||
|
||||
oepintr = udev->regs.er_out[1]->DOEPINTF;
|
||||
oepintr &= udev->regs.dr->DOEP1INTEN;
|
||||
|
||||
/* transfer complete */
|
||||
if(oepintr & DOEPINTF_TF) {
|
||||
/* clear the bit in DOEPINTn for this interrupt */
|
||||
udev->regs.er_out[1]->DOEPINTF = DOEPINTF_TF;
|
||||
|
||||
if(USB_USE_DMA == udev->bp.transfer_mode) {
|
||||
oeplen = udev->regs.er_out[1]->DOEPLEN;
|
||||
|
||||
/* ToDo : handle more than one single MPS size packet */
|
||||
udev->dev.transc_out[1].xfer_count = udev->dev.transc_out[1].max_len - \
|
||||
(oeplen & DEPLEN_TLEN);
|
||||
}
|
||||
|
||||
/* RX COMPLETE */
|
||||
usbd_out_transc(udev, 1U);
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief USB dedicated IN endpoint 1 interrupt service routine handler
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint32_t usbd_int_dedicated_ep1in(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t inten, intr, emptyen;
|
||||
|
||||
inten = udev->regs.dr->DIEP1INTEN;
|
||||
emptyen = udev->regs.dr->DIEPFEINTEN;
|
||||
|
||||
inten |= ((emptyen >> 1U ) & 0x1U) << 7U;
|
||||
|
||||
intr = udev->regs.er_in[1]->DIEPINTF & inten;
|
||||
|
||||
if(intr & DIEPINTF_TF) {
|
||||
udev->regs.dr->DIEPFEINTEN &= ~(0x1U << 1U);
|
||||
|
||||
udev->regs.er_in[1]->DIEPINTF = DIEPINTF_TF;
|
||||
|
||||
/* TX COMPLETE */
|
||||
usbd_in_transc(udev, 1U);
|
||||
}
|
||||
|
||||
if(intr & DIEPINTF_TXFE) {
|
||||
usbd_emptytxfifo_write(udev, 1U);
|
||||
|
||||
udev->regs.er_in[1]->DIEPINTF = DIEPINTF_TXFE;
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (1U == LPM_ENABLED)
|
||||
|
||||
/*!
|
||||
\brief USB LPM interrupt handler
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] active_type: active type
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg LPM_L0_ACTIVE: select L0 to active
|
||||
\arg LPM_L1_ACTIVE: select L1 to active
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbd_int_lpm(usb_core_driver *udev, usb_lpm_type active_type)
|
||||
{
|
||||
__IO uint8_t low_power = udev->bp.low_power;
|
||||
__IO uint8_t suspend = (uint8_t)(udev->regs.dr->DSTAT & DSTAT_SPST);
|
||||
__IO uint8_t is_configured = (udev->dev.cur_status == (uint8_t)USBD_CONFIGURED) ? 1U : 0U;
|
||||
|
||||
switch(active_type) {
|
||||
case LPM_L0_ACTIVE:
|
||||
udev->dev.cur_status = udev->dev.backup_status;
|
||||
|
||||
/* switch-on the OTG clocks */
|
||||
usb_clock_active(udev);
|
||||
|
||||
if(low_power) {
|
||||
/* resume MCU CLK */
|
||||
|
||||
/* reset SLEEPDEEP bit of Cortex-M7 system control register */
|
||||
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
|
||||
}
|
||||
break;
|
||||
|
||||
case LPM_L1_ACTIVE:
|
||||
udev->dev.backup_status = udev->dev.cur_status;
|
||||
udev->dev.cur_status = (uint8_t)USBD_SUSPENDED;
|
||||
|
||||
/* add delay */
|
||||
usb_mdelay(300U);
|
||||
|
||||
/* switch-off the OTG clocks */
|
||||
*udev->regs.PWRCLKCTL |= PWRCLKCTL_SUCLK | PWRCLKCTL_SHCLK;
|
||||
|
||||
if(low_power) {
|
||||
/* enter DEEP_SLEEP mode with LDO in low power mode */
|
||||
pmu_to_deepsleepmode(WFI_CMD);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
#endif /* LPM_ENABLED */
|
||||
|
||||
/*!
|
||||
\brief check FIFO for the next packet to be loaded
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] ep_num: endpoint identifier which is in (0..5)
|
||||
\param[out] none
|
||||
\retval status
|
||||
*/
|
||||
static uint32_t usbd_emptytxfifo_write(usb_core_driver *udev, uint32_t ep_num)
|
||||
{
|
||||
uint32_t len;
|
||||
uint32_t word_count;
|
||||
|
||||
usb_transc *transc = &udev->dev.transc_in[ep_num];
|
||||
|
||||
len = transc->xfer_len - transc->xfer_count;
|
||||
|
||||
/* get the data length to write */
|
||||
if(len > transc->max_len) {
|
||||
len = transc->max_len;
|
||||
}
|
||||
|
||||
word_count = (len + 3U) / 4U;
|
||||
|
||||
while(((udev->regs.er_in[ep_num]->DIEPTFSTAT & DIEPTFSTAT_IEPTFS) >= word_count) && \
|
||||
(transc->xfer_count < transc->xfer_len)) {
|
||||
len = transc->xfer_len - transc->xfer_count;
|
||||
|
||||
if(len > transc->max_len) {
|
||||
len = transc->max_len;
|
||||
}
|
||||
|
||||
/* write FIFO in word(4bytes) */
|
||||
word_count = (len + 3U) / 4U;
|
||||
|
||||
/* write the FIFO */
|
||||
(void)usb_txfifo_write(&udev->regs, transc->xfer_buf, (uint8_t)ep_num, (uint16_t)len);
|
||||
|
||||
transc->xfer_buf += len;
|
||||
transc->xfer_count += len;
|
||||
|
||||
if(transc->xfer_count == transc->xfer_len) {
|
||||
/* disable the device endpoint FIFO empty interrupt */
|
||||
udev->regs.dr->DIEPFEINTEN &= ~(0x01U << ep_num);
|
||||
}
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
@@ -0,0 +1,621 @@
|
||||
/*!
|
||||
\file drv_usbh_int.c
|
||||
\brief USB host mode interrupt handler file
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "drv_usbh_int.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (__CC_ARM) /*!< ARM compiler */
|
||||
#pragma O0
|
||||
#elif defined (__GNUC__) /*!< GNU compiler */
|
||||
#pragma GCC optimize ("O0")
|
||||
#elif defined (__TASKING__) /*!< TASKING compiler */
|
||||
#pragma optimize=0
|
||||
#endif /* __CC_ARM */
|
||||
|
||||
/* local function prototypes ('static') */
|
||||
static uint32_t usbh_int_port(usb_core_driver *udev);
|
||||
static uint32_t usbh_int_pipe(usb_core_driver *udev);
|
||||
static uint32_t usbh_int_pipe_in(usb_core_driver *udev, uint32_t pp_num);
|
||||
static uint32_t usbh_int_pipe_out(usb_core_driver *udev, uint32_t pp_num);
|
||||
static uint32_t usbh_int_rxfifonoempty(usb_core_driver *udev);
|
||||
static uint32_t usbh_int_txfifoempty(usb_core_driver *udev, usb_pipe_mode pp_mode);
|
||||
|
||||
/*!
|
||||
\brief handle global host interrupt
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
uint32_t usbh_isr(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t retval = 0U;
|
||||
|
||||
__IO uint32_t intr = 0U;
|
||||
|
||||
/* check if host mode */
|
||||
if(HOST_MODE == (udev->regs.gr->GINTF & GINTF_COPM)) {
|
||||
intr = usb_coreintr_get(&udev->regs);
|
||||
|
||||
if(!intr) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
if(intr & GINTF_SOF) {
|
||||
usbh_int_fop->SOF(udev->host.data);
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_SOF;
|
||||
}
|
||||
|
||||
if(intr & GINTF_RXFNEIF) {
|
||||
retval |= usbh_int_rxfifonoempty(udev);
|
||||
}
|
||||
|
||||
if(intr & GINTF_NPTXFEIF) {
|
||||
retval |= usbh_int_txfifoempty(udev, PIPE_NON_PERIOD);
|
||||
}
|
||||
|
||||
if(intr & GINTF_PTXFEIF) {
|
||||
retval |= usbh_int_txfifoempty(udev, PIPE_PERIOD);
|
||||
}
|
||||
|
||||
if(intr & GINTF_HCIF) {
|
||||
retval |= usbh_int_pipe(udev);
|
||||
}
|
||||
|
||||
if(intr & GINTF_HPIF) {
|
||||
retval |= usbh_int_port(udev);
|
||||
}
|
||||
|
||||
if(intr & GINTF_WKUPIF) {
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_WKUPIF;
|
||||
}
|
||||
|
||||
if(intr & GINTF_DISCIF) {
|
||||
usbh_int_fop->disconnect(udev->host.data);
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_DISCIF;
|
||||
}
|
||||
|
||||
if(intr & GINTF_ISOONCIF) {
|
||||
udev->regs.pr[0]->HCHCTL |= HCHCTL_CEN | HCHCTL_CDIS;
|
||||
|
||||
/* clear interrupt */
|
||||
udev->regs.gr->GINTF = GINTF_ISOONCIF;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle USB pipe halt
|
||||
\param[in] udev: pointer to USB core instance
|
||||
\param[in] pp_num: pp_num: host channel number which is in (0..7)
|
||||
\param[in] pp_int: pipe interrupt
|
||||
\param[in] pp_status: pipe status
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static inline void usb_pp_halt (usb_core_driver *udev, \
|
||||
uint8_t pp_num, \
|
||||
uint32_t pp_int, \
|
||||
usb_pipe_status pp_status)
|
||||
{
|
||||
udev->regs.pr[pp_num]->HCHINTEN |= HCHINTEN_CHIE;
|
||||
|
||||
usb_pipe_halt(udev, pp_num);
|
||||
|
||||
udev->regs.pr[pp_num]->HCHINTF = pp_int;
|
||||
|
||||
udev->host.pipe[pp_num].pp_status = pp_status;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the host port interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
#if defined (__ICCARM__) /*!< IAR compiler */
|
||||
#pragma optimize = none
|
||||
#endif /* __ICCARM */
|
||||
static uint32_t usbh_int_port(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t retval = 0U;
|
||||
|
||||
__IO uint32_t port_state = *udev->regs.HPCS;
|
||||
|
||||
__IO uint32_t port_reset = 0U;
|
||||
|
||||
/* clear the interrupt bit in GINTF */
|
||||
port_state &= ~(HPCS_PE | HPCS_PCD | HPCS_PEDC);
|
||||
|
||||
/* port connect detected */
|
||||
if(*udev->regs.HPCS & HPCS_PCD) {
|
||||
port_state |= HPCS_PCD;
|
||||
|
||||
usbh_int_fop->connect(udev->host.data);
|
||||
|
||||
retval |= 1U;
|
||||
}
|
||||
|
||||
/* port enable changed */
|
||||
if(*udev->regs.HPCS & HPCS_PEDC) {
|
||||
port_state |= HPCS_PEDC;
|
||||
|
||||
if(*udev->regs.HPCS & HPCS_PE) {
|
||||
uint32_t port_speed = usb_curspeed_get(udev);
|
||||
|
||||
udev->host.connect_status = 1U;
|
||||
|
||||
if(PORT_SPEED_LOW == port_speed) {
|
||||
udev->regs.hr->HFT = 6000U;
|
||||
} else if(PORT_SPEED_FULL == port_speed) {
|
||||
udev->regs.hr->HFT = 48000U;
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
port_reset = 1U;
|
||||
|
||||
usbh_int_fop->port_enabled(udev->host.data);
|
||||
|
||||
udev->regs.gr->GINTEN |= GINTEN_DISCIE | GINTEN_SOFIE;
|
||||
} else {
|
||||
usbh_int_fop->port_disabled(udev->host.data);
|
||||
}
|
||||
}
|
||||
|
||||
if(1U == port_reset) {
|
||||
usb_port_reset(udev);
|
||||
}
|
||||
|
||||
/* clear port interrupts */
|
||||
*udev->regs.HPCS = port_state;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle all host channels interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
static uint32_t usbh_int_pipe(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t pp_num = 0U;
|
||||
uint32_t retval = 0U;
|
||||
|
||||
for(pp_num = 0U; pp_num < udev->bp.num_pipe; pp_num++) {
|
||||
if((udev->regs.hr->HACHINT & HACHINT_HACHINT) & (1UL << pp_num)) {
|
||||
if(udev->regs.pr[pp_num]->HCHCTL & HCHCTL_EPDIR) {
|
||||
retval |= usbh_int_pipe_in(udev, pp_num);
|
||||
} else {
|
||||
retval |= usbh_int_pipe_out(udev, pp_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the IN channel interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] pp_num: host channel number which is in (0..7)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
#if defined (__ICCARM__) /*!< IAR compiler */
|
||||
#pragma optimize = none
|
||||
#endif /* __ICCARM */
|
||||
static uint32_t usbh_int_pipe_in(usb_core_driver *udev, uint32_t pp_num)
|
||||
{
|
||||
usb_pr *pp_reg = udev->regs.pr[pp_num];
|
||||
|
||||
usb_pipe *pp = &udev->host.pipe[pp_num];
|
||||
|
||||
uint32_t intr_pp = pp_reg->HCHINTF;
|
||||
intr_pp &= pp_reg->HCHINTEN;
|
||||
|
||||
uint8_t ep_type = (uint8_t)((pp_reg->HCHCTL & HCHCTL_EPTYPE) >> 18);
|
||||
|
||||
if(intr_pp & HCHINTF_ACK) {
|
||||
pp_reg->HCHINTF = HCHINTF_ACK;
|
||||
} else if(intr_pp & HCHINTF_STALL) {
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_STALL, PIPE_STALL);
|
||||
pp_reg->HCHINTF = HCHINTF_NAK;
|
||||
|
||||
/* note: When there is a 'STALL', reset also NAK,
|
||||
else, the udev->host.pp_status = HC_STALL
|
||||
will be overwritten by 'NAK' in code below */
|
||||
intr_pp &= ~HCHINTF_NAK;
|
||||
} else if(intr_pp & HCHINTF_DTER) {
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_DTER, PIPE_DTGERR);
|
||||
pp_reg->HCHINTF = HCHINTF_NAK;
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
if(intr_pp & HCHINTF_REQOVR) {
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_REQOVR, PIPE_REQOVR);
|
||||
} else if(intr_pp & HCHINTF_TF) {
|
||||
if((uint8_t)USB_USE_DMA == udev->bp.transfer_mode) {
|
||||
udev->host.backup_xfercount[pp_num] = pp->xfer_len - (pp_reg->HCHLEN & HCHLEN_TLEN);
|
||||
}
|
||||
|
||||
pp->pp_status = PIPE_XF;
|
||||
pp->err_count = 0U;
|
||||
|
||||
pp_reg->HCHINTF = HCHINTF_TF;
|
||||
|
||||
switch(ep_type) {
|
||||
case USB_EPTYPE_CTRL:
|
||||
case USB_EPTYPE_BULK:
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_NAK, PIPE_XF);
|
||||
|
||||
pp->data_toggle_in ^= 1U;
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_INTR:
|
||||
case USB_EPTYPE_ISOC:
|
||||
pp_reg->HCHCTL |= HCHCTL_ODDFRM;
|
||||
pp->urb_state = URB_DONE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(intr_pp & HCHINTF_CH) {
|
||||
pp_reg->HCHINTEN &= ~HCHINTEN_CHIE;
|
||||
|
||||
switch(pp->pp_status) {
|
||||
case PIPE_XF:
|
||||
pp->urb_state = URB_DONE;
|
||||
break;
|
||||
|
||||
case PIPE_STALL:
|
||||
pp->urb_state = URB_STALL;
|
||||
break;
|
||||
|
||||
case PIPE_TRACERR:
|
||||
case PIPE_DTGERR:
|
||||
pp->err_count = 0U;
|
||||
pp->urb_state = URB_ERROR;
|
||||
|
||||
pp->data_toggle_in ^= 1U;
|
||||
break;
|
||||
|
||||
case PIPE_IDLE:
|
||||
case PIPE_HALTED:
|
||||
case PIPE_NAK:
|
||||
case PIPE_NYET:
|
||||
case PIPE_BBERR:
|
||||
case PIPE_REQOVR:
|
||||
default:
|
||||
if((uint8_t)USB_EPTYPE_INTR == ep_type) {
|
||||
pp->data_toggle_in ^= 1U;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
pp_reg->HCHINTF = HCHINTF_CH;
|
||||
} else if(intr_pp & HCHINTF_USBER) {
|
||||
pp->err_count++;
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_USBER, PIPE_TRACERR);
|
||||
} else if (intr_pp & HCHINTF_NAK) {
|
||||
pp_reg->HCHINTF = HCHINTF_NAK;
|
||||
switch(ep_type) {
|
||||
case USB_EPTYPE_CTRL:
|
||||
case USB_EPTYPE_BULK:
|
||||
/* re-activate the channel */
|
||||
pp_reg->HCHCTL = (pp_reg->HCHCTL | HCHCTL_CEN) & ~HCHCTL_CDIS;
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_INTR:
|
||||
pp_reg->HCHINTEN |= HCHINTEN_CHIE;
|
||||
|
||||
(void)usb_pipe_halt(udev, (uint8_t)pp_num);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pp->pp_status = PIPE_NAK;
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the OUT channel interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] pp_num: host channel number which is in (0..7)
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
#if defined (__ICCARM__) /*!< IAR compiler */
|
||||
#pragma optimize = none
|
||||
#endif /* __ICCARM */
|
||||
static uint32_t usbh_int_pipe_out(usb_core_driver *udev, uint32_t pp_num)
|
||||
{
|
||||
usbh_host *uhost = udev->host.data;
|
||||
usb_pr *pp_reg = udev->regs.pr[pp_num];
|
||||
|
||||
usb_pipe *pp = &udev->host.pipe[pp_num];
|
||||
|
||||
uint32_t intr_pp = pp_reg->HCHINTF;
|
||||
intr_pp &= pp_reg->HCHINTEN;
|
||||
|
||||
if(intr_pp & HCHINTF_ACK) {
|
||||
if(1U == udev->host.pipe[pp_num].do_ping) {
|
||||
udev->host.pipe[pp_num].do_ping = 0U;
|
||||
pp->err_count = 0U;
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_ACK, PIPE_NAK);
|
||||
}
|
||||
|
||||
pp_reg->HCHINTF = HCHINTF_ACK;
|
||||
} else if(intr_pp & HCHINTF_STALL) {
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_STALL, PIPE_STALL);
|
||||
} else if(intr_pp & HCHINTF_DTER) {
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_DTER, PIPE_DTGERR);
|
||||
pp_reg->HCHINTF = HCHINTF_NAK;
|
||||
} else if(intr_pp & HCHINTF_REQOVR) {
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_REQOVR, PIPE_REQOVR);
|
||||
} else if(intr_pp & HCHINTF_TF) {
|
||||
pp->err_count = 0U;
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_TF, PIPE_XF);
|
||||
} else if(intr_pp & HCHINTF_NAK) {
|
||||
if(0U == udev->host.pipe[pp_num].do_ping) {
|
||||
if(1U == udev->host.pipe[pp_num].supp_ping) {
|
||||
udev->host.pipe[pp_num].do_ping = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
pp->err_count = 0U;
|
||||
if(USB_USE_FIFO == udev->bp.transfer_mode) {
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_NAK, PIPE_NAK);
|
||||
} else {
|
||||
pp_reg->HCHINTF = HCHINTF_NAK;
|
||||
}
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_NAK, PIPE_NAK);
|
||||
} else if(intr_pp & HCHINTF_USBER) {
|
||||
pp->err_count++;
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_USBER, PIPE_TRACERR);
|
||||
} else if(intr_pp & HCHINTF_NYET) {
|
||||
if(CTL_STATUS_OUT != uhost->control.ctl_state) {
|
||||
if(0U == udev->host.pipe[pp_num].do_ping) {
|
||||
if(1U == udev->host.pipe[pp_num].supp_ping) {
|
||||
udev->host.pipe[pp_num].do_ping = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_NYET, PIPE_NYET);
|
||||
} else {
|
||||
usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_NYET, PIPE_XF);
|
||||
}
|
||||
|
||||
pp->err_count = 0U;
|
||||
} else if(intr_pp & HCHINTF_CH) {
|
||||
udev->regs.pr[pp_num]->HCHINTEN &= ~HCHINTEN_CHIE;
|
||||
|
||||
switch(pp->pp_status) {
|
||||
case PIPE_XF:
|
||||
pp->urb_state = URB_DONE;
|
||||
|
||||
if((uint8_t)USB_EPTYPE_BULK == ((pp_reg->HCHCTL & HCHCTL_EPTYPE) >> 18U)) {
|
||||
pp->data_toggle_out ^= 1U;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIPE_NAK:
|
||||
pp->urb_state = URB_NOTREADY;
|
||||
break;
|
||||
|
||||
case PIPE_NYET:
|
||||
pp->urb_state = URB_DONE;
|
||||
|
||||
if((uint8_t)USB_EPTYPE_BULK == ((pp_reg->HCHCTL & HCHCTL_EPTYPE) >> 18U)) {
|
||||
pp->data_toggle_out ^= 1U;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIPE_STALL:
|
||||
pp->urb_state = URB_STALL;
|
||||
break;
|
||||
|
||||
case PIPE_TRACERR:
|
||||
if(3U == pp->err_count) {
|
||||
pp->urb_state = URB_ERROR;
|
||||
pp->err_count = 0U;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIPE_IDLE:
|
||||
case PIPE_HALTED:
|
||||
case PIPE_BBERR:
|
||||
case PIPE_REQOVR:
|
||||
case PIPE_DTGERR:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pp_reg->HCHINTF = HCHINTF_CH;
|
||||
} else {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the RX FIFO non-empty interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
#if defined (__ICCARM__) /*!< IAR compiler */
|
||||
#pragma optimize = none
|
||||
#endif /* __ICCARM */
|
||||
static uint32_t usbh_int_rxfifonoempty(usb_core_driver *udev)
|
||||
{
|
||||
uint32_t count = 0U, xfer_count = 0U;
|
||||
|
||||
__IO uint8_t pp_num = 0U;
|
||||
__IO uint32_t rx_stat = 0U;
|
||||
|
||||
/* disable the RX status queue level interrupt */
|
||||
udev->regs.gr->GINTEN &= ~GINTEN_RXFNEIE;
|
||||
|
||||
rx_stat = udev->regs.gr->GRSTATP;
|
||||
pp_num = (uint8_t)(rx_stat & GRSTATRP_CNUM);
|
||||
|
||||
switch((rx_stat & GRSTATRP_RPCKST) >> 17) {
|
||||
case GRXSTS_PKTSTS_IN:
|
||||
count = (rx_stat & GRSTATRP_BCOUNT) >> 4;
|
||||
|
||||
/* read the data into the host buffer. */
|
||||
if((NULL != udev->host.pipe[pp_num].xfer_buf) && (count > 0U)) {
|
||||
(void)usb_rxfifo_read(&udev->regs, udev->host.pipe[pp_num].xfer_buf, (uint16_t)count);
|
||||
|
||||
/* manage multiple transfer packet */
|
||||
udev->host.pipe[pp_num].xfer_buf += count;
|
||||
udev->host.pipe[pp_num].xfer_count += count;
|
||||
|
||||
xfer_count = udev->host.pipe[pp_num].xfer_count;
|
||||
|
||||
udev->host.backup_xfercount[pp_num] = xfer_count;
|
||||
|
||||
if(udev->regs.pr[pp_num]->HCHLEN & HCHLEN_PCNT) {
|
||||
/* re-activate the channel when more packets are expected */
|
||||
uint32_t pp_ctl = udev->regs.pr[pp_num]->HCHCTL;
|
||||
|
||||
pp_ctl |= HCHCTL_CEN;
|
||||
pp_ctl &= ~HCHCTL_CDIS;
|
||||
|
||||
udev->regs.pr[pp_num]->HCHCTL = pp_ctl;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GRXSTS_PKTSTS_IN_XFER_COMP:
|
||||
break;
|
||||
|
||||
case GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
|
||||
count = (rx_stat & GRSTATRP_BCOUNT) >> 4;
|
||||
|
||||
while(count > 0U) {
|
||||
rx_stat = udev->regs.gr->GRSTATP;
|
||||
count--;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRXSTS_PKTSTS_CH_HALTED:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* enable the RX status queue level interrupt */
|
||||
udev->regs.gr->GINTEN |= GINTEN_RXFNEIE;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief handle the TX FIFO empty interrupt
|
||||
\param[in] udev: pointer to USB device instance
|
||||
\param[in] pp_mode: pipe mode
|
||||
\param[out] none
|
||||
\retval operation status
|
||||
*/
|
||||
#if defined (__ICCARM__) /*!< IAR compiler */
|
||||
#pragma optimize = none
|
||||
#endif /* __ICCARM */
|
||||
static uint32_t usbh_int_txfifoempty(usb_core_driver *udev, usb_pipe_mode pp_mode)
|
||||
{
|
||||
uint8_t pp_num = 0U;
|
||||
uint16_t word_count = 0U, len = 0U;
|
||||
__IO uint32_t *txfiforeg = 0U, txfifostate = 0U;
|
||||
|
||||
if(PIPE_NON_PERIOD == pp_mode) {
|
||||
txfiforeg = &udev->regs.gr->HNPTFQSTAT;
|
||||
} else if(PIPE_PERIOD == pp_mode) {
|
||||
txfiforeg = &udev->regs.hr->HPTFQSTAT;
|
||||
} else {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
txfifostate = *txfiforeg;
|
||||
|
||||
pp_num = (uint8_t)((txfifostate & TFQSTAT_CNUM) >> 27);
|
||||
|
||||
word_count = (uint16_t)(udev->host.pipe[pp_num].xfer_len + 3U) / 4U;
|
||||
|
||||
while(((txfifostate & TFQSTAT_TXFS) >= word_count) && (0U != udev->host.pipe[pp_num].xfer_len)) {
|
||||
len = (uint16_t)(txfifostate & TFQSTAT_TXFS) * 4U;
|
||||
|
||||
if(len > udev->host.pipe[pp_num].xfer_len) {
|
||||
/* last packet */
|
||||
len = (uint16_t)udev->host.pipe[pp_num].xfer_len;
|
||||
|
||||
if(PIPE_NON_PERIOD == pp_mode) {
|
||||
udev->regs.gr->GINTEN &= ~GINTEN_NPTXFEIE;
|
||||
} else {
|
||||
udev->regs.gr->GINTEN &= ~GINTEN_PTXFEIE;
|
||||
}
|
||||
}
|
||||
|
||||
word_count = (uint16_t)((udev->host.pipe[pp_num].xfer_len + 3U) / 4U);
|
||||
usb_txfifo_write(&udev->regs, udev->host.pipe[pp_num].xfer_buf, pp_num, len);
|
||||
|
||||
udev->host.pipe[pp_num].xfer_buf += len;
|
||||
udev->host.pipe[pp_num].xfer_len -= len;
|
||||
udev->host.pipe[pp_num].xfer_count += len;
|
||||
|
||||
txfifostate = *txfiforeg;
|
||||
}
|
||||
|
||||
return 1U;
|
||||
}
|
||||
Reference in New Issue
Block a user