828eco基于GD32H7mcu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

440 lines
12 KiB

/*
* Copyright (c) 2006-2025, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-11-07 RealThread the first version
*/
#include "drv_usb_hw.h"
#include "drv_usb_core.h"
#if defined(BSP_USING_USB)
/* 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);
}
/*!
\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);
}
}
}
#endif /* BSP_USING_USB */