1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00
19389: drivers/usbdev_synopsys_dwc2: add GD32V support r=bergzand a=gschorcht

### Contribution description

This PR provides the GD32V support in `drivers/usbdev_synopsys_dwc2`. It also includes some cleanup and bug fixes.

To support GD32V (CID 1.000) the PR includes the following changes:
- XFRC interrupts are also used in Non-DMA mode to complete a transfer
- SETUP phase done (STUP) interrupt is used in Non-DMA mode
- additional XFRC interrupts in SETUP stage are ignored
- RX FIFO handling doesn't complete a transfer anymore and is handled directly in ISR
- OTG interrupt handling added

The following fixes, improvements and cleanup has been added:
- USB OTG HS definition dependencies for platforms that don't support USB OTG HS
- thread context switch at ISR exit was added for all platforms
- units in USB FIFO size definitions are clarified
- USB EP number as defined in CMSIS is used
- FIFO allocation documentation is improved
- power modes for STM32 are fixed
- CID/HW debug info added

The PR could be split into a PRs with cleanups and improvements and a PR with GD32V support if necessary.

### Testing procedure
```
BOARD=sipeed-longan-nano make -j8 -C tests/shell
```
should work with `stdio_cdc_acm`.

`periph_usbdev` should still work for other platforms. The PR was tested with `tests/usbus_cdc_ecm` together with `stdio_cdc_acm` if possible:
```
esp32s2      FS  CID: 0000, HWREV: 4f54400a, HWCFG: 224dd930  (esp32s2-devkit)
esp32s3      FS  CID: 0000, HWREV: 4f54400a, HWCFG: 224dd930  (esp32s3-devkit)
efm32gg12    FS  CID: 0000, HWREV: 4f54330a, HWCFG: 228f5910  (sltb009a)
gd32vf103cb  FS  CID: 1000, HWREV: 00000000, HWCFG: 00000000  (sipeed-longan-nano)
stm32f407vg  FS  CID: 1200, HWREV: 4f54281a, HWCFG: 229dcd20  (stm32f4discovery) 
stm32f429zi  HS  CID: 1100, HWREV: 4f54281a, HWCFG: 229ed590  (stm32f429i-disc1)
stm32f439zi  FS  CID: 1200, HWREV: 4f54281a, HWCFG: 229dcd20  (nucleo-f439ze)
stm32f446ze  FS  CID: 2000, HWREV: 4f54320a, HWCFG: 229ed520  (nucleo-f446ze)
stm32f723ie  FS  CID: 3000, HWREV: 4f54330a, HWCFG: 229ed520  (stm32f723e-disco)
stm32f723ie  HS  CID: 3100, HWREV: 4f54330a, HWCFG: 229fe1d0  (stm32f723e-disco)
stm32f746ng  FS  CID: 2000, HWREV: 4f54320a, HWCFG: 229ed520  (stm32f746g-disco)
stm32f746ng  HS  CID: 2100, HWREV: 4f54320a, HWCFG: 229fe190  (stm32f746g-disco)
stm32f767zi  FS  CID: 2000, HWREV: 4f54320a, HWCFG: 229ed520  (nucleo-f767zi)
```
Boards with HS interfaces were tested in DMA and none-DMA mode.

### Issues/PRs references

Co-authored-by: Gunar Schorcht <gunar@schorcht.net>
This commit is contained in:
bors[bot] 2023-04-17 08:36:02 +00:00 committed by GitHub
commit 82234b1d23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 275 additions and 195 deletions

View File

@ -0,0 +1,3 @@
ifneq (,$(filter stdio_cdc_acm stdio_tinyusb_cdc_acm,$(USEMODULE)))
USEMODULE += usb_board_reset
endif

View File

@ -21,14 +21,18 @@ config BOARD_SEEEDSTUDIO_GD32
select HAS_PERIPH_SPI
select HAS_PERIPH_TIMER
select HAS_PERIPH_UART
select HAS_PERIPH_USBDEV
select HAS_TINYUSB_DEVICE
select HAVE_SAUL_GPIO
select HAVE_MTD_SDCARD_DEFAULT
select MODULE_FATFS_VFS if MODULE_VFS_DEFAULT
select PACKAGE_TINYUSB if TEST_KCONFIG
select MODULE_USBUS if TEST_KCONFIG && !PACKAGE_TINYUSB
select MODULE_USBUS_CDC_ACM if MODULE_USBUS
select MODULE_USB_BOARD_RESET if MODULE_USBUS_CDC_ACM || MODULE_TINYUSB_CLASS_CDC
choice STDIO_IMPLEMENTATION
default MODULE_STDIO_CDC_ACM if MODULE_USBUS
default MODULE_STDIO_TINYUSB_CDC_ACM if PACKAGE_TINYUSB
endchoice

View File

@ -12,5 +12,5 @@ ifneq (,$(filter vfs_default,$(USEMODULE)))
USEMODULE += mtd
endif
include $(RIOTBOARD)/common/makefiles/stdio_tinyusb_cdc_acm.dep.mk
include $(RIOTBOARD)/common/makefiles/stdio_cdc_acm.dep.mk
include $(RIOTBOARD)/common/gd32v/Makefile.dep

View File

@ -7,10 +7,11 @@ FEATURES_PROVIDED += periph_pwm
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart
FEATURES_PROVIDED += periph_usbdev
# Other features provided by the board (in alphabetical order)
FEATURES_PROVIDED += highlevel_stdio
FEATURES_PROVIDED += sdcard_spi
FEATURES_PROVIDED += tinyusb_device
include $(RIOTBOARD)/common/gd32v/Makefile.features
include $(RIOTBOARD)/common/gd32v/Makefile.features

View File

@ -22,12 +22,15 @@ config BOARD_SIPEED_LONGAN_NANO
select HAS_PERIPH_SPI
select HAS_PERIPH_TIMER
select HAS_PERIPH_UART
select HAS_PERIPH_USBDEV
select HAS_TINYUSB_DEVICE
select HAVE_SAUL_GPIO
select HAVE_MTD_SDCARD_DEFAULT
select MODULE_FATFS_VFS if MODULE_VFS_DEFAULT
select PACKAGE_TINYUSB if TEST_KCONFIG
select MODULE_USBUS if TEST_KCONFIG && !PACKAGE_TINYUSB
select MODULE_USBUS_CDC_ACM if MODULE_USBUS
select MODULE_USB_BOARD_RESET if MODULE_USBUS_CDC_ACM || MODULE_TINYUSB_CLASS_CDC
menu "Sipeed Longan Nano Board Configuration"
@ -39,6 +42,7 @@ menu "Sipeed Longan Nano Board Configuration"
endmenu
choice STDIO_IMPLEMENTATION
default MODULE_STDIO_CDC_ACM if MODULE_USBUS
default MODULE_STDIO_TINYUSB_CDC_ACM if PACKAGE_TINYUSB
endchoice

View File

@ -12,5 +12,5 @@ ifneq (,$(filter vfs_default,$(USEMODULE)))
USEMODULE += mtd
endif
include $(RIOTBOARD)/common/makefiles/stdio_tinyusb_cdc_acm.dep.mk
include $(RIOTBOARD)/common/makefiles/stdio_cdc_acm.dep.mk
include $(RIOTBOARD)/common/gd32v/Makefile.dep

View File

@ -8,6 +8,7 @@ FEATURES_PROVIDED += periph_pwm
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart
FEATURES_PROVIDED += periph_usbdev
FEATURES_PROVIDED += sdcard_spi
# Other features provided by the board (in alphabetical order)

View File

@ -49,26 +49,14 @@
#define DWC2_USB_OTG_FS_NUM_EP (7)
/**
* @brief Number of USB OTG HS OUT endpoints including the control endpoint
*/
#define DWC2_USB_OTG_HS_NUM_EP (7)
/**
* @brief Size of the FIFO shared by all USB OTG FS OUT endpoints
* @brief Size of the FIFO shared by all USB OTG FS OUT endpoints in 32-bit words
*/
#ifndef DWC2_USB_OTG_FS_RX_FIFO_SIZE
#define DWC2_USB_OTG_FS_RX_FIFO_SIZE (128U)
#endif
/**
* @brief Size of the FIFO shared by all USB OTG HS OUT endpoints
*/
#ifndef DWC2_USB_OTG_HS_RX_FIFO_SIZE
#define DWC2_USB_OTG_HS_RX_FIFO_SIZE (512U)
#endif
/**
* @brief Total size of the FIFO
* @brief Total size of the FIFO in bytes
*/
#define DWC2_USB_OTG_FS_TOTAL_FIFO_SIZE (2048)

View File

@ -243,26 +243,14 @@ extern "C" {
#define DWC2_USB_OTG_FS_NUM_EP (5)
/**
* @brief Number of USB OTG HS OUT endpoints including the control endpoint
*/
#define DWC2_USB_OTG_HS_NUM_EP (5)
/**
* @brief Size of the FIFO shared by all USB OTG FS OUT endpoints
* @brief Size of the FIFO shared by all USB OTG FS OUT endpoints in 32-bit words
*/
#ifndef DWC2_USB_OTG_FS_RX_FIFO_SIZE
#define DWC2_USB_OTG_FS_RX_FIFO_SIZE (128U)
#endif
/**
* @brief Size of the FIFO shared by all USB OTG HS OUT endpoints
*/
#ifndef DWC2_USB_OTG_HS_RX_FIFO_SIZE
#define DWC2_USB_OTG_HS_RX_FIFO_SIZE (512U)
#endif
/**
* @brief Total size of the FIFO
* @brief Total size of the FIFO in bytes
*/
#define DWC2_USB_OTG_FS_TOTAL_FIFO_SIZE (1024U)

View File

@ -244,26 +244,14 @@ extern "C" {
#define DWC2_USB_OTG_FS_NUM_EP (5)
/**
* @brief Number of USB OTG HS OUT endpoints including the control endpoint
*/
#define DWC2_USB_OTG_HS_NUM_EP (5)
/**
* @brief Size of the FIFO shared by all USB OTG FS OUT endpoints
* @brief Size of the FIFO shared by all USB OTG FS OUT endpoints in 32-bit words
*/
#ifndef DWC2_USB_OTG_FS_RX_FIFO_SIZE
#define DWC2_USB_OTG_FS_RX_FIFO_SIZE (128U)
#endif
/**
* @brief Size of the FIFO shared by all USB OTG HS OUT endpoints
*/
#ifndef DWC2_USB_OTG_HS_RX_FIFO_SIZE
#define DWC2_USB_OTG_HS_RX_FIFO_SIZE (512U)
#endif
/**
* @brief Total size of the FIFO
* @brief Total size of the FIFO in bytes
*/
#define DWC2_USB_OTG_FS_TOTAL_FIFO_SIZE (1024U)

View File

@ -30,6 +30,7 @@ config CPU_FAM_GD32V
select MODULE_PERIPH_CLIC if TEST_KCONFIG
select MODULE_PERIPH_WDT if MODULE_PERIPH_PM && HAS_PERIPH_WDT
select MODULE_USBDEV_SYNOPSYS_DWC2 if MODULE_PERIPH_USBDEV
select ZTIMER_USEC if MODULE_PERIPH_I2C
select PACKAGE_NMSIS_SDK

View File

@ -11,4 +11,8 @@ ifneq (,$(filter periph_i2c,$(USEMODULE)))
USEMODULE += ztimer_usec
endif
ifneq (,$(filter periph_usbdev,$(USEMODULE)))
USEMODULE += usbdev_synopsys_dwc2
endif
include $(RIOTCPU)/riscv_common/Makefile.dep

View File

@ -462,7 +462,8 @@ typedef struct {
* @name USB device definitions
* @{
*/
#define USBDEV_NUM_ENDPOINTS 4 /**< Number of USB OTG FS endpoints including EP0 */
#define USBDEV_SET_ADDR_AFTER_STATUS 0 /**< Set device address after SETUP stage */
#define USBDEV_NUM_ENDPOINTS 4 /**< Number of USB OTG FS endpoints including EP0 */
/** @} */
/**

View File

@ -70,7 +70,7 @@
#endif
/**
* @brief Total size of the FIFO
* @brief Total size of the FIFO in bytes
*/
#define DWC2_USB_OTG_FS_TOTAL_FIFO_SIZE (1280)

View File

@ -80,7 +80,7 @@ extern "C" {
#endif
/**
* @brief USB OTG FS FIFO total size
* @brief USB OTG FS FIFO total size in bytes
*
* Some device families (F7 and L4) forgot to define the FS device FIFO size
* in their vendor headers. This define sets it to the value from the
@ -91,7 +91,7 @@ extern "C" {
#endif
/**
* @brief USB OTG FS FIFO total size
* @brief USB OTG FS FIFO total size in bytes
*
* Some device families (F7 and L4) forgot to define the HS device FIFO size
* in their vendor headers. This define sets it to the value from the
@ -102,12 +102,12 @@ extern "C" {
#endif
/**
* @brief USB OTG FS FIFO total size
* @brief USB OTG FS FIFO total size in bytes
*/
#define DWC2_USB_OTG_FS_TOTAL_FIFO_SIZE USB_OTG_FS_TOTAL_FIFO_SIZE
/**
* @brief USB OTG HS FIFO total size
* @brief USB OTG HS FIFO total size in bytes
*/
#define DWC2_USB_OTG_HS_TOTAL_FIFO_SIZE USB_OTG_HS_TOTAL_FIFO_SIZE

View File

@ -49,6 +49,8 @@
#include "usbdev_esp32.h"
#elif defined(MCU_EFM32)
#include "usbdev_efm32.h"
#elif defined(MCU_GD32V)
#include "vendor/usbdev_gd32v.h"
#else
#error "MCU not supported"
#endif
@ -70,6 +72,24 @@
#endif
#ifdef MCU_GD32V
#define RCU_CFG0_SCS_PLL (2UL << RCU_CFG0_SCS_Pos) /* PLL used */
#define USB_OTG_GCCFG_PWRON (1UL << 16) /* Power on */
#define USB_OTG_GCCFG_VBUSBCEN (1UL << 19) /* VBUS B-device comparer enable */
#define USB_OTG_GCCFG_VBUSIG (1UL << 21) /* VBUS detection ignore */
/* Although the following defines are done in `vendor/gd32vf103_rcu.h`, they
* have to be defined here since `vendor/gd32vf103_rcu.h` can't be included due
* to type conflicts with `vendor/gd32vf103_periph.h`. */
#define RCU_CKUSB_CKPLL_DIV1_5 (0UL << 22) /* USB clock is PLL clock/1.5 */
#define RCU_CKUSB_CKPLL_DIV1 (1UL << 22) /* USB clock is PLL clock */
#define RCU_CKUSB_CKPLL_DIV2_5 (2UL << 22) /* USB clock is PLL clock/2.5 */
#define RCU_CKUSB_CKPLL_DIV2 (3UL << 22) /* USB clock is PLL clock/2 */
#endif
#if defined(DWC2_USB_OTG_FS_ENABLED) && defined(DWC2_USB_OTG_HS_ENABLED)
#define _TOTAL_NUM_ENDPOINTS (DWC2_USB_OTG_FS_NUM_EP + \
DWC2_USB_OTG_HS_NUM_EP)
@ -80,14 +100,13 @@
#endif
/* Mask for the set of interrupts used */
#define DWC2_FSHS_USB_GINT_MASK \
(USB_OTG_GINTMSK_USBSUSPM | \
USB_OTG_GINTMSK_WUIM | \
USB_OTG_GINTMSK_ENUMDNEM | \
USB_OTG_GINTMSK_USBRST | \
USB_OTG_GINTMSK_OTGINT | \
USB_OTG_GINTMSK_IEPINT | \
USB_OTG_GINTMSK_OEPINT)
#define DWC2_FSHS_USB_GINT_MASK (USB_OTG_GINTMSK_USBSUSPM | \
USB_OTG_GINTMSK_WUIM | \
USB_OTG_GINTMSK_ENUMDNEM | \
USB_OTG_GINTMSK_USBRST | \
USB_OTG_GINTMSK_OTGINT | \
USB_OTG_GINTMSK_IEPINT | \
USB_OTG_GINTMSK_OEPINT)
#define DWC2_PKTSTS_GONAK 0x01 /**< Rx fifo global out nak */
#define DWC2_PKTSTS_DATA_UPDT 0x02 /**< Rx fifo data update */
@ -130,6 +149,7 @@ typedef struct {
usbdev_ep_t *in; /**< In endpoints */
dwc2_usb_otg_fshs_out_ep_t *out; /**< Out endpoints */
bool suspend; /**< Suspend status */
bool setup_stage; /**< Indicates that EP0 is in SETUP stage */
#ifdef DWC2_USB_OTG_HS_ENABLED
uint8_t *ep0_out_buf; /**< Points to the buffer of EP0 OUT handler */
#endif
@ -207,21 +227,21 @@ static __IO uint32_t *_pcgcctl_reg(const dwc2_usb_otg_fshs_config_t *conf)
*/
static size_t _max_endpoints(const dwc2_usb_otg_fshs_config_t *config)
{
return (config->type == DWC2_USB_OTG_FS) ?
DWC2_USB_OTG_FS_NUM_EP :
DWC2_USB_OTG_HS_NUM_EP;
(void)config;
#if defined(DWC2_USB_OTG_FS_ENABLED) && defined(DWC2_USB_OTG_HS_ENABLED)
return config->type == DWC2_USB_OTG_FS ? DWC2_USB_OTG_FS_NUM_EP
: DWC2_USB_OTG_HS_NUM_EP
#elif defined(DWC2_USB_OTG_FS_ENABLED)
return DWC2_USB_OTG_FS_NUM_EP;
#elif defined(DWC2_USB_OTG_HS_ENABLED)
return DWC2_USB_OTG_HS_NUM_EP;
#else
return 0;
#endif
}
static bool _uses_dma(const dwc2_usb_otg_fshs_config_t *config)
static inline bool _uses_dma(const dwc2_usb_otg_fshs_config_t *config)
{
/* DMA mode is disabled for now due to several problems:
* - The STALL bit of the OUT control endpoint does not seem to be cleared
* automatically on the next SETUP received. At least the USB OTG HS core
* does not generate an interrupt on the next SETUP received. This happens,
* for example, when CDC ACM is used and the host sends the SET_LINE_CODING
* request. In this case the enumeration of further interfaces, for example
* CDC ECM is stopped.
* - The Enumeration fails for CDC ECM interface which uses URB support. */
#ifdef DWC2_USB_OTG_HS_ENABLED
return config->type == DWC2_USB_OTG_HS;
#else
@ -471,21 +491,17 @@ static usbdev_ep_t *_get_ep(dwc2_usb_otg_fshs_t *usbdev, unsigned num,
#if defined(DEVELHELP) && !defined(NDEBUG)
static size_t _total_fifo_size(const dwc2_usb_otg_fshs_config_t *conf)
{
if (conf->type == DWC2_USB_OTG_FS) {
#ifdef DWC2_USB_OTG_FS_ENABLED
return DWC2_USB_OTG_FS_TOTAL_FIFO_SIZE;
(void)conf;
#if defined(DWC2_USB_OTG_FS_ENABLED) && defined(DWC2_USB_OTG_HS_ENABLED)
return conf->type == DWC2_USB_OTG_FS ? DWC2_USB_OTG_FS_TOTAL_FIFO_SIZE
: DWC2_USB_OTG_HS_TOTAL_FIFO_SIZE;
#elif defined(DWC2_USB_OTG_FS_ENABLED)
return DWC2_USB_OTG_FS_TOTAL_FIFO_SIZE;
#elif defined(DWC2_USB_OTG_HS_ENABLED)
return DWC2_USB_OTG_HS_TOTAL_FIFO_SIZE;
#else
return 0;
#endif /* DWC2_USB_OTG_FS_ENABLED */
}
else {
#ifdef DWC2_USB_OTG_HS_ENABLED
return DWC2_USB_OTG_HS_TOTAL_FIFO_SIZE;
#else
return 0;
#endif /* DWC2_USB_OTG_HS_ENABLED */
}
return 0;
#endif
}
#endif /* defined(DEVELHELP) && !defined(NDEBUG) */
@ -509,20 +525,49 @@ static void _configure_tx_fifo(dwc2_usb_otg_fshs_t *usbdev, size_t num,
usbdev->fifo_pos += wordlen;
}
/*
* GRFXSIZ, DWC2_USB_OTG_{HS,FS}_RX_FIFO_SIZE, DWC2_USB_OTG_FIFO_MIN_WORD_SIZE
* are given in 32-bit words
*
* +--------------------+
* | TX FIFO EPn IN |
* +--------------------+ GRFXSIZ + (n * DWC2_USB_OTG_FIFO_MIN_WORD_SIZE)
* | ... |
* +--------------------+ GRFXSIZ + (2 * DWC2_USB_OTG_FIFO_MIN_WORD_SIZE)
* | TX FIFO EP1 IN |
* +--------------------+ GRFXSIZ + (1 * DWC2_USB_OTG_FIFO_MIN_WORD_SIZE)
* | TX FIFO EP0 IN |
* +--------------------+ GRXFSIZ = DWC2_USB_OTG_{HS,FS}_RX_FIFO_SIZE
* | |
* | |
* | RX FIFO Shared OUT |
* | |
* | |
* +--------------------+ 0
*/
static void _configure_fifo(dwc2_usb_otg_fshs_t *usbdev)
{
/* TODO: cleanup, more dynamic, etc */
/* TODO: dynamic FIFO size handling */
const dwc2_usb_otg_fshs_config_t *conf = usbdev->config;
size_t rx_size = conf->type == DWC2_USB_OTG_FS
? DWC2_USB_OTG_FS_RX_FIFO_SIZE
: DWC2_USB_OTG_HS_RX_FIFO_SIZE;
size_t rx_size = 0;
#if defined(DWC2_USB_OTG_FS_ENABLED) && defined(DWC2_USB_OTG_HS_ENABLED)
rx_size = (conf->type == DWC2_USB_OTG_FS) ? DWC2_USB_OTG_FS_RX_FIFO_SIZE
: DWC2_USB_OTG_HS_RX_FIFO_SIZE;
#elif defined(DWC2_USB_OTG_FS_ENABLED)
rx_size = DWC2_USB_OTG_FS_RX_FIFO_SIZE;
#elif defined(DWC2_USB_OTG_HS_ENABLED)
rx_size = DWC2_USB_OTG_HS_RX_FIFO_SIZE;
#endif
_global_regs(conf)->GRXFSIZ =
(_global_regs(conf)->GRXFSIZ & ~USB_OTG_GRXFSIZ_RXFD) |
rx_size;
/* set size and position of TX FIFO for EP0 IN */
_global_regs(conf)->DIEPTXF0_HNPTXFSIZ =
(DWC2_USB_OTG_FIFO_MIN_WORD_SIZE << USB_OTG_TX0FD_Pos) |
rx_size;
/* position of TX FIFO for EP1 IN */
usbdev->fifo_pos = (rx_size + DWC2_USB_OTG_FIFO_MIN_WORD_SIZE);
}
@ -590,10 +635,19 @@ static void _flush_rx_fifo(const dwc2_usb_otg_fshs_config_t *conf)
static void _sleep_periph(const dwc2_usb_otg_fshs_config_t *conf)
{
*_pcgcctl_reg(conf) |= USB_OTG_PCGCCTL_STOPCLK;
/* Unblocking STM32_PM_STOP during suspend on the stm32f446 breaks
* while (un)blocking works on the stm32f401, needs more
* investigation with a larger set of chips */
#if defined(STM32_USB_OTG_CID_1x)
#if defined(MCU_STM32)
/* Unblocking STM32_PM_STOP during suspend on the stm32f446 breaks while
* (un)blocking works on the stm32f401, needs more investigation.
* Works with:
* stm32f407vg FS CID: 1200, HWREV: 4f54281a, HWCFG: 229dcd20
* stm32f429zi HS CID: 1100, HWREV: 4f54281a, HWCFG: 229ed590
* stm32f439zi FS CID: 1200, HWREV: 4f54281a, HWCFG: 229dcd20
* stm32f723ie FS CID: 3000, HWREV: 4f54330a, HWCFG: 229ed520
* stm32f723ie HS CID: 3100, HWREV: 4f54330a, HWCFG: 229fe1d0
* stm32f746ng FS CID: 2000, HWREV: 4f54320a, HWCFG: 229ed520
* stm32f746ng HS CID: 2100, HWREV: 4f54320a, HWCFG: 229fe190
* stm32f767zi FS CID: 2000, HWREV: 4f54320a, HWCFG: 229ed520
*/
pm_unblock(STM32_PM_STOP);
#elif defined(MCU_EFM32)
/* switch USB core clock source either to LFXO or LFRCO */
@ -601,12 +655,14 @@ static void _sleep_periph(const dwc2_usb_otg_fshs_config_t *conf)
pm_unblock(EFM32_PM_MODE_EM2);
#elif defined(MCU_ESP32)
pm_unblock(ESP_PM_LIGHT_SLEEP);
#elif defined(MCU_GD32V)
pm_unblock(GD32V_PM_DEEPSLEEP);
#endif
}
static void _wake_periph(const dwc2_usb_otg_fshs_config_t *conf)
{
#if defined(STM32_USB_OTG_CID_1x)
#if defined(MCU_STM32)
pm_block(STM32_PM_STOP);
#elif defined(MCU_EFM32)
pm_block(EFM32_PM_MODE_EM2);
@ -617,9 +673,11 @@ static void _wake_periph(const dwc2_usb_otg_fshs_config_t *conf)
CMU_ClockSelectSet(cmuClock_USB, cmuSelect_HFCLK);
#else
#error "EFM32 family not yet supported"
#endif
#endif /* defined(CPU_FAM_EFM32GG12B) */
#elif defined(MCU_ESP32)
pm_block(ESP_PM_LIGHT_SLEEP);
#elif defined(MCU_GD32V)
pm_block(GD32V_PM_DEEPSLEEP);
#endif
*_pcgcctl_reg(conf) &= ~USB_OTG_PCGCCTL_STOPCLK;
_flush_rx_fifo(conf);
@ -749,10 +807,54 @@ static void _usbdev_init(usbdev_t *dev)
/* USB VBUSEN pin is not yet used */
/* USB_ROUTELOC0 = location */
#elif defined(MCU_GD32V)
/* Block both DEEP_SLEEP and STANDBY, TODO DEEP_SLEEP is unblocked during
* USB suspend status */
pm_block(GD32V_PM_DEEPSLEEP);
pm_block(GD32V_PM_STANDBY);
/* ensure that PLL clock is used */
assert((RCU->CFG0 & RCU_CFG0_SCS_Msk) == RCU_CFG0_SCS_PLL);
/* ensure that the 48 MHz USB clock can be generated */
static_assert((CLOCK_CORECLOCK == MHZ(48)) || (CLOCK_CORECLOCK == MHZ(72)) ||
(CLOCK_CORECLOCK == MHZ(96)) || (CLOCK_CORECLOCK == MHZ(120)),
"CLOCK_CORECLOCK has to be 48, 72, 96 or 120");
/* divide the core clock to get 48 MHz USB clock */
RCU->CFG0 &= ~RCU_CFG0_USBFSPSC_Msk;
switch (CLOCK_CORECLOCK) {
case MHZ(48):
RCU->CFG0 |= RCU_CKUSB_CKPLL_DIV1;
break;
case MHZ(72):
RCU->CFG0 |= RCU_CKUSB_CKPLL_DIV1_5;
break;
case MHZ(96):
RCU->CFG0 |= RCU_CKUSB_CKPLL_DIV2;
break;
case MHZ(120):
RCU->CFG0 |= RCU_CKUSB_CKPLL_DIV2_5;
break;
}
/* enable USB OTG clock */
periph_clk_en(conf->bus, conf->rcu_mask);
/* reset the USB OTG peripheral */
RCU->AHBRST |= RCU_AHBRST_USBFSRST_Msk;
RCU->AHBRST &= ~RCU_AHBRST_USBFSRST_Msk;
#else
#error "MCU not supported"
#endif
#if ENABLE_DEBUG
uint32_t *_otg_core = (uint32_t *)&_global_regs(usbdev->config)->CID;
DEBUG("CID: %04" PRIx32 ", HWREV: %08" PRIx32 ", HWCFG: %08" PRIx32 "\n",
_otg_core[0], _otg_core[1], _otg_core[3]);
#endif
#ifdef DWC2_USB_OTG_HS_ENABLED
if (conf->type == DWC2_USB_OTG_HS) {
if (conf->phy == DWC2_USB_OTG_PHY_BUILTIN) {
@ -933,6 +1035,11 @@ static void _usbdev_init(usbdev_t *dev)
USB_OTG_GOTGCTL_VBVALOEN |
USB_OTG_GOTGCTL_BVALOEN |
USB_OTG_GOTGCTL_BVALOVAL;
#elif defined(MCU_GD32V)
/* disable Vbus sensing */
_global_regs(usbdev->config)->GCCFG |= USB_OTG_GCCFG_PWRON |
USB_OTG_GCCFG_VBUSIG |
USB_OTG_GCCFG_VBUSBCEN;
#else
#error "MCU not supported"
#endif
@ -964,7 +1071,7 @@ static void _usbdev_init(usbdev_t *dev)
_flush_tx_fifo(conf, 0x10);
/* Values from the reference manual tables on TRDT configuration *
* 0x09 for 24Mhz ABH frequency, 0x06 for 32Mhz or higher AHB frequency */
* 0x09 for 24Mhz AHB frequency, 0x06 for 32Mhz or higher AHB frequency */
uint8_t trdt = conf->type == DWC2_USB_OTG_FS ? 0x06 : 0x09;
_global_regs(conf)->GUSBCFG =
(_global_regs(conf)->GUSBCFG & ~USB_OTG_GUSBCFG_TRDT) |
@ -975,36 +1082,34 @@ static void _usbdev_init(usbdev_t *dev)
/* Disable the global NAK for both directions */
_disable_global_nak(conf);
uint32_t gint_mask = DWC2_FSHS_USB_GINT_MASK;
if (_uses_dma(conf)) {
_global_regs(usbdev->config)->GAHBCFG |=
/* Configure DMA */
USB_OTG_GAHBCFG_DMAEN |
/* DMA configured as 8 x 32bit accesses */
(0x05 << USB_OTG_GAHBCFG_HBSTLEN_Pos);
/* Unmask the transfer complete interrupts
* Only needed when using DMA, otherwise the RX FIFO not empty
* interrupt is used */
_device_regs(conf)->DOEPMSK |= USB_OTG_DOEPMSK_XFRCM | USB_OTG_DOEPMSK_STUPM;
_device_regs(conf)->DIEPMSK |= USB_OTG_DIEPMSK_XFRCM;
}
uint32_t gint_mask = DWC2_FSHS_USB_GINT_MASK;
if (!_uses_dma(conf)) {
else {
/* Use RXFLVL (RX FIFO Level) interrupt for IN EPs in non-DMA mode */
gint_mask |= USB_OTG_GINTMSK_RXFLVLM;
}
/* Unmask XFRC (Transfer Completed) interrupt for IN and OUT EPs */
_device_regs(conf)->DIEPMSK |= USB_OTG_DIEPMSK_XFRCM;
_device_regs(conf)->DOEPMSK |= USB_OTG_DOEPMSK_XFRCM | USB_OTG_DOEPMSK_STUPM;
/* Clear the interrupt flags and unmask those interrupts */
_global_regs(conf)->GINTSTS |= gint_mask;
_global_regs(conf)->GINTMSK |= gint_mask;
DEBUG("usbdev: USB peripheral currently in %s mode\n",
(_global_regs(
conf)->GINTSTS & USB_OTG_GINTSTS_CMOD) ? "host" : "device");
(_global_regs(conf)->GINTSTS & USB_OTG_GINTSTS_CMOD) ? "host"
: "device");
/* Enable interrupts and configure the TX level to interrupt on empty */
_global_regs(conf)->GAHBCFG |= USB_OTG_GAHBCFG_GINT |
USB_OTG_GAHBCFG_TXFELVL;
/* Enable interrupts */
_global_regs(conf)->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
#if defined(MCU_STM32)
/* Unmask the interrupt in the NVIC */
@ -1016,6 +1121,10 @@ static void _usbdev_init(usbdev_t *dev)
void isr_otg_fs(void *arg);
/* Allocate the interrupt and connect it with USB interrupt source */
esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, isr_otg_fs, NULL, NULL);
#elif defined(MCU_GD32V)
void isr_otg_fs(unsigned irq);
clic_set_handler(conf->irqn, isr_otg_fs);
clic_enable_interrupt(conf->irqn, CPU_DEFAULT_IRQ_PRIO);
#else
#error "MCU not supported"
#endif
@ -1133,6 +1242,7 @@ static void _usbdev_esr(usbdev_t *dev)
}
/* Reset all the things! */
usbdev->setup_stage = false;
_flush_rx_fifo(conf);
_flush_tx_fifo(conf, 0x10);
_reset_eps(usbdev);
@ -1161,6 +1271,13 @@ static void _usbdev_esr(usbdev_t *dev)
usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_RESUME);
}
}
else if (int_status & USB_OTG_GINTMSK_OTGINT) {
/* not handled yet, just clear GOTGINT to clear the interrupt */
event = USB_OTG_GINTMSK_OTGINT;
int_status = _global_regs(conf)->GOTGINT;
_global_regs(conf)->GOTGINT |= int_status;
DEBUG("usbdev: OTG interrupt reg %08"PRIx32"\n", int_status);
}
_global_regs(conf)->GINTSTS |= event;
_global_regs(conf)->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
@ -1323,21 +1440,13 @@ static int _usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len)
* controller in the peripheral
*/
/* Packet count seems not to decrement below 1 and thus is broken in
* combination with the TXFE irq, it does however work with control
* transfers and when using DMA */
uint32_t dieptsiz = (len & USB_OTG_DIEPTSIZ_XFRSIZ_Msk);
if (ep->num == 0 || _uses_dma(conf)) {
dieptsiz |= (1 << USB_OTG_DIEPTSIZ_PKTCNT_Pos);
}
_in_regs(conf, ep->num)->DIEPTSIZ = dieptsiz;
/* PKTCNT has to be set for all IN EPs to use the XFRC interrupt */
_in_regs(conf, ep->num)->DIEPTSIZ = (len & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) |
(1 << USB_OTG_DIEPTSIZ_PKTCNT_Pos);
/* Intentionally enabling this before the FIFO is filled, unmasking the
* interrupts after the FIFO is filled doesn't always trigger the ISR */
/* TX FIFO empty interrupt is used for EP0..EPn in non-DMA mode and
* for EP0 for DMA mode */
_device_regs(conf)->DAINTMSK |= 1 << ep->num;
_device_regs(conf)->DIEPEMPMSK |= 1 << ep->num;
_in_regs(conf, ep->num)->DIEPCTL |= USB_OTG_DIEPCTL_CNAK |
USB_OTG_DIEPCTL_EPENA;
@ -1402,37 +1511,35 @@ static void _copy_rxfifo(dwc2_usb_otg_fshs_t *usbdev, uint8_t *buf, size_t len)
}
}
static void _read_packet(dwc2_usb_otg_fshs_out_ep_t *st_ep)
static void _read_packet(dwc2_usb_otg_fshs_t *usbdev)
{
dwc2_usb_otg_fshs_t *usbdev = (dwc2_usb_otg_fshs_t *)st_ep->ep.dev;
const dwc2_usb_otg_fshs_config_t *conf = usbdev->config;
/* Pop status from the receive fifo status register */
uint32_t status = _global_regs(conf)->GRXSTSP;
unsigned epnum = (status & USB_OTG_GRXSTSP_EPNUM_Msk) >>
USB_OTG_GRXSTSP_EPNUM_Pos;
/* Packet status code */
unsigned pkt_status = (status & USB_OTG_GRXSTSP_PKTSTS_Msk) >>
USB_OTG_GRXSTSP_PKTSTS_Pos;
size_t len = (status & USB_OTG_GRXSTSP_BCNT_Msk) >>
USB_OTG_GRXSTSP_BCNT_Pos;
/* Packet is copied on the update status and copied on the transfer
* complete status */
if (pkt_status == DWC2_PKTSTS_DATA_UPDT ||
pkt_status == DWC2_PKTSTS_SETUP_UPDT) {
_copy_rxfifo(usbdev, st_ep->out_buf, len);
#if !defined(STM32_USB_OTG_CID_1x)
/* CID 2x doesn't signal SETUP_COMP on non-zero length packets, signal
* the TR_COMPLETE event immediately */
if (st_ep->ep.num == 0 && len) {
usbdev->usbdev.epcb(&st_ep->ep, USBDEV_EVENT_TR_COMPLETE);
}
#endif /* STM32_USB_OTG_CID_2x */
/* RXFLVL is only used in non-DMA mode to copy the packet from the FIFO
* and to set the flag to indicate the SETUP stage. */
if (pkt_status == DWC2_PKTSTS_SETUP_UPDT) {
/* Some versions of the USB OTG core, e.g. the GD32V USB OTG core,
* may generate an additional XFRC (Transfer Completed) interrupt in
* the SETUP stage before the STUP (SETUP phase done) interrupt. To
* prevent this additional interrupt from being processed accidentally,
* we must indicate that the SETUP stage has been started. */
usbdev->setup_stage = true;
}
/* On zero length frames, only the COMP status is signalled and the UPDT
* status is skipped */
else if (pkt_status == DWC2_PKTSTS_XFER_COMP ||
pkt_status == DWC2_PKTSTS_SETUP_COMP) {
usbdev->usbdev.epcb(&st_ep->ep, USBDEV_EVENT_TR_COMPLETE);
if (len && !_uses_dma(conf)) {
/* in DMA mode, received data are directly written into memory */
_copy_rxfifo(usbdev, usbdev->out[epnum].out_buf, len);
}
}
@ -1448,44 +1555,31 @@ static void _usbdev_ep_esr(usbdev_ep_t *ep)
if (ep->dir == USB_EP_DIR_IN) {
uint32_t status = _in_regs(conf, ep->num)->DIEPINT;
/* XFRC interrupt is used for EP1..EPn in DMA mode but
* cleared in any case */
/* XFRC (Transfer Complete) interrupt is used to signal that the
* transfer is complete. XFRC interrupts only work if the packet
* count (PKTCNT) is set in DIEPTSIZ register. */
if (status & USB_OTG_DIEPINT_XFRC) {
_in_regs(conf, ep->num)->DIEPINT = USB_OTG_DIEPINT_XFRC;
if (_uses_dma(conf) && (ep->num != 0)) {
usbdev->usbdev.epcb(ep, USBDEV_EVENT_TR_COMPLETE);
}
}
else
/* TXFE interrupt is used for all EPs in non-DMA mode but only for EP0
* in DMA mode. It is disabled in any case. */
if (status & USB_OTG_DIEPINT_TXFE) {
_device_regs(conf)->DIEPEMPMSK &= ~(1 << ep->num);
if (!_uses_dma(conf) || (ep->num == 0)) {
usbdev->usbdev.epcb(ep, USBDEV_EVENT_TR_COMPLETE);
}
usbdev->usbdev.epcb(ep, USBDEV_EVENT_TR_COMPLETE);
}
}
else {
/* RX FIFO not empty and the endpoint matches the function argument */
if ((_global_regs(conf)->GINTSTS & USB_OTG_GINTSTS_RXFLVL) &&
(_global_regs(conf)->GRXSTSR & USB_OTG_GRXSTSP_EPNUM_Msk) == ep->num &&
!_uses_dma(conf)) {
_read_packet(container_of(ep, dwc2_usb_otg_fshs_out_ep_t, ep));
}
#ifdef DWC2_USB_OTG_HS_ENABLED
else if (_out_regs(conf, ep->num)->DOEPINT & USB_OTG_DOEPINT_STUP) {
uint32_t status = _out_regs(conf, ep->num)->DOEPINT;
if (status & USB_OTG_DOEPINT_STUP) {
_out_regs(conf, ep->num)->DOEPINT = USB_OTG_DOEPINT_STUP;
_out_regs(conf, ep->num)->DOEPINT = USB_OTG_DOEPINT_XFRC;
if (_uses_dma(conf)) {
usbdev->usbdev.epcb(ep, USBDEV_EVENT_TR_COMPLETE);
}
/* Indicate that the SETUP stage has been finished */
usbdev->setup_stage = false;
usbdev->usbdev.epcb(ep, USBDEV_EVENT_TR_COMPLETE);
}
#endif
/* Transfer complete seems only reliable when used with DMA */
else if (_out_regs(conf, ep->num)->DOEPINT & USB_OTG_DOEPINT_XFRC) {
else if (status & USB_OTG_DOEPINT_XFRC) {
_out_regs(conf, ep->num)->DOEPINT = USB_OTG_DOEPINT_XFRC;
if (_uses_dma(conf)) {
/* Some versions of the USB OTG core, e.g. the GD32V USB OTG core,
* may generate an additional XFRC (Transfer Complete) interrupt in
* the SETUP stage before the STUP (SETUP phase done) interrupt is
* triggered. USBDEV_EVENT_TR_COMPLETE must not be generated
* for EP0 in this case. */
if (!usbdev->setup_stage || (ep->num != 0)) {
usbdev->usbdev.epcb(ep, USBDEV_EVENT_TR_COMPLETE);
}
}
@ -1519,23 +1613,26 @@ void _isr_common(dwc2_usb_otg_fshs_t *usbdev)
uint32_t status = _global_regs(conf)->GINTSTS;
_global_regs(conf)->GAHBCFG &= ~USB_OTG_GAHBCFG_GINT;
if (status) {
if ((status & USB_OTG_GINTSTS_RXFLVL) && !_uses_dma(conf)) {
unsigned epnum = _global_regs(conf)->GRXSTSR &
USB_OTG_GRXSTSP_EPNUM_Msk;
usbdev->usbdev.epcb(&usbdev->out[epnum].ep, USBDEV_EVENT_ESR);
if (status & USB_OTG_GINTSTS_RXFLVL) {
/* The RXFLVL interrupt is only enabled in non-DMA mode. It is only
* used to read out the RX FIFO and set the SETUP stage flasg and
* can therefore be handled directly in the ISR. */
_read_packet(usbdev);
_global_regs(conf)->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
}
else if (_global_regs(conf)->GINTSTS &
(USB_OTG_GINTSTS_OEPINT | USB_OTG_GINTSTS_IEPINT)) {
else if (status & (USB_OTG_GINTSTS_OEPINT | USB_OTG_GINTSTS_IEPINT)) {
_isr_ep(usbdev);
}
else {
/* Global interrupt */
usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_ESR);
}
_global_regs(conf)->GAHBCFG &= ~USB_OTG_GAHBCFG_GINT;
}
#ifdef MCU_STM32
#ifdef MODULE_CORTEXM_COMMON
cortexm_isr_end();
#endif
}
@ -1564,7 +1661,6 @@ void isr_otg_hs(void)
#elif defined(MCU_ESP32)
#ifdef DWC2_USB_OTG_FS_ENABLED
void isr_otg_fs(void *arg)
{
(void)arg;
@ -1574,23 +1670,10 @@ void isr_otg_fs(void *arg)
_isr_common(usbdev);
}
#endif /* DWC2_USB_OTG_FS_ENABLED */
#ifdef DWC2_USB_OTG_HS_ENABLED
void isr_otg_hs(void *arg)
{
(void)arg;
/* Take the last usbdev device from the list */
dwc2_usb_otg_fshs_t *usbdev = &_usbdevs[USBDEV_NUMOF - 1];
_isr_common(usbdev);
}
#endif /* DWC2_USB_OTG_HS_ENABLED */
#elif defined(MCU_EFM32)
void isr_usb(void)
void isr_usb(void)
{
/* Take the first device from the list */
dwc2_usb_otg_fshs_t *usbdev = &_usbdevs[0];
@ -1598,6 +1681,18 @@ void isr_otg_hs(void *arg)
_isr_common(usbdev);
}
#elif defined(MCU_GD32V)
void isr_otg_fs(unsigned irq)
{
(void)irq;
/* Take the first device from the list */
dwc2_usb_otg_fshs_t *usbdev = &_usbdevs[0];
_isr_common(usbdev);
}
#else
#error "MCU not supported"
#endif

View File

@ -12,6 +12,8 @@ USEMODULE += ps
# Boards that don't have enough endpoints to use CDC ACM together with CDC ECM
ifeq (,$(filter stdio_%,$(filter-out stdio_cdc_acm,$(USEMODULE))))
BOARD_BLACKLIST += \
sipeed-longan-nano \
seeedstudio-gd32 \
stm32f4discovery \
weact-f401cc \
weact-f401ce \