From dc7abdf723938f2c8b1c24a569bf857a4ed2dea7 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Tue, 7 Feb 2023 00:50:06 +0100 Subject: [PATCH] pkg/tinyusb: add GD32V support --- pkg/tinyusb/Kconfig | 1 + pkg/tinyusb/Makefile.dep | 2 + pkg/tinyusb/Makefile.include | 2 + pkg/tinyusb/hw/hw_gd32v.c | 116 +++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 pkg/tinyusb/hw/hw_gd32v.c diff --git a/pkg/tinyusb/Kconfig b/pkg/tinyusb/Kconfig index 01997a6047..daa10a765e 100644 --- a/pkg/tinyusb/Kconfig +++ b/pkg/tinyusb/Kconfig @@ -28,6 +28,7 @@ menuconfig PACKAGE_TINYUSB select MODULE_TINYUSB_CONTRIB select MODULE_TINYUSB_HW select MODULE_TINYUSB_PORTABLE_ESPRESSIF if CPU_FAM_ESP32S2 || CPU_FAM_ESP32S3 + select MODULE_TINYUSB_PORTABLE_SYNOPSYS_DWC2 if CPU_FAM_GD32V # Whole STM32 families F2, F4, F7 and U5 use the Synopsys DWC2 USB OTG core select MODULE_TINYUSB_PORTABLE_SYNOPSYS_DWC2 if HAS_CPU_STM32F2 select MODULE_TINYUSB_PORTABLE_SYNOPSYS_DWC2 if HAS_CPU_STM32F4 diff --git a/pkg/tinyusb/Makefile.dep b/pkg/tinyusb/Makefile.dep index f48197dad2..9d83cc463b 100644 --- a/pkg/tinyusb/Makefile.dep +++ b/pkg/tinyusb/Makefile.dep @@ -115,6 +115,8 @@ else ifeq (stm32,$(CPU)) # all other STM32 with USB interface use USB FS Device core USEMODULE += tinyusb_portable_stm32_fsdev endif +else ifeq (gd32v,$(CPU)) + USEMODULE += tinyusb_portable_synopsys_dwc2 endif # other module dependencies diff --git a/pkg/tinyusb/Makefile.include b/pkg/tinyusb/Makefile.include index bcf048baae..fc08e9ed23 100644 --- a/pkg/tinyusb/Makefile.include +++ b/pkg/tinyusb/Makefile.include @@ -30,6 +30,8 @@ else ifeq (samd21,$(CPU)) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_SAMD21 else ifeq (samd5x,$(CPU)) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_SAME5X +else ifeq (gd32v,$(CPU)) + CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_GD32VF103 else $(error CPU $(CPU) or CPU family $(CPU_FAM) not supported) endif diff --git a/pkg/tinyusb/hw/hw_gd32v.c b/pkg/tinyusb/hw/hw_gd32v.c new file mode 100644 index 0000000000..632d1f0e10 --- /dev/null +++ b/pkg/tinyusb/hw/hw_gd32v.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2023 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup pkg_tinyusb + * @brief + * @{ + * + * @brief tinyUSB hardware driver for GD32VF103 MCUs + * @author Gunar Schorcht + */ + +#include + +#include "periph_conf.h" +#include "periph/gpio.h" +#include "pm_layered.h" + +#include "tusb.h" +#include "device/usbd.h" +#include "host/usbh.h" + +#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 */ + +static int tinyusb_hw_init_dev(const dwc2_usb_otg_fshs_config_t *conf) +{ + /* 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 */ + assert((CLOCK_CORECLOCK == MHZ(48)) || (CLOCK_CORECLOCK == MHZ(72)) || + (CLOCK_CORECLOCK == MHZ(96)) || (CLOCK_CORECLOCK == MHZ(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; + + void isr_otg_fs(unsigned irq); + clic_set_handler(conf->irqn, isr_otg_fs); + clic_enable_interrupt(conf->irqn, CPU_DEFAULT_IRQ_PRIO); + + USB_OTG_GlobalTypeDef *global_regs = + (USB_OTG_GlobalTypeDef *)(conf->periph + USB_OTG_GLOBAL_BASE); + + /* disable VBUS sensing */ + global_regs->GCCFG |= USB_OTG_GCCFG_PWRON | + USB_OTG_GCCFG_VBUSIG | + USB_OTG_GCCFG_VBUSBCEN; + return 0; +} + +int tinyusb_hw_init(void) +{ + for (unsigned i = 0; i < USBDEV_NUMOF; i++) { + if (tinyusb_hw_init_dev(&dwc2_usb_otg_fshs_config[i]) != 0) { + return -ENODEV; + } + } + return 0; +} + +void isr_otg_fs(unsigned irq) +{ + (void)irq; + + /* call device interrupt handler with the first device */ + if (IS_USED(MODULE_TINYUSB_DEVICE)) { + tud_int_handler(TINYUSB_TUD_RHPORT); + } + + /* call host interrupt handler with the first device */ + if (IS_USED(MODULE_TINYUSB_HOST)) { + tuh_int_handler(TINYUSB_TUH_RHPORT); + } +}