summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHa Thach <[email protected]>2023-01-12 17:51:56 +0700
committerGitHub <[email protected]>2023-01-12 17:51:56 +0700
commitfa9d19027be7caa8dda2ab81ce8fda8b7f586a58 (patch)
treec08f1ffd212b92088968f430b81f69327f452b2e /src
parent4ee4c6f594587e8bc7763ea7585d826118b0eaed (diff)
parentb1021d53f3617491656c50f6a1cb2c21da029f6a (diff)
Merge pull request #1405 from gregdavill/ch32v307
Add WCH CH32V307 port
Diffstat (limited to 'src')
-rw-r--r--src/common/tusb_mcu.h4
-rw-r--r--src/portable/wch/ch32v307/ch32_usbhs_reg.h345
-rw-r--r--src/portable/wch/ch32v307/dcd_usbhs.c391
-rw-r--r--src/tusb_option.h3
4 files changed, 743 insertions, 0 deletions
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index bb4225ad5..0b10c5118 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -275,6 +275,10 @@
#elif TU_CHECK_MCU(OPT_MCU_F1C100S)
#define TUP_DCD_ENDPOINT_MAX 4
+//------------- WCH -------------//
+#elif TU_CHECK_MCU(OPT_MCU_CH32V307)
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_RHPORT_HIGHSPEED 1
#endif
//--------------------------------------------------------------------+
diff --git a/src/portable/wch/ch32v307/ch32_usbhs_reg.h b/src/portable/wch/ch32v307/ch32_usbhs_reg.h
new file mode 100644
index 000000000..5a2c1fbc9
--- /dev/null
+++ b/src/portable/wch/ch32v307/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 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
+
+/* 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/dcd_usbhs.c b/src/portable/wch/ch32v307/dcd_usbhs.c
new file mode 100644
index 000000000..b7a79e166
--- /dev/null
+++ b/src/portable/wch/ch32v307/dcd_usbhs.c
@@ -0,0 +1,391 @@
+/*
+ * 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_CH32V307)
+#include "device/dcd.h"
+
+#include "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 */
+TU_ATTR_ALIGNED(4) uint8_t EP0_DatabufHD[64]; // ep0(64)
+
+volatile uint8_t USBHS_Dev_Endp0_Tog = 0x01;
+
+void dcd_init(uint8_t rhport) {
+ (void)rhport;
+
+ memset(&xfer_status, 0, sizeof(xfer_status));
+
+ USBHSD->HOST_CTRL = 0x00;
+ USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM;
+
+ USBHSD->CONTROL = 0;
+
+#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
+ 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_remote_wakeup(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+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
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 69972c630..67377b7ec 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -160,6 +160,9 @@ typedef int make_iso_compilers_happy;
// Allwinner
#define OPT_MCU_F1C100S 2100 ///< Allwinner F1C100s family
+// WCH
+#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
#define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m)