Browse Source

ch569w-evt: add usbhs device mode driver (#6330)

ch569w-evt: add usbhs device mode driver

* usbd driver tested with cdc_vcom, internal loopback
  (can't run both MSH & usbd due to 16KB RAM limitation)
* reduce usrstack & main thread stack size for usbd test
* ch56x_uart.c : iron out UART0_PIN_ALT assignment
emuzit 2 years ago
parent
commit
a38b39ac25

+ 3 - 0
bsp/wch/risc-v/Libraries/ch56x_drivers/SConscript

@@ -12,6 +12,9 @@ if GetDepend('SOC_SERIES_CH569'):
     if GetDepend('RT_USING_WDT'):
         src += ['ch56x_wdt.c']
 
+if GetDepend('RT_USING_USB_DEVICE'):
+    src += ['ch56x_usbd.c']
+
 if GetDepend('RT_USING_PWM'):
     src += ['ch56x_pwm.c']
 

+ 8 - 12
bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_uart.c

@@ -45,8 +45,13 @@ static struct serial_device serial_device_0 =
 {
     .reg_base = (struct uart_registers *)UART0_REG_BASE,
     .irqn = UART0_IRQn,
+#ifndef BSP_USING_UART0_PIN_ALT
     .rxd_pin = UART_RXD0_PIN,
     .txd_pin = UART_TXD0_PIN,
+#else
+    .rxd_pin = UART_RXD0_ALT,
+    .txd_pin = UART_TXD0_ALT,
+#endif
     .name = "uart0",
 };
 #endif
@@ -250,22 +255,13 @@ int rt_hw_uart_init(void)
 
     while (--n >= 0)
     {
-        uint32_t flag, txd_pin, rxd_pin;
+        uint32_t flag;
         struct serial_device *serial = devices[n];
         serial->parent.ops = &uart_ops;
         serial->parent.config = config;
 
-        txd_pin = serial->txd_pin;
-        rxd_pin = serial->rxd_pin;
-#ifdef BSP_USING_UART0_PIN_ALT
-        if (serial->irqn == UART0_IRQn)
-        {
-            txd_pin = UART_TXD0_ALT;
-            rxd_pin = UART_RXD0_ALT;
-        }
-#endif
-        rt_pin_mode(txd_pin, PIN_MODE_OUTPUT);
-        rt_pin_mode(rxd_pin, PIN_MODE_INPUT_PULLUP);
+        rt_pin_mode(serial->txd_pin, PIN_MODE_OUTPUT);
+        rt_pin_mode(serial->rxd_pin, PIN_MODE_INPUT_PULLUP);
 
         sys_clk_off_by_irqn(serial->irqn, SYS_SLP_CLK_ON);
 

+ 574 - 0
bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_usbd.c

@@ -0,0 +1,574 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2022-08-22     Emuzit            first version
+ */
+#include <rthw.h>
+#include <rtdebug.h>
+#include <drivers/usb_common.h>
+#include <drivers/usb_device.h>
+#include "ch56x_usbhs.h"
+#include "ch56x_sys.h"
+#include "isr_sp.h"
+
+/*--------------------------------------------------------*/
+/* Warning : Not fully tested, use at your own discretion */
+/*--------------------------------------------------------*/
+
+#ifdef SOC_SERIES_CH569
+#define _attr_uepdma        __attribute__((section(".dmadata"), aligned(16)))
+#define _ep0_setup_dmabuf   _dmadata_start
+#else
+#define _attr_uepdma        __attribute__((aligned(4)))
+#define _ep0_setup_dmabuf   _dmadata_start
+#define usbhs_irq_handler   usb1_irq_handler
+#define USBHS_IRQn          USB1_IRQn
+#define USBHS_REG_BASE      USB1_REG_BASE
+#define RAMX_BASE_ADDRESS   RAMS_BASE_ADDRESS
+#define UEP0_RT_DMA         UEP_DMA[0]
+#endif
+
+#define UEP_MPS_64          64
+#define UEP_MPS_512         512
+
+#define _get_ep_idx(address)    ((address) & USB_EPNO_MASK)
+#define _get_ep_dir(address)    ((address) & USB_DIR_MASK)
+
+#define uep_dir_is_in(address)  (_get_ep_dir(address) == USB_DIR_IN)
+#define uep_dir_is_out(address) (_get_ep_dir(address) == USB_DIR_OUT)
+
+extern uint32_t _dmadata_start[];
+
+static uint32_t ep0_dmabuf[UEP_MPS_64 / 4] _attr_uepdma;
+static uint32_t epx_dmabuf[UEP_ADDRESS_MAX][UEP_MPS_512 / 4] _attr_uepdma;
+
+static struct ep_id usbhs_ep_pool[] =
+{
+    {0x0,  USB_EP_ATTR_CONTROL,   USB_DIR_INOUT, 64,  ID_ASSIGNED},
+    {0x1,  USB_EP_ATTR_BULK,      USB_DIR_IN,    512, ID_UNASSIGNED},
+    {0x1,  USB_EP_ATTR_BULK,      USB_DIR_OUT,   512, ID_UNASSIGNED},
+    {0x2,  USB_EP_ATTR_INT,       USB_DIR_IN,    512, ID_UNASSIGNED},
+    {0x2,  USB_EP_ATTR_INT,       USB_DIR_OUT,   512, ID_UNASSIGNED},
+    {0x3,  USB_EP_ATTR_BULK,      USB_DIR_IN,    512, ID_UNASSIGNED},
+    {0x3,  USB_EP_ATTR_BULK,      USB_DIR_OUT,   512, ID_UNASSIGNED},
+#ifdef SOC_SERIES_CH569
+    /* FIXME: not sure how to deal with EP4, no UEP4_DMA register */
+    {0x4,  USB_EP_ATTR_INT,       USB_DIR_IN,    512, ID_UNASSIGNED},
+    {0x4,  USB_EP_ATTR_INT,       USB_DIR_OUT,   512, ID_UNASSIGNED},
+    {0x5,  USB_EP_ATTR_BULK,      USB_DIR_IN,    512, ID_UNASSIGNED},
+    {0x5,  USB_EP_ATTR_BULK,      USB_DIR_OUT,   512, ID_UNASSIGNED},
+    {0x6,  USB_EP_ATTR_INT,       USB_DIR_IN,    512, ID_UNASSIGNED},
+    {0x6,  USB_EP_ATTR_INT,       USB_DIR_OUT,   512, ID_UNASSIGNED},
+    {0x7,  USB_EP_ATTR_BULK,      USB_DIR_IN,    512, ID_UNASSIGNED},
+    {0x7,  USB_EP_ATTR_BULK,      USB_DIR_OUT,   512, ID_UNASSIGNED},
+#endif
+    {0xff, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK,  0,   ID_ASSIGNED},
+};
+
+static struct udcd udc_device;
+
+static uint8_t setup_set_address;
+
+static rt_err_t udc_set_address(uint8_t address)
+{
+    /* DEV_AD should be updated after status stage IN token of SET_ADDRESS
+     * such that that IN token could still reach our device.
+    */
+    setup_set_address = address | 0x80;
+    return RT_EOK;
+}
+
+static rt_err_t udc_set_config(uint8_t address)
+{
+    return RT_EOK;
+}
+
+static rt_err_t udc_ep_set_stall(uint8_t address)
+{
+    volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
+
+    uint8_t ep_idx = _get_ep_idx(address);
+
+    if (uep_dir_is_in(address))
+        usbhs->UEP_CTRL[ep_idx].TX_CTRL.res_mask = UEP_RES_STALL;
+    else
+        usbhs->UEP_CTRL[ep_idx].RX_CTRL.res_mask = UEP_RES_STALL;
+
+    return RT_EOK;
+}
+
+static rt_err_t udc_ep_clear_stall(uint8_t address)
+{
+    volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
+
+    uint8_t ep_idx = _get_ep_idx(address);
+
+    if (uep_dir_is_in(address))
+        usbhs->UEP_CTRL[ep_idx].TX_CTRL.res_mask = UEP_RES_NAK;
+    else
+        usbhs->UEP_CTRL[ep_idx].RX_CTRL.res_mask = UEP_RES_NAK;
+
+    return RT_EOK;
+}
+
+static rt_err_t udc_ep_enable(struct uendpoint *ep)
+{
+    volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
+
+    uint8_t ep_idx, address, mod;
+
+    RT_ASSERT(ep != RT_NULL);
+    RT_ASSERT(ep->ep_desc != RT_NULL);
+
+    address = EP_ADDRESS(ep);
+    ep_idx = _get_ep_idx(address);
+
+    if (ep_idx > 0 && ep_idx <= UEP_ADDRESS_MAX)
+    {
+        mod = uep_dir_is_in(address) ? RB_UEP_TX_EN : RB_UEP_RX_EN;
+        mod = _uep_mod_get(usbhs, ep_idx) | mod;
+        _uep_mod_set(usbhs, ep_idx, mod);
+    }
+
+    return RT_EOK;
+}
+
+static rt_err_t udc_ep_disable(struct uendpoint *ep)
+{
+    volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
+
+    uint8_t ep_idx, address, mod;
+
+    RT_ASSERT(ep != RT_NULL);
+    RT_ASSERT(ep->ep_desc != RT_NULL);
+
+    address = EP_ADDRESS(ep);
+    ep_idx = _get_ep_idx(address);
+
+    if (ep_idx > 0 && ep_idx <= UEP_ADDRESS_MAX)
+    {
+        mod = uep_dir_is_in(address) ? RB_UEP_TX_EN : RB_UEP_RX_EN;
+        mod = _uep_mod_get(usbhs, ep_idx) & ~mod;
+        _uep_mod_set(usbhs, ep_idx, mod);
+    }
+
+    return RT_EOK;
+}
+
+static rt_size_t udc_ep_read_prepare(uint8_t address, void *buffer, rt_size_t size)
+{
+    volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
+
+    uint8_t ep_idx = _get_ep_idx(address);
+
+    uint32_t dmabuf = (uint32_t)buffer;
+
+    if (uep_dir_is_in(address))
+        return 0;
+
+    if (size > (ep_idx ? UEP_MPS_512 : UEP_MPS_64))
+        size = (ep_idx ? UEP_MPS_512 : UEP_MPS_64);
+
+    /* need extra `buffer` copy if H/W requirement not met
+     *   CH565/CH569 : DMA buffer resides in RAMX, 16-byte aligned
+     *   CH567/CH568 : 4-byte aligned
+     */
+#ifdef SOC_SERIES_CH569
+    if (size > 0 && (dmabuf < RAMX_BASE_ADDRESS || (dmabuf & 0xf)))
+    {
+        dmabuf = (uint32_t)(ep_idx ? epx_dmabuf[ep_idx] : ep0_dmabuf);
+    }
+    /* Note : usbhs->UEP_RX_DMA[0] maps to usbhs->UEP0_RT_DMA actually */
+    usbhs->UEP_RX_DMA[ep_idx] = dmabuf & UEP_RT_DMA_MASK;
+#else
+    if (size > 0 && (dmabuf & 3))
+    {
+        dmabuf = (uint32_t)(ep_idx ? epx_dmabuf[ep_idx] : ep0_dmabuf);
+    }
+    usbhs->UEP_DMA[ep_idx] = dmabuf & UEP_RT_DMA_MASK;
+#endif
+
+    if (ep_idx == 0 && size == 0)
+    {
+        /* SETUP status stage, expect DATA1 */
+        usbhs->UEP_CTRL[0].RX_CTRL.reg = RB_UEP_RES_ACK | RB_UEP_TOG_DATA1;
+    }
+    else
+    {
+        /* keep TOG_MASK & AUTOTOG */
+        usbhs->UEP_CTRL[ep_idx].RX_CTRL.res_mask = UEP_RES_ACK;
+    }
+
+    return size;
+}
+
+static rt_size_t udc_ep_read(uint8_t address, void *buffer)
+{
+    volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
+
+    uint8_t ep_idx = _get_ep_idx(address);
+
+    uint32_t dmabuf;
+    rt_size_t size;
+
+    if (uep_dir_is_in(address))
+        return 0;
+
+#ifdef SOC_SERIES_CH569
+    /* Note : usbhs->UEP_RX_DMA[0] maps to usbhs->UEP0_RT_DMA actually */
+    dmabuf = usbhs->UEP_RX_DMA[ep_idx] & UEP_RT_DMA_MASK;
+#else
+    dmabuf = usbhs->UEP_DMA[ep_idx] & UEP_RT_DMA_MASK;
+#endif
+    size = usbhs->RX_LEN;
+
+    /* copy if proxy buffer */
+    if (size > 0 && ((uint32_t)buffer & UEP_RT_DMA_MASK) != dmabuf)
+    {
+        dmabuf |= RAMX_BASE_ADDRESS;
+        rt_memcpy(buffer, (void *)dmabuf, size);
+    }
+
+    return size;
+}
+
+static rt_size_t udc_ep_write(uint8_t address, void *buffer, rt_size_t size)
+{
+    volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
+
+    uint8_t ep_idx = _get_ep_idx(address);
+
+    uint32_t dmabuf = (uint32_t)buffer;
+
+    union _uh_rt_ctrl ctrl;
+
+    if (uep_dir_is_out(address))
+        return 0;
+
+    if (size > (ep_idx ? UEP_MPS_512 : UEP_MPS_64))
+        size = (ep_idx ? UEP_MPS_512 : UEP_MPS_64);
+
+    /* need extra `buffer` copy if H/W requirement not met
+     *   CH565/CH569 : DMA buffer resides in RAMX, 16-byte aligned
+     *   CH567/CH568 : 4-byte aligned
+     */
+#ifdef SOC_SERIES_CH569
+    if (size > 0 && (dmabuf < RAMX_BASE_ADDRESS || (dmabuf & 0xf)))
+    {
+        dmabuf = (uint32_t)(ep_idx ? epx_dmabuf[ep_idx] : ep0_dmabuf);
+        rt_memcpy((void *)dmabuf, buffer, size);
+    }
+    if (ep_idx == 0)
+        usbhs->UEP0_RT_DMA = dmabuf & UEP_RT_DMA_MASK;
+    else
+        usbhs->UEP_TX_DMA[ep_idx] = dmabuf & UEP_RT_DMA_MASK;
+#else
+    if (size > 0 && (dmabuf & 3))
+    {
+        dmabuf = (uint32_t)(ep_idx ? epx_dmabuf[ep_idx] : ep0_dmabuf);
+        rt_memcpy((void *)dmabuf, buffer, size);
+    }
+    usbhs->UEP_DMA[ep_idx] = dmabuf & UEP_RT_DMA_MASK;
+#endif
+    usbhs->UEP_CTRL[ep_idx].t_len = size;
+
+    /* keep TOG_MASK & AUTOTOG */
+    usbhs->UEP_CTRL[ep_idx].TX_CTRL.res_mask = UEP_RES_ACK;
+
+    return size;
+}
+
+static rt_err_t udc_ep0_send_status(void)
+{
+    volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
+
+    /* SETUP status stage : zero data length, always DATA1 */
+    usbhs->UEP_CTRL[0].t_len = 0;
+    /* This is the only case UEP0_RT_DMA is set to 0. */
+    usbhs->UEP0_RT_DMA = 0;
+    usbhs->UEP_CTRL[0].TX_CTRL.reg = RB_UEP_RES_ACK | RB_UEP_TOG_DATA1;
+    return RT_EOK;
+}
+
+static rt_err_t udc_suspend(void)
+{
+    return RT_EOK;
+}
+
+static rt_err_t udc_wakeup(void)
+{
+    return RT_EOK;
+}
+
+static const struct udcd_ops udcd_ops =
+{
+    .set_address = udc_set_address,
+    .set_config = udc_set_config,
+    .ep_set_stall = udc_ep_set_stall,
+    .ep_clear_stall = udc_ep_clear_stall,
+    .ep_enable = udc_ep_enable,
+    .ep_disable = udc_ep_disable,
+    .ep_read_prepare = udc_ep_read_prepare,
+    .ep_read = udc_ep_read,
+    .ep_write = udc_ep_write,
+    .ep0_send_status = udc_ep0_send_status,
+    .suspend = udc_suspend,
+    .wakeup = udc_wakeup,
+};
+
+static void _hsbhs_device_mode_init(volatile struct usbhs_registers *usbhs)
+{
+    uint8_t ep_idx;
+
+    /* disable all endpoints, use single buffer mode (BUF_MOD : 0) */
+    usbhs->UHOST_CTRL.reg = 0;
+    usbhs->SUSPEND.reg = 0;
+    usbhs->R32_UEP_MOD = 0;
+    usbhs->DEV_AD = 0;
+
+    usbhs->CTRL.reg = RB_USB_RESET_SIE | RB_USB_CLR_ALL;
+    usbhs->CTRL.reg = RB_USB_DEVICE_MODE |
+                      RB_SPTP_HIGH_SPEED |
+                      RB_DEV_PU_EN |
+                      RB_USB_INT_BUSY |
+                      RB_USB_DMA_EN;
+
+    usbhs->INT_EN.reg = RB_USB_IE_BUSRST |
+                        RB_USB_IE_TRANS |
+                        RB_USB_IE_FIFOOV |
+                        RB_USB_IE_SETUPACT;
+
+    usbhs->UEP_MAX_LEN[0].reg = UEP_MPS_64;
+    /*
+     * It seems EP0 SETUP uses the first 8 bytes of RAMX as dmabuf and
+     * handles DATA0 transfer & ACK on its own. Here we still needs to
+     * RES_NAK TX/RX to block SETUP data stage till dma data is ready.
+     */
+    usbhs->UEP_CTRL[0].TX_CTRL.reg = RB_UEP_RES_NAK | RB_UEP_TOG_DATA1;
+    usbhs->UEP_CTRL[0].RX_CTRL.reg = RB_UEP_RES_NAK | RB_UEP_TOG_DATA1;
+
+    for (ep_idx = 1; ep_idx <= UEP_ADDRESS_MAX; ep_idx++)
+    {
+        usbhs->UEP_MAX_LEN[ep_idx].reg = UEP_MPS_512;
+        /* set to DATA0, remains to be initialized (SET_CONFIGURATION...) */
+        usbhs->UEP_CTRL[ep_idx].TX_CTRL.reg = RB_UEP_RES_NAK | RB_UEP_AUTOTOG;
+        usbhs->UEP_CTRL[ep_idx].RX_CTRL.reg = RB_UEP_RES_NAK | RB_UEP_AUTOTOG;
+    }
+}
+
+static rt_err_t udc_device_init(struct rt_device *device)
+{
+    volatile struct usbhs_registers *usbhs = device->user_data;
+
+    sys_clk_off_by_irqn(USBHS_IRQn, SYS_SLP_CLK_ON);
+
+    _hsbhs_device_mode_init(usbhs);
+
+    rt_hw_interrupt_umask(USBHS_IRQn);
+
+    return RT_EOK;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+static struct rt_device_ops device_ops;
+#endif
+
+static int rt_hw_usbd_init(void)
+{
+    int ret;
+
+    udc_device.parent.type = RT_Device_Class_USBDevice;
+#ifdef RT_USING_DEVICE_OPS
+    device_ops.init = udc_device_init;
+    udc_device.parent.ops = &device_ops;
+#else
+    udc_device.parent.init = udc_device_init;
+#endif
+    udc_device.parent.user_data = (void *)USBHS_REG_BASE;
+    udc_device.ops = &udcd_ops;
+    udc_device.ep_pool = usbhs_ep_pool;
+    udc_device.ep0.id = &usbhs_ep_pool[0];
+    udc_device.device_is_hs = RT_TRUE;
+
+    ret = rt_device_register(&udc_device.parent, "usbd", 0);
+    if (ret == RT_EOK)
+        ret = rt_usb_device_init();
+
+    return ret;
+}
+INIT_DEVICE_EXPORT(rt_hw_usbd_init);
+
+rt_inline uint8_t _uep_tog_datax(uint8_t tog)
+{
+    /* Note: treat tog as RB_UEP_TOG_DATA0 if not RB_UEP_TOG_DATA1 */
+    return (tog == RB_UEP_TOG_DATA1) ? RB_UEP_TOG_DATA0 : RB_UEP_TOG_DATA1;
+}
+
+static void _isr_ep_stall(volatile struct usbhs_registers *usbhs)
+{
+    uint8_t ep_idx = usbhs->INT_ST.dev_endp_mask;
+
+    usbhs->UEP_CTRL[ep_idx].TX_CTRL.res_mask == UEP_RES_STALL;
+    usbhs->UEP_CTRL[ep_idx].RX_CTRL.res_mask == UEP_RES_STALL;
+}
+
+static void _isr_handle_setup(volatile struct usbhs_registers *usbhs)
+{
+    struct urequest setup, *packet;
+
+    uint8_t ep_idx, xctrl, recipient;
+
+    /* RES_NAK to block data stage, will expect or response DATA1 */
+    usbhs->UEP_CTRL[0].TX_CTRL.reg = RB_UEP_RES_NAK | RB_UEP_TOG_DATA1;
+    usbhs->UEP_CTRL[0].RX_CTRL.reg = RB_UEP_RES_NAK | RB_UEP_TOG_DATA1;
+
+    packet = (struct urequest *)_ep0_setup_dmabuf;
+
+    setup.request_type = packet->request_type;
+    setup.bRequest = packet->bRequest;
+    setup.wValue = packet->wValue;
+    setup.wIndex = packet->wIndex;
+    setup.wLength = packet->wLength;
+
+    /* Init data toggle bit. Not sure if it has been done by h/w.*/
+    xctrl = RB_UEP_RES_NAK | RB_UEP_AUTOTOG | RB_UEP_TOG_DATA0;
+    recipient = setup.request_type & USB_REQ_TYPE_RECIPIENT_MASK;
+    if (recipient == USB_REQ_TYPE_DEVICE &&
+        setup.bRequest == USB_REQ_SET_CONFIGURATION)
+    {
+        for (ep_idx = 1; ep_idx <= UEP_ADDRESS_MAX; ep_idx++)
+        {
+            usbhs->UEP_CTRL[ep_idx].TX_CTRL.reg = xctrl;
+            usbhs->UEP_CTRL[ep_idx].RX_CTRL.reg = xctrl;
+        }
+    }
+    else if (recipient == USB_REQ_TYPE_ENDPOINT &&
+             setup.bRequest == USB_REQ_CLEAR_FEATURE &&
+             setup.wValue == USB_EP_HALT)
+    {
+        ep_idx = setup.wIndex;
+        if (ep_idx > 0 && ep_idx <= UEP_ADDRESS_MAX)
+        {
+            usbhs->UEP_CTRL[ep_idx].TX_CTRL.reg = xctrl;
+            usbhs->UEP_CTRL[ep_idx].RX_CTRL.reg = xctrl;
+        }
+    }
+
+    rt_usbd_ep0_setup_handler(&udc_device, &setup);
+}
+
+static void _isr_handle_transfer(volatile struct usbhs_registers *usbhs)
+{
+    rt_size_t size;
+
+    uint8_t ep_idx, token, tog;
+
+    ep_idx = usbhs->INT_ST.dev_endp_mask;
+    token = usbhs->INT_ST.dev_token_mask;
+
+    if (ep_idx == 0)
+    {
+        if (token == DEV_TOKEN_IN)
+        {
+            /* UEP0 does not support AUTOTOG, generate DATAx manually */
+            tog = usbhs->UEP_CTRL[0].TX_CTRL.reg & RB_UEP_TOG_MASK;
+            tog = _uep_tog_datax(tog);
+            /* wait for udc_ep_write or udc_ep0_send_status to RES_ACK */
+            usbhs->UEP_CTRL[0].TX_CTRL.reg = RB_UEP_RES_NAK | tog;
+
+            if (setup_set_address != 0 && usbhs->UEP_CTRL[0].t_len == 0)
+            {
+                usbhs->DEV_AD = setup_set_address & 0x7f;
+                setup_set_address = 0;
+            }
+            /* don't call in_handler if send_status */
+            if (usbhs->UEP0_RT_DMA != 0)
+            {
+                rt_usbd_ep0_in_handler(&udc_device);
+            }
+        }
+        else if (token == DEV_TOKEN_OUT)
+        {
+            if (usbhs->INT_ST.st_togok)
+            {
+                /* UEP0 does not support AUTOTOG, generate DATAx manually */
+                tog = usbhs->UEP_CTRL[0].RX_CTRL.reg & RB_UEP_TOG_MASK;
+                tog = _uep_tog_datax(tog);
+                /* wait for udc_ep_read_prepare to RES_ACK */
+                usbhs->UEP_CTRL[0].RX_CTRL.reg = RB_UEP_RES_NAK | tog;
+                rt_usbd_ep0_out_handler(&udc_device, usbhs->RX_LEN);
+            }
+            else
+            {
+                /* Corrupted ACK Handshake => ignore data, keep sequence bit */
+                usbhs->UEP_CTRL[0].RX_CTRL.res_mask = UEP_RES_NAK;
+            }
+        }
+    }
+    else if (token == DEV_TOKEN_IN)
+    {
+        /* wait for udc_ep_write to RES_ACK */
+        usbhs->UEP_CTRL[ep_idx].TX_CTRL.res_mask = UEP_RES_NAK;
+        size = usbhs->UEP_CTRL[ep_idx].t_len;
+        rt_usbd_ep_in_handler(&udc_device, ep_idx | USB_DIR_IN, size);
+    }
+    else if (token == DEV_TOKEN_OUT)
+    {
+        /* wait for udc_ep_read_prepare to RES_ACK */
+        usbhs->UEP_CTRL[ep_idx].RX_CTRL.res_mask = UEP_RES_NAK;
+        /* ignore data if Corrupted ACK Handshake */
+        if (usbhs->INT_ST.st_togok)
+        {
+            /* size:0 to trigger dcd_ep_read() in _data_notify() */
+            rt_usbd_ep_out_handler(&udc_device, ep_idx | USB_DIR_OUT, 0);
+        }
+    }
+}
+
+/*
+ * CAVEAT: The usbd design of ch56x relies on instant isr to RES_NAK
+ * UEP_CTRL[n].TX_CTRL/RX_CTRL. A long tarried isr may leave RES_ACK
+ * in UEP_CTRL[n] and starts unintended DMA upon arrival of IN/OUT.
+ */
+void usbhs_irq_handler(void) __attribute__((interrupt()));
+void usbhs_irq_handler(void)
+{
+    volatile struct usbhs_registers *usbhs;
+    union _usb_int_fg intflag;
+
+    isr_sp_enter();
+    rt_interrupt_enter();
+
+    usbhs = (struct usbhs_registers *)USBHS_REG_BASE;
+    intflag.reg = usbhs->INT_FG.reg;
+
+    if (intflag.fifoov)
+    {
+        /* FIXME: fifo overflow */
+        _isr_ep_stall(usbhs);
+    }
+    else
+    {
+        if (intflag.transfer)
+            _isr_handle_transfer(usbhs);
+
+        if (intflag.setupact)
+            _isr_handle_setup(usbhs);
+    }
+
+    if (intflag.busrst)
+    {
+        _hsbhs_device_mode_init(usbhs);
+        rt_usbd_reset_handler(&udc_device);
+    }
+
+    /* clear all pending intflag (suspend, isoact & nak ignored) */
+    usbhs->INT_FG.reg = intflag.reg;
+
+    rt_interrupt_leave();
+    isr_sp_leave();
+}

+ 679 - 0
bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_usbhs.h

@@ -0,0 +1,679 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2022-08-22     Emuzit            first version
+ */
+#ifndef __CH56X_USBHS_H__
+#define __CH56X_USBHS_H__
+
+#include "soc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef SOC_SERIES_CH569
+#define UEP_ADDRESS_MAX     7
+#define UEP_RT_DMA_MASK     0x1fff0
+#else
+#define UEP_ADDRESS_MAX     4
+#define UEP_RT_DMA_MASK     0x0fffc
+#endif
+
+union _usb_ctrl
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t dma_en      : 1;  // RW, USB DMA and DMA interrupt enable bit
+        uint8_t clr_all     : 1;  // RW, Empty USB interrupt flag and FIFO
+        uint8_t reset_sie   : 1;  // RW, Forcibly reset the USB SIE
+        uint8_t int_busy    : 1;  // RW, Auto pause enable bit @ RB_USB_IF_TRANSFER
+        uint8_t pu_en       : 1;  // RW, device & pull-up-R enable, DEVICE mode
+        uint8_t sptp_mask   : 2;  // RW, USB bus signal transfer rate selection bit
+        uint8_t mode        : 1;  // RW, USB working mode selection bit
+    };
+};
+#define RB_USB_DMA_EN       0x01
+#define RB_USB_CLR_ALL      0x02
+#define RB_USB_RESET_SIE    0x04
+#define RB_USB_INT_BUSY     0x08
+#define RB_DEV_PU_EN        0x10
+#define RB_USB_SPTP_MASK    0x60
+#define RB_USB_MODE         0x80
+
+#define USBHS_FULL_SPEED    0
+#define USBHS_HIGH_SPEED    1
+#define USBHS_LOW_SPEED     2
+
+#define USBHS_DEVICE_MODE   0
+#define USBHS_HOST_MODE     1
+
+#define RB_SPTP_FULL_SPEED  (USBHS_FULL_SPEED  << 5)
+#define RB_SPTP_HIGH_SPEED  (USBHS_HIGH_SPEED  << 5)
+#define RB_SPTP_LOW_SPEED   (USBHS_LOW_SPEED   << 5)
+
+#define RB_USB_DEVICE_MODE  (USBHS_DEVICE_MODE << 7)
+#define RB_USB_HOST_MODE    (USBHS_HOST_MODE   << 7)
+
+union _usb_int_en
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t busrst      : 1;  // RW, USB bus reset event IE, DEVICE mode
+        uint8_t trans       : 1;  // RW, USB transfer complete interrupt enable
+        uint8_t suspend     : 1;  // RW, USB bus suspend/wake-up event IE
+        uint8_t sof         : 1;  // RW, SOF packet/timing interrupt enable
+        uint8_t fifoov      : 1;  // RW, Internal FIFO overflow interrupt enable
+#ifdef SOC_SERIES_CH569
+        uint8_t setupact    : 1;  // RW, SETUP transaction complete interrupt
+        uint8_t isoact      : 1;  // RW, ISOchronous token received IE
+        uint8_t dev_nak     : 1;  // RW, NAK interrupt enable, DEVICE mode
+#else
+        uint8_t resv_5      : 1;
+        uint8_t dev_nak     : 1;  // RW, NAK interrupt enable, DEVICE mode
+        uint8_t dev_sof     : 1;  // RW, SOF packet received IE, DEVICE mode
+#endif
+    };
+    struct
+    {
+        uint8_t detect      : 1;  // RW, USB device connect/disconnect IE, HOST mode
+        uint8_t stuff_1     : 7;
+    };
+};
+#define RB_USB_IE_BUSRST    0x01
+#define RB_USB_IE_DETECT    0x01
+#define RB_USB_IE_TRANS     0x02
+#define RB_USB_IE_SUSPEND   0x04
+#define RB_USB_IE_SOF       0x08
+#define RB_USB_IE_FIFOOV    0x10
+
+#ifdef SOC_SERIES_CH569
+#define RB_USB_IE_SETUPACT  0x20
+#define RB_USB_IE_ISOACT    0x40
+#define RB_USB_IE_DEV_NAK   0x80
+#else
+#define RB_USB_IE_DEV_NAK   0x40
+#define RB_USB_IE_DEV_SOF   0x80
+#endif
+
+union _usb_suspend
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t resv_0      : 1;
+        uint8_t dev_wakeup  : 1;  // RW, Remote wake-up control bit
+        uint8_t resv_2      : 6;
+    };
+};
+#define RB_DEV_WAKEUP      0x02
+
+union _usb_spd_type
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t speed_mask  : 2;  // RO, Actual transfer speed
+        uint8_t resv_2      : 6;
+    };
+};
+#define RB_USBSPEED_MASK    0x03  // same USBHS_FULL_SPEED...
+
+union _usb_mis_st
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t split_en    : 1;  // RO, SPLIT packet transmission enabled, HOST mode
+        uint8_t attach      : 1;  // RO, USB device connection status bit, HOST mode
+        uint8_t bus_suspend : 1;  // RO, USB suspend status bit
+        uint8_t bus_reset   : 1;  // RO, USB bus reset status bit
+        uint8_t fifo_rdy    : 1;  // RO, USB receive FIFO data ready status bit
+        uint8_t sie_free    : 1;  // RO, Free status bit of USB protocol processor
+        uint8_t sof_act     : 1;  // RO, SOF packet transfer status bit, HOST mode
+        uint8_t sof_pres    : 1;  // RO, SOF packet presage status bit, HOST mode
+    };
+};
+#define RB_HOST_SPLIT_EN    0x01
+#define RB_USB_ATTACH       0x02
+#define RB_USBBUS_SUSPEND   0x04
+#define RB_USBBUS_RESET     0x08
+#define RB_USB_FIFO_RDY     0x10
+#define RB_USB_SIE_FREE     0x20
+#define RB_USB_SOF_ACT      0x40
+#define RB_USB_SOF_PRES     0x80
+
+union _usb_int_fg
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t busrst      : 1;  // RW1, USB bus reset event IF, DEVICE mode
+        uint8_t transfer    : 1;  // RW1, USB transmission complete interrupt flag
+        uint8_t suspend     : 1;  // RW1, USB bus suspend/wake-up event IF
+        uint8_t hst_sof     : 1;  // RW1, SOF timing interrupt flag bit, HOST mode
+        uint8_t fifoov      : 1;  // RW1, USB FIFO overflow interrupt flag
+        uint8_t setupact    : 1;  // RW1, SETUP transaction complete IF (CH569)
+        uint8_t isoact      : 1;  // RW1, ISOchronous token received IF (CH569)
+        uint8_t resv_7      : 1;
+    };
+    struct
+    {
+        uint8_t detect      : 1;  // RW1, USB device connect/disconnect IF, HOST mode
+        uint8_t stuff_1     : 7;
+    };
+};
+#define RB_USB_IF_BUSRST    0x01
+#define RB_USB_IF_DETECT    0x01
+#define RB_USB_IF_TRANSFER  0x02
+#define RB_USB_IF_SUSPEND   0x04
+#define RB_USB_IF_HST_SOF   0x08
+#define RB_USB_IF_FIFOOV    0x10
+#define RB_USB_IF_SETUPACT  0x20
+#define RB_USB_IF_ISOACT    0x40
+
+union _usb_int_st
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t host_res_mask   : 4;  // RO, Current response PID, HOST mode
+        uint8_t dev_token_mask  : 2;  // RO, Current token PID, DEVICE mode
+        uint8_t st_togok        : 1;  // RO, Current transmit DATA0/1 sync state
+        uint8_t st_nak          : 1;  // RO, NAK response status bit, DEVICE mode
+    };
+    struct
+    {
+        uint8_t dev_endp_mask   : 4;  // RO, Current endpoint number, DEVICE mode
+        uint8_t stuff_4         : 4;
+    };
+};
+#define RB_HOST_RES_MASK    0x0f
+#define RB_DEV_ENDP_MASK    0x0f
+#define RB_DEV_TOKEN_MASK   0x30
+#define RB_USB_ST_TOGOK     0x40
+#define RB_USB_ST_NAK       0x80
+
+#define DEV_TOKEN_OUT       0
+#define DEV_TOKEN_SOF       1
+#define DEV_TOKEN_IN        2
+#define DEV_TOKEN_SETUP     3  // CH567/CH568
+
+#define RB_DEV_TOKEN_OUT    (DEV_TOKEN_OUT << 4)
+#define RB_DEV_TOKEN_SOF    (DEV_TOKEN_SOF << 4)
+#define RB_DEV_TOKEN_IN     (DEV_TOKEN_IN  << 4)
+
+/*
+ * RB_UEPn_  RB_UEPn_  RB_UEPn_     R32_UEPn_DMA as starting address, low to high
+ *  RX_EN     TX_EN    BUF_MOD
+ *    0         0         x         Endpoint is disabled, UEPn_DMA not used
+ *    1         0         0         1st address of RX (OUT) buffer is R32_UEPn_RX_DMA
+ *    1         0         1         RB_UEP_R_TOG_MASK=0, use R32_UEPn_RX_DMA
+ *                                  RB_UEP_R_TOG_MASK=1, use R32_UEPn_TX_DMA
+ *    0         1         0         1st address of TX (IN) buffer is R32_UEPn_TX_DMA
+ *    0         1         1         RB_UEP_T_TOG_MASK=0, use R32_UEPn_TX_DMA
+ *                                  RB_UEP_T_TOG_MASK=1, use R32_UEPn_RX_DMA
+ */
+#define RB_UEP_BUF_MOD      0x01
+#define RB_UEP_TX_EN        0x04
+#define RB_UEP_RX_EN        0x08
+
+/* UEP_MOD offset 0 */
+#define RB_UEP4_BUF_MOD     0x01
+#define RB_UEP4_TX_EN       0x04
+#define RB_UEP4_RX_EN       0x08
+#define RB_UEP1_BUF_MOD     0x10
+#define RB_UEP1_TX_EN       0x40
+#define RB_UEP1_RX_EN       0x80
+
+/* UEP_MOD offset 1 */
+#define RB_UEP2_BUF_MOD     0x01
+#define RB_UEP2_TX_EN       0x04
+#define RB_UEP2_RX_EN       0x08
+#define RB_UEP3_BUF_MOD     0x10
+#define RB_UEP3_TX_EN       0x40
+#define RB_UEP3_RX_EN       0x80
+
+/* UEP_MOD offset 2 */
+#define RB_UEP5_BUF_MOD     0x01
+#define RB_UEP5_TX_EN       0x04
+#define RB_UEP5_RX_EN       0x08
+#define RB_UEP6_BUF_MOD     0x10
+#define RB_UEP6_TX_EN       0x40
+#define RB_UEP6_RX_EN       0x80
+
+/* UEP_MOD offset 3 */
+#define RB_UEP7_BUF_MOD     0x01
+#define RB_UEP7_TX_EN       0x04
+#define RB_UEP7_RX_EN       0x08
+
+/* each nibble is an ep index map : {hi_lo_nibble(1), reg_offset(3)} */
+#define UEP_MOD_MAP         0x3a209180
+#define uep_mod_offset(ep)  (((UEP_MOD_MAP >> (ep * 4)) & 3))
+#define uep_mod_shift(ep)   (((UEP_MOD_MAP >> (ep * 4)) & 8) ? 4 : 0)
+
+union _uep_rt_ctrl
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t res_mask    : 2;  // RW, response control bits
+        uint8_t res_no      : 1;  // RW, not expecting response
+        uint8_t tog_mask    : 2;  // RW, transmit/expect DATAx
+        uint8_t autotog     : 1;  // RW, auto DATAx toggle (not for EP0)
+        uint8_t resv_6      : 2;
+    };
+};
+#define RB_UEP_RES_MASK     0x03
+#define RB_UEP_RES_NO       0x04
+#define RB_UEP_TOG_MASK     0x18
+#define RB_UEP_AUTOTOG      0x20
+
+#define UEP_RES_ACK         0
+#define UEP_RES_NYET        1
+#define UEP_RES_NAK         2
+#define UEP_RES_STALL       3
+
+#define UEP_TOG_DATA0       0
+#define UEP_TOG_DATA1       1
+#define UEP_TOG_DATA2       2
+#define UEP_TOG_MDATA       3
+
+#define RB_UEP_RES_ACK      (UEP_RES_ACK   << 0)
+#define RB_UEP_RES_NYET     (UEP_RES_NYET  << 0)
+#define RB_UEP_RES_NAK      (UEP_RES_NAK   << 0)
+#define RB_UEP_RES_STALL    (UEP_RES_STALL << 0)
+
+#define RB_UEP_TOG_DATA0    (UEP_TOG_DATA0 << 3)
+#define RB_UEP_TOG_DATA1    (UEP_TOG_DATA1 << 3)
+#define RB_UEP_TOG_DATA2    (UEP_TOG_DATA2 << 3)
+#define RB_UEP_TOG_MDATA    (UEP_TOG_MDATA << 3)
+
+union _uh_rt_ctrl
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t res_mask    : 2;  // RW, response control bits
+        uint8_t res_no      : 1;  // RW, not expecting response
+        uint8_t tog_mask    : 2;  // RW, expected DATAx
+        uint8_t autotog     : 1;  // RW, auto DATAx toggle
+        uint8_t data_no     : 1;  // RW, not expecting data
+        uint8_t resv_7      : 1;
+    };
+};
+#define RB_UH_RES_MASK      0x03
+#define RB_UH_RES_NO        0x04
+#define RB_UH_TOG_MASK      0x18
+#define RB_UH_AUTOTOG       0x20
+#define RB_UH_DATA_NO       0x40
+
+#define UH_RES_ACK          0
+#define UH_RES_NYET         1
+#define UH_RES_NAK          2
+#define UH_RES_STALL        3
+
+#define UH_TOG_DATA0        0
+#define UH_TOG_DATA1        1
+#define UH_TOG_DATA2        2
+#define UH_TOG_MDATA        3
+
+#define RB_UH_RES_ACK       (UH_RES_ACK   << 0)
+#define RB_UH_RES_NYET      (UH_RES_NYET  << 0)
+#define RB_UH_RES_NAK       (UH_RES_NAK   << 0)
+#define RB_UH_RES_STALL     (UH_RES_STALL << 0)
+
+#define RB_UH_TOG_DATA0     (UH_TOG_DATA0 << 3)
+#define RB_UH_TOG_DATA1     (UH_TOG_DATA1 << 3)
+#define RB_UH_TOG_DATA2     (UH_TOG_DATA2 << 3)
+#define RB_UH_TOG_MDATA     (UH_TOG_MDATA << 3)
+
+union _uhost_ctrl
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t bus_reset   : 1;  // RW, USB host transmit bus reset signal
+        uint8_t bus_suspend : 1;  // RW, USB host transmit suspend signal
+        uint8_t bus_resume  : 1;  // RW, wake up device when bus suspended
+        uint8_t resv_3      : 4;
+        uint8_t autosof_en  : 1;  // RW, Auto generate SOF packet enable (CH569)
+    };
+};
+#define RB_UH_BUS_RESET     0x01
+#define RB_UH_BUS_SUSPEND   0x02
+#define RB_UH_BUS_RESUME    0x04
+#define RB_UH_AUTOSOF_EN    0x80
+
+union _uh_ep_mod
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t rbuf_mod    : 1;  // RW, CH567/CH568 only
+        uint8_t resv_1      : 2;
+        uint8_t rx_en       : 1;  // RW, enable HOST receiver (IN)
+        uint8_t tbuf_mod    : 1;  // RW, CH567/CH568 only
+        uint8_t resv_5      : 1;
+        uint8_t tx_en       : 1;  // RW, enable HOST transmitter (SETUP/OUT)
+        uint8_t resv_7      : 1;
+    };
+};
+#define RB_UH_RBUF_MOD      0x01
+#define RB_UH_RX_EN         0x08
+#define RB_UH_TBUF_MOD      0x10
+#define RB_UH_TX_EN         0x40
+
+union _uh_ep_pid
+{
+    uint16_t reg;
+    struct
+    {
+        uint8_t epnum_mask  : 4;  // RW, Set endpoint number of the target device
+        uint8_t token_mask  : 4;  // RW, Set the token PID packet identification
+        uint8_t resv;
+    };
+};
+#define RB_UH_EPNUM_MASK    0x0f
+#define RB_UH_TOKEN_MASK    0xf0
+
+#ifndef SOC_SERIES_CH569
+union _uh_setup
+{
+    uint8_t reg;
+    struct
+    {
+        uint8_t resv_0      : 6;
+        uint8_t sof_en      : 1;  // WO, Auto generate SOF packet enable
+        uint8_t resv_7      : 1;
+    };
+};
+#define RB_UH_SOF_EN        0x40
+#endif
+
+/*
+ * USBHS Global Registers :
+ *
+ * 0x00  R8_USB_CTRL:       USB control register
+ * 0x02  R8_USB_INT_EN:     USB interrupt enable register
+ * 0x03  R8_USB_DEV_AD:     USB addresss register
+ * 0x04  R16_USB_FRAME_NO:  USBHS frame number register
+ * 0x06  R8_USB_SUSPEND:    USB suspend control register
+ * 0x08  R8_USB_SPD_TYPE:   USB current speed type register
+ * 0x09  R8_USB_MIS_ST:     USB miscellaneous status register
+ * 0x0a  R8_USB_INT_FG:     USB interrupt flag register
+ * 0x0b  R8_USB_INT_ST:     USB interrpt status register
+ * 0x0c  R16_USB_RX_LEN:    USB reception length register
+ */
+
+/*
+ * CH565/CH569 USBHS DEVICE Related Registers :
+ *
+ * 0x10  R8_UEP4_1_MOD:     Endpoint 1(9) / 4(8/12) mode control register
+ * 0x11  R8_UEP2_3_MOD:     Endpoint 2(10) / 3(11) mode control register
+ * 0x12  R8_UEP5_6_MOD:     Endpoint 5(13) / 6(14) mode control register
+ * 0x13  R8_UEP7_MOD:       Endpoint 7(15) mode control register
+ * 0x14  R32_UEP0_RT_DMA:   Start address of endpoint0 buffer
+ * 0x18  R32_UEP1_RX_DMA:   Start address of endpoint 1(9) receive buffer
+ * 0x1c  R32_UEP2_RX_DMA:   Start address of endpoint 2(10) receive buffer
+ * 0x20  R32_UEP3_RX_DMA:   Start address of endpoint 3(11) receive buffer
+ * 0x24  R32_UEP4_RX_DMA:   Start address of endpoint 4(8/12) receive buffer
+ * 0x28  R32_UEP5_RX_DMA:   Start address of endpoint 5(13) receive buffer
+ * 0x2c  R32_UEP6_RX_DMA:   Start address of endpoint 6(14) receive buffer
+ * 0x30  R32_UEP7_RX_DMA:   Start address of endpoint 7(15) receive buffer
+ * 0x34  R32_UEP1_TX_DMA:   Start address of endpoint 1(9) transmit buffer
+ * 0x38  R32_UEP2_TX_DMA:   Start address of endpoint 2(10) transmit buffer
+ * 0x3c  R32_UEP3_TX_DMA:   Start address of endpoint 3(11) transmit buffer
+ * 0x40  R32_UEP4_TX_DMA:   Start address of endpoint 4(8/12) transmit buffer
+ * 0x44  R32_UEP5_TX_DMA:   Start address of endpoint 5(13) transmit buffer
+ * 0x48  R32_UEP6_TX_DMA:   Start address of endpoint 6(14) transmit buffer
+ * 0x4c  R32_UEP7_TX_DMA:   Start address of endpoint 7(15) transmit buffer
+ * 0x50  R16_UEP0_MAX_LEN:  Endpoint 0 receive maximum length packet register
+ * 0x54  R16_UEP1_MAX_LEN:  Endpoint 1(9) receive maximum length packet register
+ * 0x58  R16_UEP2_MAX_LEN:  Endpoint 2(10) receive maximum length packet register
+ * 0x5c  R16_UEP3_MAX_LEN:  Endpoint 3(11) receive maximum length packet register
+ * 0x60  R16_UEP4_MAX_LEN:  Endpoint 4(8/12) receive maximum length packet register
+ * 0x64  R16_UEP5_MAX_LEN:  Endpoint 5(13) receive maximum length packet register
+ * 0x68  R16_UEP6_MAX_LEN:  Endpoint 6(14) receive maximum length packet register
+ * 0x6c  R16_UEP7_MAX_LEN:  Endpoint 7(15) receive maximum length packet register
+ * 0x70  R16_UEP0_T_LEN:    Endpoint 0 transmission length register
+ * 0x72  R8_UEP0_TX_CTRL:   Endpoint 0 transmit control register
+ * 0x73  R8_UEP0_RX_CTRL:   Endpoint 0 receive control register
+ * 0x74  R16_UEP1_T_LEN:    Endpoint 1(9) transmission length register
+ * 0x76  R8_UEP1_TX_CTRL:   Endpoint 1(9) transmit control register
+ * 0x77  R8_UEP1_RX_CTRL:   Endpoint 1(9) receive control register
+ * 0x78  R16_UEP2_T_LEN:    Endpoint 2(10) transmission length register
+ * 0x7a  R8_UEP2_TX_CTRL:   Endpoint 2(10) transmit control register
+ * 0x7b  R8_UEP2_RX_CTRL:   Endpoint 2(10) receive control register
+ * 0x7c  R16_UEP3_T_LEN:    Endpoint 3(11) transmission length register
+ * 0x7e  R8_UEP3_TX_CTRL:   Endpoint 3(11) transmit control register
+ * 0x7f  R8_UEP3_RX_CTRL:   Endpoint 3(11) receive control register
+ * 0x80  R16_UEP4_T_LEN:    Endpoint 4(8/12) transmission length register
+ * 0x82  R8_UEP4_TX_CTRL:   Endpoint 4(8/12) transmit control register
+ * 0x83  R8_UEP4_RX_CTRL:   Endpoint 4(8/12) receive control register
+ * 0x84  R16_UEP5_T_LEN:    Endpoint 5(13) transmission length register
+ * 0x86  R8_UEP5_TX_CTRL:   Endpoint 5(13) transmit control register
+ * 0x87  R8_UEP5_RX_CTRL:   Endpoint 5(13) receive control register
+ * 0x88  R16_UEP6_T_LEN:    Endpoint 6(14) transmission length register
+ * 0x8a  R8_UEP6_TX_CTRL:   Endpoint 6(14) transmit control register
+ * 0x8b  R8_UEP6_RX_CTRL:   Endpoint 6(14) receive control register
+ * 0x8c  R16_UEP7_T_LEN:    Endpoint 7(15) transmission length register
+ * 0x8e  R8_UEP7_TX_CTRL:   Endpoint 7(15) transmit control register
+ * 0x8f  R8_UEP7_RX_CTRL:   Endpoint 7(15) receive control register
+ *
+ * CH567/CH568 USBHS DEVICE Related Registers :
+ *
+ * 0x10  UEP4_1_MOD:        Endpoint 1/4 mode control register
+ * 0x11  UEP2_3_MOD:        Endpoint 2/3 mode control register
+ * 0x14  UEP0_DMA:          Endpoint 0 DMA buffer start address
+ * 0x18  UEP1_DMA:          Endpoint 1 DMA buffer start address
+ * 0x1c  UEP2_DMA:          Endpoint 2 DMA buffer start address
+ * 0x20  UEP3_DMA:          Endpoint 3 DMA buffer start address
+ * 0x24  UEP0_MAX_LEN:      Endpoint 0 receive maximum length packet register
+ * 0x28  UEP1_MAX_LEN:      Endpoint 1 receive maximum length packet register
+ * 0x2c  UEP2_MAX_LEN:      Endpoint 2 receive maximum length packet register
+ * 0x30  UEP3_MAX_LEN:      Endpoint 3 receive maximum length packet register
+ * 0x34  UEP4_MAX_LEN:      Endpoint 4 receive maximum length packet register
+ * 0x38  UEP0_T_LEN:        Endpoint 0 transmission length register
+ * 0x3a  UEP0_TX_CTRL:      Endpoint 0 transmit control register
+ * 0x3b  UEP0_RX_CTRL:      Endpoint 0 receive control register
+ * 0x3c  UEP1_T_LEN:        Endpoint 1 transmission length register
+ * 0x3e  UEP1_TX_CTRL:      Endpoint 1 transmit control register
+ * 0x3f  UEP1_RX_CTRL:      Endpoint 1 receive control register
+ * 0x40  UEP2_T_LEN:        Endpoint 2 transmission length register
+ * 0x42  UEP2_TX_CTRL:      Endpoint 2 transmit control register
+ * 0x43  UEP2_RX_CTRL:      Endpoint 2 receive control register
+ * 0x44  UEP2_T_LEN:        Endpoint 3 transmission length register
+ * 0x46  UEP2_TX_CTRL:      Endpoint 3 transmit control register
+ * 0x47  UEP2_RX_CTRL:      Endpoint 3 receive control register
+ * 0x48  UEP4_T_LEN:        Endpoint 4 transmission length register
+ * 0x4a  UEP4_TX_CTRL:      Endpoint 4 transmit control register
+ * 0x4b  UEP4_RX_CTRL:      Endpoint 4 receive control register
+ */
+
+/*
+ * CH565/CH569 USBHS HOST Related Registers :
+ *
+ * 0x01  R8_UHOST_CTRL:     USB host control register
+ * 0x11  R8_UH_EP_MOD:      USB host endpoint mode register
+ * 0x1c  R32_UH_RX_DMA:     USB host receive buffer start address
+ * 0x3c  R32_UH_TX_DMA:     USB host transmit buffer start address
+ * 0x58  R16_UH_MAX_LEN:    USB host reception maximum length packet register
+ * 0x78  R16_UH_EP_PID:     USB host token setting register
+ * 0x7b  R8_UH_RX_CTRL:     USB host reception endpoint control register
+ * 0x7c  R16_UH_TX_LEN:     USB host transmission length register
+ * 0x7e  R8_UH_TX_CTRL:     USB host transmission endpoint control register
+ * 0x80  R16_UH_SPLIT_DATA: USB host transmit SPLIT packet data
+ *
+ * CH567/CH568 USBHS HOST Related Registers :
+ *
+ * 0x01  UHOST_CTRL:        USB host control register
+ * 0x11  UH_EP_MOD:         USB host endpoint mode register
+ * 0x1c  UH_RX_DMA:         USB host receive buffer start address
+ * 0x20  UH_TX_DMA:         USB host transmit buffer start address
+ * 0x2c  UH_RX_MAX_LEN:     USB host reception maximum length packet register
+ * 0x3e  UH_SETUP:          USB host aux config register
+ * 0x40  UH_EP_PID:         USB host token setting register
+ * 0x43  UH_RX_CTRL:        USB host reception endpoint control register
+ * 0x44  UH_TX_LEN:         USB host transmission length register
+ * 0x46  UH_TX_CTRL:        USB host transmission endpoint control register
+ * 0x48  UH_SPLIT_DATA:     USB host transmit SPLIT packet data
+ */
+struct usbhs_registers
+{
+    union
+    {
+        /* USB Global Registers */
+        struct
+        {
+            union _usb_ctrl         CTRL;
+            uint8_t                 stuff_01;
+            union _usb_int_en       INT_EN;
+            uint8_t                 DEV_AD;
+            uint16_t                FRAME_NO;
+            union _usb_suspend      SUSPEND;
+            uint8_t                 resv_07;
+            union _usb_spd_type     SPD_TYPE;
+            union _usb_mis_st       MIS_ST;
+            union _usb_int_fg       INT_FG;
+            union _usb_int_st       INT_ST;
+            uint16_t                RX_LEN;
+        };
+
+        /* USB DEVICE Related Registers */
+        struct
+        {
+            uint32_t                stuff_gr[4];
+            union
+            {
+                uint8_t             UEP_MOD[4];
+                uint32_t            R32_UEP_MOD;
+            };
+#ifdef SOC_SERIES_CH569
+            union
+            {
+                struct
+                {
+                    uint32_t        UEP0_RT_DMA;
+                    uint32_t        stuff_rt[14];
+                };
+                struct
+                {
+                    uint32_t        UEP_RX_DMA[8];  // UEP_RX_DMA[0] NOT exist
+                    uint32_t        stuff_rx[7];
+                };
+                struct
+                {
+                    uint32_t        stuff_tx[7];
+                    uint32_t        UEP_TX_DMA[8];  // UEP_TX_DMA[0] NOT exist
+                };
+            };
+#else
+            struct
+            {
+                uint16_t            reg;
+                uint16_t            resv;
+            }                       UEP_DMA[4];
+#endif
+            struct
+            {
+                uint16_t            reg;
+                uint16_t            resv;
+            }                       UEP_MAX_LEN[UEP_ADDRESS_MAX + 1];
+            struct
+            {
+                uint16_t            t_len;    // MSB 5 bits are fixed to 0
+                union _uep_rt_ctrl  TX_CTRL;
+                union _uep_rt_ctrl  RX_CTRL;
+            }                       UEP_CTRL[UEP_ADDRESS_MAX + 1];
+        };
+
+        /* USB HOST Related Registers */
+#ifdef SOC_SERIES_CH569
+        struct
+        {
+            uint8_t                 stuff_00;
+            union _uhost_ctrl       UHOST_CTRL;
+            uint8_t                 stuff_02[15];
+            union _uh_ep_mod        UH_EP_MOD;
+            uint8_t                 stuff_12[10];
+            uint32_t                UH_RX_DMA;
+            uint32_t                stuff_20[7];
+            uint32_t                UH_TX_DMA;
+            uint32_t                stuff_40[6];
+            uint16_t                UH_MAX_LEN;
+            uint16_t                stuff_5a[15];
+            union _uh_ep_pid        UH_EP_PID;
+            uint8_t                 stuff_7a;
+            union _uh_rt_ctrl       UH_RX_CTRL;
+            uint16_t                UH_TX_LEN;
+            union _uh_rt_ctrl       UH_TX_CTRL;
+            uint8_t                 stuff_7f;
+            uint16_t                UH_SPLIT_DATA;
+            uint16_t                stuff_82[7];
+        };
+#else
+        struct
+        {
+            uint8_t                 stuff_00;
+            union _uhost_ctrl       UHOST_CTRL;
+            uint8_t                 stuff_02[15];
+            union _uh_ep_mod        UH_EP_MOD;
+            uint8_t                 stuff_12[10];
+            uint32_t                UH_RX_DMA;
+            uint32_t                UH_TX_DMA;
+            uint32_t                stuff_24[2];
+            uint16_t                UH_MAX_LEN;
+            uint16_t                stuff_2e[8];
+            uint8_t                 UH_SETUP;
+            uint8_t                 stuff_3f;
+            union _uh_ep_pid        UH_EP_PID;
+            uint8_t                 stuff_42;
+            union _uh_rt_ctrl       UH_RX_CTRL;
+            uint16_t                UH_TX_LEN;
+            union _uh_rt_ctrl       UH_TX_CTRL;
+            uint8_t                 stuff_47;
+            uint16_t                UH_SPLIT_DATA;
+            uint16_t                stuff_4a;
+        };
+#endif
+    };
+} __packed;
+
+#ifdef SOC_SERIES_CH569
+CHECK_STRUCT_SIZE(struct usbhs_registers, 0x90);
+#else
+CHECK_STRUCT_SIZE(struct usbhs_registers, 0x4c);
+#endif
+
+rt_inline void _uep_mod_set(volatile struct usbhs_registers *usbhs,
+                            int ep_idx, uint8_t mod)
+{
+    int reg_n = uep_mod_offset(ep_idx);
+    int shift = uep_mod_shift(ep_idx);
+    int mask = 0x0f << shift;
+
+    /* ep_idx must be 1 ~ UEP_ADDRESS_MAX */
+    usbhs->UEP_MOD[reg_n] = (usbhs->UEP_MOD[reg_n] & ~mask) | (mod << shift);
+}
+
+rt_inline uint8_t _uep_mod_get(volatile struct usbhs_registers *usbhs, int ep_idx)
+{
+    int reg_n = uep_mod_offset(ep_idx);
+    int shift = uep_mod_shift(ep_idx);
+
+    /* ep_idx should be 1 ~ UEP_ADDRESS_MAX */
+    return (usbhs->UEP_MOD[reg_n] >> shift) & 0x0f;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 5 - 1
bsp/wch/risc-v/Libraries/ch56x_drivers/soc.h

@@ -21,6 +21,10 @@
 #define SOC_SERIES_CH569
 #endif
 
+#ifndef __packed
+#define __packed    __attribute__((packed))
+#endif
+
 #define CHECK_STRUCT_SIZE(s, size) \
         static_assert(sizeof(s) == size, #s " has wrong size")
 
@@ -29,10 +33,10 @@
 
 #define FLASH_BASE_ADDRESS  0x00000000
 #define RAMS_BASE_ADDRESS   0x20000000
-#define RAMX_BASE_ADDRESS   0x20020000
 #define BUS8_BASE_ADDRESS   0x80000000
 
 #ifdef SOC_SERIES_CH569
+#define RAMX_BASE_ADDRESS   0x20020000
 #define RAMS_SIZE           16
 #else
 #define RAMS_SIZE           32

+ 3 - 3
bsp/wch/risc-v/ch569w-evt/.config

@@ -38,9 +38,9 @@ CONFIG_RT_KSERVICE_USING_STDLIB=y
 #
 CONFIG_RT_USING_SEMAPHORE=y
 CONFIG_RT_USING_MUTEX=y
-# CONFIG_RT_USING_EVENT is not set
+CONFIG_RT_USING_EVENT=y
 CONFIG_RT_USING_MAILBOX=y
-# CONFIG_RT_USING_MESSAGEQUEUE is not set
+CONFIG_RT_USING_MESSAGEQUEUE=y
 # CONFIG_RT_USING_SIGNALS is not set
 
 #
@@ -78,7 +78,7 @@ CONFIG_ARCH_RISCV=y
 #
 CONFIG_RT_USING_COMPONENTS_INIT=y
 CONFIG_RT_USING_USER_MAIN=y
-CONFIG_RT_MAIN_THREAD_STACK_SIZE=2048
+CONFIG_RT_MAIN_THREAD_STACK_SIZE=1024
 CONFIG_RT_MAIN_THREAD_PRIORITY=10
 # CONFIG_RT_USING_LEGACY is not set
 CONFIG_RT_USING_MSH=y

+ 4 - 2
bsp/wch/risc-v/ch569w-evt/applications/SConscript

@@ -2,9 +2,11 @@ from building import *
 
 cwd = GetCurrentDir()
 
+app = ARGUMENTS.get('app', "main")
+
 src = Split("""
-main.c
-""")
+{}.c
+""".format(app))
 
 path = [cwd, str(Dir('#'))]
 

+ 47 - 0
bsp/wch/risc-v/ch569w-evt/applications/test.c

@@ -361,6 +361,52 @@ static void test_pwm(void)
     #define test_pwm()  do {} while(0)
 #endif
 
+#ifdef RT_USING_USB_DEVICE
+#if !defined(RT_USING_EVENT) || !defined(RT_USING_MESSAGEQUEUE)
+    #error "event flag or message queue IPC not enabled"
+#endif
+static struct rt_thread  *udvcom_thread;
+static rt_device_t vcom;
+
+static void usbd_vcom_thread(void *param)
+{
+    char ch;
+
+    while (1)
+    {
+        while (rt_device_read(vcom, 0, &ch, 1) != 1)
+            rt_thread_delay(1);
+        rt_kprintf("(%2d) %02x:%c\n", rt_device_write(vcom, 0, &ch, 1), ch, ch);
+        rt_pin_write(LED1_PIN, (ch & 1) ? PIN_LOW : PIN_HIGH);
+    }
+}
+
+static void test_usbd()
+{
+    char name[] = "vcom";
+
+    vcom = rt_device_find(name);
+    if (vcom && rt_device_open(vcom, RT_DEVICE_FLAG_INT_RX) == RT_EOK)
+    {
+        rt_kprintf("%s opened\n", name);
+
+        rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
+        rt_pin_write(LED1_PIN, PIN_LOW);
+
+        udvcom_thread = rt_thread_create("udvcom", usbd_vcom_thread, vcom,
+                                         512, 20, 50);
+        if (udvcom_thread != RT_NULL)
+            rt_thread_startup(udvcom_thread);
+        else
+            rt_kprintf("usvcom thread create failed !\n");
+
+        rt_device_write(vcom, 0, name, rt_strlen(name));
+    }
+}
+#else
+    #define test_usbd()  do {} while(0)
+#endif
+
 void main(void)
 {
     uint32_t wdog_timeout = 32;
@@ -372,6 +418,7 @@ void main(void)
     test_hwtimer();
     test_spi_master();
     test_pwm();
+    test_usbd();
 
     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
     rt_pin_write(LED0_PIN, led0 = PIN_LOW);

+ 166 - 164
bsp/wch/risc-v/ch569w-evt/board/linker_scripts/link.lds

@@ -1,187 +1,189 @@
 ENTRY( _start )
 
-__stack_size = 2048;
+__stack_size = 1536;
 
 PROVIDE( _stack_size = __stack_size );
 
 MEMORY
 {
-	FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 96K
-	RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K
-	RAMX (xrw) : ORIGIN = 0x20020000, LENGTH = 32K
+    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 96K
+    RAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 16K
+    RAMX (xrw) : ORIGIN = 0x20020000, LENGTH = 32K
 }
 
 SECTIONS
 {
 
-	.init :
-	{
-		_sinit = .;
-		. = ALIGN(4);
-		KEEP(*(SORT_NONE(.init)))
-		. = ALIGN(4);
-		_einit = .;
-	} >FLASH AT>FLASH
+    .init :
+    {
+        _sinit = .;
+        . = ALIGN(4);
+        KEEP(*(SORT_NONE(.init)))
+        . = ALIGN(4);
+        _einit = .;
+    } >FLASH AT>FLASH
 
     .vector :
     {
         *(.vector);
-  	    . = ALIGN(64);
+        . = ALIGN(64);
+    } >FLASH AT>FLASH
+
+    .text :
+    {
+        . = ALIGN(4);
+        *(.text)
+        *(.text.*)
+        *(.rodata)
+        *(.rodata*)
+        *(.glue_7)
+        *(.glue_7t)
+        *(.gnu.linkonce.t.*)
+
+        /* section information for finsh shell */
+        . = ALIGN(4);
+        __fsymtab_start = .;
+        KEEP(*(FSymTab))
+        __fsymtab_end = .;
+        . = ALIGN(4);
+        __vsymtab_start = .;
+        KEEP(*(VSymTab))
+        __vsymtab_end = .;
+        . = ALIGN(4);
+
+        /* section information for initial. */
+        . = ALIGN(4);
+        __rt_init_start = .;
+        KEEP(*(SORT(.rti_fn*)))
+        __rt_init_end = .;
+        . = ALIGN(4);
+
+        /* section information for modules */
+        . = ALIGN(4);
+        __rtmsymtab_start = .;
+        KEEP(*(RTMSymTab))
+        __rtmsymtab_end = .;
+        . = ALIGN(4);
+
+    } >FLASH AT>FLASH
+
+    .fini :
+    {
+        KEEP(*(SORT_NONE(.fini)))
+        . = ALIGN(4);
     } >FLASH AT>FLASH
 
-	.text :
-	{
-		. = ALIGN(4);
-		*(.text)
-		*(.text.*)
-		*(.rodata)
-		*(.rodata*)
-		*(.glue_7)
-		*(.glue_7t)
-		*(.gnu.linkonce.t.*)
-
-		/* section information for finsh shell */
-    	. = ALIGN(4);
-    	__fsymtab_start = .;
-    	KEEP(*(FSymTab))
-    	__fsymtab_end = .;
-    	. = ALIGN(4);
-    	__vsymtab_start = .;
-    	KEEP(*(VSymTab))
-    	__vsymtab_end = .;
-    	. = ALIGN(4);
-
-    	/* section information for initial. */
-    	. = ALIGN(4);
-    	__rt_init_start = .;
-    	KEEP(*(SORT(.rti_fn*)))
-    	__rt_init_end = .;
-    	. = ALIGN(4);
-
-    	/* section information for modules */
-    	. = ALIGN(4);
-    	__rtmsymtab_start = .;
-    	KEEP(*(RTMSymTab))
-    	__rtmsymtab_end = .;
-		. = 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*)
+    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 = . );
-	
-	.dmadata :
+        *(.bss*)
+        *(.gnu.linkonce.b.*)
+        *(COMMON*)
+        . = ALIGN(4);
+        PROVIDE( _ebss = .);
+    } >RAM AT>FLASH
+
+    PROVIDE( _end = _ebss);
+    PROVIDE( end = . );
+
+    .dmadata :
     {
-        . = ALIGN(16);
         PROVIDE( _dmadata_start = .);
+        /* first 8 bytes are reserved for USB ep0 SETUP */
+        . = . + 8;
+        . = ALIGN(16);
         *(.dmadata*)
         *(.dmadata.*)
         . = ALIGN(16);
@@ -195,5 +197,5 @@ SECTIONS
         PROVIDE(_susrstack = . );
         . = . + __stack_size;
         PROVIDE( _eusrstack = .);
-    } >RAM 
+    } >RAM
 }

+ 3 - 1
bsp/wch/risc-v/ch569w-evt/rtconfig.h

@@ -25,7 +25,9 @@
 
 #define RT_USING_SEMAPHORE
 #define RT_USING_MUTEX
+#define RT_USING_EVENT
 #define RT_USING_MAILBOX
+#define RT_USING_MESSAGEQUEUE
 
 /* Memory Management */
 
@@ -48,7 +50,7 @@
 
 #define RT_USING_COMPONENTS_INIT
 #define RT_USING_USER_MAIN
-#define RT_MAIN_THREAD_STACK_SIZE 2048
+#define RT_MAIN_THREAD_STACK_SIZE 1024
 #define RT_MAIN_THREAD_PRIORITY 10
 #define RT_USING_MSH
 #define RT_USING_FINSH