summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoremuzit <[email protected]>2022-07-30 14:10:51 +0800
committerGitHub <[email protected]>2022-07-30 02:10:51 -0400
commitc802fcdcf821590f193608dda2233aecb722d2d6 (patch)
tree407dfb409fb59507c8c35d580ba9f07946029951
parent226b3e19792f5a8f29fac5da8c8f6ef199d3cdcb (diff)
WCH CH569W-R0-1v0 evt board bsp port, first version (#6167)
WCH CH569W-R0-1v0 evt board bsp port, first version dev/test under Ubuntu 20.04 toolchain from MounRiver_Studio_Community_Linux_x64_V120 tested drivers : SysTick, gpio, gpio interrupt, uart1 (RX interrupt, TX polling) libcpu/risc-v/SConscript : group includes rtconfig.CPU only if folder exists libcpu/risc-v/common/cpuport.c/rt_hw_context_switch_interrupt() : make it RT_WEAK for customization
-rw-r--r--bsp/wch/risc-v/Libraries/Kconfig9
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/SConscript28
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_gpio.c399
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_gpio.h216
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_pfic.c119
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_pfic.h258
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.c249
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.h395
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_timer.c262
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_timer.h138
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_uart.c343
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_uart.h254
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_wdt.c241
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/isr_sp.h31
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/soc.h152
-rw-r--r--bsp/wch/risc-v/Libraries/ch56x_drivers/swi_gcc.S190
-rw-r--r--bsp/wch/risc-v/ch569w-evt/.config664
-rw-r--r--bsp/wch/risc-v/ch569w-evt/Kconfig21
-rw-r--r--bsp/wch/risc-v/ch569w-evt/SConscript13
-rw-r--r--bsp/wch/risc-v/ch569w-evt/SConstruct38
-rw-r--r--bsp/wch/risc-v/ch569w-evt/applications/SConscript13
-rw-r--r--bsp/wch/risc-v/ch569w-evt/applications/main.c231
-rw-r--r--bsp/wch/risc-v/ch569w-evt/board/Kconfig64
-rw-r--r--bsp/wch/risc-v/ch569w-evt/board/SConscript13
-rw-r--r--bsp/wch/risc-v/ch569w-evt/board/board.c80
-rw-r--r--bsp/wch/risc-v/ch569w-evt/board/board.h36
-rw-r--r--bsp/wch/risc-v/ch569w-evt/board/linker_scripts/link.lds199
-rw-r--r--bsp/wch/risc-v/ch569w-evt/board/startup_gcc.S174
-rw-r--r--bsp/wch/risc-v/ch569w-evt/figures/ch569w-evt.jpegbin0 -> 114930 bytes
-rw-r--r--bsp/wch/risc-v/ch569w-evt/rtconfig.h192
-rw-r--r--bsp/wch/risc-v/ch569w-evt/rtconfig.py62
-rw-r--r--libcpu/risc-v/SConscript2
-rw-r--r--libcpu/risc-v/common/cpuport.c2
33 files changed, 5085 insertions, 3 deletions
diff --git a/bsp/wch/risc-v/Libraries/Kconfig b/bsp/wch/risc-v/Libraries/Kconfig
index 6482c47a1d..3428efbab8 100644
--- a/bsp/wch/risc-v/Libraries/Kconfig
+++ b/bsp/wch/risc-v/Libraries/Kconfig
@@ -5,4 +5,11 @@ config SOC_RISCV_SERIES_CH32V103
bool
select ARCH_RISCV
select SOC_RISCV_FAMILY_CH32
- \ No newline at end of file
+
+config SOC_FAMILY_CH56X
+ bool
+ select ARCH_RISCV
+
+config SOC_SERIES_CH569
+ bool
+ select SOC_FAMILY_CH56X
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/SConscript b/bsp/wch/risc-v/Libraries/ch56x_drivers/SConscript
new file mode 100644
index 0000000000..f936f62ceb
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/SConscript
@@ -0,0 +1,28 @@
+from building import *
+
+cwd = GetCurrentDir()
+
+src = Split("""
+ch56x_sys.c
+swi_gcc.S
+""")
+
+if GetDepend('SOC_SERIES_CH569'):
+ src += ['ch56x_pfic.c']
+ if GetDepend('RT_USING_WDT'):
+ src += ['ch56x_wdt.c']
+
+if GetDepend('RT_USING_HWTIMER'):
+ src += ['ch56x_timer.c']
+
+if GetDepend('RT_USING_PIN'):
+ src += ['ch56x_gpio.c']
+
+if GetDepend(['RT_USING_SERIAL', 'BSP_USING_UART']):
+ src += ['ch56x_uart.c']
+
+path = [cwd]
+
+group = DefineGroup('Drivers', src, depend=[''], CPPPATH=path)
+
+Return('group')
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_gpio.c b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_gpio.c
new file mode 100644
index 0000000000..94c2116d98
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_gpio.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#include <rthw.h>
+#include <rtdebug.h>
+#include <drivers/pin.h>
+#include "ch56x_gpio.h"
+#include "isr_sp.h"
+
+struct port_info
+{
+ uint32_t pin_mark;
+ struct gpio_px_regs *regbase;
+};
+
+static const struct port_info pin_ports[GPIO_PORTS] =
+{
+ {GPIO_PA_PIN_MARK, (struct gpio_px_regs *)GPIO_REG_BASE_PA},
+ {GPIO_PB_PIN_MARK, (struct gpio_px_regs *)GPIO_REG_BASE_PB},
+};
+
+static struct rt_pin_irq_hdr pin_irq_hdr_table[8] =
+{
+ {-1, 0, RT_NULL, RT_NULL},
+ {-1, 0, RT_NULL, RT_NULL},
+ {-1, 0, RT_NULL, RT_NULL},
+ {-1, 0, RT_NULL, RT_NULL},
+ {-1, 0, RT_NULL, RT_NULL},
+ {-1, 0, RT_NULL, RT_NULL},
+ {-1, 0, RT_NULL, RT_NULL},
+ {-1, 0, RT_NULL, RT_NULL},
+};
+
+
+#if defined(SOC_SERIES_CH569)
+static int _gpio_pin_to_ibit(rt_base_t pin)
+{
+ /* gpio ext interrupt 7-0 : {PB15,PB12,PB11,PB4,PB3,PA4,PA3,PA2}
+ * not time critical, use linear search
+ */
+ switch (pin)
+ {
+ case GET_PIN(A, 2): return 0;
+ case GET_PIN(A, 3): return 1;
+ case GET_PIN(A, 4): return 2;
+ case GET_PIN(B, 3): return 3;
+ case GET_PIN(B, 4): return 4;
+ case GET_PIN(B, 11): return 5;
+ case GET_PIN(B, 12): return 6;
+ case GET_PIN(B, 15): return 7;
+ }
+ return -1;
+}
+
+#else
+
+static int _gpio_pin_to_ibit(rt_base_t pin)
+{
+ /* gpio ext interrupt 7-0 : {PB10,PB4,PA12,PA11,PA10,PA6,PA4,PA3}
+ * not time critical, use linear search
+ */
+ switch (pin)
+ {
+ case GET_PIN(A, 3): return 0;
+ case GET_PIN(A, 4): return 1;
+ case GET_PIN(A, 6): return 2;
+ case GET_PIN(A, 10): return 3;
+ case GET_PIN(A, 11): return 4;
+ case GET_PIN(A, 12): return 5;
+ case GET_PIN(B, 4): return 6;
+ case GET_PIN(B, 10): return 7;
+ }
+ return -1;
+}
+#endif
+
+static struct gpio_px_regs *_gpio_px_regbase(rt_base_t pin)
+{
+ /* fixed linear mapping : 32 pins per port, for ports A,B,C,D...
+ */
+ uint32_t port = (uint32_t)pin >> 5;
+ uint32_t bitpos = 1 << (pin & 0x1f);
+
+ if (port < GPIO_PORTS && (pin_ports[port].pin_mark & bitpos))
+ return pin_ports[port].regbase;
+ else
+ return RT_NULL;
+}
+
+static void gpio_pin_mode(struct rt_device *device, rt_base_t pin, rt_base_t mode)
+{
+ volatile struct gpio_px_regs *px;
+
+ uint32_t port = (uint32_t)pin >> 5;
+ uint32_t bitpos = 1 << (pin & 0x1f);
+
+ if (port < GPIO_PORTS && (pin_ports[port].pin_mark & bitpos))
+ px = pin_ports[port].regbase;
+ else
+ return;
+
+ switch (mode)
+ {
+ case PIN_MODE_OUTPUT:
+ BITS_CLR(px->PD, bitpos);
+ BITS_SET(px->DIR, bitpos);
+ break;
+ case PIN_MODE_INPUT:
+ BITS_CLR(px->PU, bitpos);
+ BITS_CLR(px->PD, bitpos);
+ BITS_CLR(px->DIR, bitpos);
+ break;
+ case PIN_MODE_INPUT_PULLUP:
+ BITS_SET(px->PU, bitpos);
+ BITS_CLR(px->PD, bitpos);
+ BITS_CLR(px->DIR, bitpos);
+ break;
+ case PIN_MODE_INPUT_PULLDOWN:
+ BITS_CLR(px->PU, bitpos);
+ BITS_SET(px->PD, bitpos);
+ BITS_CLR(px->DIR, bitpos);
+ break;
+ case PIN_MODE_OUTPUT_OD:
+ BITS_SET(px->PD, bitpos);
+ BITS_SET(px->OUT, bitpos);
+ }
+}
+
+static void gpio_pin_write(struct rt_device *device, rt_base_t pin, rt_base_t value)
+{
+ volatile struct gpio_px_regs *px;
+
+ uint32_t port = (uint32_t)pin >> 5;
+ uint32_t bitpos = 1 << (pin & 0x1f);
+
+ if (port < GPIO_PORTS && (pin_ports[port].pin_mark & bitpos))
+ px = pin_ports[port].regbase;
+ else
+ return;
+
+ if (value == 0)
+ BITS_CLR(px->OUT, bitpos);
+ else
+ BITS_SET(px->OUT, bitpos);
+}
+
+static int gpio_pin_read(struct rt_device *device, rt_base_t pin)
+{
+ volatile struct gpio_px_regs *px;
+
+ uint32_t port = (uint32_t)pin >> 5;
+ uint32_t bitpos = 1 << (pin & 0x1f);
+
+ if (port < GPIO_PORTS && (pin_ports[port].pin_mark & bitpos))
+ px = pin_ports[port].regbase;
+ else
+ return PIN_LOW;
+
+ return (px->PIN & bitpos) ? PIN_HIGH : PIN_LOW;
+}
+
+static rt_base_t gpio_pin_get(const char *name)
+{
+ int port, pin, sz, n;
+
+ /* pin name is in the form "PX.nn" (X: A,B,C,D...; nn: 0~31)
+ * fixed linear mapping : 32 pins per port, for ports A,B,C,D...
+ */
+ sz = rt_strlen(name);
+ if ((sz == 4 || sz == 5) && name[0] == 'P' && name[2] == '.')
+ {
+ port = name[1] - 'A';
+ pin = name[3] - '0';
+ if (0 <= port && port < GPIO_PORTS && 0 <= pin && pin <= 9)
+ {
+ if (sz == 5)
+ {
+ n = name[4] - '0';
+ pin = (0 <= n && n <= 9) ? (pin * 10 + n) : 32;
+ }
+ if (pin < 32 && (pin_ports[port].pin_mark & (1 << pin)))
+ {
+ return port * 32 + pin;
+ }
+ }
+ }
+
+ return -1;
+}
+
+static rt_err_t gpio_pin_attach_irq(struct rt_device *device, rt_int32_t pin,
+ rt_uint32_t mode, void (*hdr)(void *args), void *args)
+{
+ rt_base_t level;
+
+ int ibit;
+
+ switch (mode)
+ {
+ case PIN_IRQ_MODE_RISING:
+ case PIN_IRQ_MODE_FALLING:
+ case PIN_IRQ_MODE_HIGH_LEVEL:
+ case PIN_IRQ_MODE_LOW_LEVEL:
+ break;
+ case PIN_IRQ_MODE_RISING_FALLING:
+ /* hardware not supported */
+ default:
+ return -RT_EINVAL;
+ }
+
+ ibit = _gpio_pin_to_ibit(pin);
+ if (ibit < 0)
+ return -RT_EINVAL;
+
+ level = rt_hw_interrupt_disable();
+ if (pin_irq_hdr_table[ibit].pin == pin &&
+ pin_irq_hdr_table[ibit].mode == mode &&
+ pin_irq_hdr_table[ibit].hdr == hdr &&
+ pin_irq_hdr_table[ibit].args == args)
+ {
+ rt_hw_interrupt_enable(level);
+ return RT_EOK;
+ }
+
+ if (pin_irq_hdr_table[ibit].pin >= 0)
+ {
+ rt_hw_interrupt_enable(level);
+ return -RT_EFULL;
+ }
+
+ pin_irq_hdr_table[ibit].pin = pin;
+ pin_irq_hdr_table[ibit].mode = mode;
+ pin_irq_hdr_table[ibit].hdr = hdr;
+ pin_irq_hdr_table[ibit].args = args;
+
+ rt_hw_interrupt_enable(level);
+ return RT_EOK;
+}
+
+static rt_err_t gpio_pin_detach_irq(struct rt_device *device, rt_int32_t pin)
+{
+ rt_base_t level;
+
+ int ibit;
+
+ ibit = _gpio_pin_to_ibit(pin);
+ if (ibit < 0)
+ return -RT_EINVAL;
+
+ level = rt_hw_interrupt_disable();
+ if (pin_irq_hdr_table[ibit].pin < 0)
+ {
+ rt_hw_interrupt_enable(level);
+ return RT_EOK;
+ }
+ pin_irq_hdr_table[ibit].pin = -1;
+ pin_irq_hdr_table[ibit].mode = 0;
+ pin_irq_hdr_table[ibit].hdr = RT_NULL;
+ pin_irq_hdr_table[ibit].args = RT_NULL;
+ rt_hw_interrupt_enable(level);
+ return RT_EOK;
+}
+
+static rt_err_t gpio_pin_irq_enable(struct rt_device *device, rt_base_t pin,
+ rt_uint32_t enabled)
+{
+ volatile struct gpio_registers *gpio;
+
+ rt_base_t level, int_enable;
+
+ int ibit, bitpos;
+
+ ibit = _gpio_pin_to_ibit(pin);
+ if (ibit < 0)
+ return -RT_EINVAL;
+ bitpos = (1 << ibit);
+
+ gpio = (struct gpio_registers *)GPIO_REG_BASE;
+
+ if (enabled == PIN_IRQ_ENABLE)
+ {
+ level = rt_hw_interrupt_disable();
+ if (pin_irq_hdr_table[ibit].pin != pin)
+ {
+ rt_hw_interrupt_enable(level);
+ return -RT_EINVAL;
+ }
+
+ switch (pin_irq_hdr_table[ibit].mode)
+ {
+ case PIN_IRQ_MODE_RISING:
+ BITS_SET(gpio->INT_MODE.reg, bitpos);
+ BITS_SET(gpio->INT_POLAR.reg, bitpos);
+ break;
+ case PIN_IRQ_MODE_FALLING:
+ BITS_SET(gpio->INT_MODE.reg, bitpos);
+ BITS_CLR(gpio->INT_POLAR.reg, bitpos);
+ break;
+ case PIN_IRQ_MODE_HIGH_LEVEL:
+ BITS_CLR(gpio->INT_MODE.reg, bitpos);
+ BITS_SET(gpio->INT_POLAR.reg, bitpos);
+ break;
+ case PIN_IRQ_MODE_LOW_LEVEL:
+ BITS_CLR(gpio->INT_MODE.reg, bitpos);
+ BITS_CLR(gpio->INT_POLAR.reg, bitpos);
+ break;
+ case PIN_IRQ_MODE_RISING_FALLING:
+ default:
+ rt_hw_interrupt_enable(level);
+ return -RT_EINVAL;
+ }
+
+ /* clear possible pending intr, then enable pin intr */
+ int_enable = gpio->INT_ENABLE.reg;
+ gpio->INT_FLAG.reg = bitpos;
+ gpio->INT_ENABLE.reg = int_enable | bitpos;
+ /* enable GPIO_IRQn if this is the first enabled EXTIx */
+ if (int_enable == 0)
+ {
+ rt_hw_interrupt_umask(GPIO_IRQn);
+ }
+ rt_hw_interrupt_enable(level);
+ }
+ else if (enabled == PIN_IRQ_DISABLE)
+ {
+ level = rt_hw_interrupt_disable();
+ int_enable = gpio->INT_ENABLE.reg;
+ BITS_CLR(int_enable, bitpos);
+ gpio->INT_ENABLE.reg = int_enable;
+ /* disable GPIO_IRQn if no EXTIx enabled */
+ if (int_enable == 0)
+ {
+ rt_hw_interrupt_mask(GPIO_IRQn);
+ }
+ rt_hw_interrupt_enable(level);
+ }
+ else
+ {
+ return -RT_EINVAL;
+ }
+
+ return RT_EOK;
+}
+
+static const struct rt_pin_ops pin_ops =
+{
+ .pin_mode = gpio_pin_mode,
+ .pin_write = gpio_pin_write,
+ .pin_read = gpio_pin_read,
+ .pin_attach_irq = gpio_pin_attach_irq,
+ .pin_detach_irq = gpio_pin_detach_irq,
+ .pin_irq_enable = gpio_pin_irq_enable,
+ .pin_get = gpio_pin_get,
+};
+
+static int rt_hw_pin_init(void)
+{
+ return rt_device_pin_register("pin", &pin_ops, RT_NULL);
+}
+INIT_BOARD_EXPORT(rt_hw_pin_init);
+
+void gpio_irq_handler(void) __attribute__((interrupt()));
+void gpio_irq_handler(void)
+{
+ volatile struct gpio_registers *gpio;
+
+ uint8_t iflags;
+
+ int ibit, bitpos;
+
+ isr_sp_enter();
+ rt_interrupt_enter();
+
+ gpio = (struct gpio_registers *)GPIO_REG_BASE;
+ iflags = gpio->INT_FLAG.reg;
+ /* prioritized as pb15 -> pa2 (CH569), or pb10 -> pa3 */
+ for (ibit = 7; ibit >= 0; ibit--)
+ {
+ bitpos = (1 << ibit);
+ if (iflags & bitpos)
+ {
+ if (pin_irq_hdr_table[ibit].hdr)
+ {
+ pin_irq_hdr_table[ibit].hdr(pin_irq_hdr_table[ibit].args);
+ }
+ /* clear interrupt */
+ gpio->INT_FLAG.reg = bitpos;
+ }
+ }
+
+ rt_interrupt_leave();
+ isr_sp_leave();
+}
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_gpio.h b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_gpio.h
new file mode 100644
index 0000000000..2b6af1a5d5
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_gpio.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#ifndef __CH56X_GPIO_H__
+#define __CH56X_GPIO_H__
+
+#include "soc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Fixed linear mapping : 32 pins per port, for ports A,B,C,D...
+*/
+#define GET_PIN(port,pin) (GPIO_P##port##_PIN_START + pin)
+
+#ifdef SOC_SERIES_CH569
+#define GPIO_INT_PINS { \
+ GET_PIN(A,2), GET_PIN(A,3), GET_PIN(A,4), GET_PIN(B,3), \
+ GET_PIN(B,4), GET_PIN(B,11), GET_PIN(B,12), GET_PIN(B,15) \
+ }
+#else
+#define GPIO_INT_PINS { \
+ GET_PIN(A,3), GET_PIN(A,4), GET_PIN(A,6), GET_PIN(A,10), \
+ GET_PIN(A,11), GET_PIN(A,12), GET_PIN(B,4), GET_PIN(B,10), \
+ }
+#endif
+
+/*
+ * R8_GPIO_INT_FLAG / R8_GPIO_INT_STATUS (CH567,CH568):
+ * write 1 to specific bit to clear int flag
+ *
+ * R8_GPIO_INT_ENABLE:
+ * To use EXTIx function, pin should be set as input.
+ * For wakeup function, also set RB_SLP_GPIO_WAKE.
+ *
+ * R8_GPIO_INT_MODE:
+ * R8_GPIO_INT_POLAR:
+ */
+#if defined(SOC_SERIES_CH569)
+union _gpio_interrupt
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t pa2 : 1;
+ uint8_t pa3 : 1;
+ uint8_t pa4 : 1;
+ uint8_t pb3 : 1;
+ uint8_t pb4 : 1;
+ uint8_t pb11 : 1;
+ uint8_t pb12 : 1;
+ uint8_t pb15 : 1;
+ };
+};
+
+#else
+
+union _gpio_interrupt
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t pa3 : 1;
+ uint8_t pa4 : 1;
+ uint8_t pa6 : 1;
+ uint8_t pa10 : 1;
+ uint8_t pa11 : 1;
+ uint8_t pa12 : 1;
+ uint8_t pb4 : 1;
+ uint8_t pb10 : 1;
+ };
+};
+#endif
+
+#define GPIO_IE_DISABLE 0
+#define GPIO_IE_ENABLE 1
+
+#define GPIO_IM_LEVEL 0
+#define GPIO_IM_EDGE 1
+
+#define GPIO_IP_LOW_FALLING 0
+#define GPIO_IP_HIGH_RISING 1
+
+/*
+ * R8_PIN_ALTERNATE (CH569) : reset value is 0x01
+ * R8_PORT_PIN (CH567/CH568) : reset value is 0x00
+ */
+union _gpio_pin_alternate
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t pin_mii : 1; // RW, ETH uses RMII/RGMII (CH565W/CH569W)
+ uint8_t pin_tmr1 : 1; // RW, TMR1/PWM5/CAP1 remapping
+ uint8_t pin_tmr2 : 1; // RW, TMR2/PWM6/CAP2 remapping
+ uint8_t resv_3 : 1;
+ uint8_t pin_uart0 : 1; // RW, RXD0/TXD0 remapping
+ uint8_t pin_uart1 : 1; // RW, CH567 only
+ uint8_t resv_6 : 2;
+ };
+};
+#define RB_PIN_MII 0x01
+#define RB_PIN_TMR1 0x02
+#define RB_PIN_TMR2 0x04
+#define RB_PIN_UART0 0x10
+#define RB_PIN_UART1 0x20
+
+#ifdef SOC_SERIES_CH569
+#define GPIO_ALT_RMII 0
+#define GPIO_ALT_RGMII 1
+#define GPIO_ALT_TMR1_PB15 0
+#define GPIO_ALT_TMR1_PB0 1
+#define GPIO_ALT_TMR2_PA4 0
+#define GPIO_ALT_TMR2_PB3 1
+#define GPIO_ALT_UART0_PB5_6 0
+#define GPIO_ALT_UART0_PA5_6 1
+#else
+#define GPIO_ALT_TMR1_PA10 0
+#define GPIO_ALT_TMR1_PB2 1
+#define GPIO_ALT_TMR2_PA11 0
+#define GPIO_ALT_TMR2_PB11 1
+#define GPIO_ALT_UART0_PB4_7 0
+#define GPIO_ALT_UART0_PA15_14 1
+#define GPIO_ALT_UART1_PA8_9 0
+#define GPIO_ALT_UART1_PB8_9 1
+#endif
+
+struct gpio_px_regs
+{
+ uint32_t DIR; // reset value for pins is 0, input pins
+ uint32_t PIN; // RO
+ uint32_t OUT; // reset value is 0
+ uint32_t CLR; // reset value is 0
+ uint32_t PU; // reset value is 0
+ uint32_t PD; // reset value is 0
+ uint32_t DRV; // reset value for pins is 0, 8mA
+ uint32_t SMT; // reset value for pins is 1, enable schmitt trigger
+} __packed;
+
+CHECK_STRUCT_SIZE(struct gpio_px_regs, 0x20);
+
+#define GPIO_PX_DIR_IN 0
+#define GPIO_PX_DIR_OUT 1
+
+#define GPIO_PX_PU_DISABLE 0
+#define GPIO_PX_PU_ENABLE 1
+#define GPIO_PX_PD_DISABLE 0 // for DIR_IN
+#define GPIO_PX_PD_ENABLE 1 // for DIR_IN
+#define GPIO_PX_PD_PUSH_PULL 0 // for DIR_OUT
+#define GPIO_PX_PD_OPEN_DRAIN 1 // for DIR_OUT
+
+#define GPIO_PX_DRV_8mA 0
+#define GPIO_PX_DRV_16mA 1
+
+#define GPIO_PX_SMT_DISABLE 0
+#define GPIO_PX_SMT_SLOW 1 // for DIR_OUT
+#define GPIO_PX_SMT_ENABLE 1 // for DIR_IN
+
+/*
+ * 0x12 R8_PIN_ALTERNATE: GPIO multi-use remapping register
+ * 0x1c R8_GPIO_INT_FLAG: GPIO interrupt flag register
+ * 0x1d R8_GPIO_INT_ENABLE: GPIO interrupt enable register
+ * 0x1e R8_GPIO_INT_MODE: GPIO interrupt mode register
+ * 0x1f R8_GPIO_INT_POLAR: GPIO interrupt polarity register
+ *
+ * 0x40 R32_PA_DIR: PA pin direction control
+ * 0x44 R32_PA_PIN: PA pin input status
+ * 0x48 R32_PA_OUT: PA pin output register
+ * 0x4c R32_PA_CLR: PA pin output clear
+ * 0x50 R32_PA_PU: PA pin pull-up resistor enable register
+ * 0x54 R32_PA_PD: PA pin open drain output / input pull-down control
+ * 0x58 R32_PA_DRV: PA pin output driving capability register
+ * 0x5c R32_PA_SMT: PA pin slow output / schmitt trigger input control
+ *
+ * 0x60 R32_PB_DIR:
+ * 0x64 R32_PB_PIN:
+ * 0x68 R32_PB_OUT:
+ * 0x6c R32_PB_CLR:
+ * 0x70 R32_PB_PU:
+ * 0x74 R32_PB_PD:
+ * 0x78 R32_PB_DRV:
+ * 0x7c R32_PB_SMT:
+ *
+ * CAVEAT: gcc (as of 8.2.0) tends to read 32-bit word for bit field test.
+ * Be careful for those with side effect for read.
+ */
+struct gpio_registers
+{
+ uint32_t resv_00[4];
+ uint8_t resv_10[2];
+ union _gpio_pin_alternate PIN_ALTERNATE;
+ uint8_t resv_13;
+ uint32_t resv_14[2];
+ union _gpio_interrupt INT_FLAG;
+ union _gpio_interrupt INT_ENABLE;
+ union _gpio_interrupt INT_MODE;
+ union _gpio_interrupt INT_POLAR;
+ uint32_t resv_20[8];
+ struct gpio_px_regs PA;
+ struct gpio_px_regs PB;
+} __packed;
+
+CHECK_STRUCT_SIZE(struct gpio_registers, 0x80);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_pfic.c b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_pfic.c
new file mode 100644
index 0000000000..9f01264006
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_pfic.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#include <rthw.h>
+#include <rtdebug.h>
+#include "ch56x_pfic.h"
+#include "ch56x_sys.h"
+#include "isr_sp.h"
+
+void rt_hw_interrupt_mask(int vector)
+{
+ pfic_interrupt_mask(vector);
+}
+
+void rt_hw_interrupt_umask(int vector)
+{
+ pfic_interrupt_umask(vector);
+}
+
+/**
+ * @brief Trigger software interrupt.
+ */
+void pfic_swi_pendset(void)
+{
+ volatile struct pfic_registers *pfic = (void *)PFIC_REG_BASE;
+ _pfic_ireg_bit_set(pfic, IPSR, SWI_IRQn);
+}
+
+/**
+ * @brief Clear software interrupt.
+ */
+void pfic_swi_pendreset(void)
+{
+ volatile struct pfic_registers *pfic = (void *)PFIC_REG_BASE;
+ _pfic_ireg_bit_set(pfic, IPRR, SWI_IRQn);
+}
+
+/**
+ * @brief Write PFIC interrupt configuration register.
+ *
+ * @param key_bit is (PFIC_CFGR_KEYx + bit_position), one of the following :
+ * PFIC_CFGR_NMISET / PFIC_CFGR_NMIRESET
+ * PFIC_CFGR_EXCSET / PFIC_CFGR_EXCRESET
+ * PFIC_CFGR_PFICRESET
+ * PFIC_CFGR_SYSRESET
+ * All others are treated as NEST/HWSTK (B.1/B.0) write.
+ */
+void pfic_cfgr_set(uint32_t key_bit)
+{
+ volatile struct pfic_registers *pfic = (void *)PFIC_REG_BASE;
+ uint32_t u32v;
+
+ switch (key_bit)
+ {
+ case PFIC_CFGR_NMISET:
+ case PFIC_CFGR_NMIRESET:
+ case PFIC_CFGR_EXCSET:
+ case PFIC_CFGR_EXCRESET:
+ case PFIC_CFGR_PFICRESET:
+ case PFIC_CFGR_SYSRESET:
+ pfic->CFGR = key_bit;
+ default:
+ /* B.1/B.0 hold NEST/HWSTK, key ignored */
+ u32v = key_bit & (CFGR_NESTCTRL_MASK | CFGR_HWSTKCTRL_MASK);
+ pfic->CFGR = cfgr_nest_hwstk(u32v);
+ }
+}
+
+/**
+ * @brief Make SysTick ready, systick/swi irq are enabled.
+ *
+ * @param count is (HCLK/8) clocks count to generate systick irq.
+ * if 0 => calculate with current HCLK and RT_TICK_PER_SECOND
+ */
+void systick_init(uint32_t count)
+{
+ volatile struct systick_registers *systick = (void *)SysTick_REG_BASE;
+ volatile struct pfic_registers *pfic = (void *)PFIC_REG_BASE;
+
+ if (count == 0)
+ count = sys_hclk_get() / 8 / RT_TICK_PER_SECOND;
+
+ _pfic_irqn_disable(pfic, SysTick_IRQn);
+ pfic->IPRIOR[SysTick_IRQn] = 0xe0;
+ pfic->IPRIOR[SWI_IRQn] = 0xf0;
+ systick->CTLR.reg = 0;
+ systick->CNTL = 0;
+ systick->CNTH = 0;
+ systick->CMPLR = count - 1;
+ systick->CMPHR = 0;
+ systick->CNTFG.cntif = 0;
+ /* enable & reload SysTick, with HCLK/8 */
+ systick->CTLR.reg = RB_STKCTL_STRELOAD | RB_STKCTL_STIE | RB_STKCTL_STE;
+ _pfic_irqn_enable(pfic, SysTick_IRQn);
+ _pfic_irqn_enable(pfic, SWI_IRQn);
+}
+
+void systick_handler(void) __attribute__((interrupt()));
+void systick_handler(void)
+{
+ volatile struct systick_registers *systick;
+
+ isr_sp_enter();
+ rt_interrupt_enter();
+
+ rt_tick_increase();
+ systick = (struct systick_registers *)SysTick_REG_BASE;
+ /* clear count-to-zero flag */
+ systick->CNTFG.cntif = 0;
+
+ rt_interrupt_leave();
+ isr_sp_leave();
+}
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_pfic.h b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_pfic.h
new file mode 100644
index 0000000000..be3c652074
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_pfic.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#ifndef __CH56X_PFIC_H__
+#define __CH56X_PFIC_H__
+
+#include "soc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* IREG: IENR/IRER/IRSR/IPRR, make sure irqn be 12~59
+*/
+#define PFIC_IREG1_MASK 0xfffff000
+#define PFIC_IREG2_MASK 0x0fffffff
+#define PFIC_MAX_IREG_BITS 60
+
+#define _pfic_ireg_bit_get(pfic, IREG, irqn) \
+ ((pfic->IREG[(irqn) >> 5] >> ((irqn) & 0x1f)) & 1)
+
+#define _pfic_ireg_bit_set(pfic, IREG, irqn) \
+ do pfic->IREG[(irqn) >> 5] = 1 << ((irqn) & 0x1f); while(0)
+
+#define _pfic_irqn_enable(pfic, irqn) _pfic_ireg_bit_set(pfic, IENR, irqn)
+#define _pfic_irqn_disable(pfic, irqn) _pfic_ireg_bit_set(pfic, IRER, irqn)
+
+/* Note: `union _pfic_cfgr` is not used directly in the reg structure */
+union _pfic_cfgr
+{
+ uint32_t reg;
+ struct
+ {
+ uint32_t hwstkctrl : 1; // RW, hw stack push/pop control (0:enable)
+ uint32_t nestctrl : 1; // RW, nested intr enable control (0:enable)
+ uint32_t nmiset : 1; // WO, write 1 to set NMI pending
+ uint32_t nmireset : 1; // WO, write 1 to reset NMI pending
+ uint32_t excset : 1; // WO, write 1 to set exception pending
+ uint32_t excreset : 1; // WO, write 1 to reset exception pending
+ uint32_t pficreset : 1; // WO, write 1 to reset PFIC module, auto clear
+ uint32_t sysreset : 1; // WO, write 1 for a system reset, auto clear
+ uint32_t resv_8 : 8;
+ uint32_t keycode : 16; // WO, write protection keycode
+ };
+};
+#define PFIC_CFGR_KEY1 0xfa05 // for hwstkctrl & nestctrl
+#define PFIC_CFGR_KEY2 0xbcaf // for nmi & exc set/reset
+#define PFIC_CFGR_KEY3 0xbeef // for sysreset
+
+#define PFIC_CFGR_NMISET (PFIC_CFGR_KEY2 << 16 | 1 << 2)
+#define PFIC_CFGR_NMIRESET (PFIC_CFGR_KEY2 << 16 | 1 << 3)
+#define PFIC_CFGR_EXCSET (PFIC_CFGR_KEY2 << 16 | 1 << 4)
+#define PFIC_CFGR_EXCRESET (PFIC_CFGR_KEY2 << 16 | 1 << 5)
+#define PFIC_CFGR_PFICRESET (1 << 6)
+#define PFIC_CFGR_SYSRESET (PFIC_CFGR_KEY3 << 16 | 1 << 7)
+
+#define CFGR_HWSTKCTRL_ENABLE (0 << 0)
+#define CFGR_HWSTKCTRL_DISABLE (1 << 0)
+#define CFGR_HWSTKCTRL_MASK (1 << 0)
+#define CFGR_NESTCTRL_ENABLE (0 << 1)
+#define CFGR_NESTCTRL_DISABLE (1 << 1)
+#define CFGR_NESTCTRL_MASK (1 << 1)
+#define cfgr_nest_hwstk(v) (PFIC_CFGR_KEY1 << 16 | (v))
+
+union _pfic_gisr
+{
+ uint32_t reg;
+ struct
+ {
+ uint32_t neststa : 8; // RO, nested interrupt state (0/1/2)
+ uint32_t gactsta : 1; // RO, global interrupt active status
+ uint32_t gpendsta : 1; // RO, global interrupt pending status
+ uint32_t resv_10 : 22;
+ };
+};
+#define PFIC_NESTSTA_NONE 0
+#define PFIC_NESTSTA_L1 1
+#define PFIC_NESTSTA_L2 2
+
+union _pfic_fiofaddrr
+{
+ uint32_t reg;
+ struct
+ {
+ uint32_t offaddr : 24; // RW
+ uint32_t irqid : 8; // RW
+ };
+};
+
+union _pfic_sctlr
+{
+ uint32_t reg;
+ struct
+ {
+ uint32_t resv_0 : 1;
+ uint32_t sleeponexit : 1; // enter (deep) sleep mode on isr exiting
+ uint32_t sleepdeep : 1; // RW, 0/1 for sleep/deep-sleep mode
+ uint32_t wfitowfe : 1; // RW, treat WFI as WFE
+ uint32_t sevonpend : 1; // RW
+ uint32_t setevent : 1; // WO, set event for WFE
+ uint32_t resv_6 : 26;
+ };
+};
+
+/*
+ * 0x000 R32_PFIC_ISR1: PFIC interrupt enable status (# 12-31)
+ * 0x004 R32_PFIC_ISR2: PFIC interrupt enable status (# 32-59)
+ * 0x020 R32_PFIC_IPR1: PFIC interrupt pending status (# 12-31)
+ * 0x024 R32_PFIC_IPR2: PFIC interrupt pending status (# 32-59)
+ * 0x040 R32_PFIC_ITHRESDR: PFIC interrupt priority threshold (B.7-4)
+ * 0x044 R32_PFIC_FIBADDRR: PFIC fast intr base address (B.31-28)
+ * 0x048 R32_PFIC_CFGR: PFIC interrupt configuration register
+ * 0x04c R32_PFIC_GISR: PFIC global interrupt status register
+ * 0x060 R32_PFIC_FIOFADDRR0: PFIC fast intr 0 offset address (B.23-0)
+ * 0x064 R32_PFIC_FIOFADDRR1: PFIC fast intr 1 offset address (B.23-0)
+ * 0x068 R32_PFIC_FIOFADDRR2: PFIC fast intr 2 offset address (B.23-0)
+ * 0x06c R32_PFIC_FIOFADDRR3: PFIC fast intr 3 offset address (B.23-0)
+ * 0x100 R32_PFIC_IENR1: PFIC interrupt enable register (# 12-31)
+ * 0x104 R32_PFIC_IENR2: PFIC interrupt enable register (# 32-59)
+ * 0x180 R32_PFIC_IRER1: PFIC interrupt reset register (# 12-31)
+ * 0x184 R32_PFIC_IRER2: PFIC interrupt reset register (# 32-59)
+ * 0x200 R32_PFIC_IPSR1: PFIC interrupt pending set register (# 12-31)
+ * 0x204 R32_PFIC_IPSR2: PFIC interrupt pending set register (# 32-59)
+ * 0x280 R32_PFIC_IPRR1: PFIC interrupt pending reset register (# 12-31)
+ * 0x284 R32_PFIC_IPRR2: PFIC interrupt pending reset register (# 32-59)
+ * 0x300 R32_PFIC_IACTR1: PFIC interrupt active status register (# 12-31)
+ * 0x304 R32_PFIC_IACTR2: PFIC interrupt active status register (# 32-59)
+ * 0x400 R32_PFIC_IPRIORx: PFIC interrupt priority registers
+ * 0xd10 R32_PFIC_SCTLR: PFIC system control register
+ *
+ * CAVEAT: gcc (as of 8.2.0) tends to read 32-bit word for bit field test.
+ * Be careful for those with side effect for read.
+ */
+struct pfic_registers
+{
+ uint32_t ISR[2];
+ uint32_t resv_08[6];
+ uint32_t IPR[2];
+ uint32_t resv_28[6];
+ uint32_t ITHRESDR;
+ uint32_t FIBADDRR;
+ uint32_t CFGR;
+ union _pfic_gisr GISR;
+ uint32_t resv_50[4];
+ union _pfic_fiofaddrr FIOFADDRR[4];
+ uint32_t resv_70[36];
+ uint32_t IENR[2];
+ uint32_t resv_108[30];
+ uint32_t IRER[2];
+ uint32_t resv_188[30];
+ uint32_t IPSR[2];
+ uint32_t resv_208[30];
+ uint32_t IPRR[2];
+ uint32_t resv_288[30];
+ uint32_t IACTR[2];
+ uint32_t resv_308[62];
+ uint8_t IPRIOR[256];
+ uint32_t resv_500[516];
+ union _pfic_sctlr SCTLR;
+} __packed;
+
+CHECK_STRUCT_SIZE(struct pfic_registers, 0xd14);
+
+union _systick_ctlr
+{
+ uint32_t reg;
+ struct
+ {
+ uint32_t ste : 1; // RW, systick enable
+ uint32_t stie : 1; // RW, systick interrupt enable
+ uint32_t stclk : 1; // RW, systick clock source select
+ uint32_t resv_3 : 5;
+ uint32_t streload : 1; // W1, write 1 to reload systick
+ uint32_t resv_9 : 23;
+ };
+};
+#define RB_STKCTL_STE 0x001
+#define RB_STKCTL_STIE 0x002
+#define RB_STKCTL_STCLK 0x004
+#define RB_STKCTL_STRELOAD 0x100
+
+#define SYSTICK_SRC_HCLK_8 0
+#define SYSTICK_SRC_HCLK 1
+
+union _systick_cntfg
+{
+ uint32_t reg;
+ struct
+ {
+ uint32_t swie : 1; // RW, software interrupt enable
+ uint32_t cntif : 1; // RW0, counter dec to 0 (write 0 to clear)
+ uint32_t resv_2 : 30;
+ };
+};
+#define RB_CNTFG_SWIE 0X01
+#define RB_CNTFG_CNTIF 0X02
+
+/*
+ * 0x00 R32_STK_CTLR: SysTick control register
+ * 0x04 R32_STK_CNTL: SysTick counter, Lo.32
+ * 0x08 R32_STK_CNTH: SysTick counter, Hi.32
+ * 0x0c R32_STK_CMPLR: SysTick compare-reload register, Lo.32
+ * 0x10 R32_STK_CMPHR: SysTick compare-reload register, Hi.32
+ * 0x14 R32_STK_CNTFG: SysTick counter flags
+ *
+ * CAVEAT: gcc (as of 8.2.0) tends to read 32-bit word for bit field test.
+ * Be careful for those with side effect for read.
+ */
+struct systick_registers
+{
+ union _systick_ctlr CTLR;
+ uint32_t CNTL;
+ uint32_t CNTH;
+ uint32_t CMPLR;
+ uint32_t CMPHR;
+ union _systick_cntfg CNTFG;
+} __packed;
+
+CHECK_STRUCT_SIZE(struct systick_registers, 0x18);
+
+rt_inline void pfic_interrupt_umask(uint8_t irqn)
+{
+ volatile struct pfic_registers *pfic;
+
+ if (irqn < PFIC_MAX_IREG_BITS)
+ {
+ pfic = (void *)PFIC_REG_BASE;
+ _pfic_ireg_bit_set(pfic, IENR, irqn);
+ }
+}
+
+rt_inline void pfic_interrupt_mask(uint8_t irqn)
+{
+ volatile struct pfic_registers *pfic;
+
+ if (irqn < PFIC_MAX_IREG_BITS)
+ {
+ pfic = (void *)PFIC_REG_BASE;
+ _pfic_ireg_bit_set(pfic, IRER, irqn);
+ }
+}
+
+void pfic_swi_pendset(void);
+void pfic_swi_pendreset(void);
+void pfic_cfgr_set(uint32_t key_bit);
+void systick_init(uint32_t count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.c b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.c
new file mode 100644
index 0000000000..51305e4a51
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#include <rthw.h>
+#include <rtdebug.h>
+#include "ch56x_sys.h"
+
+rt_inline uint8_t _slp_clk_off0_irqn_bit(uint8_t irqn)
+{
+ uint8_t bitpos;
+
+ switch (irqn)
+ {
+ case TMR0_IRQn: bitpos = RB_SLP_CLK_TMR0; break;
+ case TMR1_IRQn: bitpos = RB_SLP_CLK_TMR1; break;
+ case TMR2_IRQn: bitpos = RB_SLP_CLK_TMR2; break;
+ /* special case to control PWMX clock in irqn way */
+ case PWMX_OFFn: bitpos = RB_SLP_CLK_PWMX; break;
+ case UART0_IRQn: bitpos = RB_SLP_CLK_UART0; break;
+ case UART1_IRQn: bitpos = RB_SLP_CLK_UART1; break;
+ case UART2_IRQn: bitpos = RB_SLP_CLK_UART2; break;
+ case UART3_IRQn: bitpos = RB_SLP_CLK_UART3; break;
+ default:
+ bitpos = 0;
+ }
+
+ return bitpos;
+}
+
+rt_inline uint8_t _slp_clk_off1_irqn_bit(uint8_t irqn)
+{
+ uint8_t bitpos;
+
+ switch (irqn)
+ {
+ case SPI0_IRQn: bitpos = RB_SLP_CLK_SPI0; break;
+ case SPI1_IRQn: bitpos = RB_SLP_CLK_SPI1; break;
+#if defined(SOC_CH567)
+ case SDC_IRQn: bitpos = RB_SLP_CLK_SDC; break;
+ case LED_IRQn: bitpos = RB_SLP_CLK_LED; break;
+ case USB0_IRQn: bitpos = RB_SLP_CLK_USB0; break;
+ case USB1_IRQn: bitpos = RB_SLP_CLK_USB1; break;
+ case ECDC_IRQn: bitpos = RB_SLP_CLK_ECDC; break;
+#elif defined(SOC_CH568)
+ case SDC_IRQn: bitpos = RB_SLP_CLK_SDC; break;
+ case LED_IRQn: bitpos = RB_SLP_CLK_LED; break;
+ case USB1_IRQn: bitpos = RB_SLP_CLK_USB1; break;
+ case USB0_IRQn: bitpos = RB_SLP_CLK_SATA; break;
+ case ECDC_IRQn: bitpos = RB_SLP_CLK_ECDC; break;
+#else
+ case EMMC_IRQn: bitpos = RB_SLP_CLK_EMMC; break;
+ case HSPI_IRQn: bitpos = RB_SLP_CLK_HSPI; break;
+ case USBHS_IRQn: bitpos = RB_SLP_CLK_USBHS; break;
+ case USBSS_IRQn: bitpos = RB_SLP_CLK_USBSS; break;
+ case SerDes_IRQn: bitpos = RB_SLP_CLK_SERD; break;
+ case DVP_IRQn: bitpos = RB_SLP_CLK_DVP; break;
+#endif
+ default:
+ bitpos = 0;
+ }
+
+ return bitpos;
+}
+
+#if defined(SOC_SERIES_CH569)
+rt_inline uint8_t _wake_clk_off_irqn_bit(uint8_t irqn)
+{
+ uint8_t bitpos;
+
+ switch (irqn)
+ {
+ case ETH_IRQn: bitpos = RB_SLP_CLK_ETH; break;
+ case ECDC_IRQn: bitpos = RB_SLP_CLK_ECDC; break;
+ default:
+ bitpos = 0;
+ }
+
+ return bitpos;
+}
+#endif
+
+/**
+ * @brief Turn on/off device clock for group clk_off0.
+ *
+ * @param bits is a bit mask to select corresponding devices.
+ *
+ * @param off is to turn off the clock (1) or trun on (0).
+ */
+void sys_slp_clk_off0(uint8_t bits, int off)
+{
+ volatile struct sys_registers *sys = (void *)SYS_REG_BASE;
+ rt_base_t level;
+ uint8_t u8v;
+
+ u8v = sys->SLP_CLK_OFF0.reg;
+ u8v = off ? (u8v | bits) : (u8v & ~bits);
+ level = rt_hw_interrupt_disable();
+ sys_safe_access_enter(sys);
+ sys->SLP_CLK_OFF0.reg = u8v;
+ sys_safe_access_leave(sys);
+ rt_hw_interrupt_enable(level);
+}
+
+/**
+ * @brief Turn on/off device clock for group clk_off1.
+ *
+ * @param bits is a bit mask to select corresponding devices.
+ *
+ * @param off is to turn off the clock (1) or trun on (0).
+ */
+void sys_slp_clk_off1(uint8_t bits, int off)
+{
+ volatile struct sys_registers *sys = (void *)SYS_REG_BASE;
+ rt_base_t level;
+ uint8_t u8v;
+
+ u8v = sys->SLP_CLK_OFF1.reg;
+ u8v = off ? (u8v | bits) : (u8v & ~bits);
+ level = rt_hw_interrupt_disable();
+ sys_safe_access_enter(sys);
+ sys->SLP_CLK_OFF1.reg = u8v;
+ sys_safe_access_leave(sys);
+ rt_hw_interrupt_enable(level);
+}
+
+/**
+ * @brief Turn on/off device clock, specified by its irq number.
+ *
+ * @param irqn is the irq number of the target device.
+ * PWMX does not have irqn, use special PWMX_OFFn number.
+ *
+ * @param off is to turn off the clock (1) or trun on (0).
+ *
+ * @return Returns if irqn-device has corresponding clk off bit :
+ * 0 if device not found; otherwise bit position of off0/off1.
+ */
+int sys_clk_off_by_irqn(uint8_t irqn, int off)
+{
+ volatile struct sys_registers *sys = (void *)SYS_REG_BASE;
+ uint8_t u8v;
+ size_t offset;
+
+ uint8_t bitpos = 0;
+
+ if (irqn < END_OF_IRQn)
+ {
+ if ((bitpos = _slp_clk_off0_irqn_bit(irqn)) != 0)
+ {
+ offset = offsetof(struct sys_registers, SLP_CLK_OFF0);
+ }
+ else if ((bitpos = _slp_clk_off1_irqn_bit(irqn)) != 0)
+ {
+ offset = offsetof(struct sys_registers, SLP_CLK_OFF1);
+ }
+#if defined(SOC_SERIES_CH569)
+ else if ((bitpos = _wake_clk_off_irqn_bit(irqn)) != 0)
+ {
+ offset = offsetof(struct sys_registers, SLP_WAKE_CTRL);
+ }
+#endif
+ if (bitpos)
+ {
+ volatile uint8_t *cxreg = (void *)sys;
+ rt_base_t level;
+ u8v = cxreg[offset];
+ u8v = off ? (u8v | bitpos) : (u8v & ~bitpos);
+ level = rt_hw_interrupt_disable();
+ sys_safe_access_enter(sys);
+ cxreg[offset] = u8v;
+ sys_safe_access_leave(sys);
+ rt_hw_interrupt_enable(level);
+ }
+ }
+
+ return bitpos;
+}
+
+/**
+ * @brief Setup HCLK frequency.
+ *
+ * @param freq is the desired hclk frequency.
+ * supported : 120/96/80/60/48/40/32/30/15/10/6/3/2 MHz
+ *
+ * @return Returns 0 if hclk is successfully set.
+ */
+int sys_hclk_set(uint32_t freq)
+{
+ volatile struct sys_registers *sys = (void *)SYS_REG_BASE;
+
+ uint8_t plldiv;
+
+ int clksel = -1;
+
+ if (freq >= 30000000)
+ {
+ if (freq <= 120000000)
+ {
+ /* supported : 120/96/80/60/48/40/32/30 MHz */
+ plldiv = 480000000 / freq; // 30M => 16 & 0xf => 0
+ clksel = RB_CLK_SEL_PLL;
+ }
+ }
+ else if (freq >= 2000000)
+ {
+ /* supported : 15/10/6/3/2 MHz */
+ plldiv = 30000000 / freq;
+ clksel = 0;
+ }
+
+ if (clksel >= 0)
+ {
+ rt_base_t level = rt_hw_interrupt_disable();
+ sys_safe_access_enter(sys);
+ sys->CLK_PLL_DIV.reg = clk_pll_div_wdat(plldiv);
+ sys->CLK_CFG_CTRL.reg = clk_cfg_ctrl_wdat(clksel);
+ sys_safe_access_leave(sys);
+ rt_hw_interrupt_enable(level);
+ clksel = 0;
+ }
+
+ return clksel;
+}
+
+/**
+ * @brief Get current HCLK frequency.
+ *
+ * @return Returns current HCLK frequency (Hz).
+ */
+uint32_t sys_hclk_get(void)
+{
+ volatile struct sys_registers *sys = (void *)SYS_REG_BASE;
+
+ uint8_t plldiv = sys->CLK_PLL_DIV.pll_div;
+
+ if (sys->CLK_CFG_CTRL.sel_pll == CLK_SEL_PLL_USB_480M)
+ {
+ return plldiv ? 480000000 / plldiv : 30000000;
+ }
+ else
+ {
+ return plldiv ? 30000000 / plldiv : 2000000;
+ }
+}
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.h b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.h
new file mode 100644
index 0000000000..9b2b7b3e54
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_sys.h
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#ifndef __CH56X_SYS_H__
+#define __CH56X_SYS_H__
+
+#include "soc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define sys_safe_access_enter(sys) \
+ do { \
+ sys->SAFE_ACCESS_SIG.reg = SAFE_ACCESS_SIG_1; \
+ sys->SAFE_ACCESS_SIG.reg = SAFE_ACCESS_SIG_2; \
+ } while(0)
+
+#define sys_safe_access_leave(sys) \
+ do sys->SAFE_ACCESS_SIG.reg = 0; while(0)
+
+union _sys_safe_access_sig
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t safe_acc_mode : 2; // RO, current safe access, 11b => RWA ok
+ uint8_t resv_2 : 2;
+ uint8_t safe_acc_timer : 3; // RO, current safe access time count
+ uint8_t resv_7 : 1;
+ };
+};
+#define RB_SAFE_ACC_MODE 0x03
+#define RB_SAFE_ACC_TIMER 0x70
+
+#define SAFE_ACCESS_SIG_1 0x57
+#define SAFE_ACCESS_SIG_2 0xa8
+
+union _sys_glob_rom_cfg
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t rom_ext_re : 1; // RO, allow programmer to read FlashROM
+ uint8_t code_ram_we : 1; // RWA, code SRAM writaboe
+ uint8_t rom_data_we : 1; // RWA, FlashROM data erasable/writable
+ uint8_t rom_code_we : 1; // RWA, FlashROM code erasable/writable
+ uint8_t rom_code_ofs : 1; // RWA, FlashROM offset for user code
+ uint8_t resv_5 : 3;
+ };
+};
+#define RB_ROM_EXT_RE 0x01
+#define RB_CODE_RAM_WE 0x02
+#define RB_ROM_DATA_WE 0x04
+#define RB_ROM_CODE_WE 0x08
+#define RB_ROM_CODE_OFS 0x10
+
+#define ROM_CODE_OFS_0x00000 0
+#define ROM_CODE_OFS_0x04000 1
+
+union _sys_rst_boot_stat
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t reset_flag : 2; // RO, last reset cause
+ uint8_t cfg_reset_en : 1; // RO, external reset pin (#RST) status
+ uint8_t cfg_boot_en : 1; // RO, reset as 1
+ uint8_t cfg_debug_en : 1; // RO
+ uint8_t boot_loader : 1; // RO
+ uint8_t resv_6 : 2;
+ };
+};
+#define RB_RESET_FLAG 0x03
+#define RB_CFG_RESET_EN 0x04
+#define RB_CFG_BOOT_EN 0x08
+#define RB_CFG_DEBUG_EN 0x10
+#define RB_BOOT_LOADER 0x20
+
+#define RESET_FLAG_IS_SOFT 0
+#define RESET_FLAG_IS_POR 1
+#define RESET_FLAG_IS_WDOG 2
+#define RESET_FLAG_IS_RSTPIN 3
+
+union _sys_rst_wdog_ctrl
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t software_reset : 1; // WA/WZ, system software reset, auto clear
+#if defined(SOC_SERIES_CH569)
+ uint8_t wdog_rst_en : 1; // RWA, enable watchdog overflow to reset
+ uint8_t wdog_int_en : 1; // RWA, enable watchdog overflow interrupt
+ uint8_t wdog_int_flag : 1; // RW1, watchdog counter overflow
+#else
+ uint8_t resv_2 : 3;
+#endif
+ uint8_t resv_4 : 4; // RO, B.7-6 must write 01b
+ };
+};
+#define RB_SOFTWARE_RESET 0x01
+#ifdef SOC_SERIES_CH569
+#define RB_WDOG_RST_EN 0x02
+#define RB_WDOG_INT_EN 0x04
+#define RB_WDOG_INT_FLAG 0x08
+#endif
+#define wdog_ctrl_wdat(v) (0x40 | (v))
+
+union _sys_clk_pll_div
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t pll_div : 4; // RWA, min 2
+ uint8_t resv_4 : 4; // RWA, B.7-6 must write 01b
+ };
+};
+#define clk_pll_div_wdat(div) (0x40 | (div))
+
+union _sys_clk_cfg_ctrl
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t pll_sleep : 1; // RWA, PLL sleep control
+ uint8_t sel_pll : 1; // RWA, clock source select
+ uint8_t resv_6 : 6; // RWA, must write 10b
+ };
+};
+#define RB_CLK_PLL_SLEEP 0x01
+#define RB_CLK_SEL_PLL 0x02
+
+#define CLK_PLL_SLEEP_DISABLE 0
+#define CLK_PLL_SLEEP_ENABLE 1
+#define CLK_SEL_PLL_HSE_30M 0
+#define CLK_SEL_PLL_USB_480M 1
+#define clk_cfg_ctrl_wdat(v) (0x80 | (v))
+
+union _sys_clk_mod_aux
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t int_125m_en : 1; // RWA, USB PHY 125MHz to ETH
+ uint8_t ext_125m_en : 1; // RWA, external 125MHz to ETH
+ uint8_t mco_sel_msk : 2; // RWA, MCO output select
+ uint8_t mco_en : 1; // RWA, MCO output enable
+ uint8_t resv_5 : 3;
+ };
+};
+#define RB_INT_125M_EN 0x01
+#define RB_EXT_125M_EN 0x02
+#define RB_MCO_SEL_MSK 0x0c
+#define RB_MCO_EN 0x10
+
+#define MCO_SEL_MSK_125M 0
+#define MCO_SEL_MSK_25M 1
+#define MCO_SEL_MSK_2_5M 2
+
+/* All bits are RWA (need safe_access_sig), 0/1 : clock on/off
+*/
+union _sys_slp_clk_off0
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t tmr0 : 1;
+ uint8_t tmr1 : 1;
+ uint8_t tmr2 : 1;
+ uint8_t pwmx : 1;
+ uint8_t uart0 : 1;
+ uint8_t uart1 : 1;
+ uint8_t uart2 : 1;
+ uint8_t uart3 : 1;
+ };
+};
+#define RB_SLP_CLK_TMR0 0x01
+#define RB_SLP_CLK_TMR1 0x02
+#define RB_SLP_CLK_TMR2 0x04
+#define RB_SLP_CLK_PWMX 0x08
+#define RB_SLP_CLK_UART0 0x10
+#define RB_SLP_CLK_UART1 0x20
+#define RB_SLP_CLK_UART2 0x40
+#define RB_SLP_CLK_UART3 0x80
+
+#define SYS_SLP_CLK_ON 0
+#define SYS_SLP_CLK_OFF 1
+
+/* All writable bits are RWA (need safe_access_sig), 0/1 : clock on/off
+*/
+union _sys_slp_clk_off1
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t spi0 : 1;
+ uint8_t spi1 : 1;
+#if defined(SOC_CH567)
+ uint8_t sdc : 1;
+ uint8_t led : 1;
+ uint8_t usb0 : 1;
+ uint8_t usb1 : 1;
+ uint8_t resv_6 : 1;
+#elif defined(SOC_CH568)
+ uint8_t sdc : 1;
+ uint8_t led : 1;
+ uint8_t resv_4 : 1;
+ uint8_t usb1 : 1;
+ uint8_t sata : 1;
+ uint8_t ecdc : 1;
+#else
+ uint8_t emmc : 1;
+ uint8_t hspi : 1;
+ uint8_t usbhs : 1;
+ uint8_t usbss : 1;
+ uint8_t serd : 1;
+ uint8_t dvp : 1;
+#endif
+ };
+};
+#define RB_SLP_CLK_SPI0 0x01
+#define RB_SLP_CLK_SPI1 0x02
+#if defined(SOC_WCH_CH567)
+#define RB_SLP_CLK_SDC 0x04
+#define RB_SLP_CLK_LED 0x08
+#define RB_SLP_CLK_USB0 0x10
+#define RB_SLP_CLK_USB1 0x20
+#define RB_SLP_CLK_ECDC 0x80
+#elif defined(SOC_WCH_CH568)
+#define RB_SLP_CLK_SDC 0x04
+#define RB_SLP_CLK_LED 0x08
+#define RB_SLP_CLK_USB1 0x20
+#define RB_SLP_CLK_SATA 0x40
+#define RB_SLP_CLK_ECDC 0x80
+#else
+#define RB_SLP_CLK_EMMC 0x04
+#define RB_SLP_CLK_HSPI 0x08
+#define RB_SLP_CLK_USBHS 0x10
+#define RB_SLP_CLK_USBSS 0x20
+#define RB_SLP_CLK_SERD 0x40
+#define RB_SLP_CLK_DVP 0x80
+#endif
+
+/* All writable bits are RWA (need safe_access_sig)
+*/
+union _sys_slp_wake_ctrl
+{
+ uint8_t reg;
+ struct
+ {
+#if defined(SOC_WCH_CH567)
+ uint8_t usb0_wake : 1;
+ uint8_t usb1_wake : 1;
+ uint8_t resv_2 : 2;
+ uint8_t gpio_wake : 1;
+ uint8_t resv_5 : 3;
+#elif defined(SOC_WCH_CH568)
+ uint8_t resv_0 : 1;
+ uint8_t usb1_wake : 1;
+ uint8_t sata_wake : 1;
+ uint8_t resv_3 : 1;
+ uint8_t gpio_wake : 1;
+ uint8_t resv_5 : 3;
+#else
+ uint8_t usbhs_wake : 1;
+ uint8_t usbss_wake : 1;
+ uint8_t clk_eth : 1;
+ uint8_t clk_ecdc : 1;
+ uint8_t gpio_wake : 1;
+ uint8_t eth_wake : 1;
+ uint8_t resv_6 : 2;
+#endif
+ };
+};
+#if defined(SOC_WCH_CH567)
+#define RB_SLP_USB0_WAKE 0x01
+#define RB_SLP_USB1_WAKE 0x02
+#define RB_SLP_GPIO_WAKE 0x10
+#elif defined(SOC_WCH_CH568)
+#define RB_SLP_USB1_WAKE 0x02
+#define RB_SLP_SATA_WAKE 0x04
+#define RB_SLP_GPIO_WAKE 0x10
+#else
+#define RB_SLP_USBHS_WAKE 0x01
+#define RB_SLP_USBSS_WAKE 0x02
+#define RB_SLP_CLK_ETH 0x04
+#define RB_SLP_CLK_ECDC 0x08
+#define RB_SLP_GPIO_WAKE 0x10
+#define RB_SLP_ETH_WAKE 0x20
+#endif
+
+union _sys_slp_power_ctrl
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t usbhs_pwrdn : 1; // RWA, USBHS power down (0:PWRUP)
+ uint8_t resv_2 : 7;
+ };
+};
+#define RB_SLP_USBHS_PWRDN 0x01
+
+union _sys_serd_ana_cfg1
+{
+ uint16_t reg;
+ struct
+ {
+ uint8_t serd_pll_cfg; // RWA, reset as 0x5a
+ uint8_t serd_30m_sel : 1; // RWA
+ uint8_t serd_dn_tst : 1; // RWA
+ uint8_t resv_10 : 6;
+ };
+};
+#define RB_SERD_PLL_CFG 0x0ff
+#define RB_SERD_30M_SEL 0x100
+#define RB_SERD_DN_TST 0x200
+
+union _sys_serd_ana_cfg2
+{
+ uint32_t reg;
+ struct
+ {
+ uint32_t serd_trx_cfg : 25; // RWA, reset as 423015h
+ uint32_t resv_25 : 7;
+ };
+};
+#define RB_SERD_TRX_CFG 0x1000000
+
+/*
+ * 0x00 R8_SAFE_ACCESS_SIG: safe access signature register
+ * 0x01 R8_CHIP_ID: RF, chip ID register
+ * 0x02 R8_SAFE_ACCESS_ID: RF, read as 02h
+ * 0x03 R8_WDOG_COUNT RW, watchdog counter
+ * 0x04 R8_GLOB_ROM_CFG: ROM config register
+ * 0x05 R8_RST_BOOT_STAT: RO, boot state register
+ * 0x06 R8_RST_WDOG_CTRL: software reset & watchdog control register
+ * 0x07 R8_GLOB_RESET_KEEP: RW, only power-on-reset can clear this register
+ * 0x08 R8_CLK_PLL_DIV: RWA, PLL output divisor register
+ * 0x0a R8_CLK_CFG_CTRL: RWA, clock config register
+ * 0x0b R8_CLK_MOD_AUX: RWA, clock auxiliary register
+ * 0x0c R8_SLP_CLK_OFF0: RWA, sleep control register 0
+ * 0x0d R8_SLP_CLK_OFF1: RWA, sleep control register 1
+ * 0x0e R8_SLP_WAKE_CTRL: RWA, wakeup control register
+ * 0x0f R8_SLP_POWER_CTRL: RWA, low power management register
+ * 0x20 R16_SERD_ANA_CFG1: RWA, SerDes PHY analog param config register 1
+ * 0x24 R32_SERD_ANA_CFG2: RWA, SerDes PHY analog param config register 2
+ *
+ * CAVEAT: gcc (as of 8.2.0) tends to read 32-bit word for bit field test.
+ * Be careful for those with side effect for read.
+ */
+struct sys_registers
+{
+ union _sys_safe_access_sig SAFE_ACCESS_SIG;
+ uint8_t CHIP_ID;
+ uint8_t SAFE_ACCESS_ID;
+ uint8_t WDOG_COUNT;
+ union _sys_glob_rom_cfg GLOB_ROM_CFG;
+ union _sys_rst_boot_stat RST_BOOT_STAT;
+ union _sys_rst_wdog_ctrl RST_WDOG_CTRL;
+ uint8_t GLOB_RESET_KEEP;
+ union _sys_clk_pll_div CLK_PLL_DIV;
+ uint8_t resv_9;
+ union _sys_clk_cfg_ctrl CLK_CFG_CTRL;
+ union _sys_clk_mod_aux CLK_MOD_AUX;
+ union _sys_slp_clk_off0 SLP_CLK_OFF0;
+ union _sys_slp_clk_off1 SLP_CLK_OFF1;
+ union _sys_slp_wake_ctrl SLP_WAKE_CTRL;
+ union _sys_slp_power_ctrl SLP_POWER_CTRL;
+#if defined(SOC_SERIES_CH569)
+ uint32_t resv_10[4];
+ union _sys_serd_ana_cfg1 SERD_ANA_CFG1;
+ uint16_t resv_22;
+ union _sys_serd_ana_cfg2 SERD_ANA_CFG2;
+#endif
+} __packed;
+
+CHECK_STRUCT_SIZE(struct sys_registers, 0x28);
+
+uint32_t sys_hclk_get(void);
+int sys_hclk_set(uint32_t freq);
+int sys_clk_off_by_irqn(uint8_t irqn, int off);
+void sys_slp_clk_off0(uint8_t bits, int off);
+void sys_slp_clk_off1(uint8_t bits, int off);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_timer.c b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_timer.c
new file mode 100644
index 0000000000..be388386c6
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_timer.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#include <rthw.h>
+#include <rtdebug.h>
+#include <drivers/hwtimer.h>
+#include "ch56x_sys.h"
+#include "ch56x_timer.h"
+#include "isr_sp.h"
+
+struct hwtimer_device
+{
+ struct rt_hwtimer_device parent;
+ struct rt_hwtimer_info hwtimer_info;
+ volatile struct timer_registers *reg_base;
+ rt_hwtimer_mode_t tmode;
+ irq_number_t irqn;
+ char *name;
+};
+
+#ifdef BSP_USING_TMR0
+static struct hwtimer_device hwtimer_device_0 =
+{
+ .hwtimer_info =
+ {
+ .maxfreq = 80000000,
+ .minfreq = 80000000,
+ .maxcnt = 0x3ffffff,
+ .cntmode = HWTIMER_CNTMODE_UP,
+ },
+ .reg_base = (struct timer_registers *)TMR0_REG_BASE,
+ .tmode = HWTIMER_MODE_PERIOD,
+ .irqn = TMR0_IRQn,
+ .name = "timer0",
+};
+#endif
+
+#ifdef BSP_USING_TMR1
+static struct hwtimer_device hwtimer_device_1 =
+{
+ .hwtimer_info =
+ {
+ .maxfreq = 80000000,
+ .minfreq = 80000000,
+ .maxcnt = 0x3ffffff,
+ .cntmode = HWTIMER_CNTMODE_UP,
+ },
+ .reg_base = (struct timer_registers *)TMR1_REG_BASE,
+ .tmode = HWTIMER_MODE_PERIOD,
+ .irqn = TMR1_IRQn,
+ .name = "timer1",
+};
+#endif
+
+#ifdef BSP_USING_TMR2
+static struct hwtimer_device hwtimer_device_2 =
+{
+ .hwtimer_info =
+ {
+ .maxfreq = 80000000,
+ .minfreq = 80000000,
+ .maxcnt = 0x3ffffff,
+ .cntmode = HWTIMER_CNTMODE_UP,
+ },
+ .reg_base = (struct timer_registers *)TMR2_REG_BASE,
+ .tmode = HWTIMER_MODE_PERIOD,
+ .irqn = TMR2_IRQn,
+ .name = "timer2",
+};
+#endif
+
+static void hwtimer_stop(struct rt_hwtimer_device *timer);
+
+static void hwtimer_init(struct rt_hwtimer_device *timer, uint32_t state)
+{
+ struct hwtimer_device *hwtimer_device = (void *)timer;
+
+ RT_ASSERT(hwtimer_device != RT_NULL);
+
+ /* no resource processing, `state` ignored */
+ hwtimer_stop(timer);
+
+ if (hwtimer_device->irqn != TMR0_IRQn)
+ {
+ hwtimer_device->reg_base->CTRL_DMA.reg = 0;
+ }
+}
+
+static rt_err_t hwtimer_start(struct rt_hwtimer_device *timer, uint32_t cnt, rt_hwtimer_mode_t mode)
+{
+ struct hwtimer_device *hwtimer_device = (void *)timer;
+ volatile struct timer_registers *txreg;
+
+ RT_ASSERT(hwtimer_device != RT_NULL);
+
+ /* hwtimer_device->tmode may be different from timer->mode.
+ * For multi-cycle ONESHOT, tmode is set to PERIOD at hwtimer_start.
+ */
+ hwtimer_device->tmode = mode;
+
+ sys_clk_off_by_irqn(hwtimer_device->irqn, SYS_SLP_CLK_ON);
+ txreg = hwtimer_device->reg_base;
+ txreg->CNT_END = cnt;
+ txreg->CTRL_MOD.reg = RB_TMR_ALL_CLEAR;
+ txreg->CTRL_MOD.reg = RB_TMR_COUNT_EN;
+ txreg->INTER_EN.cyc_end = 1;
+ rt_hw_interrupt_umask(hwtimer_device->irqn);
+
+ return RT_EOK;
+}
+
+static void hwtimer_stop(struct rt_hwtimer_device *timer)
+{
+ struct hwtimer_device *hwtimer_device = (void *)timer;
+ volatile struct timer_registers *txreg;
+
+ RT_ASSERT(hwtimer_device != RT_NULL);
+
+ rt_hw_interrupt_mask(hwtimer_device->irqn);
+ /* note: RB_TMR_COUNT_EN cleared */
+ txreg = hwtimer_device->reg_base;
+ txreg->CTRL_MOD.reg = RB_TMR_ALL_CLEAR;
+ txreg->INTER_EN.reg = 0;
+ sys_clk_off_by_irqn(hwtimer_device->irqn, SYS_SLP_CLK_OFF);
+}
+
+static uint32_t hwtimer_count_get(struct rt_hwtimer_device *timer)
+{
+ struct hwtimer_device *hwtimer_device = (void *)timer;
+
+ RT_ASSERT(hwtimer_device != RT_NULL);
+
+ return hwtimer_device->reg_base->COUNT;
+}
+
+static rt_err_t hwtimer_control(
+ struct rt_hwtimer_device *timer, uint32_t cmd, void *args)
+{
+ struct hwtimer_device *hwtimer_device = (void *)timer;
+ rt_err_t result = RT_EOK;
+
+ RT_ASSERT(hwtimer_device != RT_NULL);
+
+ switch (cmd)
+ {
+ case HWTIMER_CTRL_FREQ_SET:
+ /* clocking for ch56x timers are fixed to Fsys */
+ if (args == RT_NULL || *(uint32_t *)args != timer->info->minfreq)
+ {
+ result = -RT_EINVAL;
+ }
+ break;
+
+ case HWTIMER_CTRL_STOP:
+ case HWTIMER_CTRL_INFO_GET:
+ case HWTIMER_CTRL_MODE_SET:
+ default:
+ result = -RT_ENOSYS;
+ }
+
+ return result;
+}
+
+static const struct rt_hwtimer_ops hwtimer_ops =
+{
+ .init = hwtimer_init,
+ .start = hwtimer_start,
+ .stop = hwtimer_stop,
+ .count_get = hwtimer_count_get,
+ .control = hwtimer_control,
+};
+
+static int rt_hw_hwtimer_init(void)
+{
+ struct hwtimer_device *devices[3];
+
+ uint32_t Fsys = sys_hclk_get();
+
+ int n = 0;
+
+#ifdef BSP_USING_TMR2
+ devices[n++] = &hwtimer_device_2;
+#endif
+#ifdef BSP_USING_TMR1
+ devices[n++] = &hwtimer_device_1;
+#endif
+#ifdef BSP_USING_TMR0
+ devices[n++] = &hwtimer_device_0;
+#endif
+
+ while (--n >= 0)
+ {
+ struct hwtimer_device *hwtimer_device = devices[n];
+ /* counting frequency is fixed to Fsys */
+ hwtimer_device->hwtimer_info.maxfreq = Fsys;
+ hwtimer_device->hwtimer_info.minfreq = Fsys;
+ hwtimer_device->parent.info = &hwtimer_device->hwtimer_info;
+ hwtimer_device->parent.ops = &hwtimer_ops;
+ rt_device_hwtimer_register(
+ &hwtimer_device->parent, hwtimer_device->name, RT_NULL);
+ }
+ return RT_EOK;
+}
+INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);
+
+static void _hwtimer_isr_common(struct hwtimer_device *hwtimer_device)
+{
+ volatile struct timer_registers *txreg = hwtimer_device->reg_base;
+
+ if (txreg->INT_FLAG.cyc_end)
+ {
+ if (hwtimer_device->tmode == HWTIMER_MODE_ONESHOT)
+ {
+ /* disable timer to emulate oneshot */
+ txreg->CTRL_MOD.reg = 0;
+ }
+ rt_device_hwtimer_isr(&hwtimer_device->parent);
+ txreg->INT_FLAG.cyc_end = 1;
+ }
+}
+
+#ifdef BSP_USING_TMR0
+void tmr0_irq_handler(void) __attribute__((interrupt()));
+void tmr0_irq_handler(void)
+{
+ isr_sp_enter();
+ rt_interrupt_enter();
+ _hwtimer_isr_common(&hwtimer_device_0);
+ rt_interrupt_leave();
+ isr_sp_leave();
+}
+#endif
+
+#ifdef BSP_USING_TMR1
+void tmr1_irq_handler(void) __attribute__((interrupt()));
+void tmr1_irq_handler(void)
+{
+ isr_sp_enter();
+ rt_interrupt_enter();
+ _hwtimer_isr_common(&hwtimer_device_1);
+ rt_interrupt_leave();
+ isr_sp_leave();
+}
+#endif
+
+#ifdef BSP_USING_TMR2
+void tmr2_irq_handler(void) __attribute__((interrupt()));
+void tmr2_irq_handler(void)
+{
+ isr_sp_enter();
+ rt_interrupt_enter();
+ _hwtimer_isr_common(&hwtimer_device_2);
+ rt_interrupt_leave();
+ isr_sp_leave();
+}
+#endif
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_timer.h b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_timer.h
new file mode 100644
index 0000000000..63a5ebef13
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_timer.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#ifndef __CH56X_TIMER_H__
+#define __CH56X_TIMER_H__
+
+#include "soc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+union _timer_ctrl_mod
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t mode_in : 1; // B.0 : RW, timer mode setting
+ uint8_t all_clear : 1; // B.1 : RW, clear FIFO/count/int-flag
+ uint8_t count_en : 1; // B.2 : RW, enable timer module
+ uint8_t out_en : 1; // B.3 : RW, timer output enable
+ uint8_t out_polar : 1; // B.4 : RW, output polarity for PWM mode
+ uint8_t resv_5 : 1;
+ uint8_t pwm_repeat : 2; // B.7-6 : RW, PWM repeat count, 1/4/8/16
+ };
+ struct
+ {
+ uint8_t stuff_0 : 6;
+ uint8_t cap_edge : 2; // B.7-6 : RW, capture edge mode
+ };
+};
+#define RB_TMR_MODE_IN 0x01
+#define RB_TMR_ALL_CLEAR 0x02
+#define RB_TMR_COUNT_EN 0x04
+#define RB_TMR_OUT_EN 0x08
+#define RB_TMR_OUT_POLAR 0x10
+#define RB_TMR_CAP_COUNT 0x10
+#define RB_TMR_PWM_REPEAT 0xc0
+#define RB_TMR_CAP_EDGE 0xc0
+
+#define TMR_MODE_TIMER_PWM 0
+#define TMR_MODE_CAP_COUNT 1
+#define TMR_PWM_REPEAT_1 0
+#define TMR_PWM_REPEAT_4 1
+#define TMR_PWM_REPEAT_8 2
+#define TMR_PWM_REPEAT_16 3
+#define TMR_CAP_EDGE_NONE 0
+#define TMR_CAP_EDGE_BOTH 1
+#define TMR_CAP_EDGE_F2F 2
+#define TMR_CAP_EDGE_R2R 3
+
+union _timer_ctrl_dma
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t dma_enable : 1; // B.0 : RW, enable DMA
+ uint8_t resv_1 : 1;
+ uint8_t dma_loop : 1; // B.2 : RW, enable DMA address looping
+ uint8_t resv_3 : 5;
+ };
+};
+#define RB_TMR_DMA_ENABLE 0x01
+#define RB_TMR_DMA_LOOP 0x04
+
+union _timer_interrupt
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t cyc_end : 1; // B.0
+ uint8_t data_act : 1; // B.1
+ uint8_t fifo_hf : 1; // B.2
+ uint8_t dma_end : 1; // B.3
+ uint8_t fifo_ov : 1; // B.4
+ uint8_t resv_5 : 3;
+ };
+};
+#define RB_TMR_IX_MASK 0x1f
+#define RB_TMR_IE_CYC_END 0x01 // RW, enable interrupt for timer capture count timeout or PWM cycle end
+#define RB_TMR_IE_DATA_ACT 0x02 // RW, enable interrupt for timer capture input action or PWM trigger
+#define RB_TMR_IE_FIFO_HF 0x04 // RW, enable interrupt for timer FIFO half (capture fifo >=4 or PWM fifo <=3)
+#define RB_TMR_IE_DMA_END 0x08 // RW, enable interrupt for timer1/2 DMA completion
+#define RB_TMR_IE_FIFO_OV 0x10 // RW, enable interrupt for timer FIFO overflow
+
+#define RB_TMR_IF_CYC_END 0x01 // RW1, interrupt flag for timer capture count timeout or PWM cycle end
+#define RB_TMR_IF_DATA_ACT 0x02 // RW1, interrupt flag for timer capture input action or PWM trigger
+#define RB_TMR_IF_FIFO_HF 0x04 // RW1, interrupt flag for timer FIFO half (capture fifo >=4 or PWM fifo <=3)
+#define RB_TMR_IF_DMA_END 0x08 // RW1, interrupt flag for timer1/2 DMA completion
+#define RB_TMR_IF_FIFO_OV 0x10 // RW1, interrupt flag for timer FIFO overflow
+
+/*
+ * 0x00 R8_TMRx_CTRL_MOD: mode setting register
+ * 0x01 R8_TMRx_CTRL_DMA: DMA control register
+ * 0x02 R8_TMRx_INTER_EN: interrupt enable register
+ * 0x06 R8_TMRx_INT_FLAG: interrupt flag register
+ * 0x07 R8_TMRx_FIFO_COUNT: RO, FIFO count register
+ * 0x08 R32_TMRx_COUNT: RO, timer current count register
+ * 0x0c R32_TMRx_CNT_END: RW, timer count end register
+ * 0x10 R32_TMRx_FIFO: RO/WO, FIFO data register, LSB 26 bits
+ * 0x14 R32_TMRx_DMA_NOW: RW, DMA buffer current address, LSB 18 bits
+ * 0x18 R32_TMRx_DMA_BEG: RW, DMA buffer begin address, LSB 18 bits
+ * 0x1c R32_TMRx_DMA_END: RW, DMA buffer end address (exclusive), LSB 18 bits
+ *
+ * Note: DMA related registers (0x10,0x14,0x18,0x1c) are TMR1/2 only
+ *
+ * CAVEAT: gcc (as of 8.2.0) tends to read 32-bit word for bit field test.
+ * Be careful for those with side effect for read.
+ */
+struct timer_registers
+{
+ union _timer_ctrl_mod CTRL_MOD;
+ union _timer_ctrl_dma CTRL_DMA;
+ union _timer_interrupt INTER_EN;
+ uint8_t resv_3[3];
+ union _timer_interrupt INT_FLAG;
+ uint8_t FIFO_COUNT;
+ uint32_t COUNT;
+ uint32_t CNT_END;
+ uint32_t FIFO;
+ uint32_t DMA_NOW;
+ uint32_t DMA_BEG;
+ uint32_t DMA_END;
+} __packed;
+
+CHECK_STRUCT_SIZE(struct timer_registers, 0x20);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_uart.c b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_uart.c
new file mode 100644
index 0000000000..d0230d21fb
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_uart.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#include <rthw.h>
+#include <rtdebug.h>
+#include <ipc/completion.h>
+#include <ipc/dataqueue.h>
+#ifdef RT_USING_SERIAL_V2
+ #include <drivers/serial_v2.h>
+#else
+ #include <drivers/serial.h>
+#endif
+#include "ch56x_sys.h"
+#include "ch56x_uart.h"
+#include "isr_sp.h"
+
+#if !defined(BSP_USING_UART0) && !defined(BSP_USING_UART1) && \
+ !defined(BSP_USING_UART2) && !defined(BSP_USING_UART3)
+ #error "Please define at least one UARTx"
+#endif
+
+struct serial_device
+{
+ struct rt_serial_device parent;
+ volatile struct uart_registers *reg_base;
+ irq_number_t irqn;
+ char *name;
+};
+
+#ifdef BSP_USING_UART0
+static struct serial_device serial_device_0 =
+{
+ .reg_base = (struct uart_registers *)UART0_REG_BASE,
+ .irqn = UART0_IRQn,
+ .name = "uart0",
+};
+#endif
+
+#ifdef BSP_USING_UART1
+static struct serial_device serial_device_1 =
+{
+ .reg_base = (struct uart_registers *)UART1_REG_BASE,
+ .irqn = UART1_IRQn,
+ .name = "uart1",
+};
+#endif
+
+#ifdef BSP_USING_UART2
+static struct serial_device serial_device_2 =
+{
+ .reg_base = (struct uart_registers *)UART2_REG_BASE,
+ .irqn = UART2_IRQn,
+ .name = "uart2",
+};
+#endif
+
+#ifdef BSP_USING_UART3
+static struct serial_device serial_device_3 =
+{
+ .reg_base = (struct uart_registers *)UART3_REG_BASE,
+ .irqn = UART3_IRQn,
+ .name = "uart3",
+};
+#endif
+
+static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
+{
+ struct serial_device *serial_device = (struct serial_device *)serial;
+ volatile struct uart_registers *uxreg = serial_device->reg_base;
+
+ union _uart_fcr fcr;
+ union _uart_lcr lcr;
+ uint32_t x;
+
+ x = 10 * sys_hclk_get() / 8 / cfg->baud_rate;
+ x = (x + 5) / 10;
+ uxreg->DL = x;
+ uxreg->DIV = 1;
+
+ lcr.reg = 0;
+ switch (cfg->data_bits)
+ {
+ case DATA_BITS_5:
+ lcr.word_sz = LCR_DATA_BITS_5;
+ break;
+ case DATA_BITS_6:
+ lcr.word_sz = LCR_DATA_BITS_6;
+ break;
+ case DATA_BITS_7:
+ lcr.word_sz = LCR_DATA_BITS_7;
+ break;
+ case DATA_BITS_8:
+ default:
+ lcr.word_sz = LCR_DATA_BITS_8;
+ break;
+ }
+
+ switch (cfg->stop_bits)
+ {
+ case STOP_BITS_2:
+ lcr.stop_bit = LCR_STOP_BITS_2;
+ break;
+ case STOP_BITS_1:
+ default:
+ lcr.stop_bit = LCR_STOP_BITS_1;
+ break;
+ }
+
+ switch (cfg->parity)
+ {
+ case PARITY_ODD:
+ lcr.par_mod = LCR_PARITY_ODD;
+ lcr.par_en = 1;
+ break;
+ case PARITY_EVEN:
+ lcr.par_mod = LCR_PARITY_EVEN;
+ lcr.par_en = 1;
+ break;
+ case PARITY_NONE:
+ default:
+ lcr.par_en = 0;
+ break;
+ }
+ uxreg->LCR.reg = lcr.reg;
+
+ fcr.reg = RB_FCR_FIFO_EN | RB_FCR_RX_FIFO_CLR | RB_FCR_TX_FIFO_CLR;
+ fcr.fifo_trig = UART_1BYTE_TRIG;
+ uxreg->FCR.reg = fcr.reg;
+
+ /* TXD pin output enable */
+ uxreg->IER.txd_en = 1;
+
+ return RT_EOK;
+}
+
+static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *args)
+{
+ struct serial_device *serial_device = (struct serial_device *)serial;
+ volatile struct uart_registers *uxreg = serial_device->reg_base;
+
+ switch (cmd)
+ {
+ case RT_DEVICE_CTRL_CLR_INT:
+ uxreg->IER.recv_rdy = 0;
+ uxreg->IER.line_stat = 0;
+ uxreg->IER.thr_empty = 0;
+ rt_hw_interrupt_mask(serial_device->irqn);
+ break;
+ case RT_DEVICE_CTRL_SET_INT:
+ uxreg->FCR.fifo_trig = UART_1BYTE_TRIG;
+ uxreg->MCR.int_oe = 1;
+ uxreg->IER.recv_rdy = 1;
+ uxreg->IER.line_stat = 1;
+ if (serial->parent.open_flag & RT_DEVICE_FLAG_INT_TX)
+ {
+ uxreg->IER.thr_empty = 1;
+ }
+ rt_hw_interrupt_umask(serial_device->irqn);
+ break;
+ default:
+ break;
+ }
+
+ return RT_EOK;
+}
+
+static int uart_putc(struct rt_serial_device *serial, char ch)
+{
+ struct serial_device *serial_device = (struct serial_device *)serial;
+ volatile struct uart_registers *uxreg = serial_device->reg_base;
+
+ if (serial->parent.open_flag & RT_DEVICE_FLAG_INT_TX)
+ {
+ if (uxreg->TFC >= UART_FIFO_SIZE)
+ return -1;
+ }
+ else
+ {
+ while (uxreg->TFC >= UART_FIFO_SIZE)
+ {
+ if (rt_thread_self() && rt_interrupt_get_nest() == 0)
+ rt_thread_yield();
+ }
+ }
+ uxreg->THR = ch;
+
+ return 1;
+}
+
+static int uart_getc(struct rt_serial_device *serial)
+{
+ struct serial_device *serial_device = (struct serial_device *)serial;
+ volatile struct uart_registers *uxreg = serial_device->reg_base;
+
+ /* UART_II_RECV_RDY is cleared by reading RBR */
+ return (uxreg->RFC > 0) ? uxreg->RBR : -1;
+}
+
+static const struct rt_uart_ops uart_ops =
+{
+ .configure = uart_configure,
+ .control = uart_control,
+ .putc = uart_putc,
+ .getc = uart_getc,
+ .dma_transmit = RT_NULL,
+};
+
+int rt_hw_uart_init(void)
+{
+ struct serial_device *devices[4];
+
+ /* Note: HCLK should be at least 8MHz for default 115200 baud to work */
+ struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
+
+ int n = 0;
+
+#ifdef BSP_USING_UART3
+ devices[n++] = &serial_device_3;
+#endif
+#ifdef BSP_USING_UART2
+ devices[n++] = &serial_device_2;
+#endif
+#ifdef BSP_USING_UART1
+ devices[n++] = &serial_device_1;
+#endif
+#ifdef BSP_USING_UART0
+ devices[n++] = &serial_device_0;
+#endif
+
+ /* IMPORTANT: pin mode should be set properly @ board init */
+
+ while (--n >= 0)
+ {
+ uint32_t flag;
+ struct serial_device *serial = devices[n];
+ serial->parent.ops = &uart_ops;
+ serial->parent.config = config;
+
+ sys_clk_off_by_irqn(serial->irqn, SYS_SLP_CLK_ON);
+
+ flag = RT_DEVICE_FLAG_RDWR |
+ RT_DEVICE_FLAG_STREAM | // for converting '\n'
+ RT_DEVICE_FLAG_INT_TX |
+ RT_DEVICE_FLAG_INT_RX ;
+ rt_hw_serial_register(&serial->parent, serial->name, flag, RT_NULL);
+
+ /* rt_serial_open => uart_control with RT_DEVICE_CTRL_SET_INT */
+ }
+
+ return 0;
+}
+
+static void _uart_isr_common(struct serial_device *serial_device)
+{
+ struct rt_serial_device *serial = &serial_device->parent;
+ volatile struct uart_registers *uxreg = serial_device->reg_base;
+
+ switch (uxreg->IIR.int_mask)
+ {
+ case UART_II_RECV_TOUT:
+ /* FIXME: It's a bad idea to read RBR to clear UART_II_RECV_TOUT.
+ * Race condition may happen that actual rx data is dropped.
+ */
+ if (uxreg->RFC == 0)
+ {
+ uxreg->RBR;
+ //rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_TIMEOUT);
+ break;
+ }
+ /* pass through as if UART_II_RECV_RDY */
+ case UART_II_RECV_RDY:
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+ break;
+ case UART_II_THR_EMPTY:
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DONE);
+ break;
+ case UART_II_LINE_STAT:
+ uxreg->LSR;
+ break;
+ case UART_II_MODEM_CHG:
+ uxreg->MSR;
+ break;
+ case UART_II_SLV_ADDR:
+ uxreg->IIR;
+ break;
+ default:
+ break;
+ }
+}
+
+#ifdef BSP_USING_UART0
+void uart0_irq_handler(void) __attribute__((interrupt()));
+void uart0_irq_handler(void)
+{
+ isr_sp_enter();
+ rt_interrupt_enter();
+ _uart_isr_common(&serial_device_0);
+ rt_interrupt_leave();
+ isr_sp_leave();
+}
+#endif
+
+#ifdef BSP_USING_UART1
+void uart1_irq_handler(void) __attribute__((interrupt()));
+void uart1_irq_handler(void)
+{
+ isr_sp_enter();
+ rt_interrupt_enter();
+ _uart_isr_common(&serial_device_1);
+ rt_interrupt_leave();
+ isr_sp_leave();
+}
+#endif
+
+#ifdef BSP_USING_UART2
+void uart2_irq_handler(void) __attribute__((interrupt()));
+void uart2_irq_handler(void)
+{
+ isr_sp_enter();
+ rt_interrupt_enter();
+ _uart_isr_common(&serial_device_2);
+ rt_interrupt_leave();
+ isr_sp_leave();
+}
+#endif
+
+#ifdef BSP_USING_UART3
+void uart3_irq_handler(void) __attribute__((interrupt()));
+void uart3_irq_handler(void)
+{
+ isr_sp_enter();
+ rt_interrupt_enter();
+ _uart_isr_common(&serial_device_3);
+ rt_interrupt_leave();
+ isr_sp_leave();
+}
+#endif
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_uart.h b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_uart.h
new file mode 100644
index 0000000000..c34c6b5c21
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_uart.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#ifndef __CH56X_UART_H__
+#define __CH56X_UART_H__
+
+#include "soc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef UART_FIFO_SIZE
+#define UART_FIFO_SIZE 8
+#endif
+
+#ifndef UART_RECV_RDY_SZ
+#define UART_RECV_RDY_SZ 7 // FIFO trigger level for rx data available
+#endif
+
+union _uart_mcr
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t dtr : 1; // B.0 : RW, DTR output (UART0 only)
+ uint8_t rts : 1; // B.1 : RW, RTS output (UART0 only)
+ uint8_t out1 : 1; // B.2 : RW, user defined modem control (UART0 only)
+ uint8_t int_oe : 1; // B.3 : RW, interrupt output enable / OUT2
+ uint8_t loop : 1; // B.4 : RW, enable internal loop test (UART0 only)
+ uint8_t au_flow_en : 1; // B.5 : RW, enable CTS/RTS autoflow control
+ uint8_t tnow : 1; // B.6 : RW, enable DTR TNOW output (UART0 only)
+ uint8_t half : 1; // B.7 : RW, enable half-duplex mode (UART0 only)
+ };
+};
+#define RB_MCR_DTR 0x01
+#define RB_MCR_RTS 0x02
+#define RB_MCR_OUT1 0x04
+#define RB_MCR_OUT2 0x08
+#define RB_MCR_INT_OE 0x08
+#define RB_MCR_LOOP 0x10
+#define RB_MCR_AU_FLOW_EN 0x20
+#define RB_MCR_TNOW 0x40
+#define RB_MCR_HALF 0x80
+
+union _uart_ier
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t recv_rdy : 1; // B.0 : RW, enable rx data ready intr
+ uint8_t thr_empty : 1; // B.1 : RW, enable THR empty intr
+ uint8_t line_stat : 1; // B.2 : RW, enable rx line status intr
+ uint8_t modem_chg : 1; // B.3 : RW, enable modem status change intr (UART0 only)
+ uint8_t dtr_en : 1; // B.4 : RW, DTR/TNOW output pin enable (UART0 only)
+ uint8_t rts_en : 1; // B.5 : RW, RTS output pin enable (UART0 only)
+ uint8_t txd_en : 1; // B.6 : RW, TXD pin enable
+ uint8_t reset : 1; // B.7 : WZ, software reset control, active high, auto clear
+ };
+};
+#define RB_IER_RECV_RDY 0x01
+#define RB_IER_THR_EMPTY 0x02
+#define RB_IER_LINE_STAT 0x04
+#define RB_IER_MODEM_CHG 0x08
+#define RB_IER_DTR_EN 0x10
+#define RB_IER_RTS_EN 0x20
+#define RB_IER_TXD_EN 0x40
+#define RB_IER_RESET 0x80
+
+union _uart_fcr
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t fifo_en : 1; // B.0 : RW, FIFO enable
+ uint8_t rx_fifo_clr : 1; // B.1 : WZ, write 1 to clear rx FIFO, auto clear
+ uint8_t tx_fifo_clr : 1; // B.2 : WZ, write 1 to clear tx FIFO, auto clear
+ uint8_t resv_3 : 3;
+ uint8_t fifo_trig : 2; // B.7-6 : RW, rx FIFO trigger level, 1/2/4/7 bytes
+ };
+};
+#define RB_FCR_FIFO_EN 0x01
+#define RB_FCR_RX_FIFO_CLR 0x02
+#define RB_FCR_TX_FIFO_CLR 0x04
+#define RB_FCR_FIFO_TRIG 0xc0
+
+#define UART_1BYTE_TRIG 0
+#define UART_2BYTE_TRIG 1
+#define UART_4BYTE_TRIG 2
+#define UART_7BYTE_TRIG 3
+
+union _uart_lcr
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t word_sz : 2; // B.1-0 : RW, word bit length, 5/6/7/8 bits
+ uint8_t stop_bit : 1; // B.2 : RW, stop bit length, 1/2 bits
+ uint8_t par_en : 1; // B.3 : RW, parity enable
+ uint8_t par_mod : 2; // B.5-4 : RW, parity mode, odd/even/mark/space
+ uint8_t break_en : 1; // B.6 : RW, force BREAK line condition
+ uint8_t dlab : 1; // B.7 : RW, user defined general purpose bit
+ };
+};
+#define RB_LCR_WORD_SZ 0x03
+#define RB_LCR_STOP_BIT 0x04
+#define RB_LCR_PAR_EN 0x08
+#define RB_LCR_PAR_MOD 0x30
+#define RB_LCR_BREAK_EN 0x40
+#define RB_LCR_DLAB 0x80
+#define RB_LCR_GP_BIT 0x80
+
+#define LCR_DATA_BITS_5 0
+#define LCR_DATA_BITS_6 1
+#define LCR_DATA_BITS_7 2
+#define LCR_DATA_BITS_8 3
+
+#define LCR_STOP_BITS_1 0
+#define LCR_STOP_BITS_2 1
+
+#define LCR_PARITY_ODD 0
+#define LCR_PARITY_EVEN 1
+#define LCR_PARITY_MARK 2
+#define LCR_PARITY_SPACE 3
+
+union _uart_iir
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t int_mask : 4; // B.3-0 : RO, interrupt mask (intr if B.0 is 0)
+ uint8_t resv_4 : 2;
+ uint8_t fifo_id : 2; // B.7-6 : RO, FIFO enabled flag
+ };
+};
+#define RB_IIR_NO_INT 0x01
+#define RB_IIR_INT_MASK 0x0f
+#define RB_IIR_FIFO_ID 0xc0
+
+/* RB_IIR_INT_MASK (IIR bits 3:0) definition
+*/
+#define UART_II_SLV_ADDR 0x0e // UART0 slave address match interrupt
+#define UART_II_LINE_STAT 0x06 // rx line status interrupt
+#define UART_II_RECV_RDY 0x04 // rx data available interrupt
+#define UART_II_RECV_TOUT 0x0c // rx fifo timeout interrupt
+#define UART_II_THR_EMPTY 0x02 // THR empty interrupt
+#define UART_II_MODEM_CHG 0x00 // UART0 modem status change interrupt
+#define UART_II_NO_INTER 0x01 // no interrupt pending
+
+union _uart_lsr
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t data_rdy : 1; // B.0 : RO, rx FIFO data ready
+ uint8_t over_err : 1; // B.1 : RZ, rx FIFO data overrun
+ uint8_t par_err : 1; // B.2 : RZ, rx parity error
+ uint8_t frame_err : 1; // B.3 : RZ, rx frame error
+ uint8_t break_err : 1; // B.4 : RZ, rx BREAK detected
+ uint8_t tx_fifo_emp : 1; // B.5 : RO, tx FIFO empty
+ uint8_t tx_all_emp : 1; // B.6 : RO, THR/TSR all empty
+ uint8_t err_rx_fifo : 1; // B.7 : RO, PAR/FRAME/BREAK ERR in rx FIFO
+ };
+};
+#define RB_LSR_DATA_RDY 0x01
+#define RB_LSR_OVER_ERR 0x02
+#define RB_LSR_PAR_ERR 0x04
+#define RB_LSR_FRAME_ERR 0x08
+#define RB_LSR_BREAK_ERR 0x10
+#define RB_LSR_TX_FIFO_EMP 0x20
+#define RB_LSR_TX_ALL_EMP 0x40
+#define RB_LSR_ERR_RX_FIFO 0x80
+
+union _uart_msr
+{
+ uint8_t reg;
+ struct
+ {
+ uint8_t cts_chg : 1; // B.0 : RZ, CTS input changed
+ uint8_t dsr_chg : 1; // B.1 : RZ, DSR input changed
+ uint8_t ri_chg : 1; // B.2 : RZ, RI input changed
+ uint8_t dcd_chg : 1; // B.3 : RZ, DCD input changed
+ uint8_t cts : 1; // B.4 : RO, CTS action status
+ uint8_t dsr : 1; // B.5 : RO, DSR action status
+ uint8_t ri : 1; // B.6 : RO, RI action status
+ uint8_t dcd : 1; // B.7 : RO, DCD action status
+ };
+};
+#define RB_MSR_CTS_CHG 0x01
+#define RB_MSR_DSR_CHG 0x02
+#define RB_MSR_RI_CHG 0x04
+#define RB_MSR_DCD_CHG 0x08
+#define RB_MSR_CTS 0x10
+#define RB_MSR_DSR 0x20
+#define RB_MSR_RI 0x40
+#define RB_MSR_DCD 0x80
+
+/*
+ * 0x00 R8_UARTx_MCR: Modem Control Register
+ * 0x01 R8_UARTx_IER: Interrupt Enable Register
+ * 0x02 R8_UARTx_FCR: FIFO Control Register
+ * 0x03 R8_UARTx_LCR: Line Control Register
+ * 0x04 R8_UARTx_IIR: Interrupt Identification Register
+ * 0x05 R8_UARTx_LSR: Line Status Register
+ * 0x06 R8_UARTx_MSR: Modem Status Register (UART0 only)
+ * 0x08 R8_UARTx_RBR: Rx Buffer Register
+ * 0x08 R8_UARTx_THR: Tx Hold Register
+ * 0x0a R8_UARTx_RFC: Rx FIFO count register
+ * 0x0b R8_UARTx_TFC: Tx FIFO count register
+ * 0x0c R16_UARTx_DL: Divisor Latch
+ * 0x0e R8_UARTx_DIV: frequency pre divider
+ * 0x0f R8_UARTx_ADR: Address Register (UART0 only)
+ *
+ * CAVEAT: gcc (as of 8.2.0) tends to read 32-bit word for bit field test.
+ * Be careful for those with side effect for read (e.g. RBR, IIR).
+ */
+struct uart_registers
+{
+ union _uart_mcr MCR;
+ union _uart_ier IER;
+ union _uart_fcr FCR;
+ union _uart_lcr LCR;
+ union _uart_iir IIR;
+ union _uart_lsr LSR;
+ union _uart_lsr MSR;
+ uint8_t resv_7;
+ union
+ {
+ uint8_t RBR;
+ uint8_t THR;
+ };
+ uint8_t resv_9;
+ uint8_t RFC;
+ uint8_t TFC;
+ uint16_t DL;
+ uint8_t DIV;
+ uint8_t ADR;
+} __packed;
+
+CHECK_STRUCT_SIZE(struct uart_registers, 0x10);
+
+int rt_hw_uart_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_wdt.c b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_wdt.c
new file mode 100644
index 0000000000..200f71b061
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/ch56x_wdt.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-20 Emuzit first version
+ */
+#include <rthw.h>
+#include <rtdebug.h>
+#include <drivers/watchdog.h>
+#include "ch56x_sys.h"
+
+#define WDOG_HICOUNT_MAX 0xfff // enough to hold (4095 * 120M/524288) >> 8
+
+struct watchdog_device
+{
+ rt_watchdog_t parent;
+ volatile uint32_t hicount;
+ uint32_t timeout;
+ uint32_t reload;
+ uint8_t is_start;
+};
+
+static struct watchdog_device watchdog_device;
+
+static void wdt_reload_counter(rt_watchdog_t *wdt, int cmd)
+{
+ struct watchdog_device *wdt_dev = (void *)wdt;
+
+ volatile struct sys_registers *sys = (void *)SYS_REG_BASE;
+
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ /* reload WDOG_COUNT also clears RB_WDOG_INT_FLAG*/
+ sys->WDOG_COUNT = (uint8_t)wdt_dev->reload;
+ wdt_dev->hicount = wdt_dev->reload >> 8;
+ if (cmd != RT_DEVICE_CTRL_WDT_KEEPALIVE && wdt_dev->is_start)
+ {
+ sys_safe_access_enter(sys);
+ if ((wdt_dev->reload >> 8) == WDOG_HICOUNT_MAX)
+ {
+ /* WDOG_COUNT can work on its own, no wdog_irq needed */
+ sys->RST_WDOG_CTRL.reg = wdog_ctrl_wdat(RB_WDOG_RST_EN);
+ rt_hw_interrupt_mask(WDOG_IRQn);
+ }
+ else
+ {
+ /* Extend wdt with wdt_dev->hicount through wdog_irq.
+ * CAVEAT: wdt not effective if global interrupt disabled !!
+ */
+ sys->RST_WDOG_CTRL.reg = wdog_ctrl_wdat(RB_WDOG_INT_EN);
+ rt_hw_interrupt_umask(WDOG_IRQn);
+ }
+ sys_safe_access_leave(sys);
+ }
+ rt_hw_interrupt_enable(level);
+}
+
+static uint32_t wdt_get_timeleft(rt_watchdog_t *wdt)
+{
+ struct watchdog_device *wdt_dev = (void *)wdt;
+
+ volatile struct sys_registers *sys = (void *)SYS_REG_BASE;
+
+ uint32_t countleft;
+ uint64_t count64;
+
+ if ((wdt_dev->reload >> 8) == WDOG_HICOUNT_MAX)
+ {
+ /* WDOG_COUNT can work on its own, without hicount */
+ countleft = 0xff - sys->WDOG_COUNT;
+ }
+ else
+ {
+ uint32_t c1 = sys->WDOG_COUNT;
+ uint32_t hc = wdt_dev->hicount;
+ uint32_t c2 = sys->WDOG_COUNT;
+ /* check if WDOG_COUNT overflows between c1/c2 reads */
+ if (c2 < c1)
+ {
+ rt_base_t level = rt_hw_interrupt_disable();
+ hc = wdt_dev->hicount;
+ if (sys->RST_WDOG_CTRL.wdog_int_flag && sys->RST_WDOG_CTRL.wdog_int_en)
+ {
+ hc++;
+ }
+ rt_hw_interrupt_enable(level);
+ }
+ countleft = ((WDOG_HICOUNT_MAX << 8) + 0xff) - ((hc << 8) + c2);
+ }
+
+ /* convert wdt count to seconds : count / (Fsys/524288) */
+ count64 = countleft;
+ return (uint32_t)((count64 << 19) / sys_hclk_get());
+}
+
+static uint32_t _convert_timeout_to_reload(uint32_t seconds)
+{
+ uint32_t N, R, Fsys, reload = -1;
+
+ /* timeout is limited to 4095, not to overflow 32-bit (T * 2^19) */
+ if (seconds < 4096)
+ {
+ /* watchdog timer is clocked at Fsys/524288, arround 3~228Hz */
+ Fsys = sys_hclk_get();
+ /* T * (Fsys/2^19) => (T * N) + T * (R/2^19) */
+ N = Fsys >> 19;
+ R = Fsys & 0x7ffff;
+ reload = (WDOG_HICOUNT_MAX << 8) + 0xff;
+ reload -= seconds * N + ((seconds * R) >> 19) + 1;
+ }
+
+ return reload;
+}
+
+static void _stop_wdog_operation()
+{
+ volatile struct sys_registers *sys = (void *)SYS_REG_BASE;
+
+ rt_base_t level = rt_hw_interrupt_disable();
+ sys_safe_access_enter(sys);
+ sys->RST_WDOG_CTRL.reg = wdog_ctrl_wdat(RB_WDOG_INT_FLAG);
+ sys_safe_access_leave(sys);
+ rt_hw_interrupt_enable(level);
+
+ rt_hw_interrupt_mask(WDOG_IRQn);
+}
+
+static rt_err_t wdt_init(rt_watchdog_t *wdt)
+{
+ struct watchdog_device *wdt_dev = (void *)wdt;
+
+ _stop_wdog_operation();
+ wdt_dev->is_start = 0;
+ wdt_dev->timeout = -1;
+ wdt_dev->reload = -1;
+
+ return RT_EOK;
+}
+
+static rt_err_t wdt_control(rt_watchdog_t *wdt, int cmd, void *arg)
+{
+ struct watchdog_device *wdt_dev = (void *)wdt;
+
+ uint32_t reload, timeout;
+
+ switch (cmd)
+ {
+ case RT_DEVICE_CTRL_WDT_KEEPALIVE:
+ wdt_reload_counter(wdt, cmd);
+ break;
+ case RT_DEVICE_CTRL_WDT_GET_TIMELEFT:
+ *((uint32_t *)arg) = wdt_get_timeleft(wdt);
+ break;
+ case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
+ *((uint32_t *)arg) = wdt_dev->timeout;
+ break;
+ case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
+ /* CAVEAT: Setting timeout larger than an 8-bit WDOG_COUNT can
+ * hold turns the wdog into interrupt mode, which makes wdog
+ * usless if cause of death is lost global interrupt enable.
+ */
+ timeout = *((uint32_t *)arg);
+ reload = _convert_timeout_to_reload(timeout);
+ if ((reload >> 8) > WDOG_HICOUNT_MAX)
+ {
+ return -RT_EINVAL;
+ }
+ wdt_dev->timeout = timeout;
+ wdt_dev->reload = reload;
+ /* FIXME: code example implies wdt started by SET_TIMEOUT ? */
+ case RT_DEVICE_CTRL_WDT_START:
+ if ((wdt_dev->reload >> 8) > WDOG_HICOUNT_MAX)
+ {
+ return -RT_EINVAL;
+ }
+ wdt_dev->is_start = 1;
+ wdt_reload_counter(wdt, cmd);
+ break;
+ case RT_DEVICE_CTRL_WDT_STOP:
+ _stop_wdog_operation();
+ wdt_dev->is_start = 0;
+ break;
+ default:
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+static struct rt_watchdog_ops watchdog_ops =
+{
+ .init = wdt_init,
+ .control = wdt_control,
+};
+
+int rt_hw_wdt_init(void)
+{
+ rt_uint32_t flag;
+
+ watchdog_device.parent.ops = &watchdog_ops;
+
+ flag = RT_DEVICE_FLAG_DEACTIVATE;
+ return rt_hw_watchdog_register(&watchdog_device.parent, "wdt", flag, RT_NULL);
+}
+INIT_BOARD_EXPORT(rt_hw_wdt_init);
+
+void wdog_irq_handler(void) __attribute__((interrupt()));
+void wdog_irq_handler(void)
+{
+ volatile struct pfic_registers *pfic;
+ volatile struct sys_registers *sys;
+
+ rt_interrupt_enter();
+
+ sys = (struct sys_registers *)SYS_REG_BASE;
+ /* FIXME: RB_WDOG_INT_FLAG seems completely not functioning at all !!
+ * It's not set at WDOG_COUNT overflow, writing 1 to it does not clear
+ * wdt interrupt. Bit 16 of pfic->IPR[0] is not effective thereof.
+ */
+ if (watchdog_device.hicount < WDOG_HICOUNT_MAX)
+ {
+ watchdog_device.hicount++;
+ /* clear interrupt flag */
+ //sys->RST_WDOG_CTRL.reg |= RB_WDOG_INT_FLAG;
+ sys->WDOG_COUNT = sys->WDOG_COUNT;
+ }
+ else
+ {
+ /* reset system if watchdog timeout */
+ uint8_t u8v = RB_SOFTWARE_RESET | RB_WDOG_INT_FLAG;
+ sys_safe_access_enter(sys);
+ sys->RST_WDOG_CTRL.reg = wdog_ctrl_wdat(u8v);
+ sys_safe_access_leave(sys);
+ }
+
+ rt_interrupt_leave();
+}
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/isr_sp.h b/bsp/wch/risc-v/Libraries/ch56x_drivers/isr_sp.h
new file mode 100644
index 0000000000..54c33ed942
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/isr_sp.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-27 Emuzit first version
+ */
+#ifndef __ISR_SP_H__
+#define __ISR_SP_H__
+
+/* usrstack is no more in use right after rt_system_scheduler_start().
+ * It is also the time global interrupt is enabled.
+*/
+#define isr_sp_enter() \
+ asm("la t0, rt_interrupt_nest"); \
+ asm("bnez t0, 1f"); \
+ asm("la t0, _eusrstack"); \
+ asm("sw sp, -4(t0)"); \
+ asm("addi sp, t0, -4"); \
+ asm("1:")
+
+#define isr_sp_leave() \
+ asm("la t0, rt_interrupt_nest"); \
+ asm("bnez t0, 1f"); \
+ asm("la t0, _eusrstack"); \
+ asm("lw sp, -4(t0)"); \
+ asm("1:")
+
+#endif
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/soc.h b/bsp/wch/risc-v/Libraries/ch56x_drivers/soc.h
new file mode 100644
index 0000000000..579996bcdd
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/soc.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#ifndef __SOC_H__
+#define __SOC_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <assert.h>
+
+#if !defined(SOC_CH567) && \
+ !defined(SOC_CH568) && \
+ !defined(SOC_SERIES_CH569)
+#define SOC_SERIES_CH569
+#endif
+
+#define CHECK_STRUCT_SIZE(s, size) \
+ static_assert(sizeof(s) == size, #s " has wrong size")
+
+#define BITS_SET(x, bits) do x |= bits; while(0)
+#define BITS_CLR(x, bits) do x &= ~bits; while(0)
+
+#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 RAMS_SIZE 16
+#else
+#define RAMS_SIZE 32
+#endif
+#define RAMS_END (RAMS_BASE_ADDRESS + RAMS_SIZE * 1024)
+
+#define SYS_REG_BASE 0x40001000
+#define GPIO_REG_BASE 0x40001000
+#define GPIO_REG_BASE_PA 0x40001040
+#define GPIO_REG_BASE_PB 0x40001060
+
+#define GPIO_PORTS 2 // 2 ports : PA & PB
+#define GPIO_PA_PIN_START 0 // PA : pin number 0~31
+#define GPIO_PB_PIN_START 32 // PB : pin number 32~63
+
+#ifdef SOC_SERIES_CH569
+#define GPIO_PA_PIN_MARK 0x00ffffff // PA : bits 0~23
+#define GPIO_PB_PIN_MARK 0x01ffffff // PB : bits 0~24
+#else
+#define GPIO_PA_PIN_MARK 0x0000ffff // PA : bits 0~15
+#define GPIO_PB_PIN_MARK 0x00003fff // PB : bits 0~13
+#endif
+
+#define TMR0_REG_BASE 0x40002000
+#define TMR1_REG_BASE 0x40002400
+#define TMR2_REG_BASE 0x40002800
+
+#define UART0_REG_BASE 0x40003000
+#define UART1_REG_BASE 0x40003400
+#define UART2_REG_BASE 0x40003800
+#define UART3_REG_BASE 0x40003c00
+
+#define SPI0_REG_BASE 0x40004000
+#define SPI1_REG_BASE 0x40004400
+
+#define PWMX_REG_BASE 0x40005000
+
+#define PFIC_REG_BASE 0xe000e000
+#define SysTick_REG_BASE 0xe000f000
+
+#ifdef SOC_SERIES_CH569
+#define HSPI_REG_BASE 0x40006000 // CH569W
+#define ECDC_REG_BASE 0x40007000
+#define USBSS_REG_BASE 0x40008000
+#define USBHS_REG_BASE 0x40009000
+#define EMMC_REG_BASE 0x4000a000
+#define SERDES_REG_BASE 0x4000b000
+#define ETH_REG_BASE 0x4000c000 // CH565W/CH569W
+#define DVP_REG_BASE 0x4000e000 // CH565W/CH565M
+#else
+#define LED_REG_BASE 0x40006000
+#define USB0_REG_BASE 0x40008000 // CH567
+#define USB1_REG_BASE 0x40009000 // CH567
+#define USB_REG_BASE 0x40009000 // CH568
+#define SDC_REG_BASE 0x4000a000
+#define SATA_REG_BASE 0x4000b000 // CH568
+#define ECDC_REG_BASE 0x4000c400
+#endif
+
+#if defined(SOC_SERIES_CH569)
+typedef enum
+{
+ PWMX_OFFn = 0,
+ NMI_IRQn = 2,
+ EXC_IRQn = 3,
+ SysTick_IRQn = 12,
+ SWI_IRQn = 14,
+ WDOG_IRQn = 16,
+ TMR0_IRQn = 17,
+ GPIO_IRQn = 18,
+ SPI0_IRQn = 19,
+ USBSS_IRQn = 20,
+ LINK_IRQn = 21,
+ TMR1_IRQn = 22,
+ TMR2_IRQn = 23,
+ UART0_IRQn = 24,
+ USBHS_IRQn = 25,
+ EMMC_IRQn = 26,
+ DVP_IRQn = 27,
+ HSPI_IRQn = 28,
+ SPI1_IRQn = 29,
+ UART1_IRQn = 30,
+ UART2_IRQn = 31,
+ UART3_IRQn = 32,
+ SerDes_IRQn = 33,
+ ETH_IRQn = 34,
+ PMT_IRQn = 35,
+ ECDC_IRQn = 36,
+ END_OF_IRQn
+} irq_number_t;
+
+#else
+
+typedef enum
+{
+ PWMX_OFFn = 0,
+ SOFT_IRQn = 0,
+ TMR0_IRQn = 1,
+ GPIO_IRQn = 2,
+ SPI0_IRQn = 3,
+ USB0_IRQn = 4, // CH567
+ SATA_IRQn = 4, // CH568
+ TMR1_IRQn = 5,
+ TMR2_IRQn = 6,
+ UART0_IRQn = 7,
+ USB1_IRQn = 8,
+ SDC_IRQn = 9,
+ ECDC_IRQn = 10,
+ LED_IRQn = 11,
+ SPI1_IRQn = 12,
+ UART1_IRQn = 13,
+ UART2_IRQn = 14,
+ UART3_IRQn = 15,
+ END_OF_IRQn
+} irq_number_t;
+#endif
+
+#endif
diff --git a/bsp/wch/risc-v/Libraries/ch56x_drivers/swi_gcc.S b/bsp/wch/risc-v/Libraries/ch56x_drivers/swi_gcc.S
new file mode 100644
index 0000000000..3e064e7b59
--- /dev/null
+++ b/bsp/wch/risc-v/Libraries/ch56x_drivers/swi_gcc.S
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-09-09 WCH the first version
+ * 2022-07-15 Emuzit adapt to ch569w-evt
+ */
+
+#include "cpuport.h"
+
+ .global swi_handler
+ .align 2
+swi_handler:
+ /* save all from thread context */
+#ifdef ARCH_RISCV_FPU
+ addi sp, sp, -32 * FREGBYTES
+ FSTORE f0, 0 * FREGBYTES(sp)
+ FSTORE f1, 1 * FREGBYTES(sp)
+ FSTORE f2, 2 * FREGBYTES(sp)
+ FSTORE f3, 3 * FREGBYTES(sp)
+ FSTORE f4, 4 * FREGBYTES(sp)
+ FSTORE f5, 5 * FREGBYTES(sp)
+ FSTORE f6, 6 * FREGBYTES(sp)
+ FSTORE f7, 7 * FREGBYTES(sp)
+ FSTORE f8, 8 * FREGBYTES(sp)
+ FSTORE f9, 9 * FREGBYTES(sp)
+ FSTORE f10, 10 * FREGBYTES(sp)
+ FSTORE f11, 11 * FREGBYTES(sp)
+ FSTORE f12, 12 * FREGBYTES(sp)
+ FSTORE f13, 13 * FREGBYTES(sp)
+ FSTORE f14, 14 * FREGBYTES(sp)
+ FSTORE f15, 15 * FREGBYTES(sp)
+ FSTORE f16, 16 * FREGBYTES(sp)
+ FSTORE f17, 17 * FREGBYTES(sp)
+ FSTORE f18, 18 * FREGBYTES(sp)
+ FSTORE f19, 19 * FREGBYTES(sp)
+ FSTORE f20, 20 * FREGBYTES(sp)
+ FSTORE f21, 21 * FREGBYTES(sp)
+ FSTORE f22, 22 * FREGBYTES(sp)
+ FSTORE f23, 23 * FREGBYTES(sp)
+ FSTORE f24, 24 * FREGBYTES(sp)
+ FSTORE f25, 25 * FREGBYTES(sp)
+ FSTORE f26, 26 * FREGBYTES(sp)
+ FSTORE f27, 27 * FREGBYTES(sp)
+ FSTORE f28, 28 * FREGBYTES(sp)
+ FSTORE f29, 29 * FREGBYTES(sp)
+ FSTORE f30, 30 * FREGBYTES(sp)
+ FSTORE f31, 31 * FREGBYTES(sp)
+#endif
+
+ addi sp, sp, -32 * REGBYTES
+
+ STORE x1, 1 * REGBYTES(sp)
+
+ /* saved MPIE */
+ li x1, 0x80
+ STORE x1, 2 * REGBYTES(sp)
+
+ STORE x4, 4 * REGBYTES(sp)
+ STORE x5, 5 * REGBYTES(sp)
+ STORE x6, 6 * REGBYTES(sp)
+ STORE x7, 7 * REGBYTES(sp)
+ STORE x8, 8 * REGBYTES(sp)
+ STORE x9, 9 * REGBYTES(sp)
+ STORE x10, 10 * REGBYTES(sp)
+ STORE x11, 11 * REGBYTES(sp)
+ STORE x12, 12 * REGBYTES(sp)
+ STORE x13, 13 * REGBYTES(sp)
+ STORE x14, 14 * REGBYTES(sp)
+ STORE x15, 15 * REGBYTES(sp)
+ STORE x16, 16 * REGBYTES(sp)
+ STORE x17, 17 * REGBYTES(sp)
+ STORE x18, 18 * REGBYTES(sp)
+ STORE x19, 19 * REGBYTES(sp)
+ STORE x20, 20 * REGBYTES(sp)
+ STORE x21, 21 * REGBYTES(sp)
+ STORE x22, 22 * REGBYTES(sp)
+ STORE x23, 23 * REGBYTES(sp)
+ STORE x24, 24 * REGBYTES(sp)
+ STORE x25, 25 * REGBYTES(sp)
+ STORE x26, 26 * REGBYTES(sp)
+ STORE x27, 27 * REGBYTES(sp)
+ STORE x28, 28 * REGBYTES(sp)
+ STORE x29, 29 * REGBYTES(sp)
+ STORE x30, 30 * REGBYTES(sp)
+ STORE x31, 31 * REGBYTES(sp)
+
+ /* rt_thread_switch_interrupt_flag not 0 => clear & switch thread */
+ la t0, rt_thread_switch_interrupt_flag
+ lw t1, 0(t0)
+ beqz t1, .L_restore
+ sw zero, 0(t0)
+
+ /* prepare to switch to rt_interrupt_to_thread */
+ csrr t1, mepc
+ STORE t1, 0 * REGBYTES(sp)
+
+ la t0, rt_interrupt_from_thread
+ LOAD t1, 0(t0)
+ STORE sp, 0(t1)
+
+ la t0, rt_interrupt_to_thread
+ LOAD t1, 0(t0)
+ LOAD sp, 0(t1)
+
+ LOAD t1, 0 * REGBYTES(sp)
+ csrw mepc, t1
+
+.L_restore:
+
+ /* clear software interrupt */
+ jal pfic_swi_pendreset
+
+ LOAD x1, 1 * REGBYTES(sp)
+
+ li t0, 0x1800
+ csrs mstatus, t0
+ LOAD t0, 2 * REGBYTES(sp)
+ csrs mstatus, t0
+
+ LOAD x4, 4 * REGBYTES(sp)
+ LOAD x5, 5 * REGBYTES(sp)
+ LOAD x6, 6 * REGBYTES(sp)
+ LOAD x7, 7 * REGBYTES(sp)
+ LOAD x8, 8 * REGBYTES(sp)
+ LOAD x9, 9 * REGBYTES(sp)
+ LOAD x10, 10 * REGBYTES(sp)
+ LOAD x11, 11 * REGBYTES(sp)
+ LOAD x12, 12 * REGBYTES(sp)
+ LOAD x13, 13 * REGBYTES(sp)
+ LOAD x14, 14 * REGBYTES(sp)
+ LOAD x15, 15 * REGBYTES(sp)
+ LOAD x16, 16 * REGBYTES(sp)
+ LOAD x17, 17 * REGBYTES(sp)
+ LOAD x18, 18 * REGBYTES(sp)
+ LOAD x19, 19 * REGBYTES(sp)
+ LOAD x20, 20 * REGBYTES(sp)
+ LOAD x21, 21 * REGBYTES(sp)
+ LOAD x22, 22 * REGBYTES(sp)
+ LOAD x23, 23 * REGBYTES(sp)
+ LOAD x24, 24 * REGBYTES(sp)
+ LOAD x25, 25 * REGBYTES(sp)
+ LOAD x26, 26 * REGBYTES(sp)
+ LOAD x27, 27 * REGBYTES(sp)
+ LOAD x28, 28 * REGBYTES(sp)
+ LOAD x29, 29 * REGBYTES(sp)
+ LOAD x30, 30 * REGBYTES(sp)
+ LOAD x31, 31 * REGBYTES(sp)
+ addi sp, sp, 32 * REGBYTES
+
+ /* load float reg */
+#ifdef ARCH_RISCV_FPU
+ FLOAD f0, 0 * FREGBYTES(sp)
+ FLOAD f1, 1 * FREGBYTES(sp)
+ FLOAD f2, 2 * FREGBYTES(sp)
+ FLOAD f3, 3 * FREGBYTES(sp)
+ FLOAD f4, 4 * FREGBYTES(sp)
+ FLOAD f5, 5 * FREGBYTES(sp)
+ FLOAD f6, 6 * FREGBYTES(sp)
+ FLOAD f7, 7 * FREGBYTES(sp)
+ FLOAD f8, 8 * FREGBYTES(sp)
+ FLOAD f9, 9 * FREGBYTES(sp)
+ FLOAD f10, 10 * FREGBYTES(sp)
+ FLOAD f11, 11 * FREGBYTES(sp)
+ FLOAD f12, 12 * FREGBYTES(sp)
+ FLOAD f13, 13 * FREGBYTES(sp)
+ FLOAD f14, 14 * FREGBYTES(sp)
+ FLOAD f15, 15 * FREGBYTES(sp)
+ FLOAD f16, 16 * FREGBYTES(sp)
+ FLOAD f17, 17 * FREGBYTES(sp)
+ FLOAD f18, 18 * FREGBYTES(sp)
+ FLOAD f19, 19 * FREGBYTES(sp)
+ FLOAD f20, 20 * FREGBYTES(sp)
+ FLOAD f21, 21 * FREGBYTES(sp)
+ FLOAD f22, 22 * FREGBYTES(sp)
+ FLOAD f23, 23 * FREGBYTES(sp)
+ FLOAD f24, 24 * FREGBYTES(sp)
+ FLOAD f25, 25 * FREGBYTES(sp)
+ FLOAD f26, 26 * FREGBYTES(sp)
+ FLOAD f27, 27 * FREGBYTES(sp)
+ FLOAD f28, 28 * FREGBYTES(sp)
+ FLOAD f29, 29 * FREGBYTES(sp)
+ FLOAD f30, 30 * FREGBYTES(sp)
+ FLOAD f31, 31 * FREGBYTES(sp)
+ addi sp, sp, 32 * FREGBYTES
+#endif
+ mret
diff --git a/bsp/wch/risc-v/ch569w-evt/.config b/bsp/wch/risc-v/ch569w-evt/.config
new file mode 100644
index 0000000000..cb3bcbf285
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/.config
@@ -0,0 +1,664 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# RT-Thread Configuration
+#
+
+#
+# RT-Thread Kernel
+#
+CONFIG_RT_NAME_MAX=8
+# CONFIG_RT_USING_ARCH_DATA_TYPE is not set
+# CONFIG_RT_USING_SMP is not set
+CONFIG_RT_ALIGN_SIZE=4
+# CONFIG_RT_THREAD_PRIORITY_8 is not set
+CONFIG_RT_THREAD_PRIORITY_32=y
+# CONFIG_RT_THREAD_PRIORITY_256 is not set
+CONFIG_RT_THREAD_PRIORITY_MAX=32
+CONFIG_RT_TICK_PER_SECOND=200
+# CONFIG_RT_USING_OVERFLOW_CHECK is not set
+CONFIG_RT_USING_HOOK=y
+CONFIG_RT_HOOK_USING_FUNC_PTR=y
+CONFIG_RT_USING_IDLE_HOOK=y
+CONFIG_RT_IDLE_HOOK_LIST_SIZE=4
+CONFIG_IDLE_THREAD_STACK_SIZE=384
+# CONFIG_RT_USING_TIMER_SOFT is not set
+
+#
+# kservice optimization
+#
+CONFIG_RT_KSERVICE_USING_STDLIB=y
+# CONFIG_RT_KSERVICE_USING_STDLIB_MEMORY is not set
+# CONFIG_RT_KSERVICE_USING_TINY_SIZE is not set
+# CONFIG_RT_USING_TINY_FFS is not set
+# CONFIG_RT_KPRINTF_USING_LONGLONG is not set
+# CONFIG_RT_DEBUG is not set
+
+#
+# Inter-Thread communication
+#
+CONFIG_RT_USING_SEMAPHORE=y
+CONFIG_RT_USING_MUTEX=y
+# CONFIG_RT_USING_EVENT is not set
+CONFIG_RT_USING_MAILBOX=y
+# CONFIG_RT_USING_MESSAGEQUEUE is not set
+# CONFIG_RT_USING_SIGNALS is not set
+
+#
+# Memory Management
+#
+CONFIG_RT_USING_MEMPOOL=y
+CONFIG_RT_USING_SMALL_MEM=y
+# CONFIG_RT_USING_SLAB is not set
+# CONFIG_RT_USING_MEMHEAP is not set
+CONFIG_RT_USING_SMALL_MEM_AS_HEAP=y
+# CONFIG_RT_USING_MEMHEAP_AS_HEAP is not set
+# CONFIG_RT_USING_SLAB_AS_HEAP is not set
+# CONFIG_RT_USING_USERHEAP is not set
+# CONFIG_RT_USING_NOHEAP is not set
+# CONFIG_RT_USING_MEMTRACE is not set
+# CONFIG_RT_USING_HEAP_ISR is not set
+CONFIG_RT_USING_HEAP=y
+
+#
+# Kernel Device Object
+#
+CONFIG_RT_USING_DEVICE=y
+# CONFIG_RT_USING_DEVICE_OPS is not set
+CONFIG_RT_USING_INTERRUPT_INFO=y
+CONFIG_RT_USING_CONSOLE=y
+CONFIG_RT_CONSOLEBUF_SIZE=128
+CONFIG_RT_CONSOLE_DEVICE_NAME="uart1"
+CONFIG_RT_VER_NUM=0x40101
+# CONFIG_RT_USING_CPU_FFS is not set
+CONFIG_ARCH_RISCV=y
+# CONFIG_ARCH_CPU_STACK_GROWS_UPWARD is not set
+
+#
+# RT-Thread Components
+#
+CONFIG_RT_USING_COMPONENTS_INIT=y
+CONFIG_RT_USING_USER_MAIN=y
+CONFIG_RT_MAIN_THREAD_STACK_SIZE=2048
+CONFIG_RT_MAIN_THREAD_PRIORITY=10
+# CONFIG_RT_USING_LEGACY is not set
+CONFIG_RT_USING_MSH=y
+CONFIG_RT_USING_FINSH=y
+CONFIG_FINSH_USING_MSH=y
+CONFIG_FINSH_THREAD_NAME="tshell"
+CONFIG_FINSH_THREAD_PRIORITY=20
+CONFIG_FINSH_THREAD_STACK_SIZE=4096
+CONFIG_FINSH_USING_HISTORY=y
+CONFIG_FINSH_HISTORY_LINES=5
+CONFIG_FINSH_USING_SYMTAB=y
+CONFIG_FINSH_CMD_SIZE=80
+CONFIG_MSH_USING_BUILT_IN_COMMANDS=y
+CONFIG_FINSH_USING_DESCRIPTION=y
+# CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set
+# CONFIG_FINSH_USING_AUTH is not set
+CONFIG_FINSH_ARG_MAX=10
+# CONFIG_RT_USING_DFS is not set
+# CONFIG_RT_USING_FAL is not set
+
+#
+# Device Drivers
+#
+CONFIG_RT_USING_DEVICE_IPC=y
+# CONFIG_RT_USING_SYSTEM_WORKQUEUE is not set
+CONFIG_RT_USING_SERIAL=y
+CONFIG_RT_USING_SERIAL_V1=y
+# CONFIG_RT_USING_SERIAL_V2 is not set
+# CONFIG_RT_SERIAL_USING_DMA is not set
+CONFIG_RT_SERIAL_RB_BUFSZ=64
+# CONFIG_RT_USING_CAN is not set
+CONFIG_RT_USING_HWTIMER=y
+# CONFIG_RT_USING_CPUTIME is not set
+# CONFIG_RT_USING_I2C is not set
+# CONFIG_RT_USING_PHY is not set
+CONFIG_RT_USING_PIN=y
+# CONFIG_RT_USING_ADC is not set
+# CONFIG_RT_USING_DAC is not set
+# CONFIG_RT_USING_PWM is not set
+# CONFIG_RT_USING_MTD_NOR is not set
+# CONFIG_RT_USING_MTD_NAND is not set
+# CONFIG_RT_USING_PM is not set
+# CONFIG_RT_USING_RTC is not set
+# CONFIG_RT_USING_SDIO is not set
+# CONFIG_RT_USING_SPI is not set
+CONFIG_RT_USING_WDT=y
+# CONFIG_RT_USING_AUDIO is not set
+# CONFIG_RT_USING_SENSOR is not set
+# CONFIG_RT_USING_TOUCH is not set
+# CONFIG_RT_USING_HWCRYPTO is not set
+# CONFIG_RT_USING_PULSE_ENCODER is not set
+# CONFIG_RT_USING_INPUT_CAPTURE is not set
+# CONFIG_RT_USING_WIFI is not set
+
+#
+# Using USB
+#
+# CONFIG_RT_USING_USB is not set
+# CONFIG_RT_USING_USB_HOST is not set
+# CONFIG_RT_USING_USB_DEVICE is not set
+
+#
+# C/C++ and POSIX layer
+#
+CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
+
+#
+# POSIX (Portable Operating System Interface) layer
+#
+# CONFIG_RT_USING_POSIX_FS is not set
+# CONFIG_RT_USING_POSIX_DELAY is not set
+# CONFIG_RT_USING_POSIX_CLOCK is not set
+# CONFIG_RT_USING_POSIX_TIMER is not set
+# CONFIG_RT_USING_PTHREADS is not set
+# CONFIG_RT_USING_MODULE is not set
+
+#
+# Interprocess Communication (IPC)
+#
+# CONFIG_RT_USING_POSIX_PIPE is not set
+# CONFIG_RT_USING_POSIX_MESSAGE_QUEUE is not set
+# CONFIG_RT_USING_POSIX_MESSAGE_SEMAPHORE is not set
+
+#
+# Socket is in the 'Network' category
+#
+# CONFIG_RT_USING_CPLUSPLUS is not set
+
+#
+# Network
+#
+# CONFIG_RT_USING_SAL is not set
+# CONFIG_RT_USING_NETDEV is not set
+# CONFIG_RT_USING_LWIP is not set
+# CONFIG_RT_USING_AT is not set
+
+#
+# Utilities
+#
+# CONFIG_RT_USING_RYM is not set
+# CONFIG_RT_USING_ULOG is not set
+# CONFIG_RT_USING_UTEST is not set
+# CONFIG_RT_USING_VAR_EXPORT is not set
+# CONFIG_RT_USING_RT_LINK is not set
+# CONFIG_RT_USING_VBUS is not set
+
+#
+# RT-Thread Utestcases
+#
+# CONFIG_RT_USING_UTESTCASES is not set
+
+#
+# RT-Thread online packages
+#
+
+#
+# IoT - internet of things
+#
+# CONFIG_PKG_USING_LWIP is not set
+# CONFIG_PKG_USING_LORAWAN_DRIVER is not set
+# CONFIG_PKG_USING_PAHOMQTT is not set
+# CONFIG_PKG_USING_UMQTT is not set
+# CONFIG_PKG_USING_WEBCLIENT is not set
+# CONFIG_PKG_USING_WEBNET is not set
+# CONFIG_PKG_USING_MONGOOSE is not set
+# CONFIG_PKG_USING_MYMQTT is not set
+# CONFIG_PKG_USING_KAWAII_MQTT is not set
+# CONFIG_PKG_USING_BC28_MQTT is not set
+# CONFIG_PKG_USING_WEBTERMINAL is not set
+# CONFIG_PKG_USING_LIBMODBUS is not set
+# CONFIG_PKG_USING_FREEMODBUS is not set
+# CONFIG_PKG_USING_NANOPB is not set
+
+#
+# Wi-Fi
+#
+
+#
+# Marvell WiFi
+#
+# CONFIG_PKG_USING_WLANMARVELL is not set
+
+#
+# Wiced WiFi
+#
+# CONFIG_PKG_USING_WLAN_WICED is not set
+# CONFIG_PKG_USING_RW007 is not set
+# CONFIG_PKG_USING_COAP is not set
+# CONFIG_PKG_USING_NOPOLL is not set
+# CONFIG_PKG_USING_NETUTILS is not set
+# CONFIG_PKG_USING_CMUX is not set
+# CONFIG_PKG_USING_PPP_DEVICE is not set
+# CONFIG_PKG_USING_AT_DEVICE is not set
+# CONFIG_PKG_USING_ATSRV_SOCKET is not set
+# CONFIG_PKG_USING_WIZNET is not set
+# CONFIG_PKG_USING_ZB_COORDINATOR is not set
+
+#
+# IoT Cloud
+#
+# CONFIG_PKG_USING_ONENET is not set
+# CONFIG_PKG_USING_GAGENT_CLOUD is not set
+# CONFIG_PKG_USING_ALI_IOTKIT is not set
+# CONFIG_PKG_USING_AZURE is not set
+# CONFIG_PKG_USING_TENCENT_IOT_EXPLORER is not set
+# CONFIG_PKG_USING_JIOT-C-SDK is not set
+# CONFIG_PKG_USING_UCLOUD_IOT_SDK is not set
+# CONFIG_PKG_USING_JOYLINK is not set
+# CONFIG_PKG_USING_EZ_IOT_OS is not set
+# CONFIG_PKG_USING_IOTSHARP_SDK is not set
+# CONFIG_PKG_USING_NIMBLE is not set
+# CONFIG_PKG_USING_LLSYNC_SDK_ADAPTER is not set
+# CONFIG_PKG_USING_OTA_DOWNLOADER is not set
+# CONFIG_PKG_USING_IPMSG is not set
+# CONFIG_PKG_USING_LSSDP is not set
+# CONFIG_PKG_USING_AIRKISS_OPEN is not set
+# CONFIG_PKG_USING_LIBRWS is not set
+# CONFIG_PKG_USING_TCPSERVER is not set
+# CONFIG_PKG_USING_PROTOBUF_C is not set
+# CONFIG_PKG_USING_DLT645 is not set
+# CONFIG_PKG_USING_QXWZ is not set
+# CONFIG_PKG_USING_SMTP_CLIENT is not set
+# CONFIG_PKG_USING_ABUP_FOTA is not set
+# CONFIG_PKG_USING_LIBCURL2RTT is not set
+# CONFIG_PKG_USING_CAPNP is not set
+# CONFIG_PKG_USING_AGILE_TELNET is not set
+# CONFIG_PKG_USING_NMEALIB is not set
+# CONFIG_PKG_USING_PDULIB is not set
+# CONFIG_PKG_USING_BTSTACK is not set
+# CONFIG_PKG_USING_LORAWAN_ED_STACK is not set
+# CONFIG_PKG_USING_WAYZ_IOTKIT is not set
+# CONFIG_PKG_USING_MAVLINK is not set
+# CONFIG_PKG_USING_BSAL is not set
+# CONFIG_PKG_USING_AGILE_MODBUS is not set
+# CONFIG_PKG_USING_AGILE_FTP is not set
+# CONFIG_PKG_USING_EMBEDDEDPROTO is not set
+# CONFIG_PKG_USING_RT_LINK_HW is not set
+# CONFIG_PKG_USING_LORA_PKT_FWD is not set
+# CONFIG_PKG_USING_LORA_GW_DRIVER_LIB is not set
+# CONFIG_PKG_USING_LORA_PKT_SNIFFER is not set
+# CONFIG_PKG_USING_HM is not set
+# CONFIG_PKG_USING_SMALL_MODBUS is not set
+# CONFIG_PKG_USING_NET_SERVER is not set
+# CONFIG_PKG_USING_ZFTP is not set
+
+#
+# security packages
+#
+# CONFIG_PKG_USING_MBEDTLS is not set
+# CONFIG_PKG_USING_LIBSODIUM is not set
+# CONFIG_PKG_USING_LIBHYDROGEN is not set
+# CONFIG_PKG_USING_TINYCRYPT is not set
+# CONFIG_PKG_USING_TFM is not set
+# CONFIG_PKG_USING_YD_CRYPTO is not set
+
+#
+# language packages
+#
+
+#
+# JSON: JavaScript Object Notation, a lightweight data-interchange format
+#
+# CONFIG_PKG_USING_CJSON is not set
+# CONFIG_PKG_USING_LJSON is not set
+# CONFIG_PKG_USING_RT_CJSON_TOOLS is not set
+# CONFIG_PKG_USING_RAPIDJSON is not set
+# CONFIG_PKG_USING_JSMN is not set
+# CONFIG_PKG_USING_AGILE_JSMN is not set
+
+#
+# XML: Extensible Markup Language
+#
+# CONFIG_PKG_USING_SIMPLE_XML is not set
+# CONFIG_PKG_USING_EZXML is not set
+# CONFIG_PKG_USING_LUATOS_SOC is not set
+# CONFIG_PKG_USING_LUA is not set
+# CONFIG_PKG_USING_JERRYSCRIPT is not set
+# CONFIG_PKG_USING_MICROPYTHON is not set
+# CONFIG_PKG_USING_PIKASCRIPT is not set
+# CONFIG_PKG_USING_RTT_RUST is not set
+
+#
+# multimedia packages
+#
+
+#
+# LVGL: powerful and easy-to-use embedded GUI library
+#
+# CONFIG_PKG_USING_LVGL is not set
+# CONFIG_PKG_USING_LITTLEVGL2RTT is not set
+# CONFIG_PKG_USING_LV_MUSIC_DEMO is not set
+# CONFIG_PKG_USING_GUI_GUIDER_DEMO is not set
+
+#
+# u8g2: a monochrome graphic library
+#
+# CONFIG_PKG_USING_U8G2_OFFICIAL is not set
+# CONFIG_PKG_USING_U8G2 is not set
+# CONFIG_PKG_USING_OPENMV is not set
+# CONFIG_PKG_USING_MUPDF is not set
+# CONFIG_PKG_USING_STEMWIN is not set
+# CONFIG_PKG_USING_WAVPLAYER is not set
+# CONFIG_PKG_USING_TJPGD is not set
+# CONFIG_PKG_USING_PDFGEN is not set
+# CONFIG_PKG_USING_HELIX is not set
+# CONFIG_PKG_USING_AZUREGUIX is not set
+# CONFIG_PKG_USING_TOUCHGFX2RTT is not set
+# CONFIG_PKG_USING_NUEMWIN is not set
+# CONFIG_PKG_USING_MP3PLAYER is not set
+# CONFIG_PKG_USING_TINYJPEG is not set
+# CONFIG_PKG_USING_UGUI is not set
+
+#
+# PainterEngine: A cross-platform graphics application framework written in C language
+#
+# CONFIG_PKG_USING_PAINTERENGINE is not set
+# CONFIG_PKG_USING_PAINTERENGINE_AUX is not set
+# CONFIG_PKG_USING_MCURSES is not set
+# CONFIG_PKG_USING_TERMBOX is not set
+# CONFIG_PKG_USING_VT100 is not set
+# CONFIG_PKG_USING_QRCODE is not set
+# CONFIG_PKG_USING_GUIENGINE is not set
+
+#
+# tools packages
+#
+# CONFIG_PKG_USING_CMBACKTRACE is not set
+# CONFIG_PKG_USING_EASYFLASH is not set
+# CONFIG_PKG_USING_EASYLOGGER is not set
+# CONFIG_PKG_USING_SYSTEMVIEW is not set
+# CONFIG_PKG_USING_SEGGER_RTT is not set
+# CONFIG_PKG_USING_RDB is not set
+# CONFIG_PKG_USING_ULOG_EASYFLASH is not set
+# CONFIG_PKG_USING_ULOG_FILE is not set
+# CONFIG_PKG_USING_LOGMGR is not set
+# CONFIG_PKG_USING_ADBD is not set
+# CONFIG_PKG_USING_COREMARK is not set
+# CONFIG_PKG_USING_DHRYSTONE is not set
+# CONFIG_PKG_USING_MEMORYPERF is not set
+# CONFIG_PKG_USING_NR_MICRO_SHELL is not set
+# CONFIG_PKG_USING_CHINESE_FONT_LIBRARY is not set
+# CONFIG_PKG_USING_LUNAR_CALENDAR is not set
+# CONFIG_PKG_USING_BS8116A is not set
+# CONFIG_PKG_USING_GPS_RMC is not set
+# CONFIG_PKG_USING_URLENCODE is not set
+# CONFIG_PKG_USING_UMCN is not set
+# CONFIG_PKG_USING_LWRB2RTT is not set
+# CONFIG_PKG_USING_CPU_USAGE is not set
+# CONFIG_PKG_USING_GBK2UTF8 is not set
+# CONFIG_PKG_USING_VCONSOLE is not set
+# CONFIG_PKG_USING_KDB is not set
+# CONFIG_PKG_USING_WAMR is not set
+# CONFIG_PKG_USING_MICRO_XRCE_DDS_CLIENT is not set
+# CONFIG_PKG_USING_LWLOG is not set
+# CONFIG_PKG_USING_ANV_TRACE is not set
+# CONFIG_PKG_USING_ANV_MEMLEAK is not set
+# CONFIG_PKG_USING_ANV_TESTSUIT is not set
+# CONFIG_PKG_USING_ANV_BENCH is not set
+# CONFIG_PKG_USING_DEVMEM is not set
+# CONFIG_PKG_USING_REGEX is not set
+# CONFIG_PKG_USING_MEM_SANDBOX is not set
+# CONFIG_PKG_USING_SOLAR_TERMS is not set
+# CONFIG_PKG_USING_GAN_ZHI is not set
+# CONFIG_PKG_USING_FDT is not set
+# CONFIG_PKG_USING_CBOX is not set
+# CONFIG_PKG_USING_SNOWFLAKE is not set
+# CONFIG_PKG_USING_HASH_MATCH is not set
+# CONFIG_PKG_USING_FIRE_PID_CURVE is not set
+# CONFIG_PKG_USING_ARMV7M_DWT_TOOL is not set
+
+#
+# system packages
+#
+
+#
+# enhanced kernel services
+#
+# CONFIG_PKG_USING_RT_MEMCPY_CM is not set
+# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
+# CONFIG_PKG_USING_RT_VSNPRINTF_FULL is not set
+
+#
+# acceleration: Assembly language or algorithmic acceleration packages
+#
+# CONFIG_PKG_USING_QFPLIB_M0_FULL is not set
+# CONFIG_PKG_USING_QFPLIB_M0_TINY is not set
+# CONFIG_PKG_USING_QFPLIB_M3 is not set
+
+#
+# CMSIS: ARM Cortex-M Microcontroller Software Interface Standard
+#
+# CONFIG_PKG_USING_CMSIS_5 is not set
+# CONFIG_PKG_USING_CMSIS_RTOS1 is not set
+# CONFIG_PKG_USING_CMSIS_RTOS2 is not set
+
+#
+# Micrium: Micrium software products porting for RT-Thread
+#
+# CONFIG_PKG_USING_UCOSIII_WRAPPER is not set
+# CONFIG_PKG_USING_UCOSII_WRAPPER is not set
+# CONFIG_PKG_USING_UC_CRC is not set
+# CONFIG_PKG_USING_UC_CLK is not set
+# CONFIG_PKG_USING_UC_COMMON is not set
+# CONFIG_PKG_USING_UC_MODBUS is not set
+# CONFIG_PKG_USING_RTDUINO is not set
+# CONFIG_PKG_USING_CAIRO is not set
+# CONFIG_PKG_USING_PIXMAN is not set
+# CONFIG_PKG_USING_PARTITION is not set
+# CONFIG_PKG_USING_PERF_COUNTER is not set
+# CONFIG_PKG_USING_FLASHDB is not set
+# CONFIG_PKG_USING_SQLITE is not set
+# CONFIG_PKG_USING_RTI is not set
+# CONFIG_PKG_USING_DFS_YAFFS is not set
+# CONFIG_PKG_USING_LITTLEFS is not set
+# CONFIG_PKG_USING_DFS_JFFS2 is not set
+# CONFIG_PKG_USING_DFS_UFFS is not set
+# CONFIG_PKG_USING_LWEXT4 is not set
+# CONFIG_PKG_USING_THREAD_POOL is not set
+# CONFIG_PKG_USING_ROBOTS is not set
+# CONFIG_PKG_USING_EV is not set
+# CONFIG_PKG_USING_SYSWATCH is not set
+# CONFIG_PKG_USING_SYS_LOAD_MONITOR is not set
+# CONFIG_PKG_USING_PLCCORE is not set
+# CONFIG_PKG_USING_RAMDISK is not set
+# CONFIG_PKG_USING_MININI is not set
+# CONFIG_PKG_USING_QBOOT is not set
+# CONFIG_PKG_USING_PPOOL is not set
+# CONFIG_PKG_USING_OPENAMP is not set
+# CONFIG_PKG_USING_LPM is not set
+# CONFIG_PKG_USING_TLSF is not set
+# CONFIG_PKG_USING_EVENT_RECORDER is not set
+# CONFIG_PKG_USING_ARM_2D is not set
+# CONFIG_PKG_USING_MCUBOOT is not set
+# CONFIG_PKG_USING_TINYUSB is not set
+# CONFIG_PKG_USING_CHERRYUSB is not set
+# CONFIG_PKG_USING_KMULTI_RTIMER is not set
+# CONFIG_PKG_USING_TFDB is not set
+# CONFIG_PKG_USING_QPC is not set
+
+#
+# peripheral libraries and drivers
+#
+# CONFIG_PKG_USING_SENSORS_DRIVERS is not set
+# CONFIG_PKG_USING_REALTEK_AMEBA is not set
+# CONFIG_PKG_USING_SHT2X is not set
+# CONFIG_PKG_USING_SHT3X is not set
+# CONFIG_PKG_USING_AS7341 is not set
+# CONFIG_PKG_USING_STM32_SDIO is not set
+# CONFIG_PKG_USING_ICM20608 is not set
+# CONFIG_PKG_USING_BUTTON is not set
+# CONFIG_PKG_USING_PCF8574 is not set
+# CONFIG_PKG_USING_SX12XX is not set
+# CONFIG_PKG_USING_SIGNAL_LED is not set
+# CONFIG_PKG_USING_LEDBLINK is not set
+# CONFIG_PKG_USING_LITTLED is not set
+# CONFIG_PKG_USING_LKDGUI is not set
+# CONFIG_PKG_USING_NRF5X_SDK is not set
+# CONFIG_PKG_USING_NRFX is not set
+# CONFIG_PKG_USING_WM_LIBRARIES is not set
+# CONFIG_PKG_USING_KENDRYTE_SDK is not set
+# CONFIG_PKG_USING_INFRARED is not set
+# CONFIG_PKG_USING_MULTI_INFRARED is not set
+# CONFIG_PKG_USING_AGILE_BUTTON is not set
+# CONFIG_PKG_USING_AGILE_LED is not set
+# CONFIG_PKG_USING_AT24CXX is not set
+# CONFIG_PKG_USING_MOTIONDRIVER2RTT is not set
+# CONFIG_PKG_USING_AD7746 is not set
+# CONFIG_PKG_USING_PCA9685 is not set
+# CONFIG_PKG_USING_I2C_TOOLS is not set
+# CONFIG_PKG_USING_NRF24L01 is not set
+# CONFIG_PKG_USING_TOUCH_DRIVERS is not set
+# CONFIG_PKG_USING_MAX17048 is not set
+# CONFIG_PKG_USING_RPLIDAR is not set
+# CONFIG_PKG_USING_AS608 is not set
+# CONFIG_PKG_USING_RC522 is not set
+# CONFIG_PKG_USING_WS2812B is not set
+# CONFIG_PKG_USING_EMBARC_BSP is not set
+# CONFIG_PKG_USING_EXTERN_RTC_DRIVERS is not set
+# CONFIG_PKG_USING_MULTI_RTIMER is not set
+# CONFIG_PKG_USING_MAX7219 is not set
+# CONFIG_PKG_USING_BEEP is not set
+# CONFIG_PKG_USING_EASYBLINK is not set
+# CONFIG_PKG_USING_PMS_SERIES is not set
+# CONFIG_PKG_USING_NUCLEI_SDK is not set
+# CONFIG_PKG_USING_CAN_YMODEM is not set
+# CONFIG_PKG_USING_LORA_RADIO_DRIVER is not set
+# CONFIG_PKG_USING_QLED is not set
+# CONFIG_PKG_USING_PAJ7620 is not set
+# CONFIG_PKG_USING_AGILE_CONSOLE is not set
+# CONFIG_PKG_USING_LD3320 is not set
+# CONFIG_PKG_USING_WK2124 is not set
+# CONFIG_PKG_USING_LY68L6400 is not set
+# CONFIG_PKG_USING_DM9051 is not set
+# CONFIG_PKG_USING_SSD1306 is not set
+# CONFIG_PKG_USING_QKEY is not set
+# CONFIG_PKG_USING_RS485 is not set
+# CONFIG_PKG_USING_RS232 is not set
+# CONFIG_PKG_USING_NES is not set
+# CONFIG_PKG_USING_VIRTUAL_SENSOR is not set
+# CONFIG_PKG_USING_VDEVICE is not set
+# CONFIG_PKG_USING_SGM706 is not set
+# CONFIG_PKG_USING_STM32WB55_SDK is not set
+# CONFIG_PKG_USING_RDA58XX is not set
+# CONFIG_PKG_USING_LIBNFC is not set
+# CONFIG_PKG_USING_MFOC is not set
+# CONFIG_PKG_USING_TMC51XX is not set
+# CONFIG_PKG_USING_TCA9534 is not set
+# CONFIG_PKG_USING_KOBUKI is not set
+# CONFIG_PKG_USING_ROSSERIAL is not set
+# CONFIG_PKG_USING_MICRO_ROS is not set
+# CONFIG_PKG_USING_MCP23008 is not set
+# CONFIG_PKG_USING_BLUETRUM_SDK is not set
+# CONFIG_PKG_USING_MISAKA_AT24CXX is not set
+# CONFIG_PKG_USING_MISAKA_RGB_BLING is not set
+# CONFIG_PKG_USING_LORA_MODEM_DRIVER is not set
+# CONFIG_PKG_USING_BL_MCU_SDK is not set
+# CONFIG_PKG_USING_SOFT_SERIAL is not set
+# CONFIG_PKG_USING_MB85RS16 is not set
+# CONFIG_PKG_USING_CW2015 is not set
+# CONFIG_PKG_USING_RFM300 is not set
+
+#
+# AI packages
+#
+# CONFIG_PKG_USING_LIBANN is not set
+# CONFIG_PKG_USING_NNOM is not set
+# CONFIG_PKG_USING_ONNX_BACKEND is not set
+# CONFIG_PKG_USING_ONNX_PARSER is not set
+# CONFIG_PKG_USING_TENSORFLOWLITEMICRO is not set
+# CONFIG_PKG_USING_ELAPACK is not set
+# CONFIG_PKG_USING_ULAPACK is not set
+# CONFIG_PKG_USING_QUEST is not set
+# CONFIG_PKG_USING_NAXOS is not set
+
+#
+# miscellaneous packages
+#
+
+#
+# project laboratory
+#
+
+#
+# samples: kernel and components samples
+#
+# CONFIG_PKG_USING_KERNEL_SAMPLES is not set
+# CONFIG_PKG_USING_FILESYSTEM_SAMPLES is not set
+# CONFIG_PKG_USING_NETWORK_SAMPLES is not set
+# CONFIG_PKG_USING_PERIPHERAL_SAMPLES is not set
+
+#
+# entertainment: terminal games and other interesting software packages
+#
+# CONFIG_PKG_USING_CMATRIX is not set
+# CONFIG_PKG_USING_SL is not set
+# CONFIG_PKG_USING_CAL is not set
+# CONFIG_PKG_USING_ACLOCK is not set
+# CONFIG_PKG_USING_THREES is not set
+# CONFIG_PKG_USING_2048 is not set
+# CONFIG_PKG_USING_SNAKE is not set
+# CONFIG_PKG_USING_TETRIS is not set
+# CONFIG_PKG_USING_DONUT is not set
+# CONFIG_PKG_USING_COWSAY is not set
+# CONFIG_PKG_USING_LIBCSV is not set
+# CONFIG_PKG_USING_OPTPARSE is not set
+# CONFIG_PKG_USING_FASTLZ is not set
+# CONFIG_PKG_USING_MINILZO is not set
+# CONFIG_PKG_USING_QUICKLZ is not set
+# CONFIG_PKG_USING_LZMA is not set
+# CONFIG_PKG_USING_MULTIBUTTON is not set
+# CONFIG_PKG_USING_FLEXIBLE_BUTTON is not set
+# CONFIG_PKG_USING_CANFESTIVAL is not set
+# CONFIG_PKG_USING_ZLIB is not set
+# CONFIG_PKG_USING_MINIZIP is not set
+# CONFIG_PKG_USING_HEATSHRINK is not set
+# CONFIG_PKG_USING_DSTR is not set
+# CONFIG_PKG_USING_TINYFRAME is not set
+# CONFIG_PKG_USING_KENDRYTE_DEMO is not set
+# CONFIG_PKG_USING_DIGITALCTRL is not set
+# CONFIG_PKG_USING_UPACKER is not set
+# CONFIG_PKG_USING_UPARAM is not set
+# CONFIG_PKG_USING_HELLO is not set
+# CONFIG_PKG_USING_VI is not set
+# CONFIG_PKG_USING_KI is not set
+# CONFIG_PKG_USING_ARMv7M_DWT is not set
+# CONFIG_PKG_USING_UKAL is not set
+# CONFIG_PKG_USING_CRCLIB is not set
+# CONFIG_PKG_USING_LWGPS is not set
+# CONFIG_PKG_USING_STATE_MACHINE is not set
+# CONFIG_PKG_USING_DESIGN_PATTERN is not set
+# CONFIG_PKG_USING_CONTROLLER is not set
+# CONFIG_PKG_USING_PHASE_LOCKED_LOOP is not set
+# CONFIG_PKG_USING_MFBD is not set
+# CONFIG_PKG_USING_SLCAN2RTT is not set
+# CONFIG_PKG_USING_SOEM is not set
+CONFIG_SOC_FAMILY_CH56X=y
+CONFIG_SOC_SERIES_CH569=y
+
+#
+# Hardware Drivers Config
+#
+CONFIG_SOC_CH569W=y
+
+#
+# On-chip Peripheral Drivers
+#
+CONFIG_BSP_USING_UART=y
+# CONFIG_BSP_USING_UART0 is not set
+CONFIG_BSP_USING_UART1=y
+# CONFIG_BSP_USING_UART2 is not set
+# CONFIG_BSP_USING_UART3 is not set
+CONFIG_BSP_USING_TIMER=y
+CONFIG_BSP_USING_TMR0=y
+CONFIG_BSP_USING_TMR1=y
+# CONFIG_BSP_USING_TMR2 is not set
+
+#
+# Onboard Peripheral Drivers
+#
+
+#
+# Board extended module Drivers
+#
diff --git a/bsp/wch/risc-v/ch569w-evt/Kconfig b/bsp/wch/risc-v/ch569w-evt/Kconfig
new file mode 100644
index 0000000000..c80a8958fd
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/Kconfig
@@ -0,0 +1,21 @@
+mainmenu "RT-Thread Configuration"
+
+config BSP_DIR
+ string
+ option env="BSP_ROOT"
+ default "."
+
+config RTT_DIR
+ string
+ option env="RTT_ROOT"
+ default "../../../.."
+
+config PKGS_DIR
+ string
+ option env="PKGS_ROOT"
+ default "packages"
+
+source "$RTT_DIR/Kconfig"
+source "$PKGS_DIR/Kconfig"
+source "../Libraries/Kconfig"
+source "board/Kconfig"
diff --git a/bsp/wch/risc-v/ch569w-evt/SConscript b/bsp/wch/risc-v/ch569w-evt/SConscript
new file mode 100644
index 0000000000..fab6e36f21
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/SConscript
@@ -0,0 +1,13 @@
+import os
+from building import *
+
+objs = []
+
+cwd = GetCurrentDir()
+list = os.listdir(cwd)
+
+for d in list:
+ if os.path.isfile(os.path.join(cwd, d, 'SConscript')):
+ objs = objs + SConscript(os.path.join(d, 'SConscript'))
+
+Return('objs')
diff --git a/bsp/wch/risc-v/ch569w-evt/SConstruct b/bsp/wch/risc-v/ch569w-evt/SConstruct
new file mode 100644
index 0000000000..0264ce6202
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/SConstruct
@@ -0,0 +1,38 @@
+import os
+import sys
+import rtconfig
+
+if os.getenv('RTT_ROOT'):
+ RTT_ROOT = os.getenv('RTT_ROOT')
+else:
+ RTT_ROOT = os.path.normpath(os.getcwd() + '/../../../..')
+
+sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')]
+try:
+ from building import *
+except:
+ print('Cannot find RT-Thread root directory, please check RTT_ROOT')
+ print('RTT_ROOT: ' + RTT_ROOT)
+ exit(-1)
+
+TARGET = 'rtthread.' + rtconfig.TARGET_EXT
+
+DefaultEnvironment(tools=[])
+env = Environment(tools = ['mingw'],
+ AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS,
+ CC = rtconfig.CC, CFLAGS = rtconfig.CFLAGS,
+ AR = rtconfig.AR, ARFLAGS = '-rc',
+ LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
+env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
+
+Export('RTT_ROOT')
+Export('rtconfig')
+
+# prepare building environment
+objs = PrepareBuilding(env, RTT_ROOT, has_libcpu=False)
+
+objs.extend(SConscript('../Libraries/ch56x_drivers/SConscript',
+ variant_dir='build/libraries/ch56x_drivers', duplicate=0))
+
+# make a building
+DoBuilding(TARGET, objs)
diff --git a/bsp/wch/risc-v/ch569w-evt/applications/SConscript b/bsp/wch/risc-v/ch569w-evt/applications/SConscript
new file mode 100644
index 0000000000..72c14ab8db
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/applications/SConscript
@@ -0,0 +1,13 @@
+from building import *
+
+cwd = GetCurrentDir()
+
+src = Split("""
+main.c
+""")
+
+path = [cwd, str(Dir('#'))]
+
+group = DefineGroup('Applications', src, depend=[''], CPPPATH=path)
+
+Return('group')
diff --git a/bsp/wch/risc-v/ch569w-evt/applications/main.c b/bsp/wch/risc-v/ch569w-evt/applications/main.c
new file mode 100644
index 0000000000..3c126ce04f
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/applications/main.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ * 2022-07-20 Emuzit add watchdog test
+ * 2022-07-26 Emuzit add hwtimer test
+ */
+#include <rtthread.h>
+#include <rtdebug.h>
+#include <drivers/pin.h>
+#include <drivers/watchdog.h>
+#include <drivers/hwtimer.h>
+#include "board.h"
+
+static const rt_base_t gpio_int_pins[8] = GPIO_INT_PINS;
+
+/* note : PIN_IRQ_MODE_RISING_FALLING not supported */
+static const uint32_t gpint_mode[] =
+{
+ PIN_IRQ_MODE_RISING,
+ PIN_IRQ_MODE_RISING,
+ PIN_IRQ_MODE_RISING,
+ PIN_IRQ_MODE_RISING,
+ PIN_IRQ_MODE_FALLING,
+ PIN_IRQ_MODE_FALLING,
+ PIN_IRQ_MODE_FALLING,
+ PIN_IRQ_MODE_FALLING,
+};
+
+static struct rt_mailbox *gpint_mb = RT_NULL;
+static struct rt_thread *gpint_thread = RT_NULL;
+
+static rt_base_t led0, led1;
+
+static rt_device_t wdg_dev;
+
+static struct rt_device *tmr_dev_0;
+static struct rt_device *tmr_dev_1;
+
+static void gpio_int_callback(void *pin)
+{
+ led1 = (led1 == PIN_LOW) ? PIN_HIGH : PIN_LOW;
+ rt_pin_write(LED1_PIN, led1);
+
+ if (gpint_mb != RT_NULL)
+ {
+ /* non-block, silently ignore RT_EFULL */
+ rt_mb_send(gpint_mb, (uint32_t)pin);
+ }
+}
+
+static void gpio_int_thread(void *param)
+{
+ while (1)
+ {
+ rt_err_t res;
+ uint32_t pin;
+
+ res = rt_mb_recv(gpint_mb, &pin, RT_WAITING_FOREVER);
+ if (res == RT_EOK)
+ {
+ rt_kprintf("gpio_int #%d (%d)\n", pin, rt_pin_read(pin));
+ }
+ rt_thread_mdelay(100);
+
+#ifdef RT_USING_WDT
+ rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_KEEPALIVE, RT_NULL);
+#endif
+ }
+}
+
+#ifdef RT_USING_HWTIMER
+static rt_err_t tmr_timeout_cb(rt_device_t dev, rt_size_t size)
+{
+ rt_tick_t tick = rt_tick_get();
+
+ int tmr = (dev == tmr_dev_1) ? 1 : 0;
+
+ rt_kprintf("hwtimer %d timeout callback fucntion @tick %d\n", tmr, tick);
+
+ return RT_EOK;
+}
+#endif
+
+void main(void)
+{
+ rt_hwtimerval_t timerval;
+ rt_hwtimer_mode_t mode;
+ rt_size_t tsize;
+
+ uint32_t seconds;
+ rt_err_t res;
+
+ int i;
+
+ rt_kprintf("\nCH569W-R0-1v0, HCLK: %dMHz\n\n", sys_hclk_get() / 1000000);
+
+ /* Enable all gpio interrupt with various modes.
+ * LED0 or GND touching can be used to trigger pin interrupt.
+ */
+ gpint_mb = rt_mb_create("pximb", 8, RT_IPC_FLAG_FIFO);
+ if (gpint_mb == RT_NULL)
+ {
+ rt_kprintf("gpint mailbox create failed !\n");
+ }
+ else
+ {
+ gpint_thread = rt_thread_create("pxith", gpio_int_thread, RT_NULL,
+ 512, RT_MAIN_THREAD_PRIORITY, 50);
+ if (gpint_thread == RT_NULL)
+ {
+ rt_kprintf("gpint thread create failed !\n");
+ }
+ else
+ {
+ rt_thread_startup(gpint_thread);
+
+ for (i = 0; i < 8; i++)
+ {
+ rt_base_t pin = gpio_int_pins[i];
+ rt_pin_mode(pin, PIN_MODE_INPUT_PULLUP);
+ res = rt_pin_attach_irq(
+ pin, gpint_mode[i], gpio_int_callback, (void *)pin);
+ if (res != RT_EOK)
+ {
+ rt_kprintf("rt_pin_attach_irq failed (%d:%d)\n", i, res);
+ }
+ else
+ {
+ rt_pin_irq_enable(pin, PIN_IRQ_ENABLE);
+ }
+ }
+ }
+ }
+
+#ifdef RT_USING_WDT
+ /* Test watchdog with 30s timeout, keepalive with gpio interrupt.
+ *
+ * CAVEAT: With only 8-bit WDOG_COUNT and fixed clocking at Fsys/524288,
+ * watchdog of ch56x may be quite limited with very short timeout.
+ */
+ seconds = 30;
+ wdg_dev = rt_device_find("wdt");
+ if (!wdg_dev)
+ {
+ rt_kprintf("watchdog device not found !\n");
+ }
+ else if (rt_device_init(wdg_dev) != RT_EOK ||
+ rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &seconds) != RT_EOK)
+ {
+ rt_kprintf("watchdog setup failed !\n");
+ }
+ else
+ {
+ rt_kprintf("WDT_TIMEOUT in %d seconds, trigger gpio interrupt to keep alive.\n\n", seconds);
+ }
+#endif
+
+#ifdef RT_USING_HWTIMER
+ /* setup two timers, ONESHOT & PERIOD each
+ */
+ tmr_dev_0 = rt_device_find("timer0");
+ tmr_dev_1 = rt_device_find("timer1");
+ if (tmr_dev_0 == RT_NULL || tmr_dev_1 == RT_NULL)
+ {
+ rt_kprintf("hwtimer device(s) not found !\n");
+ }
+ else if (rt_device_open(tmr_dev_0, RT_DEVICE_OFLAG_RDWR) != RT_EOK ||
+ rt_device_open(tmr_dev_1, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
+ {
+ rt_kprintf("hwtimer device(s) open failed !\n");
+ }
+ else
+ {
+ rt_device_set_rx_indicate(tmr_dev_0, tmr_timeout_cb);
+ rt_device_set_rx_indicate(tmr_dev_1, tmr_timeout_cb);
+
+ timerval.sec = 3;
+ timerval.usec = 500000;
+ tsize = sizeof(timerval);
+ mode = HWTIMER_MODE_ONESHOT;
+ if (rt_device_control(tmr_dev_0, HWTIMER_CTRL_MODE_SET, &mode) != RT_EOK)
+ {
+ rt_kprintf("timer0 set mode failed !\n");
+ }
+ else if (rt_device_write(tmr_dev_0, 0, &timerval, tsize) != tsize)
+ {
+ rt_kprintf("timer0 start failed !\n");
+ }
+ else
+ {
+ rt_kprintf("timer0 started !\n");
+ }
+
+ timerval.sec = 5;
+ timerval.usec = 0;
+ tsize = sizeof(timerval);
+ mode = HWTIMER_MODE_PERIOD;
+ if (rt_device_control(tmr_dev_1, HWTIMER_CTRL_MODE_SET, &mode) != RT_EOK)
+ {
+ rt_kprintf("timer1 set mode failed !\n");
+ }
+ else if (rt_device_write(tmr_dev_1, 0, &timerval, tsize) != tsize)
+ {
+ rt_kprintf("timer1 start failed !\n");
+ }
+ else
+ {
+ rt_kprintf("timer1 started !\n");
+ }
+ }
+#endif
+
+ rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
+ rt_pin_write(LED1_PIN, led1 = PIN_HIGH);
+
+ rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
+ rt_pin_write(LED0_PIN, led0 = PIN_LOW);
+
+ while (1)
+ {
+ /* flashing LED0 every 1 second */
+ rt_thread_mdelay(500);
+ led0 = (led0 == PIN_LOW) ? PIN_HIGH : PIN_LOW;
+ rt_pin_write(LED0_PIN, led0);
+ }
+}
diff --git a/bsp/wch/risc-v/ch569w-evt/board/Kconfig b/bsp/wch/risc-v/ch569w-evt/board/Kconfig
new file mode 100644
index 0000000000..80a2613d03
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/board/Kconfig
@@ -0,0 +1,64 @@
+menu "Hardware Drivers Config"
+
+config SOC_CH569W
+ bool
+ select SOC_FAMILY_CH56X
+ select SOC_SERIES_CH569
+ select RT_USING_COMPONENTS_INIT
+ select RT_USING_USER_MAIN
+ default y
+
+menu "On-chip Peripheral Drivers"
+
+config BSP_USING_UART
+ bool "using on-chip uart"
+ select RT_USING_SERIAL
+ default y
+
+ if BSP_USING_UART
+ config BSP_USING_UART0
+ bool "using UART0"
+ default n
+
+ config BSP_USING_UART1
+ bool "using UART1"
+ default y
+
+ config BSP_USING_UART2
+ bool "using UART2"
+ default n
+
+ config BSP_USING_UART3
+ bool "using UART3"
+ default n
+ endif
+
+config BSP_USING_TIMER
+ bool "using on-chip timer"
+ select RT_USING_HWTIMER
+ default n
+
+ if BSP_USING_TIMER
+ config BSP_USING_TMR0
+ bool "using TMR0"
+ default y
+
+ config BSP_USING_TMR1
+ bool "using TMR1"
+ default n
+
+ config BSP_USING_TMR2
+ bool "using TMR2"
+ default n
+ endif
+endmenu
+
+menu "Onboard Peripheral Drivers"
+
+endmenu
+
+menu "Board extended module Drivers"
+
+endmenu
+
+endmenu
diff --git a/bsp/wch/risc-v/ch569w-evt/board/SConscript b/bsp/wch/risc-v/ch569w-evt/board/SConscript
new file mode 100644
index 0000000000..fee2061360
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/board/SConscript
@@ -0,0 +1,13 @@
+from building import *
+
+cwd = GetCurrentDir()
+
+src = Split('''
+board.c
+startup_gcc.S
+''')
+
+path = [cwd]
+
+group = DefineGroup('Drivers', src, depend=[''], CPPPATH=path)
+Return('group')
diff --git a/bsp/wch/risc-v/ch569w-evt/board/board.c b/bsp/wch/risc-v/ch569w-evt/board/board.c
new file mode 100644
index 0000000000..6b4b6dbc81
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/board/board.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#include <rthw.h>
+#include <drivers/pin.h>
+#include "board.h"
+#include "ch56x_pfic.h"
+#include "ch56x_uart.h"
+
+extern rt_uint32_t rt_thread_switch_interrupt_flag;
+
+/* FIXME: Use rt_interrupt_leave_hook to trigger SWI for context switch.
+ * Hopefully there's a standard riscv way instead of this clumsy patch.
+*/
+static void irq_leave_hook(void)
+{
+ if (rt_thread_switch_interrupt_flag)
+ {
+ pfic_swi_pendset();
+ }
+}
+
+/*
+ * _start -> handle_reset
+ * src/components.c/entry() -> rtthread_startup()
+ * libcpu/risc-v/common/context_gcc.S/rt_hw_interrupt_disable
+ */
+void rt_hw_board_init()
+{
+ volatile struct pfic_registers *pfic = (void *)PFIC_REG_BASE;
+
+ /* disable all pfic interrupts */
+ pfic->IRER[0] = PFIC_IREG1_MASK;
+ pfic->IRER[1] = PFIC_IREG2_MASK;
+
+ /* disable hwstack push/pop & nested interrupt */
+ pfic->CFGR = cfgr_nest_hwstk(CFGR_NESTCTRL_DISABLE | CFGR_HWSTKCTRL_DISABLE);
+
+ /* disable clock input for all peripheral devices */
+ sys_slp_clk_off0(0xff, SYS_SLP_CLK_OFF);
+ sys_slp_clk_off1(0xff, SYS_SLP_CLK_OFF);
+ sys_clk_off_by_irqn(ETH_IRQn, SYS_SLP_CLK_OFF);
+ sys_clk_off_by_irqn(ECDC_IRQn, SYS_SLP_CLK_OFF);
+
+ /* setup HCLK for systick & peripheral devices */
+ sys_hclk_set(SYS_HCLK_FREQ);
+
+ /* set SysTick to RT_TICK_PER_SECOND with current HCLK */
+ systick_init(0);
+
+ /* Note: keep MSTATUS_MIE disabled to prevent SysTick from processing
+ * thread scheduling, which may not be ready upon 1st systick irq.
+ * MSTATUS_MIE will be set when rt_system_scheduler_start() starts
+ * the first thread and copies mstatus from stack_frame.
+ */
+
+#ifdef RT_USING_HEAP
+ rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
+#endif
+
+#ifdef RT_USING_COMPONENTS_INIT
+ rt_components_board_init();
+#endif
+
+#ifdef RT_USING_CONSOLE
+ /* console is uart1, TXD1/RXD1 : PA8/PA7 */
+ rt_pin_mode(GET_PIN(A, 8), PIN_MODE_OUTPUT);
+ rt_pin_mode(GET_PIN(A, 7), PIN_MODE_INPUT_PULLUP);
+ rt_hw_uart_init();
+ rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
+#endif
+
+ rt_interrupt_leave_sethook(irq_leave_hook);
+}
diff --git a/bsp/wch/risc-v/ch569w-evt/board/board.h b/bsp/wch/risc-v/ch569w-evt/board/board.h
new file mode 100644
index 0000000000..631352203c
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/board/board.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-15 Emuzit first version
+ */
+#ifndef __BOARD_H__
+#define __BOARD_H__
+
+#include <stdint.h>
+#include "ch56x_sys.h"
+#include "ch56x_gpio.h"
+
+#define LED0_PIN GET_PIN(B, 24)
+#define LED1_PIN GET_PIN(B, 22)
+#define LED2_PIN GET_PIN(B, 23)
+
+#define SYS_HCLK_FREQ 80000000 // 80 MHz
+
+#define RAMX_SIZE 32 // USER_MEM 00/01/1x : 32/64/96 KB
+#define RAMX_END (RAMX_BASE_ADDRESS + RAMX_SIZE * 1024)
+
+extern uint32_t _ebss, _heap_end;
+extern uint32_t _susrstack, _eusrstack;
+
+#define HEAP_BEGIN ((void *)&_ebss)
+#define HEAP_END ((void *)&_heap_end)
+#define SUSRSTACK ((void *)&_susrstack)
+#define EUSRSTACK ((void *)&_eusrstack)
+
+void rt_hw_board_init(void);
+
+#endif /* __BOARD_H__ */
diff --git a/bsp/wch/risc-v/ch569w-evt/board/linker_scripts/link.lds b/bsp/wch/risc-v/ch569w-evt/board/linker_scripts/link.lds
new file mode 100644
index 0000000000..41dce1bbea
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/board/linker_scripts/link.lds
@@ -0,0 +1,199 @@
+ENTRY( _start )
+
+__stack_size = 2048;
+
+PROVIDE( _stack_size = __stack_size );
+
+MEMORY
+{
+ 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
+
+ .vector :
+ {
+ *(.vector);
+ . = 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
+
+ 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 :
+ {
+ . = ALIGN(16);
+ PROVIDE( _dmadata_start = .);
+ *(.dmadata*)
+ *(.dmadata.*)
+ . = ALIGN(16);
+ PROVIDE( _dmadata_end = .);
+ } >RAMX AT>FLASH /**/
+
+ .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size :
+ {
+ PROVIDE( _heap_end = . );
+ . = ALIGN(4);
+ PROVIDE(_susrstack = . );
+ . = . + __stack_size;
+ PROVIDE( _eusrstack = .);
+ } >RAM
+}
diff --git a/bsp/wch/risc-v/ch569w-evt/board/startup_gcc.S b/bsp/wch/risc-v/ch569w-evt/board/startup_gcc.S
new file mode 100644
index 0000000000..71649eff1e
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/board/startup_gcc.S
@@ -0,0 +1,174 @@
+/********************************** (C) COPYRIGHT *******************************
+* File Name : startup_gcc.s
+* Author : WCH
+* Version : V1.0
+* Date : 2020/07/31
+* Description : CH56x vector table for eclipse toolchain.
+*******************************************************************************/
+
+ .section .init,"ax",@progbits
+ .global _start
+ .align 1
+_start:
+ j handle_reset
+
+ .section .vector,"ax",@progbits
+ .align 1
+_vector_base:
+ .option norvc;
+ .word 0
+ .word 0
+ j nmi_handler
+ j hardfault_handler
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ j systick_handler
+ .word 0
+ j swi_handler
+ .word 0
+ /* External Interrupts */
+ j wdog_irq_handler
+ j tmr0_irq_handler
+ j gpio_irq_handler
+ j spi0_irq_handler
+ j usbss_irq_handler
+ j link_irq_handler
+ j tmr1_irq_handler
+ j tmr2_irq_handler
+ j uart0_irq_handler
+ j usbhs_irq_handler
+ j emmc_irq_handler
+ j dvp_irq_handler
+ j hspi_irq_handler
+ j spi1_irq_handler
+ j uart1_irq_handler
+ j uart2_irq_handler
+ j uart3_irq_handler
+ j serdes_irq_handler
+ j eth_irq_handler
+ j pmt_irq_handler
+ j ecdc_irq_handler
+
+ .option rvc;
+
+ .section .text.vector_handler,"ax", @prsocogbits
+
+ .weak nmi_handler
+ .weak hardfault_handler
+ .weak systick_handler
+ .weak swi_handler
+ .weak wdog_irq_handler
+ .weak tmr0_irq_handler
+ .weak gpio_irq_handler
+ .weak spi0_irq_handler
+ .weak usbss_irq_handler
+ .weak link_irq_handler
+ .weak tmr1_irq_handler
+ .weak tmr2_irq_handler
+ .weak uart0_irq_handler
+ .weak usbhs_irq_handler
+ .weak emmc_irq_handler
+ .weak dvp_irq_handler
+ .weak hspi_irq_handler
+ .weak spi1_irq_handler
+ .weak uart1_irq_handler
+ .weak uart2_irq_handler
+ .weak uart3_irq_handler
+ .weak serdes_irq_handler
+ .weak eth_irq_handler
+ .weak pmt_irq_handler
+ .weak ecdc_irq_handler
+
+nmi_handler: j .L_rip
+hardfault_handler: j .L_rip
+systick_handler: j .L_rip
+swi_handler: j .L_rip
+wdog_irq_handler: j .L_rip
+tmr0_irq_handler: j .L_rip
+gpio_irq_handler: j .L_rip
+spi0_irq_handler: j .L_rip
+usbss_irq_handler: j .L_rip
+link_irq_handler: j .L_rip
+tmr1_irq_handler: j .L_rip
+tmr2_irq_handler: j .L_rip
+uart0_irq_handler: j .L_rip
+usbhs_irq_handler: j .L_rip
+emmc_irq_handler: j .L_rip
+dvp_irq_handler: j .L_rip
+hspi_irq_handler: j .L_rip
+spi1_irq_handler: j .L_rip
+uart1_irq_handler: j .L_rip
+uart2_irq_handler: j .L_rip
+uart3_irq_handler: j .L_rip
+serdes_irq_handler: j .L_rip
+eth_irq_handler: j .L_rip
+pmt_irq_handler: j .L_rip
+ecdc_irq_handler: j .L_rip
+
+.L_rip:
+ csrr t0, mepc
+ csrr t1, mstatus
+ csrr t2, mcause
+ csrr t3, mtval
+ csrr t4, mscratch
+1: j 1b
+
+ .section .text.handle_reset,"ax",@progbits
+ .weak handle_reset
+ .align 1
+handle_reset:
+ .option push
+ .option norelax
+ la gp, __global_pointer$
+ .option pop
+1:
+ la sp, _eusrstack
+
+/* Load data section from flash to RAM */
+2:
+ la a0, _data_lma
+ la a1, _data_vma
+ la a2, _edata
+ bgeu a1, a2, 2f
+1:
+ lw t0, (a0)
+ sw t0, (a1)
+ addi a0, a0, 4
+ addi a1, a1, 4
+ bltu a1, a2, 1b
+/* clear bss section */
+2:
+ la a0, _sbss
+ la a1, _ebss
+ bgeu a0, a1, 2f
+1:
+ sw zero, (a0)
+ addi a0, a0, 4
+ bltu a0, a1, 1b
+
+/* clear dmadata section */
+2:
+ la a0, _dmadata_start
+ la a1, _dmadata_end
+ bgeu a0, a1, 2f
+1:
+ sw zero, (a0)
+ addi a0, a0, 4
+ bltu a0, a1, 1b
+
+2:
+ /* leave all interrupt disabled */
+ li t0, 0x1800
+ csrs mstatus, t0
+ la t0, _vector_base
+ ori t0, t0, 1
+ csrw mtvec, t0
+ la t0, entry
+ csrw mepc, t0
+ mret
diff --git a/bsp/wch/risc-v/ch569w-evt/figures/ch569w-evt.jpeg b/bsp/wch/risc-v/ch569w-evt/figures/ch569w-evt.jpeg
new file mode 100644
index 0000000000..74e645b708
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/figures/ch569w-evt.jpeg
Binary files differ
diff --git a/bsp/wch/risc-v/ch569w-evt/rtconfig.h b/bsp/wch/risc-v/ch569w-evt/rtconfig.h
new file mode 100644
index 0000000000..99bad3ce80
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/rtconfig.h
@@ -0,0 +1,192 @@
+#ifndef RT_CONFIG_H__
+#define RT_CONFIG_H__
+
+/* Automatically generated file; DO NOT EDIT. */
+/* RT-Thread Configuration */
+
+/* RT-Thread Kernel */
+
+#define RT_NAME_MAX 8
+#define RT_ALIGN_SIZE 4
+#define RT_THREAD_PRIORITY_32
+#define RT_THREAD_PRIORITY_MAX 32
+#define RT_TICK_PER_SECOND 200
+#define RT_USING_HOOK
+#define RT_HOOK_USING_FUNC_PTR
+#define RT_USING_IDLE_HOOK
+#define RT_IDLE_HOOK_LIST_SIZE 4
+#define IDLE_THREAD_STACK_SIZE 384
+
+/* kservice optimization */
+
+#define RT_KSERVICE_USING_STDLIB
+
+/* Inter-Thread communication */
+
+#define RT_USING_SEMAPHORE
+#define RT_USING_MUTEX
+#define RT_USING_MAILBOX
+
+/* Memory Management */
+
+#define RT_USING_MEMPOOL
+#define RT_USING_SMALL_MEM
+#define RT_USING_SMALL_MEM_AS_HEAP
+#define RT_USING_HEAP
+
+/* Kernel Device Object */
+
+#define RT_USING_DEVICE
+#define RT_USING_INTERRUPT_INFO
+#define RT_USING_CONSOLE
+#define RT_CONSOLEBUF_SIZE 128
+#define RT_CONSOLE_DEVICE_NAME "uart1"
+#define RT_VER_NUM 0x40101
+#define ARCH_RISCV
+
+/* RT-Thread Components */
+
+#define RT_USING_COMPONENTS_INIT
+#define RT_USING_USER_MAIN
+#define RT_MAIN_THREAD_STACK_SIZE 2048
+#define RT_MAIN_THREAD_PRIORITY 10
+#define RT_USING_MSH
+#define RT_USING_FINSH
+#define FINSH_USING_MSH
+#define FINSH_THREAD_NAME "tshell"
+#define FINSH_THREAD_PRIORITY 20
+#define FINSH_THREAD_STACK_SIZE 4096
+#define FINSH_USING_HISTORY
+#define FINSH_HISTORY_LINES 5
+#define FINSH_USING_SYMTAB
+#define FINSH_CMD_SIZE 80
+#define MSH_USING_BUILT_IN_COMMANDS
+#define FINSH_USING_DESCRIPTION
+#define FINSH_ARG_MAX 10
+
+/* Device Drivers */
+
+#define RT_USING_DEVICE_IPC
+#define RT_USING_SERIAL
+#define RT_USING_SERIAL_V1
+#define RT_SERIAL_RB_BUFSZ 64
+#define RT_USING_HWTIMER
+#define RT_USING_PIN
+#define RT_USING_WDT
+
+/* Using USB */
+
+
+/* C/C++ and POSIX layer */
+
+#define RT_LIBC_DEFAULT_TIMEZONE 8
+
+/* POSIX (Portable Operating System Interface) layer */
+
+
+/* Interprocess Communication (IPC) */
+
+
+/* Socket is in the 'Network' category */
+
+
+/* Network */
+
+
+/* Utilities */
+
+
+/* RT-Thread Utestcases */
+
+
+/* RT-Thread online packages */
+
+/* IoT - internet of things */
+
+
+/* Wi-Fi */
+
+/* Marvell WiFi */
+
+
+/* Wiced WiFi */
+
+
+/* IoT Cloud */
+
+
+/* security packages */
+
+
+/* language packages */
+
+/* JSON: JavaScript Object Notation, a lightweight data-interchange format */
+
+
+/* XML: Extensible Markup Language */
+
+
+/* multimedia packages */
+
+/* LVGL: powerful and easy-to-use embedded GUI library */
+
+
+/* u8g2: a monochrome graphic library */
+
+
+/* PainterEngine: A cross-platform graphics application framework written in C language */
+
+
+/* tools packages */
+
+
+/* system packages */
+
+/* enhanced kernel services */
+
+
+/* acceleration: Assembly language or algorithmic acceleration packages */
+
+
+/* CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */
+
+
+/* Micrium: Micrium software products porting for RT-Thread */
+
+
+/* peripheral libraries and drivers */
+
+
+/* AI packages */
+
+
+/* miscellaneous packages */
+
+/* project laboratory */
+
+/* samples: kernel and components samples */
+
+
+/* entertainment: terminal games and other interesting software packages */
+
+#define SOC_FAMILY_CH56X
+#define SOC_SERIES_CH569
+
+/* Hardware Drivers Config */
+
+#define SOC_CH569W
+
+/* On-chip Peripheral Drivers */
+
+#define BSP_USING_UART
+#define BSP_USING_UART1
+#define BSP_USING_TIMER
+#define BSP_USING_TMR0
+#define BSP_USING_TMR1
+
+/* Onboard Peripheral Drivers */
+
+/* Board extended module Drivers */
+
+
+#endif
diff --git a/bsp/wch/risc-v/ch569w-evt/rtconfig.py b/bsp/wch/risc-v/ch569w-evt/rtconfig.py
new file mode 100644
index 0000000000..d6e291657a
--- /dev/null
+++ b/bsp/wch/risc-v/ch569w-evt/rtconfig.py
@@ -0,0 +1,62 @@
+import os
+ARCH = 'risc-v'
+CPU = 'ch56x'
+# toolchains options
+CROSS_TOOL = 'gcc'
+
+#------- toolchains path -------------------------------------------------------
+if os.getenv('RTT_CC'):
+ CROSS_TOOL = os.getenv('RTT_CC')
+
+if CROSS_TOOL == 'gcc':
+ PLATFORM = 'gcc'
+ EXEC_PATH = r'/opt/mrs-riscv-none-embed/bin'
+else:
+ print('Please make sure your toolchains is GNU GCC!')
+ exit(0)
+
+if os.getenv('RTT_EXEC_PATH'):
+ EXEC_PATH = os.getenv('RTT_EXEC_PATH')
+
+#BUILD = 'debug'
+BUILD = 'release'
+
+CORE = 'risc-v'
+MAP_FILE = 'rtthread.map'
+LINK_FILE = './board/linker_scripts/link.lds'
+TARGET_NAME = 'rtthread.bin'
+
+#------- GCC settings ----------------------------------------------------------
+if PLATFORM == 'gcc':
+ # toolchains
+ PREFIX = 'riscv-none-embed-'
+ CC = PREFIX + 'gcc'
+ CXX= PREFIX + 'g++'
+ AS = PREFIX + 'gcc'
+ AR = PREFIX + 'ar'
+ LINK = PREFIX + 'gcc'
+ TARGET_EXT = 'elf'
+ SIZE = PREFIX + 'size'
+ OBJDUMP = PREFIX + 'objdump'
+ OBJCPY = PREFIX + 'objcopy'
+
+ DEVICE = ' -march=rv32imac -mabi=ilp32 -DUSE_PLIC -DUSE_M_TIME -DNO_INIT -mcmodel=medany -msmall-data-limit=8 -L. -nostartfiles -lc '
+ CFLAGS = DEVICE
+ CFLAGS += ' -save-temps=obj'
+ AFLAGS = '-c'+ DEVICE + ' -x assembler-with-cpp'
+ LFLAGS = DEVICE
+ LFLAGS += ' -Wl,--gc-sections,-cref,-Map=' + MAP_FILE
+ LFLAGS += ' -T ' + LINK_FILE
+ LFLAGS += ' -Wl,-wrap=memset'
+
+ CPATH = ''
+ LPATH = ''
+
+ if BUILD == 'debug':
+ CFLAGS += ' -O0 -g3'
+ AFLAGS += ' -g3'
+ else:
+ CFLAGS += ' -O2'
+
+ POST_ACTION = OBJCPY + ' -O binary $TARGET ' + TARGET_NAME + '\n'
+ POST_ACTION += SIZE + ' $TARGET\n'
diff --git a/libcpu/risc-v/SConscript b/libcpu/risc-v/SConscript
index ffb2e7ae17..7e6b9947a3 100644
--- a/libcpu/risc-v/SConscript
+++ b/libcpu/risc-v/SConscript
@@ -24,7 +24,7 @@ else :
# cpu porting code files
if rtconfig.CPU == "e9xx" :
group = group + SConscript(os.path.join(rtconfig.VENDOR, rtconfig.CPU, 'SConscript'))
-else :
+elif rtconfig.CPU in list:
group = group + SConscript(os.path.join(rtconfig.CPU, 'SConscript'))
Return('group')
diff --git a/libcpu/risc-v/common/cpuport.c b/libcpu/risc-v/common/cpuport.c
index 97f34d8c4c..9e9957e66c 100644
--- a/libcpu/risc-v/common/cpuport.c
+++ b/libcpu/risc-v/common/cpuport.c
@@ -138,7 +138,7 @@ rt_uint8_t *rt_hw_stack_init(void *tentry,
* #endif
*/
#ifndef RT_USING_SMP
-void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to)
+RT_WEAK void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to)
{
if (rt_thread_switch_interrupt_flag == 0)
rt_interrupt_from_thread = from;