From fccbcfc88977ebdfb1448f6787cb052cfa949788 Mon Sep 17 00:00:00 2001
From: Greg Davill <greg.davill@gmail.com>
Date: Mon, 21 Mar 2022 10:01:11 +1030
Subject: [PATCH 01/20] Add WCH CH32V307 port

Add WCH mcu submodule
Add CH32V307V-R1-1v0 bsp
---
 .gitmodules                                   |   3 +
 .../ch32v307/boards/CH32V307V-R1-1v0/board.mk |   3 +
 .../boards/CH32V307V-R1-1v0/debug_uart.c      | 110 +++
 .../boards/CH32V307V-R1-1v0/debug_uart.h      |  31 +
 hw/bsp/ch32v307/ch32v30x_conf.h               |  43 +
 hw/bsp/ch32v307/ch32v30x_it.c                 |  49 ++
 hw/bsp/ch32v307/ch32v30x_it.h                 |  18 +
 hw/bsp/ch32v307/core_riscv.h                  | 384 +++++++++
 hw/bsp/ch32v307/family.c                      | 160 ++++
 hw/bsp/ch32v307/family.mk                     |  62 ++
 hw/bsp/ch32v307/system_ch32v30x.c             | 776 ++++++++++++++++++
 hw/bsp/ch32v307/system_ch32v30x.h             |  30 +
 hw/mcu/wch/ch32v307                           |   1 +
 src/common/tusb_mcu.h                         |   4 +
 .../wch/ch32v307/usb_ch32_usbhs_reg.h         | 345 ++++++++
 src/portable/wch/ch32v307/usb_dc_usbhs.c      | 388 +++++++++
 src/tusb_option.h                             |   3 +
 17 files changed, 2410 insertions(+)
 create mode 100644 hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk
 create mode 100644 hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c
 create mode 100644 hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h
 create mode 100644 hw/bsp/ch32v307/ch32v30x_conf.h
 create mode 100644 hw/bsp/ch32v307/ch32v30x_it.c
 create mode 100644 hw/bsp/ch32v307/ch32v30x_it.h
 create mode 100644 hw/bsp/ch32v307/core_riscv.h
 create mode 100644 hw/bsp/ch32v307/family.c
 create mode 100644 hw/bsp/ch32v307/family.mk
 create mode 100644 hw/bsp/ch32v307/system_ch32v30x.c
 create mode 100644 hw/bsp/ch32v307/system_ch32v30x.h
 create mode 160000 hw/mcu/wch/ch32v307
 create mode 100644 src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h
 create mode 100644 src/portable/wch/ch32v307/usb_dc_usbhs.c

diff --git a/.gitmodules b/.gitmodules
index 21bbf08c0..fd2b75cb8 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -146,3 +146,6 @@
 [submodule "hw/mcu/allwinner"]
 	path = hw/mcu/allwinner
 	url = https://github.com/hathach/allwinner_driver.git
+[submodule "hw/mcu/wch/ch32v307"]
+	path = hw/mcu/wch/ch32v307
+	url = https://github.com/openwch/ch32v307.git
diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk
new file mode 100644
index 000000000..f71def2c7
--- /dev/null
+++ b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk
@@ -0,0 +1,3 @@
+LINKER_SCRIPTS = $(CH32V307_SDK_SRC)/Ld
+
+LD_FILE = $(LINKER_SCRIPTS)/Link.ld # CH32V307
diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c
new file mode 100644
index 000000000..416782d0e
--- /dev/null
+++ b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c
@@ -0,0 +1,110 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Greg Davill
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "debug_uart.h"
+#include <ch32v30x.h>
+
+
+#define UART_RINGBUFFER_SIZE_TX 64
+#define UART_RINGBUFFER_MASK_TX (UART_RINGBUFFER_SIZE_TX-1)
+
+static char tx_buf[UART_RINGBUFFER_SIZE_TX];
+static unsigned int tx_produce;
+static volatile unsigned int tx_consume;
+
+void USART1_IRQHandler(void) __attribute__((naked));
+void USART1_IRQHandler(void) { 
+      __asm volatile ("call USART1_IRQHandler_impl; mret");
+}
+
+__attribute__((used)) void USART1_IRQHandler_impl(void)
+{
+	if(USART_GetITStatus(USART1, USART_IT_TC) != RESET)
+    {
+        USART_ClearITPendingBit(USART1, USART_IT_TC);
+
+		if(tx_consume != tx_produce) {
+			USART_SendData(USART1, tx_buf[tx_consume]);
+			tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX;
+		}
+    }
+
+}
+
+void uart_write(char c)
+{
+	unsigned int tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX;
+	
+    NVIC_DisableIRQ(USART1_IRQn);
+    if((tx_consume != tx_produce) || (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)) {
+		tx_buf[tx_produce] = c;
+		tx_produce = tx_produce_next;
+	} else {
+		USART_SendData(USART1, c);
+	}
+    NVIC_EnableIRQ(USART1_IRQn);
+}
+
+
+void uart_sync(void)
+{
+	while(tx_consume != tx_produce);
+}
+
+
+void USART_Printf_Init(uint32_t baudrate)
+{
+    GPIO_InitTypeDef  GPIO_InitStructure;
+    USART_InitTypeDef USART_InitStructure;
+
+	tx_produce = 0;
+	tx_consume = 0;
+
+    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
+
+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+    GPIO_Init(GPIOA, &GPIO_InitStructure);
+
+    USART_InitStructure.USART_BaudRate = baudrate;
+    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
+    USART_InitStructure.USART_StopBits = USART_StopBits_1;
+    USART_InitStructure.USART_Parity = USART_Parity_No;
+    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
+    USART_InitStructure.USART_Mode = USART_Mode_Tx;
+
+    USART_Init(USART1, &USART_InitStructure);
+    USART_ITConfig(USART1, USART_IT_TC, ENABLE);
+    USART_Cmd(USART1, ENABLE);
+
+    NVIC_InitTypeDef  NVIC_InitStructure = {0};
+    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
+    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
+    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
+    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+    NVIC_Init(&NVIC_InitStructure);
+}
diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h
new file mode 100644
index 000000000..4348438bb
--- /dev/null
+++ b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h
@@ -0,0 +1,31 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Greg Davill
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include <stdint.h>
+
+void uart_write(char c);
+void uart_sync(void);
+void USART_Printf_Init(uint32_t baudrate);
diff --git a/hw/bsp/ch32v307/ch32v30x_conf.h b/hw/bsp/ch32v307/ch32v30x_conf.h
new file mode 100644
index 000000000..399feaf68
--- /dev/null
+++ b/hw/bsp/ch32v307/ch32v30x_conf.h
@@ -0,0 +1,43 @@
+/********************************** (C) COPYRIGHT *******************************
+* File Name          : ch32v30x_conf.h
+* Author             : WCH
+* Version            : V1.0.0
+* Date               : 2021/06/06
+* Description        : Library configuration file.
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* SPDX-License-Identifier: Apache-2.0
+*******************************************************************************/ 
+#ifndef __CH32V30x_CONF_H
+#define __CH32V30x_CONF_H
+
+#include "ch32v30x_adc.h"
+#include "ch32v30x_bkp.h"
+#include "ch32v30x_can.h"
+#include "ch32v30x_crc.h"
+#include "ch32v30x_dac.h"
+#include "ch32v30x_dbgmcu.h"
+#include "ch32v30x_dma.h"
+#include "ch32v30x_exti.h"
+#include "ch32v30x_flash.h"
+#include "ch32v30x_fsmc.h"
+#include "ch32v30x_gpio.h"
+#include "ch32v30x_i2c.h"
+#include "ch32v30x_iwdg.h"
+#include "ch32v30x_pwr.h"
+#include "ch32v30x_rcc.h"
+#include "ch32v30x_rtc.h"
+#include "ch32v30x_sdio.h"
+#include "ch32v30x_spi.h"
+#include "ch32v30x_tim.h"
+#include "ch32v30x_usart.h"
+#include "ch32v30x_wwdg.h"
+#include "ch32v30x_it.h"
+#include "ch32v30x_misc.h"
+
+
+#endif /* __CH32V30x_CONF_H */
+
+
+	
+	
+	
diff --git a/hw/bsp/ch32v307/ch32v30x_it.c b/hw/bsp/ch32v307/ch32v30x_it.c
new file mode 100644
index 000000000..d348dd989
--- /dev/null
+++ b/hw/bsp/ch32v307/ch32v30x_it.c
@@ -0,0 +1,49 @@
+/********************************** (C) COPYRIGHT *******************************
+* File Name          : ch32v30x_it.c
+* Author             : WCH
+* Version            : V1.0.0
+* Date               : 2021/06/06
+* Description        : Main Interrupt Service Routines.
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* SPDX-License-Identifier: Apache-2.0
+*******************************************************************************/
+#include "ch32v30x_it.h"
+
+void NMI_Handler(void) __attribute__((naked));
+void HardFault_Handler(void) __attribute__((naked));
+
+/*********************************************************************
+ * @fn      NMI_Handler
+ *
+ * @brief   This function handles NMI exception.
+ *
+ * @return  none
+ */
+void NMI_Handle(void){
+      __asm volatile ("call NMI_Handler_impl; mret");
+}
+
+__attribute__((used)) void NMI_Handler_impl(void)
+{
+
+}
+
+/*********************************************************************
+ * @fn      HardFault_Handler
+ *
+ * @brief   This function handles Hard Fault exception.
+ *
+ * @return  none
+ */
+void HardFault_Handler(void){
+      __asm volatile ("call HardFault_Handler_impl; mret");
+}
+
+__attribute__((used)) void HardFault_Handler_impl(void)
+{
+  while (1)
+  {
+  }
+}
+
+
diff --git a/hw/bsp/ch32v307/ch32v30x_it.h b/hw/bsp/ch32v307/ch32v30x_it.h
new file mode 100644
index 000000000..6475c5f11
--- /dev/null
+++ b/hw/bsp/ch32v307/ch32v30x_it.h
@@ -0,0 +1,18 @@
+/********************************** (C) COPYRIGHT *******************************
+* File Name          : ch32v30x_it.h
+* Author             : WCH
+* Version            : V1.0.0
+* Date               : 2021/06/06
+* Description        : This file contains the headers of the interrupt handlers.
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* SPDX-License-Identifier: Apache-2.0
+*******************************************************************************/
+#ifndef __CH32V30x_IT_H
+#define __CH32V30x_IT_H
+
+#include "debug.h"
+
+
+#endif /* __CH32V30x_IT_H */
+
+
diff --git a/hw/bsp/ch32v307/core_riscv.h b/hw/bsp/ch32v307/core_riscv.h
new file mode 100644
index 000000000..2e94ec683
--- /dev/null
+++ b/hw/bsp/ch32v307/core_riscv.h
@@ -0,0 +1,384 @@
+/********************************** (C) COPYRIGHT  *******************************
+* File Name          : core_riscv.h
+* Author             : WCH
+* Version            : V1.0.0
+* Date               : 2021/06/06
+* Description        : RISC-V Core Peripheral Access Layer Header File for CH32V30x
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* SPDX-License-Identifier: Apache-2.0
+*******************************************************************************/
+#ifndef __CORE_RISCV_H__
+#define __CORE_RISCV_H__
+
+/* IO definitions */
+#ifdef __cplusplus
+  #define     __I     volatile                /* defines 'read only' permissions */
+#else
+  #define     __I     volatile const          /* defines 'read only' permissions */
+#endif
+#define     __O     volatile                  /* defines 'write only' permissions */
+#define     __IO    volatile                  /* defines 'read / write' permissions */
+
+/* Standard Peripheral Library old types (maintained for legacy purpose) */
+typedef __I uint64_t vuc64;  /* Read Only */
+typedef __I uint32_t vuc32;  /* Read Only */
+typedef __I uint16_t vuc16;  /* Read Only */
+typedef __I uint8_t vuc8;   /* Read Only */
+
+typedef const uint64_t uc64;  /* Read Only */
+typedef const uint32_t uc32;  /* Read Only */
+typedef const uint16_t uc16;  /* Read Only */
+typedef const uint8_t uc8;   /* Read Only */
+
+typedef __I int64_t vsc64;  /* Read Only */
+typedef __I int32_t vsc32;  /* Read Only */
+typedef __I int16_t vsc16;  /* Read Only */
+typedef __I int8_t vsc8;   /* Read Only */
+
+typedef const int64_t sc64;  /* Read Only */
+typedef const int32_t sc32;  /* Read Only */
+typedef const int16_t sc16;  /* Read Only */
+typedef const int8_t sc8;   /* Read Only */
+
+typedef __IO uint64_t  vu64;
+typedef __IO uint32_t  vu32;
+typedef __IO uint16_t vu16;
+typedef __IO uint8_t  vu8;
+
+typedef uint64_t  u64;
+typedef uint32_t  u32;
+typedef uint16_t u16;
+typedef uint8_t  u8;
+
+typedef __IO int64_t  vs64;
+typedef __IO int32_t  vs32;
+typedef __IO int16_t  vs16;
+typedef __IO int8_t   vs8;
+
+typedef int64_t  s64;
+typedef int32_t  s32;
+typedef int16_t s16;
+typedef int8_t  s8;
+
+typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
+
+typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
+
+typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
+
+#define   RV_STATIC_INLINE  static  inline
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct{
+  __I  uint32_t ISR[8];
+  __I  uint32_t IPR[8];
+  __IO uint32_t ITHRESDR;
+  __IO uint32_t RESERVED;
+  __IO uint32_t CFGR;
+  __I  uint32_t GISR;
+  uint8_t VTFIDR[4];
+  uint8_t RESERVED0[12];
+  __IO uint32_t VTFADDR[4];
+  uint8_t RESERVED1[0x90];
+  __O  uint32_t IENR[8];
+  uint8_t RESERVED2[0x60];
+  __O  uint32_t IRER[8];
+  uint8_t RESERVED3[0x60];
+  __O  uint32_t IPSR[8];
+  uint8_t RESERVED4[0x60];
+  __O  uint32_t IPRR[8];
+  uint8_t RESERVED5[0x60];
+  __IO uint32_t IACTR[8];
+  uint8_t RESERVED6[0xE0];
+  __IO uint8_t IPRIOR[256];
+  uint8_t RESERVED7[0x810];
+  __IO uint32_t SCTLR;
+}PFIC_Type;
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+    __IO u32 CTLR;
+    __IO u32 SR;
+    __IO u64 CNT;
+    __IO u64 CMP;
+}SysTick_Type;
+
+
+#define PFIC            ((PFIC_Type *) 0xE000E000 )
+#define NVIC            PFIC
+#define NVIC_KEY1       ((uint32_t)0xFA050000)
+#define	NVIC_KEY2				((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3				((uint32_t)0xBEEF0000)
+
+#define SysTick         ((SysTick_Type *) 0xE000F000)
+
+
+/*********************************************************************
+ * @fn      __enable_irq
+ *
+ * @brief   Enable Global Interrupt
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void __enable_irq(void)
+{
+  __asm volatile ("csrw 0x800, %0" : : "r" (0x6088) );
+}
+
+/*********************************************************************
+ * @fn      __disable_irq
+ *
+ * @brief   Disable Global Interrupt
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void __disable_irq(void)
+{
+  __asm volatile ("csrw 0x800, %0" : : "r" (0x6000) );
+}
+
+/*********************************************************************
+ * @fn      __NOP
+ *
+ * @brief   nop
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void __NOP(void)
+{
+  __asm volatile ("nop");
+}
+
+/*********************************************************************
+ * @fn      NVIC_EnableIRQ
+ *
+ * @brief   Enable Interrupt
+ *
+ * @param   IRQn: Interrupt Numbers
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
+{
+  NVIC->IENR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
+}
+
+/*********************************************************************
+ * @fn      NVIC_DisableIRQ
+ *
+ * @brief   Disable Interrupt
+ *
+ * @param   IRQn: Interrupt Numbers
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
+{
+  NVIC->IRER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
+}
+
+/*********************************************************************
+ * @fn      NVIC_GetStatusIRQ
+ *
+ * @brief   Get Interrupt Enable State
+ *
+ * @param   IRQn: Interrupt Numbers
+ *
+ * @return  1 - Interrupt Enable
+ *          0 - Interrupt Disable
+ */
+RV_STATIC_INLINE uint32_t NVIC_GetStatusIRQ(IRQn_Type IRQn)
+{
+  return((uint32_t) ((NVIC->ISR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
+}
+
+/*********************************************************************
+ * @fn      NVIC_GetPendingIRQ
+ *
+ * @brief   Get Interrupt Pending State
+ *
+ * @param   IRQn: Interrupt Numbers
+ *
+ * @return  1 - Interrupt Pending Enable
+ *          0 - Interrupt Pending Disable
+ */
+RV_STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
+{
+  return((uint32_t) ((NVIC->IPR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
+}
+
+/*********************************************************************
+ * @fn      NVIC_SetPendingIRQ
+ *
+ * @brief   Set Interrupt Pending
+ *
+ * @param   IRQn: Interrupt Numbers
+ *
+ * @return  None
+ */
+RV_STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
+{
+  NVIC->IPSR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
+}
+
+/*********************************************************************
+ * @fn      NVIC_ClearPendingIRQ
+ *
+ * @brief   Clear Interrupt Pending
+ *
+ * @param   IRQn: Interrupt Numbers
+ *
+ * @return  None
+ */
+RV_STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
+{
+  NVIC->IPRR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
+}
+
+/*********************************************************************
+ * @fn      NVIC_GetActive
+ *
+ * @brief   Get Interrupt Active State
+ *
+ * @param   IRQn: Interrupt Numbers
+ *
+ * @return  1 - Interrupt Active
+ *          0 - Interrupt No Active
+ */
+RV_STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)
+{
+  return((uint32_t)((NVIC->IACTR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
+}
+
+/*********************************************************************
+ * @fn      NVIC_SetPriority
+ *
+ * @brief   Set Interrupt Priority
+ *
+ * @param   IRQn - Interrupt Numbers
+ *          priority -
+ *              bit7 - pre-emption priority
+ *              bit6~bit4 - subpriority
+ * @return  None
+ */
+RV_STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint8_t priority)
+{
+  NVIC->IPRIOR[(uint32_t)(IRQn)] = priority;
+}
+
+/*********************************************************************
+ * @fn      __WFI
+ *
+ * @brief   Wait for Interrupt
+ *
+ * @return  None
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFI(void)
+{
+  NVIC->SCTLR &= ~(1<<3);	// wfi
+  asm volatile ("wfi");
+}
+
+/*********************************************************************
+ * @fn      __WFE
+ *
+ * @brief   Wait for Events
+ *
+ * @return  None
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFE(void)
+{
+  uint32_t t;
+
+  t = NVIC->SCTLR;
+  NVIC->SCTLR |= (1<<3)|(1<<5);		// (wfi->wfe)+(__sev)
+  NVIC->SCTLR = (NVIC->SCTLR & ~(1<<5)) | ( t & (1<<5));
+  asm volatile ("wfi");
+  asm volatile ("wfi");
+}
+
+/*********************************************************************
+ * @fn      SetVTFIRQ
+ *
+ * @brief   Set VTF Interrupt
+ *
+ * @param   add - VTF interrupt service function base address.
+ *          IRQn -Interrupt Numbers
+ *          num - VTF Interrupt Numbers
+ *          NewState - DISABLE or ENABLE
+ * @return  None
+ */
+RV_STATIC_INLINE void SetVTFIRQ(uint32_t addr, IRQn_Type IRQn, uint8_t num, FunctionalState NewState){
+  if(num > 3)  return ;
+
+  if (NewState != DISABLE)
+  {
+      NVIC->VTFIDR[num] = IRQn;
+      NVIC->VTFADDR[num] = ((addr&0xFFFFFFFE)|0x1);
+  }
+  else{
+      NVIC->VTFIDR[num] = IRQn;
+      NVIC->VTFADDR[num] = ((addr&0xFFFFFFFE)&(~0x1));
+  }
+}
+
+/*********************************************************************
+ * @fn      NVIC_SystemReset
+ *
+ * @brief   Initiate a system reset request
+ *
+ * @return  None
+ */
+RV_STATIC_INLINE void NVIC_SystemReset(void)
+{
+  NVIC->CFGR = NVIC_KEY3|(1<<7);
+}
+
+
+/* Core_Exported_Functions */  
+extern uint32_t __get_FFLAGS(void);
+extern void __set_FFLAGS(uint32_t value);
+extern uint32_t __get_FRM(void);
+extern void __set_FRM(uint32_t value);
+extern uint32_t __get_FCSR(void);
+extern void __set_FCSR(uint32_t value);
+extern uint32_t __get_MSTATUS(void);
+extern void __set_MSTATUS(uint32_t value);
+extern uint32_t __get_MISA(void);
+extern void __set_MISA(uint32_t value);
+extern uint32_t __get_MIE(void);
+extern void __set_MIE(uint32_t value);
+extern uint32_t __get_MTVEC(void);
+extern void __set_MTVEC(uint32_t value);
+extern uint32_t __get_MSCRATCH(void);
+extern void __set_MSCRATCH(uint32_t value);
+extern uint32_t __get_MEPC(void);
+extern void __set_MEPC(uint32_t value);
+extern uint32_t __get_MCAUSE(void);
+extern void __set_MCAUSE(uint32_t value);
+extern uint32_t __get_MTVAL(void);
+extern void __set_MTVAL(uint32_t value);
+extern uint32_t __get_MIP(void);
+extern void __set_MIP(uint32_t value);
+extern uint32_t __get_MCYCLE(void);
+extern void __set_MCYCLE(uint32_t value);
+extern uint32_t __get_MCYCLEH(void);
+extern void __set_MCYCLEH(uint32_t value);
+extern uint32_t __get_MINSTRET(void);
+extern void __set_MINSTRET(uint32_t value);
+extern uint32_t __get_MINSTRETH(void);
+extern void __set_MINSTRETH(uint32_t value);
+extern uint32_t __get_MVENDORID(void);
+extern uint32_t __get_MARCHID(void);
+extern uint32_t __get_MIMPID(void);
+extern uint32_t __get_MHARTID(void);
+extern uint32_t __get_SP(void);
+
+
+#endif
+
+
+
+
+
diff --git a/hw/bsp/ch32v307/family.c b/hw/bsp/ch32v307/family.c
new file mode 100644
index 000000000..ea1c252c4
--- /dev/null
+++ b/hw/bsp/ch32v307/family.c
@@ -0,0 +1,160 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Greg Davill
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "stdio.h"
+#include "debug_uart.h"
+#include "ch32v30x.h"
+
+#include "../board.h"
+
+//--------------------------------------------------------------------+
+// Forward USB interrupt events to TinyUSB IRQ Handler
+//--------------------------------------------------------------------+
+
+void USBHS_IRQHandler(void) __attribute__((naked));
+void USBHS_IRQHandler(void) { 
+        __asm volatile ("call USBHS_IRQHandler_impl; mret");
+}
+
+__attribute__ ((used)) void USBHS_IRQHandler_impl(void) { 
+  tud_int_handler(0); 
+}
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
+
+uint32_t SysTick_Config(uint32_t ticks)
+{
+    NVIC_EnableIRQ(SysTicK_IRQn);
+    SysTick->CTLR=0;
+    SysTick->SR=0;
+    SysTick->CNT=0;
+    SysTick->CMP=ticks-1;
+    SysTick->CTLR=0xF;
+    return 0;
+}
+
+void board_init(void) {
+
+  /* Disable interrupts during init */
+  __disable_irq();
+
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+  SysTick_Config(SystemCoreClock / 1000);
+#endif
+
+	USART_Printf_Init(115200);
+
+  RCC_USBCLK48MConfig(RCC_USBCLK48MCLKSource_USBPHY);
+  RCC_USBHSPLLCLKConfig(RCC_HSBHSPLLCLKSource_HSE);
+  RCC_USBHSConfig(RCC_USBPLL_Div2);
+  RCC_USBHSPLLCKREFCLKConfig(RCC_USBHSPLLCKREFCLK_4M);
+  RCC_USBHSPHYPLLALIVEcmd(ENABLE);
+  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBHS, ENABLE);
+
+  GPIO_InitTypeDef GPIO_InitStructure = {0};
+
+  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
+  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
+  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
+  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+  GPIO_Init(GPIOC, &GPIO_InitStructure);
+
+  /* Enable interrupts globaly */
+  __enable_irq();
+
+  board_delay(2);
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+
+volatile uint32_t system_ticks = 0;
+
+/* Small workaround to support HW stack save/restore */
+void SysTick_Handler(void) __attribute__((naked));
+void SysTick_Handler(void) { 
+      __asm volatile ("call SysTick_Handler_impl; mret");
+}
+
+__attribute__((used)) void SysTick_Handler_impl(void) { 
+  SysTick->SR=0;
+  system_ticks++;
+}
+
+uint32_t board_millis(void) { return system_ticks; }
+
+#endif
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+
+void board_led_write(bool state) {
+  (void) state;
+
+  GPIO_WriteBit(GPIOC, GPIO_Pin_0, state);
+}
+
+uint32_t board_button_read(void) {
+  return false;
+}
+
+int board_uart_read(uint8_t* buf, int len) {
+  (void)buf;
+  (void)len;
+  return 0;
+}
+
+int board_uart_write(void const* buf, int len) {
+  int txsize = len;
+  while (txsize--) {
+    uart_write(*(uint8_t const*)buf);
+    buf++;
+  }
+  return len;
+}
+
+
+
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief  Reports the name of the source file and the source line number
+ *         where the assert_param error has occurred.
+ * @param  file: pointer to the source file name
+ * @param  line: assert_param error line source number
+ * @retval None
+ */
+void assert_failed(char* file, uint32_t line) {
+  /* USER CODE BEGIN 6 */
+  /* User can add his own implementation to report the file name and line
+     number,
+     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line)
+   */
+  /* USER CODE END 6 */
+}
+#endif /* USE_FULL_ASSERT */
diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk
new file mode 100644
index 000000000..dfb4853d9
--- /dev/null
+++ b/hw/bsp/ch32v307/family.mk
@@ -0,0 +1,62 @@
+# https://www.embecosm.com/resources/tool-chain-downloads/#riscv-stable
+#CROSS_COMPILE ?= riscv32-unknown-elf-
+
+# Toolchain from https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack
+CROSS_COMPILE ?= riscv-none-embed-
+
+# Submodules
+CH32V307_SDK = hw/mcu/wch/ch32v307
+DEPS_SUBMODULES += $(CH32V307_SDK)
+
+# WCH-SDK paths
+CH32V307_SDK_SRC = $(CH32V307_SDK)/EVT/EXAM/SRC
+CH32V307_SDK_SRC_TOP = $(TOP)/$(CH32V307_SDK_SRC)
+CH32V307_STARTUP_ASM = $(CH32V307_SDK_SRC)/Startup
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+SKIP_NANOLIB = 1
+
+CFLAGS += \
+	-flto \
+	-march=rv32imac \
+	-mabi=ilp32 \
+	-msmall-data-limit=8 \
+	-mno-save-restore -Os \
+	-fmessage-length=0 \
+	-fsigned-char \
+	-ffunction-sections \
+	-fdata-sections \
+	-nostdlib -nostartfiles \
+	-DCFG_TUSB_MCU=OPT_MCU_CH32VF307 \
+	-Xlinker --gc-sections \
+    -DBOARD_DEVICE_RHPORT_SPEED=OPT_MODE_HIGH_SPEED
+
+LDFLAGS += \
+  -Xlinker --gc-sections --specs=nano.specs --specs=nosys.specs
+
+SRC_C += \
+	src/portable/wch/ch32v307/usb_dc_usbhs.c \
+	$(CH32V307_SDK_SRC_TOP)/Core/core_riscv.c \
+	$(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_gpio.c \
+	$(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_misc.c \
+	$(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_rcc.c \
+	$(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_usart.c 
+	
+SRC_S += \
+	$(CH32V307_STARTUP_ASM)/startup_ch32v30x_D8C.S 
+
+INC += \
+	src/portable/wch/ch32v307 \
+	$(TOP)/$(BOARD_PATH)/.. \
+	$(TOP)/$(BOARD_PATH) \
+	$(CH32V307_SDK_SRC_TOP)/Peripheral/inc \
+	$(CH32V307_SDK_SRC_TOP)/Debug \
+	$(CH32V307_SDK_SRC_TOP)
+
+# For freeRTOS port source
+FREERTOS_PORT = RISC-V
+
+# flash target ROM bootloader
+flash: $(BUILD)/$(PROJECT).elf
+	openocd -f wch-riscv.cfg  -c init -c halt  -c "program  $<  0x08000000"  -c reset -c exit
diff --git a/hw/bsp/ch32v307/system_ch32v30x.c b/hw/bsp/ch32v307/system_ch32v30x.c
new file mode 100644
index 000000000..12b18d7b8
--- /dev/null
+++ b/hw/bsp/ch32v307/system_ch32v30x.c
@@ -0,0 +1,776 @@
+/********************************** (C) COPYRIGHT *******************************
+* File Name          : system_ch32v30x.c
+* Author             : WCH
+* Version            : V1.0.0
+* Date               : 2021/06/06
+* Description        : CH32V30x Device Peripheral Access Layer System Source File.
+*                      For HSE = 8Mhz
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* SPDX-License-Identifier: Apache-2.0
+*********************************************************************************/
+#include "ch32v30x.h" 
+
+/* 
+* Uncomment the line corresponding to the desired System clock (SYSCLK) frequency (after 
+* reset the HSI is used as SYSCLK source).
+* If none of the define below is enabled, the HSI is used as System clock source. 
+*/
+// #define SYSCLK_FREQ_HSE    HSE_VALUE
+/* #define SYSCLK_FREQ_24MHz  24000000  */ 
+//#define SYSCLK_FREQ_48MHz  48000000
+/* #define SYSCLK_FREQ_56MHz  56000000  */  
+//#define SYSCLK_FREQ_72MHz  72000000
+//#define SYSCLK_FREQ_96MHz  96000000
+//#define SYSCLK_FREQ_120MHz  120000000
+#define SYSCLK_FREQ_144MHz  144000000
+
+/* Clock Definitions */
+#ifdef SYSCLK_FREQ_HSE
+  uint32_t SystemCoreClock         = SYSCLK_FREQ_HSE;          /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_24MHz
+  uint32_t SystemCoreClock         = SYSCLK_FREQ_24MHz;        /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_48MHz
+  uint32_t SystemCoreClock         = SYSCLK_FREQ_48MHz;        /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_56MHz
+  uint32_t SystemCoreClock         = SYSCLK_FREQ_56MHz;        /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_72MHz
+  uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;        /* System Clock Frequency (Core Clock) */
+
+#elif defined SYSCLK_FREQ_96MHz
+  uint32_t SystemCoreClock         = SYSCLK_FREQ_96MHz;        /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_120MHz
+  uint32_t SystemCoreClock         = SYSCLK_FREQ_120MHz;        /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_144MHz
+  uint32_t SystemCoreClock         = SYSCLK_FREQ_144MHz;        /* System Clock Frequency (Core Clock) */
+
+#else /* HSI Selected as System Clock source */
+  uint32_t SystemCoreClock         = HSI_VALUE;                /* System Clock Frequency (Core Clock) */
+#endif
+
+__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+
+
+/* system_private_function_proto_types */
+static void SetSysClock(void);
+
+#ifdef SYSCLK_FREQ_HSE
+  static void SetSysClockToHSE(void);
+#elif defined SYSCLK_FREQ_24MHz
+  static void SetSysClockTo24(void);
+#elif defined SYSCLK_FREQ_48MHz
+  static void SetSysClockTo48(void);
+#elif defined SYSCLK_FREQ_56MHz
+  static void SetSysClockTo56(void);  
+#elif defined SYSCLK_FREQ_72MHz
+  static void SetSysClockTo72(void);
+
+#elif defined SYSCLK_FREQ_96MHz
+  static void SetSysClockTo96(void);
+#elif defined SYSCLK_FREQ_120MHz
+  static void SetSysClockTo120(void);
+#elif defined SYSCLK_FREQ_144MHz
+  static void SetSysClockTo144(void);
+
+#endif
+
+
+/*********************************************************************
+ * @fn      SystemInit
+ *
+ * @brief   Setup the microcontroller system Initialize the Embedded Flash Interface,
+ *        the PLL and update the SystemCoreClock variable.
+ *
+ * @return  none
+ */
+void SystemInit (void)
+{
+  RCC->CTLR |= (uint32_t)0x00000001;
+
+#ifdef CH32V30x_D8C
+  RCC->CFGR0 &= (uint32_t)0xF8FF0000;
+#else
+  RCC->CFGR0 &= (uint32_t)0xF0FF0000;
+#endif 
+
+  RCC->CTLR &= (uint32_t)0xFEF6FFFF;
+  RCC->CTLR &= (uint32_t)0xFFFBFFFF;
+  RCC->CFGR0 &= (uint32_t)0xFF80FFFF;
+
+#ifdef CH32V30x_D8C
+  RCC->CTLR &= (uint32_t)0xEBFFFFFF;
+  RCC->INTR = 0x00FF0000;
+  RCC->CFGR2 = 0x00000000;
+#else
+  RCC->INTR = 0x009F0000;   
+#endif   
+  SetSysClock();
+}
+
+/*********************************************************************
+ * @fn      SystemCoreClockUpdate
+ *
+ * @brief   Update SystemCoreClock variable according to Clock Register Values.
+ *
+ * @return  none
+ */
+void SystemCoreClockUpdate (void)
+{
+  uint32_t tmp = 0, pllmull = 0, pllsource = 0, Pll_6_5 = 0;
+
+  tmp = RCC->CFGR0 & RCC_SWS;
+  
+  switch (tmp)
+  {
+    case 0x00:
+      SystemCoreClock = HSI_VALUE;
+      break;
+    case 0x04:  
+      SystemCoreClock = HSE_VALUE;
+      break;
+    case 0x08: 
+      pllmull = RCC->CFGR0 & RCC_PLLMULL;
+      pllsource = RCC->CFGR0 & RCC_PLLSRC; 
+      pllmull = ( pllmull >> 18) + 2;
+
+#ifdef CH32V30x_D8
+          if(pllmull == 17) pllmull = 18;
+#else
+          if(pllmull == 2) pllmull = 18;
+          if(pllmull == 15){
+              pllmull = 13;  /* *6.5 */
+              Pll_6_5 = 1;
+          }
+          if(pllmull == 16) pllmull = 15;
+          if(pllmull == 17) pllmull = 16;
+#endif
+
+      if (pllsource == 0x00)
+      {
+        SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
+      }
+      else
+      {    
+        if ((RCC->CFGR0 & RCC_PLLXTPRE) != (uint32_t)RESET)
+        {
+          SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
+        }
+        else
+        {
+          SystemCoreClock = HSE_VALUE * pllmull;
+        }
+      }
+
+      if(Pll_6_5 == 1) SystemCoreClock = (SystemCoreClock / 2);
+
+      break;
+    default:
+      SystemCoreClock = HSI_VALUE;
+      break;
+  }
+ 
+  tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)];
+  SystemCoreClock >>= tmp;  
+}
+
+/*********************************************************************
+ * @fn      SetSysClock
+ *
+ * @brief   Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return  none
+ */
+static void SetSysClock(void)
+{
+#ifdef SYSCLK_FREQ_HSE
+  SetSysClockToHSE();
+#elif defined SYSCLK_FREQ_24MHz
+  SetSysClockTo24();
+#elif defined SYSCLK_FREQ_48MHz
+  SetSysClockTo48();
+#elif defined SYSCLK_FREQ_56MHz
+  SetSysClockTo56();  
+#elif defined SYSCLK_FREQ_72MHz
+  SetSysClockTo72();
+#elif defined SYSCLK_FREQ_96MHz
+  SetSysClockTo96();
+#elif defined SYSCLK_FREQ_120MHz
+  SetSysClockTo120();
+#elif defined SYSCLK_FREQ_144MHz
+  SetSysClockTo144();
+
+#endif
+ 
+ /* If none of the define above is enabled, the HSI is used as System clock
+  * source (default after reset) 
+    */
+}
+
+
+#ifdef SYSCLK_FREQ_HSE
+
+/*********************************************************************
+ * @fn      SetSysClockToHSE
+ *
+ * @brief   Sets HSE as System clock source and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return  none
+ */
+static void SetSysClockToHSE(void)
+{
+  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+   
+  RCC->CTLR |= ((uint32_t)RCC_HSEON);
+ 
+  /* Wait till HSE is ready and if Time out is reached exit */
+  do
+  {
+    HSEStatus = RCC->CTLR & RCC_HSERDY;
+    StartUpCounter++;  
+  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+  if ((RCC->CTLR & RCC_HSERDY) != RESET)
+  {
+    HSEStatus = (uint32_t)0x01;
+  }
+  else
+  {
+    HSEStatus = (uint32_t)0x00;
+  }  
+
+  if (HSEStatus == (uint32_t)0x01)
+  {
+    /* HCLK = SYSCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;      
+    /* PCLK2 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+    /* PCLK1 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;
+    
+    /* Select HSE as system clock source */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
+    RCC->CFGR0 |= (uint32_t)RCC_SW_HSE;    
+
+    /* Wait till HSE is used as system clock source */
+    while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x04)
+    {
+    }
+  }
+  else
+  { 
+        /* If HSE fails to start-up, the application will have wrong clock
+     * configuration. User can add here some code to deal with this error 
+         */
+  }  
+}
+
+#elif defined SYSCLK_FREQ_24MHz
+
+/*********************************************************************
+ * @fn      SetSysClockTo24
+ *
+ * @brief   Sets System clock frequency to 24MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return  none
+ */
+static void SetSysClockTo24(void)
+{
+  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+     
+  RCC->CTLR |= ((uint32_t)RCC_HSEON);
+ 
+  /* Wait till HSE is ready and if Time out is reached exit */
+  do
+  {
+    HSEStatus = RCC->CTLR & RCC_HSERDY;
+    StartUpCounter++;  
+  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+  if ((RCC->CTLR & RCC_HSERDY) != RESET)
+  {
+    HSEStatus = (uint32_t)0x01;
+  }
+  else
+  {
+    HSEStatus = (uint32_t)0x00;
+  }  
+  if (HSEStatus == (uint32_t)0x01)
+  {
+    /* HCLK = SYSCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;   
+    /* PCLK2 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; 
+    /* PCLK1 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;
+
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL3);
+#else
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL3_EXTEN);
+#endif
+    /* Enable PLL */
+    RCC->CTLR |= RCC_PLLON;
+
+    /* Wait till PLL is ready */
+    while((RCC->CTLR & RCC_PLLRDY) == 0)
+    {
+    }
+    /* Select PLL as system clock source */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
+    RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;    
+    /* Wait till PLL is used as system clock source */
+    while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
+    {
+    }
+  }
+  else
+  { 
+        /* If HSE fails to start-up, the application will have wrong clock
+     * configuration. User can add here some code to deal with this error 
+         */
+  } 
+}
+
+#elif defined SYSCLK_FREQ_48MHz
+
+/*********************************************************************
+ * @fn      SetSysClockTo48
+ *
+ * @brief   Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return  none
+ */
+static void SetSysClockTo48(void)
+{
+  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+     
+   
+  RCC->CTLR |= ((uint32_t)RCC_HSEON);
+  /* Wait till HSE is ready and if Time out is reached exit */
+  do
+  {
+    HSEStatus = RCC->CTLR & RCC_HSERDY;
+    StartUpCounter++;  
+  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+  if ((RCC->CTLR & RCC_HSERDY) != RESET)
+  {
+    HSEStatus = (uint32_t)0x01;
+  }
+  else
+  {
+    HSEStatus = (uint32_t)0x00;
+  }  
+
+  if (HSEStatus == (uint32_t)0x01)
+  {
+    /* HCLK = SYSCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;    
+    /* PCLK2 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;  
+    /* PCLK1 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+
+    /*  PLL configuration: PLLCLK = HSE * 6 = 48 MHz */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL6);
+#else
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL6_EXTEN);
+#endif
+
+    /* Enable PLL */
+    RCC->CTLR |= RCC_PLLON;
+    /* Wait till PLL is ready */
+    while((RCC->CTLR & RCC_PLLRDY) == 0)
+    {
+    }
+    /* Select PLL as system clock source */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
+    RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;    
+    /* Wait till PLL is used as system clock source */
+    while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
+    {
+    }
+  }
+  else
+  { 
+        /*
+         * If HSE fails to start-up, the application will have wrong clock
+     * configuration. User can add here some code to deal with this error 
+         */
+  } 
+}
+
+#elif defined SYSCLK_FREQ_56MHz
+
+/*********************************************************************
+ * @fn      SetSysClockTo56
+ *
+ * @brief   Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return  none
+ */
+static void SetSysClockTo56(void)
+{
+  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+     
+  RCC->CTLR |= ((uint32_t)RCC_HSEON);
+
+  /* Wait till HSE is ready and if Time out is reached exit */
+  do
+  {
+    HSEStatus = RCC->CTLR & RCC_HSERDY;
+    StartUpCounter++;  
+  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+  if ((RCC->CTLR & RCC_HSERDY) != RESET)
+  {
+    HSEStatus = (uint32_t)0x01;
+  }
+  else
+  {
+    HSEStatus = (uint32_t)0x00;
+  }  
+
+  if (HSEStatus == (uint32_t)0x01)
+  {
+    /* HCLK = SYSCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;   
+    /* PCLK2 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+    /* PCLK1 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+  
+    /* PLL configuration: PLLCLK = HSE * 7 = 56 MHz */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL7);
+#else
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL7_EXTEN);
+#endif
+
+    /* Enable PLL */
+    RCC->CTLR |= RCC_PLLON;
+    /* Wait till PLL is ready */
+    while((RCC->CTLR & RCC_PLLRDY) == 0)
+    {
+    }
+
+    /* Select PLL as system clock source */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
+    RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;    
+    /* Wait till PLL is used as system clock source */
+    while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
+    {
+    }
+  }
+  else
+  { 
+        /*
+         * If HSE fails to start-up, the application will have wrong clock
+     * configuration. User can add here some code to deal with this error 
+         */
+  } 
+}
+
+#elif defined SYSCLK_FREQ_72MHz
+
+/*********************************************************************
+ * @fn      SetSysClockTo72
+ *
+ * @brief   Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return  none
+ */
+static void SetSysClockTo72(void)
+{
+  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+     
+  RCC->CTLR |= ((uint32_t)RCC_HSEON);
+ 
+  /* Wait till HSE is ready and if Time out is reached exit */
+  do
+  {
+    HSEStatus = RCC->CTLR & RCC_HSERDY;
+    StartUpCounter++;  
+  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+  if ((RCC->CTLR & RCC_HSERDY) != RESET)
+  {
+    HSEStatus = (uint32_t)0x01;
+  }
+  else
+  {
+    HSEStatus = (uint32_t)0x00;
+  }  
+
+  if (HSEStatus == (uint32_t)0x01)
+  {
+    /* HCLK = SYSCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; 
+    /* PCLK2 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; 
+    /* PCLK1 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+ 
+    /* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
+                                        RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9);
+#else
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9_EXTEN);
+#endif
+
+    /* Enable PLL */
+    RCC->CTLR |= RCC_PLLON;
+    /* Wait till PLL is ready */
+    while((RCC->CTLR & RCC_PLLRDY) == 0)
+    {
+    }    
+    /* Select PLL as system clock source */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
+    RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;    
+    /* Wait till PLL is used as system clock source */
+    while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
+    {
+    }
+  }
+  else
+  { 
+        /*
+         * If HSE fails to start-up, the application will have wrong clock
+     * configuration. User can add here some code to deal with this error 
+         */
+  }
+}
+
+
+#elif defined SYSCLK_FREQ_96MHz
+
+/*********************************************************************
+ * @fn      SetSysClockTo96
+ *
+ * @brief   Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return  none
+ */
+static void SetSysClockTo96(void)
+{
+  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+
+  RCC->CTLR |= ((uint32_t)RCC_HSEON);
+
+  /* Wait till HSE is ready and if Time out is reached exit */
+  do
+  {
+    HSEStatus = RCC->CTLR & RCC_HSERDY;
+    StartUpCounter++;
+  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+  if ((RCC->CTLR & RCC_HSERDY) != RESET)
+  {
+    HSEStatus = (uint32_t)0x01;
+  }
+  else
+  {
+    HSEStatus = (uint32_t)0x00;
+  }
+
+  if (HSEStatus == (uint32_t)0x01)
+  {
+    /* HCLK = SYSCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
+    /* PCLK2 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+    /* PCLK1 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+
+    /*  PLL configuration: PLLCLK = HSE * 12 = 96 MHz */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
+                                        RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL12);
+#else
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL12_EXTEN);
+#endif
+
+    /* Enable PLL */
+    RCC->CTLR |= RCC_PLLON;
+    /* Wait till PLL is ready */
+    while((RCC->CTLR & RCC_PLLRDY) == 0)
+    {
+    }
+    /* Select PLL as system clock source */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
+    RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
+    /* Wait till PLL is used as system clock source */
+    while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
+    {
+    }
+  }
+  else
+  {
+        /*
+         * If HSE fails to start-up, the application will have wrong clock
+     * configuration. User can add here some code to deal with this error
+         */
+  }
+}
+
+
+#elif defined SYSCLK_FREQ_120MHz
+
+/*********************************************************************
+ * @fn      SetSysClockTo120
+ *
+ * @brief   Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return  none
+ */
+static void SetSysClockTo120(void)
+{
+  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+
+  RCC->CTLR |= ((uint32_t)RCC_HSEON);
+
+  /* Wait till HSE is ready and if Time out is reached exit */
+  do
+  {
+    HSEStatus = RCC->CTLR & RCC_HSERDY;
+    StartUpCounter++;
+  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+  if ((RCC->CTLR & RCC_HSERDY) != RESET)
+  {
+    HSEStatus = (uint32_t)0x01;
+  }
+  else
+  {
+    HSEStatus = (uint32_t)0x00;
+  }
+
+  if (HSEStatus == (uint32_t)0x01)
+  {
+    /* HCLK = SYSCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
+    /* PCLK2 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+    /* PCLK1 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+
+    /*  PLL configuration: PLLCLK = HSE * 15 = 120 MHz */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
+                                        RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL15);
+#else
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL15_EXTEN);
+#endif
+
+    /* Enable PLL */
+    RCC->CTLR |= RCC_PLLON;
+    /* Wait till PLL is ready */
+    while((RCC->CTLR & RCC_PLLRDY) == 0)
+    {
+    }
+    /* Select PLL as system clock source */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
+    RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
+    /* Wait till PLL is used as system clock source */
+    while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
+    {
+    }
+  }
+  else
+  {
+        /*
+         * If HSE fails to start-up, the application will have wrong clock
+     * configuration. User can add here some code to deal with this error
+         */
+  }
+}
+
+
+#elif defined SYSCLK_FREQ_144MHz
+
+/*********************************************************************
+ * @fn      SetSysClockTo144
+ *
+ * @brief   Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return  none
+ */
+static void SetSysClockTo144(void)
+{
+  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+
+  RCC->CTLR |= ((uint32_t)RCC_HSEON);
+
+  /* Wait till HSE is ready and if Time out is reached exit */
+  do
+  {
+    HSEStatus = RCC->CTLR & RCC_HSERDY;
+    StartUpCounter++;
+  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+  if ((RCC->CTLR & RCC_HSERDY) != RESET)
+  {
+    HSEStatus = (uint32_t)0x01;
+  }
+  else
+  {
+    HSEStatus = (uint32_t)0x00;
+  }
+
+  if (HSEStatus == (uint32_t)0x01)
+  {
+    /* HCLK = SYSCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
+    /* PCLK2 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+    /* PCLK1 = HCLK */
+    RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+
+    /*  PLL configuration: PLLCLK = HSE * 18 = 144 MHz */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
+                                        RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL18);
+#else
+        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL18_EXTEN);
+#endif
+
+    /* Enable PLL */
+    RCC->CTLR |= RCC_PLLON;
+    /* Wait till PLL is ready */
+    while((RCC->CTLR & RCC_PLLRDY) == 0)
+    {
+    }
+    /* Select PLL as system clock source */
+    RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
+    RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
+    /* Wait till PLL is used as system clock source */
+    while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
+    {
+    }
+  }
+  else
+  {
+        /*
+         * If HSE fails to start-up, the application will have wrong clock
+     * configuration. User can add here some code to deal with this error
+         */
+  }
+}
+
+
+#endif
diff --git a/hw/bsp/ch32v307/system_ch32v30x.h b/hw/bsp/ch32v307/system_ch32v30x.h
new file mode 100644
index 000000000..0e0ef4e51
--- /dev/null
+++ b/hw/bsp/ch32v307/system_ch32v30x.h
@@ -0,0 +1,30 @@
+/********************************** (C) COPYRIGHT *******************************
+* File Name          : system_ch32v30x.h
+* Author             : WCH
+* Version            : V1.0.0
+* Date               : 2021/06/06
+* Description        : CH32V30x Device Peripheral Access Layer System Header File.
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* SPDX-License-Identifier: Apache-2.0
+*******************************************************************************/
+#ifndef __SYSTEM_CH32V30x_H 
+#define __SYSTEM_CH32V30x_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif 
+
+extern uint32_t SystemCoreClock;          /* System Clock Frequency (Core Clock) */
+
+/* System_Exported_Functions */  
+extern void SystemInit(void);
+extern void SystemCoreClockUpdate(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__CH32V30x_SYSTEM_H */
+
+
+
diff --git a/hw/mcu/wch/ch32v307 b/hw/mcu/wch/ch32v307
new file mode 160000
index 000000000..17761f5cf
--- /dev/null
+++ b/hw/mcu/wch/ch32v307
@@ -0,0 +1 @@
+Subproject commit 17761f5cf9dbbf2dcf665b7c04934188add20082
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 8eb4ad475..84d629eac 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -266,6 +266,10 @@
 #elif TU_CHECK_MCU(OPT_MCU_F1C100S)
   #define TUP_DCD_ENDPOINT_MAX    4
 
+//------------- WCH -------------//
+#elif TU_CHECK_MCU(OPT_MCU_CH32VF307)
+  #define TUP_DCD_ENDPOINT_MAX    8
+
 #endif
 
 //--------------------------------------------------------------------+
diff --git a/src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h b/src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h
new file mode 100644
index 000000000..1b7c0e791
--- /dev/null
+++ b/src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h
@@ -0,0 +1,345 @@
+#ifndef _USB_CH32_USBHS_REG_H
+#define _USB_CH32_USBHS_REG_H
+
+#include <ch32v30x.h>
+
+/******************* GLOBAL ******************/
+
+// USB CONTROL
+#define USBHS_CONTROL_OFFSET 0x00
+#define USBHS_DMA_EN         (1 << 0)
+#define USBHS_ALL_CLR        (1 << 1)
+#define USBHS_FORCE_RST      (1 << 2)
+#define USBHS_INT_BUSY_EN    (1 << 3)
+#define USBHS_DEV_PU_EN      (1 << 4)
+#define USBHS_SPEED_MASK     (3 << 5)
+#define USBHS_FULL_SPEED     (0 << 5)
+#define USBHS_HIGH_SPEED     (1 << 5)
+#define USBHS_LOW_SPEED      (2 << 5)
+#define USBHS_HOST_MODE      (1 << 7)
+
+// USB_INT_EN
+#define USBHS_INT_EN_OFFSET 0x02
+#define USBHS_BUS_RST_EN    (1 << 0)
+#define USBHS_DETECT_EN     (1 << 0)
+#define USBHS_TRANSFER_EN   (1 << 1)
+#define USBHS_SUSPEND_EN    (1 << 2)
+#define USBHS_SOF_ACT_EN    (1 << 3)
+#define USBHS_FIFO_OV_EN    (1 << 4)
+#define USBHS_SETUP_ACT_EN  (1 << 5)
+#define USBHS_ISO_ACT_EN    (1 << 6)
+#define USBHS_DEV_NAK_EN    (1 << 7)
+
+// USB DEV AD
+#define USBHS_DEV_AD_OFFSET 0x03
+// USB FRAME_NO
+#define USBHS_FRAME_NO_OFFSET 0x04
+// USB SUSPEND
+#define USBHS_SUSPEND_OFFSET    0x06
+#define USBHS_DEV_REMOTE_WAKEUP (1 << 2)
+#define USBHS_LINESTATE_MASK    (2 << 4) /* Read Only */
+
+// RESERVED0
+
+// USB SPEED TYPE
+#define USBHS_SPEED_TYPE_OFFSET 0x08
+#define USBSPEED_MASK           (0x03)
+
+// USB_MIS_ST
+#define USBHS_MIS_ST_OFFSET 0x09
+#define USBHS_SPLIT_CAN     (1 << 0)
+#define USBHS_ATTACH        (1 << 1)
+#define USBHS_SUSPEND       (1 << 2)
+#define USBHS_BUS_RESET     (1 << 3)
+#define USBHS_R_FIFO_RDY    (1 << 4)
+#define USBHS_SIE_FREE      (1 << 5)
+#define USBHS_SOF_ACT       (1 << 6)
+#define USBHS_SOF_PRES      (1 << 7)
+
+// INT_FLAG
+#define USBHS_INT_FLAG_OFFSET 0x0A
+#define USBHS_BUS_RST_FLAG    (1 << 0)
+#define USBHS_DETECT_FLAG     (1 << 0)
+#define USBHS_TRANSFER_FLAG   (1 << 1)
+#define USBHS_SUSPEND_FLAG    (1 << 2)
+#define USBHS_HST_SOF_FLAG    (1 << 3)
+#define USBHS_FIFO_OV_FLAG    (1 << 4)
+#define USBHS_SETUP_FLAG      (1 << 5)
+#define USBHS_ISO_ACT_FLAG    (1 << 6)
+
+// INT_ST
+#define USBHS_INT_ST_OFFSET  0x0B
+#define USBHS_DEV_UIS_IS_NAK (1 << 7)
+#define USBHS_DEV_UIS_TOG_OK (1 << 6)
+#define MASK_UIS_TOKEN       (3 << 4)
+#define MASK_UIS_ENDP        (0x0F)
+#define MASK_UIS_H_RES       (0x0F)
+
+#define USBHS_TOGGLE_OK (0x40)
+#define USBHS_HOST_RES  (0x0f)
+
+//USB_RX_LEN
+#define USBHS_RX_LEN_OFFSET 0x0C
+/******************* DEVICE ******************/
+
+//UEP_CONFIG
+#define USBHS_UEP_CONFIG_OFFSET 0x10
+#define USBHS_EP0_T_EN          (1 << 0)
+#define USBHS_EP0_R_EN          (1 << 16)
+
+#define USBHS_EP1_T_EN (1 << 1)
+#define USBHS_EP1_R_EN (1 << 17)
+
+#define USBHS_EP2_T_EN (1 << 2)
+#define USBHS_EP2_R_EN (1 << 18)
+
+#define USBHS_EP3_T_EN (1 << 3)
+#define USBHS_EP3_R_EN (1 << 19)
+
+#define USBHS_EP4_T_EN (1 << 4)
+#define USBHS_EP4_R_EN (1 << 20)
+
+#define USBHS_EP5_T_EN (1 << 5)
+#define USBHS_EP5_R_EN (1 << 21)
+
+#define USBHS_EP6_T_EN (1 << 6)
+#define USBHS_EP6_R_EN (1 << 22)
+
+#define USBHS_EP7_T_EN (1 << 7)
+#define USBHS_EP7_R_EN (1 << 23)
+
+#define USBHS_EP8_T_EN (1 << 8)
+#define USBHS_EP8_R_EN (1 << 24)
+
+#define USBHS_EP9_T_EN (1 << 9)
+#define USBHS_EP9_R_EN (1 << 25)
+
+#define USBHS_EP10_T_EN (1 << 10)
+#define USBHS_EP10_R_EN (1 << 26)
+
+#define USBHS_EP11_T_EN (1 << 11)
+#define USBHS_EP11_R_EN (1 << 27)
+
+#define USBHS_EP12_T_EN (1 << 12)
+#define USBHS_EP12_R_EN (1 << 28)
+
+#define USBHS_EP13_T_EN (1 << 13)
+#define USBHS_EP13_R_EN (1 << 29)
+
+#define USBHS_EP14_T_EN (1 << 14)
+#define USBHS_EP14_R_EN (1 << 30)
+
+#define USBHS_EP15_T_EN (1 << 15)
+#define USBHS_EP15_R_EN (1 << 31)
+
+//UEP_TYPE
+#define USBHS_UEP_TYPE_OFFSET 0x14
+#define USBHS_EP0_T_TYP       (1 << 0)
+#define USBHS_EP0_R_TYP       (1 << 16)
+
+#define USBHS_EP1_T_TYP (1 << 1)
+#define USBHS_EP1_R_TYP (1 << 17)
+
+#define USBHS_EP2_T_TYP (1 << 2)
+#define USBHS_EP2_R_TYP (1 << 18)
+
+#define USBHS_EP3_T_TYP (1 << 3)
+#define USBHS_EP3_R_TYP (1 << 19)
+
+#define USBHS_EP4_T_TYP (1 << 4)
+#define USBHS_EP4_R_TYP (1 << 20)
+
+#define USBHS_EP5_T_TYP (1 << 5)
+#define USBHS_EP5_R_TYP (1 << 21)
+
+#define USBHS_EP6_T_TYP (1 << 6)
+#define USBHS_EP6_R_TYP (1 << 22)
+
+#define USBHS_EP7_T_TYP (1 << 7)
+#define USBHS_EP7_R_TYP (1 << 23)
+
+#define USBHS_EP8_T_TYP (1 << 8)
+#define USBHS_EP8_R_TYP (1 << 24)
+
+#define USBHS_EP9_T_TYP (1 << 8)
+#define USBHS_EP9_R_TYP (1 << 25)
+
+#define USBHS_EP10_T_TYP (1 << 10)
+#define USBHS_EP10_R_TYP (1 << 26)
+
+#define USBHS_EP11_T_TYP (1 << 11)
+#define USBHS_EP11_R_TYP (1 << 27)
+
+#define USBHS_EP12_T_TYP (1 << 12)
+#define USBHS_EP12_R_TYP (1 << 28)
+
+#define USBHS_EP13_T_TYP (1 << 13)
+#define USBHS_EP13_R_TYP (1 << 29)
+
+#define USBHS_EP14_T_TYP (1 << 14)
+#define USBHS_EP14_R_TYP (1 << 30)
+
+#define USBHS_EP15_T_TYP (1 << 15)
+#define USBHS_EP15_R_TYP (1 << 31)
+
+/* BUF_MOD UEP1~15 */
+#define USBHS_BUF_MOD_OFFSET  0x18
+#define USBHS_EP0_BUF_MOD     (1 << 0)
+#define USBHS_EP0_ISO_BUF_MOD (1 << 16)
+
+#define USBHS_EP1_BUF_MOD     (1 << 1)
+#define USBHS_EP1_ISO_BUF_MOD (1 << 17)
+
+#define USBHS_EP2_BUF_MOD     (1 << 2)
+#define USBHS_EP2_ISO_BUF_MOD (1 << 18)
+
+#define USBHS_EP3_BUF_MOD     (1 << 3)
+#define USBHS_EP3_ISO_BUF_MOD (1 << 19)
+
+#define USBHS_EP4_BUF_MOD     (1 << 4)
+#define USBHS_EP4_ISO_BUF_MOD (1 << 20)
+
+#define USBHS_EP5_BUF_MOD     (1 << 5)
+#define USBHS_EP5_ISO_BUF_MOD (1 << 21)
+
+#define USBHS_EP6_BUF_MOD     (1 << 6)
+#define USBHS_EP6_ISO_BUF_MOD (1 << 22)
+
+#define USBHS_EP7_BUF_MOD     (1 << 7)
+#define USBHS_EP7_ISO_BUF_MOD (1 << 23)
+
+#define USBHS_EP8_BUF_MOD     (1 << 8)
+#define USBHS_EP8_ISO_BUF_MOD (1 << 24)
+
+#define USBHS_EP9_BUF_MOD     (1 << 9)
+#define USBHS_EP9_ISO_BUF_MOD (1 << 25)
+
+#define USBHS_EP10_BUF_MOD     (1 << 10)
+#define USBHS_EP10_ISO_BUF_MOD (1 << 26)
+
+#define USBHS_EP11_BUF_MOD     (1 << 11)
+#define USBHS_EP11_ISO_BUF_MOD (1 << 27)
+
+#define USBHS_EP12_BUF_MOD     (1 << 12)
+#define USBHS_EP12_ISO_BUF_MOD (1 << 28)
+
+#define USBHS_EP13_BUF_MOD     (1 << 13)
+#define USBHS_EP13_ISO_BUF_MOD (1 << 29)
+
+#define USBHS_EP14_BUF_MOD     (1 << 14)
+#define USBHS_EP14_ISO_BUF_MOD (1 << 30)
+
+#define USBHS_EP15_BUF_MOD     (1 << 15)
+#define USBHS_EP15_ISO_BUF_MOD (1 << 31)
+//USBHS_EPn_T_EN  USBHS_EPn_R_EN  USBHS_EPn_BUF_MOD  锟斤拷锟斤拷锟斤拷锟斤拷UEPn_DMA为锟斤拷始锟斤拷址锟缴碉拷锟斤拷锟斤拷锟斤拷锟�
+//      0               0               x            锟剿点被锟斤拷锟矫o拷未锟矫碉拷UEPn_*_DMA锟斤拷锟斤拷锟斤拷锟斤拷
+//      1               0               0            锟斤拷锟秸o拷OUT锟斤拷锟斤拷锟斤拷锟斤拷锟阶碉拷址为UEPn_RX_DMA
+//      1               0               1            bUEPn_RX_TOG[0]=0,使锟矫伙拷锟斤拷锟斤拷UEPn_RX_DMA锟斤拷bUEPn_RX_TOG[0]=1,使锟矫伙拷锟斤拷锟斤拷UEPn_TX_DMA
+//      0               1               0            锟斤拷锟斤拷(IN)锟斤拷锟斤拷锟斤拷锟阶碉拷址为UEPn_TX_DMA锟斤拷
+//      0               1               1            bUEPn_TX_TOG[0]=0,使锟矫伙拷锟斤拷锟斤拷UEPn_TX_DMA锟斤拷bUEPn_TX_TOG[0]=1,使锟矫伙拷锟斤拷锟斤拷UEPn_RX_DMA
+
+/* USB0_DMA */
+#define USBHS_UEP0_DMA_OFFSET(n) (0x1C) // endpoint 0 DMA buffer address
+
+/* USBX_RX_DMA */
+#define USBHS_UEPx_RX_DMA_OFFSET(n) (0x1C + 4 * (n)) // endpoint x DMA buffer address
+
+#define USBHS_UEPx_TX_DMA_OFFSET(n) (0x58 + 4 * (n)) // endpoint x DMA buffer address
+
+#define USBHS_UEPx_MAX_LEN_OFFSET(n) (0x98 + 4 * (n)) // endpoint x DMA buffer address
+
+#define USBHS_UEPx_T_LEN_OFFSET(n)   (0xD8 + 4 * (n)) // endpoint x DMA buffer address
+#define USBHS_UEPx_TX_CTRL_OFFSET(n) (0xD8 + 4 * (n) + 2) // endpoint x DMA buffer address
+#define USBHS_UEPx_RX_CTRL_OFFSET(n) (0xD8 + 4 * (n) + 3) // endpoint x DMA buffer address
+
+// UEPn_T_LEN
+#define USBHS_EP_T_LEN_MASK (0x7FF)
+
+//UEPn_TX_CTRL
+#define USBHS_EP_T_RES_MASK  (3 << 0)
+#define USBHS_EP_T_RES_ACK   (0 << 0)
+#define USBHS_EP_T_RES_NYET  (1 << 0)
+#define USBHS_EP_T_RES_NAK   (2 << 0)
+#define USBHS_EP_T_RES_STALL (3 << 0)
+
+#define USBHS_EP_T_TOG_MASK (3 << 3)
+#define USBHS_EP_T_TOG_0    (0 << 3)
+#define USBHS_EP_T_TOG_1    (1 << 3)
+#define USBHS_EP_T_TOG_2    (2 << 3)
+#define USBHS_EP_T_TOG_M    (3 << 3)
+
+#define USBHS_EP_T_AUTOTOG (1 << 5)
+
+//UEPn_RX_CTRL
+#define USBHS_EP_R_RES_MASK  (3 << 0)
+#define USBHS_EP_R_RES_ACK   (0 << 0)
+#define USBHS_EP_R_RES_NYET  (1 << 0)
+#define USBHS_EP_R_RES_NAK   (2 << 0)
+#define USBHS_EP_R_RES_STALL (3 << 0)
+
+#define USBHS_EP_R_TOG_MASK (3 << 3)
+#define USBHS_EP_R_TOG_0    (0 << 3)
+#define USBHS_EP_R_TOG_1    (1 << 3)
+#define USBHS_EP_R_TOG_2    (2 << 3)
+#define USBHS_EP_R_TOG_M    (3 << 3)
+
+#define USBHS_EP_R_AUTOTOG (1 << 5)
+
+#define USBHS_TOG_MATCH (1 << 6)
+
+/******************* HOST ******************/
+// USB HOST_CTRL
+#define USBHS_SEND_BUS_RESET   (1 << 0)
+#define USBHS_SEND_BUS_SUSPEND (1 << 1)
+#define USBHS_SEND_BUS_RESUME  (1 << 2)
+#define USBHS_REMOTE_WAKE      (1 << 3)
+#define USBHS_PHY_SUSPENDM     (1 << 4)
+#define USBHS_UH_SOFT_FREE     (1 << 6)
+#define USBHS_SEND_SOF_EN      (1 << 7)
+
+//UH_CONFIG
+#define USBHS_HOST_TX_EN (1 << 3)
+#define USBHS_HOST_RX_EN (1 << 18)
+
+// HOST_EP_TYPE
+#define USBHS_ENDP_TX_ISO (1 << 3)
+#define USBHS_ENDP_RX_ISO (1 << (16 + 2))
+
+// R32_UH_EP_PID
+#define USBHS_HOST_MASK_TOKEN (0x0f)
+#define USBHS_HOST_MASK_ENDP  (0x0f << 4)
+
+//R8_UH_RX_CTRL
+#define USBHS_EP_R_RES_MASK  (3 << 0)
+#define USBHS_EP_R_RES_ACK   (0 << 0)
+#define USBHS_EP_R_RES_NYET  (1 << 0)
+#define USBHS_EP_R_RES_NAK   (2 << 0)
+#define USBHS_EP_R_RES_STALL (3 << 0)
+
+#define USBHS_UH_R_RES_NO   (1 << 2)
+#define USBHS_UH_R_TOG_1    (1 << 3)
+#define USBHS_UH_R_TOG_2    (2 << 3)
+#define USBHS_UH_R_TOG_3    (3 << 3)
+#define USBHS_UH_R_TOG_AUTO (1 << 5)
+#define USBHS_UH_R_DATA_NO  (1 << 6)
+//R8_UH_TX_CTRL
+#define USBHS_UH_T_RES_MASK  (3 << 0)
+#define USBHS_UH_T_RES_ACK   (0 << 0)
+#define USBHS_UH_T_RES_NYET  (1 << 0)
+#define USBHS_UH_T_RES_NAK   (2 << 0)
+#define USBHS_UH_T_RES_STALL (3 << 0)
+
+#define USBHS_UH_T_RES_NO   (1 << 2)
+#define USBHS_UH_T_TOG_1    (1 << 3)
+#define USBHS_UH_T_TOG_2    (2 << 3)
+#define USBHS_UH_T_TOG_3    (3 << 3)
+#define USBHS_UH_T_TOG_AUTO (1 << 5)
+#define USBHS_UH_T_DATA_NO  (1 << 6)
+
+// 00: OUT, 01:SOF, 10:IN, 11:SETUP
+#define PID_OUT   0
+#define PID_SOF   1
+#define PID_IN    2
+#define PID_SETUP 3
+
+#endif
diff --git a/src/portable/wch/ch32v307/usb_dc_usbhs.c b/src/portable/wch/ch32v307/usb_dc_usbhs.c
new file mode 100644
index 000000000..32645dc5f
--- /dev/null
+++ b/src/portable/wch/ch32v307/usb_dc_usbhs.c
@@ -0,0 +1,388 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Greg Davill 
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_CH32VF307)
+#include "device/dcd.h"
+
+#include "usb_ch32_usbhs_reg.h"
+#include "core_riscv.h"
+
+// Max number of bi-directional endpoints including EP0
+#define EP_MAX 16
+
+typedef struct {
+    uint8_t *buffer;
+    // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
+    uint16_t total_len;
+    uint16_t queued_len;
+    uint16_t max_size;
+    bool short_packet;
+} xfer_ctl_t;
+
+#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
+static xfer_ctl_t xfer_status[EP_MAX][2];
+
+#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep)*2)
+#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep)*4)
+#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep)*4)
+#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep)*2)
+
+#define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1))
+#define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1))
+
+/* Endpoint Buffer */
+__attribute__((aligned(4))) uint8_t setup[8];           // ep0(64)
+__attribute__((aligned(4))) uint8_t EP0_DatabufHD[64];  // ep0(64)
+
+volatile uint8_t mps_over_flag = 0;
+volatile uint8_t USBHS_Dev_Endp0_Tog = 0x01;
+
+void dcd_init(uint8_t rhport) {
+    (void)rhport;
+
+    memset(&xfer_status, 0, sizeof(xfer_status));
+
+    // usb_dc_low_level_init();
+
+    USBHSD->HOST_CTRL = 0x00;
+    USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM;
+
+    USBHSD->CONTROL = 0;
+#if 1
+    USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
+#else
+    USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED;
+#endif
+
+    USBHSD->INT_EN = 0;
+    USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_DETECT_EN | USBHS_SUSPEND_EN;
+
+    /* ALL endpoint enable */
+    USBHSD->ENDP_CONFIG = 0xffffffff;
+
+    USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
+    USBHSD->ENDP_TYPE = 0x00;
+    USBHSD->BUF_MODE = 0x00;
+
+    USBHSD->UEP0_MAX_LEN = 64;
+
+    USBHSD->UEP0_DMA = (uint32_t)EP0_DatabufHD;
+
+    USBHSD->UEP0_TX_LEN = 0;
+    USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_NAK;
+    USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
+
+    for (int ep = 1; ep < EP_MAX; ep++) {
+        EP_TX_LEN(ep) = 0;
+        EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
+        EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+
+        EP_RX_MAX_LEN(ep) = 512;
+    }
+
+    USBHSD->DEV_AD = 0;
+    USBHSD->CONTROL |= USBHS_DEV_PU_EN;
+}
+
+void dcd_int_enable(uint8_t rhport) {
+    (void)rhport;
+
+    NVIC_EnableIRQ(USBHS_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport) {
+    (void)rhport;
+
+    NVIC_DisableIRQ(USBHS_IRQn);
+}
+
+void dcd_edpt_close_all(uint8_t rhport) {
+    (void)rhport;
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
+    (void)dev_addr;
+
+    // Response with zlp status
+    dcd_edpt_xfer(rhport, 0x80, NULL, 0);
+}
+
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) {
+    (void)rhport;
+
+    if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+        request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
+        request->bRequest == TUSB_REQ_SET_ADDRESS) {
+        USBHSD->DEV_AD = (uint8_t)request->wValue;
+    }
+
+    EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK;
+    EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK;
+}
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt) {
+    (void)rhport;
+
+    uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
+    uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
+
+    TU_ASSERT(epnum < EP_MAX);
+
+    xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
+    xfer->max_size = tu_edpt_packet_size(desc_edpt);
+
+    if (epnum != 0) {
+        if (tu_edpt_dir(desc_edpt->bEndpointAddress) == TUSB_DIR_OUT) {
+            EP_RX_CTRL(epnum) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_ACK;
+        } else {
+            EP_TX_LEN(epnum) = 0;
+            EP_TX_CTRL(epnum) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+        }
+    }
+
+    return true;
+}
+
+int usbd_ep_close(const uint8_t ep) {
+    (void)ep;
+
+    return 0;
+}
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
+    (void)rhport;
+
+    uint8_t const epnum = tu_edpt_number(ep_addr);
+    uint8_t const dir = tu_edpt_dir(ep_addr);
+
+    if (epnum == 0) {
+        if (dir == TUSB_DIR_OUT) {
+            USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_STALL;
+        } else {
+            USBHSD->UEP0_TX_LEN = 0;
+            USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_STALL;
+        }
+    } else {
+        if (dir == TUSB_DIR_OUT) {
+            EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_STALL;
+
+        } else {
+            EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~USBHS_EP_T_RES_MASK) | USBHS_EP_T_RES_STALL;
+        }
+    }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
+    (void)rhport;
+
+    uint8_t const epnum = tu_edpt_number(ep_addr);
+    uint8_t const dir = tu_edpt_dir(ep_addr);
+
+    if (epnum == 0) {
+        if (dir == TUSB_DIR_OUT) {
+            USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
+        } else {
+        }
+    } else {
+        if (dir == TUSB_DIR_OUT) {
+            EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~(USBHS_EP_R_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_ACK;
+
+        } else {
+            EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_NAK;
+        }
+    }
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) {
+    (void)rhport;
+    uint8_t const epnum = tu_edpt_number(ep_addr);
+    uint8_t const dir = tu_edpt_dir(ep_addr);
+
+    xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
+    xfer->buffer = buffer;
+    // xfer->ff           = NULL; // TODO support dcd_edpt_xfer_fifo API
+    xfer->total_len = total_bytes;
+    xfer->queued_len = 0;
+    xfer->short_packet = false;
+
+    // uint16_t num_packets = (total_bytes / xfer->max_size);
+    uint16_t short_packet_size = total_bytes % (xfer->max_size + 1);
+
+    // Zero-size packet is special case.
+    if (short_packet_size == 0 || (total_bytes == 0)) {
+        xfer->short_packet = true;
+    }
+
+    if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
+        if (!total_bytes) {
+            xfer->short_packet = true;
+            if (epnum == 0) {
+                USBHSD->UEP0_TX_LEN = 0;
+                USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
+                USBHS_Dev_Endp0_Tog ^= 1;
+            } else {
+                EP_TX_LEN(epnum) = 0;
+                EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
+            }
+        } else {
+            if (epnum == 0) {
+                xfer->queued_len += short_packet_size;
+                memcpy(&EP0_DatabufHD[0], buffer, short_packet_size);
+
+                USBHSD->UEP0_TX_LEN = short_packet_size;
+                USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
+                USBHS_Dev_Endp0_Tog ^= 1;
+            } else {
+                xfer->queued_len += short_packet_size;
+                
+                EP_TX_DMA_ADDR(epnum) = (uint32_t)buffer;
+                USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << epnum);
+                EP_TX_LEN(epnum) = short_packet_size;
+                EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
+            }
+        }
+    } else { /* TUSB_DIR_OUT */
+        if (epnum == 0) {
+            uint32_t read_count = USBHSD->RX_LEN;
+            read_count = TU_MIN(read_count, total_bytes);
+
+            if ((total_bytes == 8)) {
+                read_count = 8;
+                memcpy(buffer, &EP0_DatabufHD[0], 8);
+            } else {
+                memcpy(buffer, &EP0_DatabufHD[0], read_count);
+            }
+        } else {
+            EP_RX_DMA_ADDR(epnum) = (uint32_t)xfer->buffer;
+            USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << epnum);
+        }
+
+        // usbd_ep_read(ep_addr, buffer, total_bytes, &ret_bytes);
+    }
+    return true;
+}
+
+
+static void receive_packet(xfer_ctl_t *xfer, uint16_t xfer_size) {
+    // xfer->queued_len = xfer->total_len - remaining;
+
+    uint16_t remaining = xfer->total_len - xfer->queued_len;
+    uint16_t to_recv_size;
+
+    if (remaining <= xfer->max_size) {
+        // Avoid buffer overflow.
+        to_recv_size = (xfer_size > remaining) ? remaining : xfer_size;
+    } else {
+        // Room for full packet, choose recv_size based on what the microcontroller
+        // claims.
+        to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
+    }
+
+    if (to_recv_size) {
+    }
+
+    xfer->queued_len += xfer_size;
+
+    // Per USB spec, a short OUT packet (including length 0) is always
+    // indicative of the end of a transfer (at least for ctl, bulk, int).
+    xfer->short_packet = (xfer_size < xfer->max_size);
+}
+
+void dcd_int_handler(uint8_t rhport) {
+    (void)rhport;
+
+    uint32_t end_num, rx_token;
+    uint8_t intflag = 0;
+
+    intflag = USBHSD->INT_FG;
+
+    if (intflag & USBHS_TRANSFER_FLAG) {
+
+        end_num = (USBHSD->INT_ST) & MASK_UIS_ENDP;
+        rx_token = (((USBHSD->INT_ST) & MASK_UIS_TOKEN) >> 4) & 0x03;
+
+        uint8_t endp = end_num | (rx_token == PID_IN ? TUSB_DIR_IN_MASK : 0);
+
+        xfer_ctl_t *xfer = XFER_CTL_BASE(end_num, tu_edpt_dir(endp));
+
+        if (rx_token == PID_OUT) {
+            uint16_t rx_len = USBHSD->RX_LEN;
+
+            receive_packet(xfer, rx_len);
+
+            if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
+                xfer->short_packet = false;
+
+                dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+            }
+
+            if (end_num == 0) {
+                USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
+            }
+
+        } else if (rx_token == PID_IN) {
+            if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
+                xfer->short_packet = false;
+                xfer->total_len = 0;
+                dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+
+                EP_TX_CTRL(end_num) = (EP_TX_CTRL(end_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK;
+
+                if (end_num == 0) {
+                }
+            } else {
+                dcd_edpt_xfer(0, endp, xfer->buffer + xfer->queued_len, xfer->total_len - xfer->queued_len);
+            }
+        }
+
+        USBHSD->INT_FG = USBHS_TRANSFER_FLAG; /* Clear flag */
+    } else if (intflag & USBHS_SETUP_FLAG) {
+        USBHS_Dev_Endp0_Tog = 1;
+        dcd_event_setup_received(0, EP0_DatabufHD, true);
+        
+        USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */
+    } else if (intflag & USBHS_DETECT_FLAG) {
+        USBHS_Dev_Endp0_Tog = 1;
+
+        xfer_status[0][TUSB_DIR_OUT].max_size = 64;
+        xfer_status[0][TUSB_DIR_IN].max_size = 64;
+
+        dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true);
+
+        USBHSD->DEV_AD = 0;
+        USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
+
+        USBHSD->INT_FG = USBHS_DETECT_FLAG; /* Clear flag */
+    } else if (intflag & USBHS_SUSPEND_FLAG) {
+        dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SUSPEND };
+        dcd_event_handler(&event, true);
+
+        USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */
+    }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/tusb_option.h b/src/tusb_option.h
index bd87a953c..ffeec2241 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -149,6 +149,9 @@
 // Allwinner
 #define OPT_MCU_F1C100S          2100 ///< Allwinner F1C100s family
 
+// WCH
+#define OPT_MCU_CH32VF307        2200 ///< WCH CH32V307 config
+
 // Helper to check if configured MCU is one of listed
 // Apply _TU_CHECK_MCU with || as separator to list of input
 #define _TU_CHECK_MCU(_m)   (CFG_TUSB_MCU == _m)

From 1d254be1a48264f906c5bbc50c4eca56eea063df Mon Sep 17 00:00:00 2001
From: Greg Davill <greg.davill@gmail.com>
Date: Tue, 22 Mar 2022 16:03:53 +1030
Subject: [PATCH 02/20] Increase stack size to 4096 bytes

---
 hw/bsp/ch32v307/Link.ld                       | 170 ++++++++++++++++++
 .../ch32v307/boards/CH32V307V-R1-1v0/board.mk |   2 +-
 2 files changed, 171 insertions(+), 1 deletion(-)
 create mode 100644 hw/bsp/ch32v307/Link.ld

diff --git a/hw/bsp/ch32v307/Link.ld b/hw/bsp/ch32v307/Link.ld
new file mode 100644
index 000000000..af7c06615
--- /dev/null
+++ b/hw/bsp/ch32v307/Link.ld
@@ -0,0 +1,170 @@
+ENTRY( _start )
+
+__stack_size = 4096;
+
+PROVIDE( _stack_size = __stack_size );
+
+
+MEMORY
+{
+	FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 288K
+	RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
+}
+
+
+SECTIONS
+{
+
+	.init :
+	{
+		_sinit = .;
+		. = ALIGN(4);
+		KEEP(*(SORT_NONE(.init)))
+		. = ALIGN(4);
+		_einit = .;
+	} >FLASH AT>FLASH
+
+  .vector :
+  {
+      *(.vector);
+	  . = ALIGN(64);
+  } >FLASH AT>FLASH
+
+	.text :
+	{
+		. = ALIGN(4);
+		*(.text)
+		*(.text.*)
+		*(.rodata)
+		*(.rodata*)
+		*(.glue_7)
+		*(.glue_7t)
+		*(.gnu.linkonce.t.*)
+		. = ALIGN(4);
+	} >FLASH AT>FLASH 
+
+	.fini :
+	{
+		KEEP(*(SORT_NONE(.fini)))
+		. = ALIGN(4);
+	} >FLASH AT>FLASH
+
+	PROVIDE( _etext = . );
+	PROVIDE( _eitcm = . );	
+
+	.preinit_array  :
+	{
+	  PROVIDE_HIDDEN (__preinit_array_start = .);
+	  KEEP (*(.preinit_array))
+	  PROVIDE_HIDDEN (__preinit_array_end = .);
+	} >FLASH AT>FLASH 
+	
+	.init_array     :
+	{
+	  PROVIDE_HIDDEN (__init_array_start = .);
+	  KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+	  KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
+	  PROVIDE_HIDDEN (__init_array_end = .);
+	} >FLASH AT>FLASH 
+	
+	.fini_array     :
+	{
+	  PROVIDE_HIDDEN (__fini_array_start = .);
+	  KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+	  KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
+	  PROVIDE_HIDDEN (__fini_array_end = .);
+	} >FLASH AT>FLASH 
+	
+	.ctors          :
+	{
+	  /* gcc uses crtbegin.o to find the start of
+	     the constructors, so we make sure it is
+	     first.  Because this is a wildcard, it
+	     doesn't matter if the user does not
+	     actually link against crtbegin.o; the
+	     linker won't look for a file to match a
+	     wildcard.  The wildcard also means that it
+	     doesn't matter which directory crtbegin.o
+	     is in.  */
+	  KEEP (*crtbegin.o(.ctors))
+	  KEEP (*crtbegin?.o(.ctors))
+	  /* We don't want to include the .ctor section from
+	     the crtend.o file until after the sorted ctors.
+	     The .ctor section from the crtend file contains the
+	     end of ctors marker and it must be last */
+	  KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+	  KEEP (*(SORT(.ctors.*)))
+	  KEEP (*(.ctors))
+	} >FLASH AT>FLASH 
+	
+	.dtors          :
+	{
+	  KEEP (*crtbegin.o(.dtors))
+	  KEEP (*crtbegin?.o(.dtors))
+	  KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+	  KEEP (*(SORT(.dtors.*)))
+	  KEEP (*(.dtors))
+	} >FLASH AT>FLASH 
+
+	.dalign :
+	{
+		. = ALIGN(4);
+		PROVIDE(_data_vma = .);
+	} >RAM AT>FLASH	
+
+	.dlalign :
+	{
+		. = ALIGN(4); 
+		PROVIDE(_data_lma = .);
+	} >FLASH AT>FLASH
+
+	.data :
+	{
+    	*(.gnu.linkonce.r.*)
+    	*(.data .data.*)
+    	*(.gnu.linkonce.d.*)
+		. = ALIGN(8);
+    	PROVIDE( __global_pointer$ = . + 0x800 );
+    	*(.sdata .sdata.*)
+		*(.sdata2.*)
+    	*(.gnu.linkonce.s.*)
+    	. = ALIGN(8);
+    	*(.srodata.cst16)
+    	*(.srodata.cst8)
+    	*(.srodata.cst4)
+    	*(.srodata.cst2)
+    	*(.srodata .srodata.*)
+    	. = ALIGN(4);
+		PROVIDE( _edata = .);
+	} >RAM AT>FLASH
+
+	.bss :
+	{
+		. = ALIGN(4);
+		PROVIDE( _sbss = .);
+  	    *(.sbss*)
+        *(.gnu.linkonce.sb.*)
+		*(.bss*)
+     	*(.gnu.linkonce.b.*)		
+		*(COMMON*)
+		. = ALIGN(4);
+		PROVIDE( _ebss = .);
+	} >RAM AT>FLASH
+
+	PROVIDE( _end = _ebss);
+	PROVIDE( end = . );
+
+    .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size :
+    {
+        PROVIDE( _heap_end = . );    
+        . = ALIGN(4);
+        PROVIDE(_susrstack = . );
+        . = . + __stack_size;
+        PROVIDE( _eusrstack = .);
+        __freertos_irq_stack_top = .;
+    } >RAM 
+
+}
+
+
+
diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk
index f71def2c7..a7c359588 100644
--- a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk
+++ b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk
@@ -1,3 +1,3 @@
-LINKER_SCRIPTS = $(CH32V307_SDK_SRC)/Ld
+LINKER_SCRIPTS = $(BOARD_PATH)/../..
 
 LD_FILE = $(LINKER_SCRIPTS)/Link.ld # CH32V307

From ac058a4c4553a237b297812be712a9c8dce0069a Mon Sep 17 00:00:00 2001
From: Greg Davill <greg.davill@gmail.com>
Date: Tue, 22 Mar 2022 22:32:53 +1030
Subject: [PATCH 03/20] Add ch32v307 to build workflow

---
 .github/workflows/build_riscv.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/build_riscv.yml b/.github/workflows/build_riscv.yml
index 0c7b2d154..4ac265da3 100644
--- a/.github/workflows/build_riscv.yml
+++ b/.github/workflows/build_riscv.yml
@@ -15,6 +15,7 @@ jobs:
       matrix:
         family:
         # Alphabetical order
+        - 'ch32v307'
         - 'fomu'
         - 'gd32vf103'
     steps:

From d828d203fcdc9f6839330e1007a331f740224ab8 Mon Sep 17 00:00:00 2001
From: Greg Davill <greg.davill@gmail.com>
Date: Tue, 22 Mar 2022 23:29:09 +1030
Subject: [PATCH 04/20] Skip freertos for ch32v307

---
 examples/device/cdc_msc_freertos/skip.txt       | 1 +
 examples/device/hid_composite_freertos/skip.txt | 1 +
 2 files changed, 2 insertions(+)

diff --git a/examples/device/cdc_msc_freertos/skip.txt b/examples/device/cdc_msc_freertos/skip.txt
index 7137b78af..edb8a34aa 100644
--- a/examples/device/cdc_msc_freertos/skip.txt
+++ b/examples/device/cdc_msc_freertos/skip.txt
@@ -6,5 +6,6 @@ mcu:MKL25ZXX
 mcu:RP2040
 mcu:SAMX7X
 mcu:GD32VF103
+mcu:CH32V307
 family:broadcom_64bit
 family:broadcom_32bit
\ No newline at end of file
diff --git a/examples/device/hid_composite_freertos/skip.txt b/examples/device/hid_composite_freertos/skip.txt
index e64187fd4..b12de1a90 100644
--- a/examples/device/hid_composite_freertos/skip.txt
+++ b/examples/device/hid_composite_freertos/skip.txt
@@ -5,5 +5,6 @@ mcu:VALENTYUSB_EPTRI
 mcu:RP2040
 mcu:SAMX7X
 mcu:GD32VF103
+mcu:CH32V307
 family:broadcom_64bit
 family:broadcom_32bit
\ No newline at end of file

From a09c1648f56580bcdb59b08af255442d9240281c Mon Sep 17 00:00:00 2001
From: Greg Davill <greg.davill@gmail.com>
Date: Tue, 22 Mar 2022 23:31:20 +1030
Subject: [PATCH 05/20] Fix typo

---
 hw/bsp/ch32v307/family.mk                | 2 +-
 src/common/tusb_mcu.h                    | 2 +-
 src/portable/wch/ch32v307/usb_dc_usbhs.c | 2 +-
 src/tusb_option.h                        | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk
index dfb4853d9..ef2af26e6 100644
--- a/hw/bsp/ch32v307/family.mk
+++ b/hw/bsp/ch32v307/family.mk
@@ -28,7 +28,7 @@ CFLAGS += \
 	-ffunction-sections \
 	-fdata-sections \
 	-nostdlib -nostartfiles \
-	-DCFG_TUSB_MCU=OPT_MCU_CH32VF307 \
+	-DCFG_TUSB_MCU=OPT_MCU_CH32V307 \
 	-Xlinker --gc-sections \
     -DBOARD_DEVICE_RHPORT_SPEED=OPT_MODE_HIGH_SPEED
 
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 84d629eac..9de092e34 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -267,7 +267,7 @@
   #define TUP_DCD_ENDPOINT_MAX    4
 
 //------------- WCH -------------//
-#elif TU_CHECK_MCU(OPT_MCU_CH32VF307)
+#elif TU_CHECK_MCU(OPT_MCU_CH32V307)
   #define TUP_DCD_ENDPOINT_MAX    8
 
 #endif
diff --git a/src/portable/wch/ch32v307/usb_dc_usbhs.c b/src/portable/wch/ch32v307/usb_dc_usbhs.c
index 32645dc5f..3a2c9979e 100644
--- a/src/portable/wch/ch32v307/usb_dc_usbhs.c
+++ b/src/portable/wch/ch32v307/usb_dc_usbhs.c
@@ -26,7 +26,7 @@
 
 #include "tusb_option.h"
 
-#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_CH32VF307)
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_CH32V307)
 #include "device/dcd.h"
 
 #include "usb_ch32_usbhs_reg.h"
diff --git a/src/tusb_option.h b/src/tusb_option.h
index ffeec2241..28bf8a60d 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -150,7 +150,7 @@
 #define OPT_MCU_F1C100S          2100 ///< Allwinner F1C100s family
 
 // WCH
-#define OPT_MCU_CH32VF307        2200 ///< WCH CH32V307 config
+#define OPT_MCU_CH32V307        2200 ///< WCH CH32V307 config
 
 // Helper to check if configured MCU is one of listed
 // Apply _TU_CHECK_MCU with || as separator to list of input

From 325923b6c61d0a914a0c6f78e650c6b85fbd13d2 Mon Sep 17 00:00:00 2001
From: Greg Davill <greg.davill@gmail.com>
Date: Tue, 22 Mar 2022 23:40:54 +1030
Subject: [PATCH 06/20] Update comments about endpoint buffer modes

---
 src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h b/src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h
index 1b7c0e791..5a2c1fbc9 100644
--- a/src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h
+++ b/src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h
@@ -231,12 +231,12 @@
 
 #define USBHS_EP15_BUF_MOD     (1 << 15)
 #define USBHS_EP15_ISO_BUF_MOD (1 << 31)
-//USBHS_EPn_T_EN  USBHS_EPn_R_EN  USBHS_EPn_BUF_MOD  锟斤拷锟斤拷锟斤拷锟斤拷UEPn_DMA为锟斤拷始锟斤拷址锟缴碉拷锟斤拷锟斤拷锟斤拷锟�
-//      0               0               x            锟剿点被锟斤拷锟矫o拷未锟矫碉拷UEPn_*_DMA锟斤拷锟斤拷锟斤拷锟斤拷
-//      1               0               0            锟斤拷锟秸o拷OUT锟斤拷锟斤拷锟斤拷锟斤拷锟阶碉拷址为UEPn_RX_DMA
-//      1               0               1            bUEPn_RX_TOG[0]=0,使锟矫伙拷锟斤拷锟斤拷UEPn_RX_DMA锟斤拷bUEPn_RX_TOG[0]=1,使锟矫伙拷锟斤拷锟斤拷UEPn_TX_DMA
-//      0               1               0            锟斤拷锟斤拷(IN)锟斤拷锟斤拷锟斤拷锟阶碉拷址为UEPn_TX_DMA锟斤拷
-//      0               1               1            bUEPn_TX_TOG[0]=0,使锟矫伙拷锟斤拷锟斤拷UEPn_TX_DMA锟斤拷bUEPn_TX_TOG[0]=1,使锟矫伙拷锟斤拷锟斤拷UEPn_RX_DMA
+//USBHS_EPn_T_EN  USBHS_EPn_R_EN  USBHS_EPn_BUF_MOD  Description: Arrange from low to high with UEPn_DMA as the starting address
+//      0               0               x            The endpoint is disabled and the UEPn_*_DMA buffers are not used.
+//      1               0               0            The first address of the receive (OUT) buffer is UEPn_RX_DMA
+//      1               0               1            RB_UEPn_RX_TOG[0]=0, use buffer UEPn_RX_DMA RB_UEPn_RX_TOG[0]=1, use buffer UEPn_TX_DMA
+//      0               1               0            The first address of the transmit (IN) buffer is UEPn_TX_DMA.
+//      0               1               1            RB_UEPn_TX_TOG[0]=0, use buffer UEPn_TX_DMA RB_UEPn_TX_TOG[0]=1, use buffer UEPn_RX_DMA
 
 /* USB0_DMA */
 #define USBHS_UEP0_DMA_OFFSET(n) (0x1C) // endpoint 0 DMA buffer address

From cdb8a1a2a1dd863f35fd91d58c18ec83115f9326 Mon Sep 17 00:00:00 2001
From: Greg Davill <greg.davill@gmail.com>
Date: Wed, 23 Mar 2022 00:00:06 +1030
Subject: [PATCH 07/20] Clean up driver

---
 src/common/tusb_mcu.h                    |  2 +-
 src/portable/wch/ch32v307/usb_dc_usbhs.c | 10 ++++------
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 9de092e34..fb0cdd361 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -268,7 +268,7 @@
 
 //------------- WCH -------------//
 #elif TU_CHECK_MCU(OPT_MCU_CH32V307)
-  #define TUP_DCD_ENDPOINT_MAX    8
+  #define TUP_DCD_ENDPOINT_MAX    16
 
 #endif
 
diff --git a/src/portable/wch/ch32v307/usb_dc_usbhs.c b/src/portable/wch/ch32v307/usb_dc_usbhs.c
index 3a2c9979e..e647389ee 100644
--- a/src/portable/wch/ch32v307/usb_dc_usbhs.c
+++ b/src/portable/wch/ch32v307/usb_dc_usbhs.c
@@ -56,10 +56,8 @@ static xfer_ctl_t xfer_status[EP_MAX][2];
 #define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1))
 
 /* Endpoint Buffer */
-__attribute__((aligned(4))) uint8_t setup[8];           // ep0(64)
-__attribute__((aligned(4))) uint8_t EP0_DatabufHD[64];  // ep0(64)
+TU_ATTR_ALIGNED(4) uint8_t EP0_DatabufHD[64];  // ep0(64)
 
-volatile uint8_t mps_over_flag = 0;
 volatile uint8_t USBHS_Dev_Endp0_Tog = 0x01;
 
 void dcd_init(uint8_t rhport) {
@@ -67,15 +65,15 @@ void dcd_init(uint8_t rhport) {
 
     memset(&xfer_status, 0, sizeof(xfer_status));
 
-    // usb_dc_low_level_init();
-
     USBHSD->HOST_CTRL = 0x00;
     USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM;
 
     USBHSD->CONTROL = 0;
-#if 1
+
+#if (BOARD_DEVICE_RHPORT_SPEED == OPT_MODE_HIGH_SPEED)
     USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
 #else
+    #error OPT_MODE_FULL_SPEED not currently supported on CH32V307
     USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED;
 #endif
 

From 46fb850e02ae5010e0f7209775e1f5392112efa4 Mon Sep 17 00:00:00 2001
From: Greg Davill <greg.davill@gmail.com>
Date: Wed, 23 Mar 2022 00:06:51 +1030
Subject: [PATCH 08/20] Update support table

---
 docs/reference/supported.rst | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/docs/reference/supported.rst b/docs/reference/supported.rst
index 7ce982713..aebee2c29 100644
--- a/docs/reference/supported.rst
+++ b/docs/reference/supported.rst
@@ -102,6 +102,8 @@ Supported MCUs
 +--------------+-----------------------+--------+------+-----------+-------------------+--------------+
 | ValentyUSB   | eptri                 | ✔      | ✖    | ✖         | eptri             |              |
 +--------------+-----------------------+--------+------+-----------+-------------------+--------------+
+| WCH          | CH32V307              | ✔      | ✖    | ✔         | ch32v307          |              |
++--------------+-----------------------+--------+------+-----------+-------------------+--------------+
 
 
 Table Legend
@@ -388,3 +390,8 @@ Tomu
 ----
 
 -  `Fomu <https://www.crowdsupply.com/sutajio-kosagi/fomu>`__
+
+WCH
+---
+
+- `CH32V307V-R1-1v0 <https://lcsc.com/product-detail/Development-Boards-Kits_WCH-Jiangsu-Qin-Heng-CH32V307V-EVT-R1_C2943980.html>`

From 7d395c674ca083a245df0601c8a6d392c75b34e8 Mon Sep 17 00:00:00 2001
From: Greg Davill <greg.davill@gmail.com>
Date: Wed, 23 Mar 2022 00:46:44 +1030
Subject: [PATCH 09/20] Update supported table

---
 docs/reference/supported.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/reference/supported.rst b/docs/reference/supported.rst
index aebee2c29..7543e44ab 100644
--- a/docs/reference/supported.rst
+++ b/docs/reference/supported.rst
@@ -102,7 +102,7 @@ Supported MCUs
 +--------------+-----------------------+--------+------+-----------+-------------------+--------------+
 | ValentyUSB   | eptri                 | ✔      | ✖    | ✖         | eptri             |              |
 +--------------+-----------------------+--------+------+-----------+-------------------+--------------+
-| WCH          | CH32V307              | ✔      | ✖    | ✔         | ch32v307          |              |
+| WCH          | CH32V307              | ✔      |      | ✔         | ch32v307          |              |
 +--------------+-----------------------+--------+------+-----------+-------------------+--------------+
 
 

From 817227a850d4942cf48ede675325d635e2e7b3d5 Mon Sep 17 00:00:00 2001
From: Rafael Silva <perigoso@riseup.net>
Date: Fri, 1 Apr 2022 10:05:14 +0100
Subject: [PATCH 10/20] Add WCH CH32V307 to readme supported list

---
 README.rst | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.rst b/README.rst
index 5b994c357..755bd97e9 100644
--- a/README.rst
+++ b/README.rst
@@ -54,6 +54,7 @@ The stack supports the following MCUs:
 - **ST:** STM32 series: F0, F1, F2, F3, F4, F7, H7, G4, L0, L1, L4, L4+
 - **TI:** MSP430, MSP432E4, TM4C123
 - **ValentyUSB:** eptri
+- **WCH:** CH32V307
 
 Here is the list of `Supported Devices`_ that can be used with provided examples.
 

From a7e1de1e837961b33021a8ae4ca63571fbf1f4a2 Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Sun, 8 Jan 2023 00:02:17 +0700
Subject: [PATCH 11/20] temporarily suppress redundant-decls due to
 USART_Printf_Init()

fix codespell
---
 hw/bsp/ch32v307/family.c  | 2 +-
 hw/bsp/ch32v307/family.mk | 5 ++++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/hw/bsp/ch32v307/family.c b/hw/bsp/ch32v307/family.c
index ea1c252c4..428466ad7 100644
--- a/hw/bsp/ch32v307/family.c
+++ b/hw/bsp/ch32v307/family.c
@@ -85,7 +85,7 @@ void board_init(void) {
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_Init(GPIOC, &GPIO_InitStructure);
 
-  /* Enable interrupts globaly */
+  /* Enable interrupts globally */
   __enable_irq();
 
   board_delay(2);
diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk
index ef2af26e6..12565016d 100644
--- a/hw/bsp/ch32v307/family.mk
+++ b/hw/bsp/ch32v307/family.mk
@@ -30,7 +30,10 @@ CFLAGS += \
 	-nostdlib -nostartfiles \
 	-DCFG_TUSB_MCU=OPT_MCU_CH32V307 \
 	-Xlinker --gc-sections \
-    -DBOARD_DEVICE_RHPORT_SPEED=OPT_MODE_HIGH_SPEED
+	-DBOARD_DEVICE_RHPORT_SPEED=OPT_MODE_HIGH_SPEED
+
+# caused by extra void USART_Printf_Init() in debug_uart.h and EVT/EXAME/SRC/DEBUG/debug.h
+CFLAGS += -Wno-error=redundant-decls
 
 LDFLAGS += \
   -Xlinker --gc-sections --specs=nano.specs --specs=nosys.specs

From 3cc6cece0783e893d9fadc868f7fb58c81625fe0 Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Thu, 12 Jan 2023 10:25:48 +0700
Subject: [PATCH 12/20] add note for openocd with wch, also add wch-riscv.cfg

---
 hw/bsp/ch32v307/family.mk                | 18 +++++++++++++++---
 hw/bsp/ch32v307/wch-riscv.cfg            | 15 +++++++++++++++
 src/portable/wch/ch32v307/usb_dc_usbhs.c |  4 ++--
 3 files changed, 32 insertions(+), 5 deletions(-)
 create mode 100644 hw/bsp/ch32v307/wch-riscv.cfg

diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk
index 12565016d..58542041f 100644
--- a/hw/bsp/ch32v307/family.mk
+++ b/hw/bsp/ch32v307/family.mk
@@ -30,7 +30,7 @@ CFLAGS += \
 	-nostdlib -nostartfiles \
 	-DCFG_TUSB_MCU=OPT_MCU_CH32V307 \
 	-Xlinker --gc-sections \
-	-DBOARD_DEVICE_RHPORT_SPEED=OPT_MODE_HIGH_SPEED
+	-DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
 
 # caused by extra void USART_Printf_Init() in debug_uart.h and EVT/EXAME/SRC/DEBUG/debug.h
 CFLAGS += -Wno-error=redundant-decls
@@ -51,7 +51,6 @@ SRC_S += \
 
 INC += \
 	src/portable/wch/ch32v307 \
-	$(TOP)/$(BOARD_PATH)/.. \
 	$(TOP)/$(BOARD_PATH) \
 	$(CH32V307_SDK_SRC_TOP)/Peripheral/inc \
 	$(CH32V307_SDK_SRC_TOP)/Debug \
@@ -60,6 +59,19 @@ INC += \
 # For freeRTOS port source
 FREERTOS_PORT = RISC-V
 
+# wch-link is not supported yet in official openOCD yet. We need to either use
+# 1. download openocd as part of mounriver studio http://www.mounriver.com/download or
+# 2. compiled from modified source https://github.com/kprasadvnsi/riscv-openocd-wch
+#
+# Note: For Linux, somehow openocd in mounriver studio does not seem to have wch-link enable, 
+# therefore we need to compile it from source as follows:
+# 	git clone https://github.com/kprasadvnsi/riscv-openocd-wch
+# 	cd riscv-openocd-wch
+#		./bootstrap
+#		./configure CFLAGS="-Wno-error" --enable-wlink
+#		make
+# openocd binaries will be generated in riscv-openocd-wch/src
+
 # flash target ROM bootloader
 flash: $(BUILD)/$(PROJECT).elf
-	openocd -f wch-riscv.cfg  -c init -c halt  -c "program  $<  0x08000000"  -c reset -c exit
+	openocd -f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg -c init -c halt -c "program $<" -c reset -c exit
diff --git a/hw/bsp/ch32v307/wch-riscv.cfg b/hw/bsp/ch32v307/wch-riscv.cfg
new file mode 100644
index 000000000..0d24d16ca
--- /dev/null
+++ b/hw/bsp/ch32v307/wch-riscv.cfg
@@ -0,0 +1,15 @@
+#interface wlink
+adapter driver wlink
+wlink_set
+set _CHIPNAME riscv
+jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001
+
+set _TARGETNAME $_CHIPNAME.cpu
+
+target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME
+$_TARGETNAME.0 configure  -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1
+set _FLASHNAME $_CHIPNAME.flash
+
+flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0
+
+echo "Ready for Remote Connections"
diff --git a/src/portable/wch/ch32v307/usb_dc_usbhs.c b/src/portable/wch/ch32v307/usb_dc_usbhs.c
index e647389ee..39fd41392 100644
--- a/src/portable/wch/ch32v307/usb_dc_usbhs.c
+++ b/src/portable/wch/ch32v307/usb_dc_usbhs.c
@@ -70,7 +70,7 @@ void dcd_init(uint8_t rhport) {
 
     USBHSD->CONTROL = 0;
 
-#if (BOARD_DEVICE_RHPORT_SPEED == OPT_MODE_HIGH_SPEED)
+#if TUD_OPT_HIGH_SPEED
     USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
 #else
     #error OPT_MODE_FULL_SPEED not currently supported on CH32V307
@@ -383,4 +383,4 @@ void dcd_int_handler(uint8_t rhport) {
     }
 }
 
-#endif
\ No newline at end of file
+#endif

From e61d4aefe6b9fbab862e7c440ff9ff25ebb5092c Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Thu, 12 Jan 2023 12:08:56 +0700
Subject: [PATCH 13/20] rename driver with dcd_ to be consitent with other
 ports

---
 hw/bsp/ch32v307/family.mk                     | 22 ++++++++-----------
 ...{usb_ch32_usbhs_reg.h => ch32_usbhs_reg.h} |  0
 .../ch32v307/{usb_dc_usbhs.c => dcd_usbhs.c}  |  2 +-
 3 files changed, 10 insertions(+), 14 deletions(-)
 rename src/portable/wch/ch32v307/{usb_ch32_usbhs_reg.h => ch32_usbhs_reg.h} (100%)
 rename src/portable/wch/ch32v307/{usb_dc_usbhs.c => dcd_usbhs.c} (99%)

diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk
index 58542041f..ffc992f21 100644
--- a/hw/bsp/ch32v307/family.mk
+++ b/hw/bsp/ch32v307/family.mk
@@ -10,8 +10,6 @@ DEPS_SUBMODULES += $(CH32V307_SDK)
 
 # WCH-SDK paths
 CH32V307_SDK_SRC = $(CH32V307_SDK)/EVT/EXAM/SRC
-CH32V307_SDK_SRC_TOP = $(TOP)/$(CH32V307_SDK_SRC)
-CH32V307_STARTUP_ASM = $(CH32V307_SDK_SRC)/Startup
 
 include $(TOP)/$(BOARD_PATH)/board.mk
 
@@ -39,22 +37,20 @@ LDFLAGS += \
   -Xlinker --gc-sections --specs=nano.specs --specs=nosys.specs
 
 SRC_C += \
-	src/portable/wch/ch32v307/usb_dc_usbhs.c \
-	$(CH32V307_SDK_SRC_TOP)/Core/core_riscv.c \
-	$(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_gpio.c \
-	$(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_misc.c \
-	$(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_rcc.c \
-	$(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_usart.c 
+	src/portable/wch/ch32v307/dcd_usbhs.c \
+	$(CH32V307_SDK_SRC)/Core/core_riscv.c \
+	$(CH32V307_SDK_SRC)/Peripheral/src/ch32v30x_gpio.c \
+	$(CH32V307_SDK_SRC)/Peripheral/src/ch32v30x_misc.c \
+	$(CH32V307_SDK_SRC)/Peripheral/src/ch32v30x_rcc.c \
+	$(CH32V307_SDK_SRC)/Peripheral/src/ch32v30x_usart.c 
 	
 SRC_S += \
-	$(CH32V307_STARTUP_ASM)/startup_ch32v30x_D8C.S 
+	$(CH32V307_SDK_SRC)/Startup/startup_ch32v30x_D8C.S 
 
 INC += \
-	src/portable/wch/ch32v307 \
 	$(TOP)/$(BOARD_PATH) \
-	$(CH32V307_SDK_SRC_TOP)/Peripheral/inc \
-	$(CH32V307_SDK_SRC_TOP)/Debug \
-	$(CH32V307_SDK_SRC_TOP)
+	$(TOP)/$(CH32V307_SDK_SRC)/Peripheral/inc \
+	$(TOP)/$(CH32V307_SDK_SRC)/Debug
 
 # For freeRTOS port source
 FREERTOS_PORT = RISC-V
diff --git a/src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h b/src/portable/wch/ch32v307/ch32_usbhs_reg.h
similarity index 100%
rename from src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h
rename to src/portable/wch/ch32v307/ch32_usbhs_reg.h
diff --git a/src/portable/wch/ch32v307/usb_dc_usbhs.c b/src/portable/wch/ch32v307/dcd_usbhs.c
similarity index 99%
rename from src/portable/wch/ch32v307/usb_dc_usbhs.c
rename to src/portable/wch/ch32v307/dcd_usbhs.c
index 39fd41392..7a0dcfc23 100644
--- a/src/portable/wch/ch32v307/usb_dc_usbhs.c
+++ b/src/portable/wch/ch32v307/dcd_usbhs.c
@@ -29,7 +29,7 @@
 #if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_CH32V307)
 #include "device/dcd.h"
 
-#include "usb_ch32_usbhs_reg.h"
+#include "ch32_usbhs_reg.h"
 #include "core_riscv.h"
 
 // Max number of bi-directional endpoints including EP0

From 658897cf4e3058aee66f65c17a152ef65b1671c1 Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Thu, 12 Jan 2023 12:30:18 +0700
Subject: [PATCH 14/20] fix redundant-decls warnings with USART_Printf_Init()

---
 hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c | 2 +-
 hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h | 2 +-
 hw/bsp/ch32v307/ch32v30x_it.h                        | 2 +-
 hw/bsp/ch32v307/family.c                             | 2 +-
 hw/bsp/ch32v307/family.mk                            | 6 +-----
 5 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c
index 416782d0e..ad8b32957 100644
--- a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c
+++ b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c
@@ -75,7 +75,7 @@ void uart_sync(void)
 }
 
 
-void USART_Printf_Init(uint32_t baudrate)
+void usart_printf_init(uint32_t baudrate)
 {
     GPIO_InitTypeDef  GPIO_InitStructure;
     USART_InitTypeDef USART_InitStructure;
diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h
index 4348438bb..a7e070585 100644
--- a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h
+++ b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h
@@ -28,4 +28,4 @@
 
 void uart_write(char c);
 void uart_sync(void);
-void USART_Printf_Init(uint32_t baudrate);
+void usart_printf_init(uint32_t baudrate);
diff --git a/hw/bsp/ch32v307/ch32v30x_it.h b/hw/bsp/ch32v307/ch32v30x_it.h
index 6475c5f11..42f285edf 100644
--- a/hw/bsp/ch32v307/ch32v30x_it.h
+++ b/hw/bsp/ch32v307/ch32v30x_it.h
@@ -10,7 +10,7 @@
 #ifndef __CH32V30x_IT_H
 #define __CH32V30x_IT_H
 
-#include "debug.h"
+// #include "debug.h"
 
 
 #endif /* __CH32V30x_IT_H */
diff --git a/hw/bsp/ch32v307/family.c b/hw/bsp/ch32v307/family.c
index 428466ad7..0260918ab 100644
--- a/hw/bsp/ch32v307/family.c
+++ b/hw/bsp/ch32v307/family.c
@@ -68,7 +68,7 @@ void board_init(void) {
   SysTick_Config(SystemCoreClock / 1000);
 #endif
 
-	USART_Printf_Init(115200);
+	usart_printf_init(115200);
 
   RCC_USBCLK48MConfig(RCC_USBCLK48MCLKSource_USBPHY);
   RCC_USBHSPLLCLKConfig(RCC_HSBHSPLLCLKSource_HSE);
diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk
index ffc992f21..93370fc57 100644
--- a/hw/bsp/ch32v307/family.mk
+++ b/hw/bsp/ch32v307/family.mk
@@ -30,9 +30,6 @@ CFLAGS += \
 	-Xlinker --gc-sections \
 	-DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
 
-# caused by extra void USART_Printf_Init() in debug_uart.h and EVT/EXAME/SRC/DEBUG/debug.h
-CFLAGS += -Wno-error=redundant-decls
-
 LDFLAGS += \
   -Xlinker --gc-sections --specs=nano.specs --specs=nosys.specs
 
@@ -49,8 +46,7 @@ SRC_S += \
 
 INC += \
 	$(TOP)/$(BOARD_PATH) \
-	$(TOP)/$(CH32V307_SDK_SRC)/Peripheral/inc \
-	$(TOP)/$(CH32V307_SDK_SRC)/Debug
+	$(TOP)/$(CH32V307_SDK_SRC)/Peripheral/inc
 
 # For freeRTOS port source
 FREERTOS_PORT = RISC-V

From e6a3cfb3506fdd908c47ad0cf63fc67a1ef2455c Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Thu, 12 Jan 2023 13:12:37 +0700
Subject: [PATCH 15/20] rename link file

---
 hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk | 4 +---
 hw/bsp/ch32v307/{Link.ld => ch32v307.ld}         | 0
 2 files changed, 1 insertion(+), 3 deletions(-)
 rename hw/bsp/ch32v307/{Link.ld => ch32v307.ld} (100%)

diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk
index a7c359588..4e91d8938 100644
--- a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk
+++ b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk
@@ -1,3 +1 @@
-LINKER_SCRIPTS = $(BOARD_PATH)/../..
-
-LD_FILE = $(LINKER_SCRIPTS)/Link.ld # CH32V307
+LD_FILE = $(FAMILY_PATH)/ch32v307.ld
diff --git a/hw/bsp/ch32v307/Link.ld b/hw/bsp/ch32v307/ch32v307.ld
similarity index 100%
rename from hw/bsp/ch32v307/Link.ld
rename to hw/bsp/ch32v307/ch32v307.ld

From 65f7a8006cdeae74e5258657250ae7568b607cd1 Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Thu, 12 Jan 2023 13:31:36 +0700
Subject: [PATCH 16/20] rename board to lower case ch32v307v-r1-1v0

---
 .../boards/{CH32V307V-R1-1v0 => ch32v307v-r1-1v0}/board.mk      | 0
 .../boards/{CH32V307V-R1-1v0 => ch32v307v-r1-1v0}/debug_uart.c  | 0
 .../boards/{CH32V307V-R1-1v0 => ch32v307v-r1-1v0}/debug_uart.h  | 0
 hw/bsp/ch32v307/family.mk                                       | 2 +-
 4 files changed, 1 insertion(+), 1 deletion(-)
 rename hw/bsp/ch32v307/boards/{CH32V307V-R1-1v0 => ch32v307v-r1-1v0}/board.mk (100%)
 rename hw/bsp/ch32v307/boards/{CH32V307V-R1-1v0 => ch32v307v-r1-1v0}/debug_uart.c (100%)
 rename hw/bsp/ch32v307/boards/{CH32V307V-R1-1v0 => ch32v307v-r1-1v0}/debug_uart.h (100%)

diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk b/hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/board.mk
similarity index 100%
rename from hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk
rename to hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/board.mk
diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c b/hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/debug_uart.c
similarity index 100%
rename from hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c
rename to hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/debug_uart.c
diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h b/hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/debug_uart.h
similarity index 100%
rename from hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h
rename to hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/debug_uart.h
diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk
index 93370fc57..49e496853 100644
--- a/hw/bsp/ch32v307/family.mk
+++ b/hw/bsp/ch32v307/family.mk
@@ -66,4 +66,4 @@ FREERTOS_PORT = RISC-V
 
 # flash target ROM bootloader
 flash: $(BUILD)/$(PROJECT).elf
-	openocd -f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg -c init -c halt -c "program $<" -c reset -c exit
+	openocd -f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg -c init -c halt -c "program $<" -c wlink_reset_resume -c exit

From f05f81e8b3d7ac6b061eaab20fc456fbed89d690 Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Thu, 12 Jan 2023 15:19:26 +0700
Subject: [PATCH 17/20] add button support

---
 .../ch32v307/boards/ch32v307v-r1-1v0/board.h  | 50 +++++++++++++
 hw/bsp/ch32v307/family.c                      | 71 +++++++++++--------
 2 files changed, 92 insertions(+), 29 deletions(-)
 create mode 100644 hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/board.h

diff --git a/hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/board.h b/hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/board.h
new file mode 100644
index 000000000..0eab34916
--- /dev/null
+++ b/hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/board.h
@@ -0,0 +1,50 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Ha Thach (tinyusb.org) for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// LED: need to wire pin LED1 to PC0 in the J3 header
+#define LED_PORT              GPIOC
+#define LED_PIN               GPIO_Pin_0
+#define LED_STATE_ON          0
+#define LED_CLOCK_EN()        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE)
+
+// Button: need to wire pin KEY to PC1 in the J3 header
+#define BUTTON_PORT           GPIOC
+#define BUTTON_PIN            GPIO_Pin_1
+#define BUTTON_STATE_ACTIVE   0
+#define BUTTON_CLOCK_EN()     do { } while(0) // same as LED clock, no need to do anything
+
+// TODO UART port
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/hw/bsp/ch32v307/family.c b/hw/bsp/ch32v307/family.c
index 0260918ab..65519ce50 100644
--- a/hw/bsp/ch32v307/family.c
+++ b/hw/bsp/ch32v307/family.c
@@ -28,19 +28,22 @@
 #include "debug_uart.h"
 #include "ch32v30x.h"
 
-#include "../board.h"
+#include "bsp/board.h"
+#include "board.h"
 
 //--------------------------------------------------------------------+
 // Forward USB interrupt events to TinyUSB IRQ Handler
 //--------------------------------------------------------------------+
 
-void USBHS_IRQHandler(void) __attribute__((naked));
-void USBHS_IRQHandler(void) { 
-        __asm volatile ("call USBHS_IRQHandler_impl; mret");
+void USBHS_IRQHandler (void) __attribute__((naked));
+void USBHS_IRQHandler (void)
+{
+  __asm volatile ("call USBHS_IRQHandler_impl; mret");
 }
 
-__attribute__ ((used)) void USBHS_IRQHandler_impl(void) { 
-  tud_int_handler(0); 
+__attribute__ ((used)) void USBHS_IRQHandler_impl (void)
+{
+  tud_int_handler(0);
 }
 
 //--------------------------------------------------------------------+
@@ -49,13 +52,13 @@ __attribute__ ((used)) void USBHS_IRQHandler_impl(void) {
 
 uint32_t SysTick_Config(uint32_t ticks)
 {
-    NVIC_EnableIRQ(SysTicK_IRQn);
-    SysTick->CTLR=0;
-    SysTick->SR=0;
-    SysTick->CNT=0;
-    SysTick->CMP=ticks-1;
-    SysTick->CTLR=0xF;
-    return 0;
+  NVIC_EnableIRQ(SysTicK_IRQn);
+  SysTick->CTLR=0;
+  SysTick->SR=0;
+  SysTick->CNT=0;
+  SysTick->CMP=ticks-1;
+  SysTick->CTLR=0xF;
+  return 0;
 }
 
 void board_init(void) {
@@ -63,7 +66,6 @@ void board_init(void) {
   /* Disable interrupts during init */
   __disable_irq();
 
-
 #if CFG_TUSB_OS == OPT_OS_NONE
   SysTick_Config(SystemCoreClock / 1000);
 #endif
@@ -79,11 +81,19 @@ void board_init(void) {
 
   GPIO_InitTypeDef GPIO_InitStructure = {0};
 
-  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
-  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
+  // LED
+  LED_CLOCK_EN();
+  GPIO_InitStructure.GPIO_Pin = LED_PIN;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-  GPIO_Init(GPIOC, &GPIO_InitStructure);
+  GPIO_Init(LED_PORT, &GPIO_InitStructure);
+
+  // Button
+  BUTTON_CLOCK_EN();
+  GPIO_InitStructure.GPIO_Pin = BUTTON_PIN;
+  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
+  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+  GPIO_Init(BUTTON_PORT, &GPIO_InitStructure);
 
   /* Enable interrupts globally */
   __enable_irq();
@@ -114,26 +124,29 @@ uint32_t board_millis(void) { return system_ticks; }
 // Board porting API
 //--------------------------------------------------------------------+
 
-void board_led_write(bool state) {
-  (void) state;
-
-  GPIO_WriteBit(GPIOC, GPIO_Pin_0, state);
+void board_led_write (bool state)
+{
+  GPIO_WriteBit(LED_PORT, LED_PIN, state);
 }
 
-uint32_t board_button_read(void) {
-  return false;
+uint32_t board_button_read (void)
+{
+  return BUTTON_STATE_ACTIVE == GPIO_ReadInputDataBit(BUTTON_PORT, BUTTON_PIN);
 }
 
-int board_uart_read(uint8_t* buf, int len) {
-  (void)buf;
-  (void)len;
+int board_uart_read (uint8_t *buf, int len)
+{
+  (void) buf;
+  (void) len;
   return 0;
 }
 
-int board_uart_write(void const* buf, int len) {
+int board_uart_write (void const *buf, int len)
+{
   int txsize = len;
-  while (txsize--) {
-    uart_write(*(uint8_t const*)buf);
+  while ( txsize-- )
+  {
+    uart_write(*(uint8_t const*) buf);
     buf++;
   }
   return len;

From 3cf21c66b6ef19c6dd648f952e8679a654b15803 Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Thu, 12 Jan 2023 15:26:48 +0700
Subject: [PATCH 18/20] add dcd_remote_wakeup() stub

---
 src/portable/wch/ch32v307/dcd_usbhs.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/portable/wch/ch32v307/dcd_usbhs.c b/src/portable/wch/ch32v307/dcd_usbhs.c
index 7a0dcfc23..b7a79e166 100644
--- a/src/portable/wch/ch32v307/dcd_usbhs.c
+++ b/src/portable/wch/ch32v307/dcd_usbhs.c
@@ -130,6 +130,11 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
     dcd_edpt_xfer(rhport, 0x80, NULL, 0);
 }
 
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+}
+
 void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) {
     (void)rhport;
 

From 160d64b00a1b4ad46cd61cba3b649a07901d3c65 Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Thu, 12 Jan 2023 15:34:29 +0700
Subject: [PATCH 19/20] minor clean up. ch32v307 has issue with uart LOG=2
 (skipping characters)

---
 .../boards/ch32v307v-r1-1v0/debug_uart.c      | 48 +++++++++----------
 hw/bsp/ch32v307/family.c                      | 17 ++++---
 hw/bsp/ch32v307/family.mk                     |  5 --
 3 files changed, 35 insertions(+), 35 deletions(-)

diff --git a/hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/debug_uart.c b/hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/debug_uart.c
index ad8b32957..45fc9e3aa 100644
--- a/hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/debug_uart.c
+++ b/hw/bsp/ch32v307/boards/ch32v307v-r1-1v0/debug_uart.c
@@ -77,34 +77,34 @@ void uart_sync(void)
 
 void usart_printf_init(uint32_t baudrate)
 {
-    GPIO_InitTypeDef  GPIO_InitStructure;
-    USART_InitTypeDef USART_InitStructure;
+  GPIO_InitTypeDef GPIO_InitStructure;
+  USART_InitTypeDef USART_InitStructure;
 
-	tx_produce = 0;
-	tx_consume = 0;
+  tx_produce = 0;
+  tx_consume = 0;
 
-    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
+  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
 
-    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
-    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-    GPIO_Init(GPIOA, &GPIO_InitStructure);
+  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
+  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+  GPIO_Init(GPIOA, &GPIO_InitStructure);
 
-    USART_InitStructure.USART_BaudRate = baudrate;
-    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
-    USART_InitStructure.USART_StopBits = USART_StopBits_1;
-    USART_InitStructure.USART_Parity = USART_Parity_No;
-    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
-    USART_InitStructure.USART_Mode = USART_Mode_Tx;
+  USART_InitStructure.USART_BaudRate = baudrate;
+  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
+  USART_InitStructure.USART_StopBits = USART_StopBits_1;
+  USART_InitStructure.USART_Parity = USART_Parity_No;
+  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
+  USART_InitStructure.USART_Mode = USART_Mode_Tx;
 
-    USART_Init(USART1, &USART_InitStructure);
-    USART_ITConfig(USART1, USART_IT_TC, ENABLE);
-    USART_Cmd(USART1, ENABLE);
+  USART_Init(USART1, &USART_InitStructure);
+  USART_ITConfig(USART1, USART_IT_TC, ENABLE);
+  USART_Cmd(USART1, ENABLE);
 
-    NVIC_InitTypeDef  NVIC_InitStructure = {0};
-    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
-    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
-    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
-    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
-    NVIC_Init(&NVIC_InitStructure);
+  NVIC_InitTypeDef NVIC_InitStructure = { 0 };
+  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
+  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
+  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
+  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+  NVIC_Init(&NVIC_InitStructure);
 }
diff --git a/hw/bsp/ch32v307/family.c b/hw/bsp/ch32v307/family.c
index 65519ce50..d5602c7b4 100644
--- a/hw/bsp/ch32v307/family.c
+++ b/hw/bsp/ch32v307/family.c
@@ -106,17 +106,22 @@ void board_init(void) {
 volatile uint32_t system_ticks = 0;
 
 /* Small workaround to support HW stack save/restore */
-void SysTick_Handler(void) __attribute__((naked));
-void SysTick_Handler(void) { 
-      __asm volatile ("call SysTick_Handler_impl; mret");
+void SysTick_Handler (void) __attribute__((naked));
+void SysTick_Handler (void)
+{
+  __asm volatile ("call SysTick_Handler_impl; mret");
 }
 
-__attribute__((used)) void SysTick_Handler_impl(void) { 
-  SysTick->SR=0;
+__attribute__((used)) void SysTick_Handler_impl (void)
+{
+  SysTick->SR = 0;
   system_ticks++;
 }
 
-uint32_t board_millis(void) { return system_ticks; }
+uint32_t board_millis (void)
+{
+  return system_ticks;
+}
 
 #endif
 
diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk
index 49e496853..15f6724a8 100644
--- a/hw/bsp/ch32v307/family.mk
+++ b/hw/bsp/ch32v307/family.mk
@@ -13,8 +13,6 @@ CH32V307_SDK_SRC = $(CH32V307_SDK)/EVT/EXAM/SRC
 
 include $(TOP)/$(BOARD_PATH)/board.mk
 
-SKIP_NANOLIB = 1
-
 CFLAGS += \
 	-flto \
 	-march=rv32imac \
@@ -30,9 +28,6 @@ CFLAGS += \
 	-Xlinker --gc-sections \
 	-DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
 
-LDFLAGS += \
-  -Xlinker --gc-sections --specs=nano.specs --specs=nosys.specs
-
 SRC_C += \
 	src/portable/wch/ch32v307/dcd_usbhs.c \
 	$(CH32V307_SDK_SRC)/Core/core_riscv.c \

From b1021d53f3617491656c50f6a1cb2c21da029f6a Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Thu, 12 Jan 2023 15:38:18 +0700
Subject: [PATCH 20/20] add TUP_RHPORT_HIGHSPEED for ch32v307

---
 src/common/tusb_mcu.h | 2 +-
 src/tusb_option.h     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index b37ce9a34..0b10c5118 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -278,7 +278,7 @@
 //------------- WCH -------------//
 #elif TU_CHECK_MCU(OPT_MCU_CH32V307)
   #define TUP_DCD_ENDPOINT_MAX    16
-
+  #define TUP_RHPORT_HIGHSPEED    1
 #endif
 
 //--------------------------------------------------------------------+
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 92fbbd33f..67377b7ec 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -161,7 +161,7 @@ typedef int make_iso_compilers_happy;
 #define OPT_MCU_F1C100S          2100 ///< Allwinner F1C100s family
 
 // WCH
-#define OPT_MCU_CH32V307        2200 ///< WCH CH32V307 config
+#define OPT_MCU_CH32V307         2200 ///< WCH CH32V307
 
 // Helper to check if configured MCU is one of listed
 // Apply _TU_CHECK_MCU with || as separator to list of input