diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 65d3e5aa58ba..9fa3afa3ae63 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4349,6 +4349,22 @@ VFS: tests: - filesystem +WCH Platforms: + status: maintained + maintainers: + - xingrz + files: + - boards/wch/ + - drivers/*/*ch32* + - drivers/*/*ch5* + - dts/riscv/wch/ + - dts/bindings/*/wch,* + - soc/wch/ + labels: + - "platform: WCH" + description: >- + WCH SoCs, dts files and related drivers. WCH boards. + West: status: odd fixes collaborators: diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 4ef91c6be8df..ca878e0e3c27 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -27,6 +27,16 @@ config RISCV_GP global pointer at program start or earlier than any instruction using GP relative addressing. +config RISCV_CUSTOM_INTERRUPT_CONTROLLER + bool + help + This option indicates that the RISC-V CPU is connected to a custom + interrupt controller. + + When this option is selected, the architecture interrupt control + functions are mapped to the SoC interrupt control interface, which is + implemented at the SoC level. + config RISCV_ALWAYS_SWITCH_THROUGH_ECALL bool "Do not use mret outside a trap handler context" depends on MULTITHREADING diff --git a/boards/common/wchisp.board.cmake b/boards/common/wchisp.board.cmake new file mode 100644 index 000000000000..19d403b0e715 --- /dev/null +++ b/boards/common/wchisp.board.cmake @@ -0,0 +1,5 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +board_set_flasher_ifnset(wchisp) +board_finalize_runner_args(wchisp) diff --git a/boards/wch/ch565w_evt/Kconfig.ch565w_evt b/boards/wch/ch565w_evt/Kconfig.ch565w_evt new file mode 100644 index 000000000000..bfebbf9a30cc --- /dev/null +++ b/boards/wch/ch565w_evt/Kconfig.ch565w_evt @@ -0,0 +1,5 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_CH565W_EVT + select SOC_CH565 diff --git a/boards/wch/ch565w_evt/board.cmake b/boards/wch/ch565w_evt/board.cmake new file mode 100644 index 000000000000..d9939ce8df2a --- /dev/null +++ b/boards/wch/ch565w_evt/board.cmake @@ -0,0 +1,4 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/wchisp.board.cmake) diff --git a/boards/wch/ch565w_evt/board.yml b/boards/wch/ch565w_evt/board.yml new file mode 100644 index 000000000000..64be88b3217a --- /dev/null +++ b/boards/wch/ch565w_evt/board.yml @@ -0,0 +1,5 @@ +board: + name: ch565w_evt + vendor: wch + socs: + - name: ch565 diff --git a/boards/wch/ch565w_evt/ch565w_evt.dts b/boards/wch/ch565w_evt/ch565w_evt.dts new file mode 100644 index 000000000000..2e74652adc0b --- /dev/null +++ b/boards/wch/ch565w_evt/ch565w_evt.dts @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include + +/ { + model = "WCH CH565W-EVT"; + compatible = "wch,ch565w-evt"; + + aliases { + led0 = &led_0; + led1 = &led_1; + led2 = &led_2; + }; + + chosen { + zephyr,sram = &rams; + zephyr,flash = &flash; + zephyr,console = &uart1; + zephyr,shell-uart = &uart1; + }; + + leds { + compatible = "gpio-leds"; + + led_0: led-0 { + gpios = <&gpioa 9 GPIO_ACTIVE_LOW>; + label = "LED0"; + }; + + led_1: led-1 { + gpios = <&gpiob 22 GPIO_ACTIVE_LOW>; + label = "LED1"; + }; + + led_2: led-2 { + gpios = <&gpiob 23 GPIO_ACTIVE_LOW>; + label = "LED2"; + }; + }; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; diff --git a/boards/wch/ch565w_evt/ch565w_evt.yaml b/boards/wch/ch565w_evt/ch565w_evt.yaml new file mode 100644 index 000000000000..d6e57d00d7c9 --- /dev/null +++ b/boards/wch/ch565w_evt/ch565w_evt.yaml @@ -0,0 +1,13 @@ +identifier: ch565w_evt +name: WCH CH565W-EVT +type: mcu +arch: riscv32 +toolchain: + - zephyr +supported: + - clock-control + - gpio + - interrupt-controller + - pinctrl + - serial + - timer diff --git a/boards/wch/ch565w_evt/ch565w_evt_defconfig b/boards/wch/ch565w_evt/ch565w_evt_defconfig new file mode 100644 index 000000000000..f3095fffa9ff --- /dev/null +++ b/boards/wch/ch565w_evt/ch565w_evt_defconfig @@ -0,0 +1,7 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_GPIO=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/wch/ch565w_evt/doc/index.rst b/boards/wch/ch565w_evt/doc/index.rst new file mode 100644 index 000000000000..e4578a0aef53 --- /dev/null +++ b/boards/wch/ch565w_evt/doc/index.rst @@ -0,0 +1,81 @@ +.. _ch565w_evt: + +CH565W-EVT +########## + +Overview +******** + +The CH565W-EVT is a evaluation board for the CH565 chip. + +CH565/9 is a member of the QingKe V3A family developed by WCH. + +Hardware +******** +- QingKe V3A RISC-V RV32IMAC core, running up to 120MHz +- 448KB Flash +- 32/64/96KB + 16KB SRAM +- 49 GPIOs +- 4 UARTs +- 2 SPIs +- 1 DVP +- USB 2.0 High Speed +- USB 3.0 Super Speed + +Supported Features +================== +The CH565W-EVT supports the following features: + +.. list-table:: + :header-rows: 1 + + * - Peripheral + - Kconfig option + - Devicetree compatible + * - Clock Mux + - N/A + - :dtcompatible:`wch,ch56x-clkmux` + * - GPIO + - :kconfig:option:`CONFIG_GPIO` + - :dtcompatible:`wch,ch56x-gpio` + * - PFIC + - N/A + - :dtcompatible:`wch,ch32v-pfic` + * - PINCTRL + - :kconfig:option:`CONFIG_PINCTRL` + - :dtcompatible:`wch,ch5xx-pinctrl` + * - SYSTICK + - N/A + - :dtcompatible:`wch,ch32v-v3-systick` + * - UART + - :kconfig:option:`CONFIG_SERIAL` + - :dtcompatible:`wch,ch5xx-uart` + +Other hardware features have not been enabled yet for this board. + +Programming and Debugging +************************* + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: ch565w_evt + :goals: build + +Flashing +======== + +The WCH MCUs can be flashed via USB (using WCHISPTool), or via WCH-Link. + +WCHISPTool +---------- + +`WCHISPTool_CMD`_ is required to flash the board. Add it to the ``PATH`` +environment variable, and refer to the tool's documentation for generating the +device configuration file. + +.. code-block:: sh + + west flash --device XXXX --cfg-file /path/to/CH565.ini + +.. _WCHISPTool_CMD: + https://wch-ic.com/downloads/WCHISPTool_CMD_ZIP.html diff --git a/boards/wch/ch569w_evt/Kconfig.ch569w_evt b/boards/wch/ch569w_evt/Kconfig.ch569w_evt new file mode 100644 index 000000000000..0565d2b653eb --- /dev/null +++ b/boards/wch/ch569w_evt/Kconfig.ch569w_evt @@ -0,0 +1,5 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_CH569W_EVT + select SOC_CH569 diff --git a/boards/wch/ch569w_evt/board.cmake b/boards/wch/ch569w_evt/board.cmake new file mode 100644 index 000000000000..d9939ce8df2a --- /dev/null +++ b/boards/wch/ch569w_evt/board.cmake @@ -0,0 +1,4 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/wchisp.board.cmake) diff --git a/boards/wch/ch569w_evt/board.yml b/boards/wch/ch569w_evt/board.yml new file mode 100644 index 000000000000..a5c19203a142 --- /dev/null +++ b/boards/wch/ch569w_evt/board.yml @@ -0,0 +1,5 @@ +board: + name: ch569w_evt + vendor: wch + socs: + - name: ch569 diff --git a/boards/wch/ch569w_evt/ch569w_evt.dts b/boards/wch/ch569w_evt/ch569w_evt.dts new file mode 100644 index 000000000000..1ccf548e62ea --- /dev/null +++ b/boards/wch/ch569w_evt/ch569w_evt.dts @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include + +/ { + model = "WCH CH569W-EVT"; + compatible = "wch,ch569w-evt"; + + aliases { + led0 = &led_0; + led1 = &led_1; + led2 = &led_2; + }; + + chosen { + zephyr,sram = &rams; + zephyr,flash = &flash; + zephyr,console = &uart1; + zephyr,shell-uart = &uart1; + }; + + leds { + compatible = "gpio-leds"; + + led_0: led-0 { + gpios = <&gpiob 24 GPIO_ACTIVE_LOW>; + label = "LED0"; + }; + + led_1: led-1 { + gpios = <&gpiob 22 GPIO_ACTIVE_LOW>; + label = "LED1"; + }; + + led_2: led-2 { + gpios = <&gpiob 23 GPIO_ACTIVE_LOW>; + label = "LED2"; + }; + }; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; diff --git a/boards/wch/ch569w_evt/ch569w_evt.yaml b/boards/wch/ch569w_evt/ch569w_evt.yaml new file mode 100644 index 000000000000..36ee4c9da2f0 --- /dev/null +++ b/boards/wch/ch569w_evt/ch569w_evt.yaml @@ -0,0 +1,13 @@ +identifier: ch569w_evt +name: WCH CH569W-EVT +type: mcu +arch: riscv32 +toolchain: + - zephyr +supported: + - clock-control + - gpio + - interrupt-controller + - pinctrl + - serial + - timer diff --git a/boards/wch/ch569w_evt/ch569w_evt_defconfig b/boards/wch/ch569w_evt/ch569w_evt_defconfig new file mode 100644 index 000000000000..f3095fffa9ff --- /dev/null +++ b/boards/wch/ch569w_evt/ch569w_evt_defconfig @@ -0,0 +1,7 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_GPIO=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/wch/ch569w_evt/doc/index.rst b/boards/wch/ch569w_evt/doc/index.rst new file mode 100644 index 000000000000..23bc479fa43e --- /dev/null +++ b/boards/wch/ch569w_evt/doc/index.rst @@ -0,0 +1,81 @@ +.. _ch569w_evt: + +CH569W-EVT +########## + +Overview +******** + +The CH569W-EVT is a evaluation board for the CH569 chip. + +CH569/9 is a member of the QingKe V3A family developed by WCH. + +Hardware +******** +- QingKe V3A RISC-V RV32IMAC core, running up to 120MHz +- 448KB Flash +- 32/64/96KB + 16KB SRAM +- 49 GPIOs +- 4 UARTs +- 2 SPIs +- 1 HSPI +- USB 2.0 High Speed +- USB 3.0 Super Speed + +Supported Features +================== +The CH569W-EVT supports the following features: + +.. list-table:: + :header-rows: 1 + + * - Peripheral + - Kconfig option + - Devicetree compatible + * - Clock Mux + - N/A + - :dtcompatible:`wch,ch56x-clkmux` + * - GPIO + - :kconfig:option:`CONFIG_GPIO` + - :dtcompatible:`wch,ch56x-gpio` + * - PFIC + - N/A + - :dtcompatible:`wch,ch32v-pfic` + * - PINCTRL + - :kconfig:option:`CONFIG_PINCTRL` + - :dtcompatible:`wch,ch5xx-pinctrl` + * - SYSTICK + - N/A + - :dtcompatible:`wch,ch32v-v3-systick` + * - UART + - :kconfig:option:`CONFIG_SERIAL` + - :dtcompatible:`wch,ch5xx-uart` + +Other hardware features have not been enabled yet for this board. + +Programming and Debugging +************************* + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: ch569w_evt + :goals: build + +Flashing +======== + +The WCH MCUs can be flashed via USB (using WCHISPTool), or via WCH-Link. + +WCHISPTool +---------- + +`WCHISPTool_CMD`_ is required to flash the board. Add it to the ``PATH`` +environment variable, and refer to the tool's documentation for generating the +device configuration file. + +.. code-block:: sh + + west flash --device XXXX --cfg-file /path/to/CH569.ini + +.. _WCHISPTool_CMD: + https://wch-ic.com/downloads/WCHISPTool_CMD_ZIP.html diff --git a/boards/wch/index.rst b/boards/wch/index.rst new file mode 100644 index 000000000000..278d1c0b0e83 --- /dev/null +++ b/boards/wch/index.rst @@ -0,0 +1,10 @@ +.. _boards-wch: + +WCH +### + +.. toctree:: + :maxdepth: 1 + :glob: + + **/* diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index fc2d33efd19f..bc6024532d3b 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -86,3 +86,4 @@ endif() zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AST10X0 clock_control_ast10x0.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MAX32 clock_control_max32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_AUXPLL clock_control_nrf_auxpll.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_CH56X_CLKMUX clock_control_ch56x_clkmux.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index 42a5f23ad1f5..2fde43f009d5 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -98,4 +98,6 @@ source "drivers/clock_control/Kconfig.nrf_auxpll" source "drivers/clock_control/Kconfig.arm_scmi" +source "drivers/clock_control/Kconfig.ch32v" + endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.ch32v b/drivers/clock_control/Kconfig.ch32v new file mode 100644 index 000000000000..673815d6696e --- /dev/null +++ b/drivers/clock_control/Kconfig.ch32v @@ -0,0 +1,9 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_CH56X_CLKMUX + bool "WCH CH56x clock mux controller" + default y + depends on DT_HAS_WCH_CH56X_CLKMUX_ENABLED + help + Enable WCH CH56x clock mux controller. diff --git a/drivers/clock_control/clock_control_ch56x_clkmux.c b/drivers/clock_control/clock_control_ch56x_clkmux.c new file mode 100644 index 000000000000..a9553ac506ce --- /dev/null +++ b/drivers/clock_control/clock_control_ch56x_clkmux.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT wch_ch56x_clkmux + +#include +#include +#include +#include +#include + +/* CH32V_SYS_R8_CLK_PLL_DIV_REG */ +#define CLK_PLL_DIV_KEY (0x40) +#define CLK_PLL_DIV(div) (div & BIT_MASK(4)) + +/* CH32V_SYS_R8_CLK_CFG_CTRL_REG */ +#define CLK_CFG_CTRL_KEY (0x80) +#define CLK_SEL_PLL BIT(1) +#define CLK_SEL_OSC (0) + +struct ch56x_clkmux_config { + uint32_t hclk_freq; +}; + +static int ch56x_clkmux_on(const struct device *dev, clock_control_subsys_t sys) +{ + ARG_UNUSED(dev); + ARG_UNUSED(sys); + + return 0; +} + +static int ch56x_clkmux_off(const struct device *dev, clock_control_subsys_t sys) +{ + ARG_UNUSED(dev); + ARG_UNUSED(sys); + + return 0; +} + +static int ch56x_clkmux_get_rate(const struct device *dev, clock_control_subsys_t sys, + uint32_t *rate) +{ + const struct ch56x_clkmux_config *cfg = dev->config; + + ARG_UNUSED(sys); + + *rate = cfg->hclk_freq; + + return 0; +} + +static enum clock_control_status ch56x_clkmux_get_status(const struct device *dev, + clock_control_subsys_t sys) +{ + return CLOCK_CONTROL_STATUS_ON; +} + +static int ch56x_clkmux_init(const struct device *dev) +{ + const struct ch56x_clkmux_config *cfg = dev->config; + uint32_t source, divider; + + switch (cfg->hclk_freq) { + case MHZ(2): + source = CLK_SEL_OSC; + /* For 2MHz, divider is 0 */ + divider = 0; + break; + case MHZ(15): + source = CLK_SEL_OSC; + divider = 2; + break; + case MHZ(30): + source = CLK_SEL_PLL; + /* For 30MHz, divider is 0 */ + divider = 0; + break; + case MHZ(60): + source = CLK_SEL_PLL; + divider = 8; + break; + case MHZ(80): + source = CLK_SEL_PLL; + divider = 6; + break; + case MHZ(96): + source = CLK_SEL_PLL; + divider = 5; + break; + case MHZ(120): + source = CLK_SEL_PLL; + divider = 4; + break; + default: + return -EINVAL; + } + + /* Configure HCLK source and divider */ + ch32v_sys_unlock(); + sys_write8(CLK_PLL_DIV_KEY | CLK_PLL_DIV(divider), CH32V_SYS_R8_CLK_PLL_DIV_REG); + + ch32v_sys_unlock(); + sys_write8(CLK_CFG_CTRL_KEY | source, CH32V_SYS_R8_CLK_CFG_CTRL_REG); + + ch32v_sys_relock(); + + return 0; +} + +static const struct clock_control_driver_api ch56x_clkmux_api = { + .on = ch56x_clkmux_on, + .off = ch56x_clkmux_off, + .get_rate = ch56x_clkmux_get_rate, + .get_status = ch56x_clkmux_get_status, +}; + +#define CH56X_CLKMUX_INST(n) \ + static const struct ch56x_clkmux_config ch56x_clkmux_cfg_##n = { \ + .hclk_freq = DT_INST_PROP(n, clock_frequency), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, ch56x_clkmux_init, NULL, NULL, &ch56x_clkmux_cfg_##n, \ + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &ch56x_clkmux_api); + +DT_INST_FOREACH_STATUS_OKAY(CH56X_CLKMUX_INST) diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 4cc80c0e4fe4..121ab3892932 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -17,6 +17,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_BD8LB600FS gpio_bd8lb600fs.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BRCMSTB gpio_brcmstb.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CC13XX_CC26XX gpio_cc13xx_cc26xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CC32XX gpio_cc32xx.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_CH56X gpio_ch56x.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CMSDK_AHB gpio_cmsdk_ahb.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CY8C95XX gpio_cy8c95xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_DAVINCI gpio_davinci.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 81dbd40a2c6e..5d685494886e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -108,6 +108,7 @@ source "drivers/gpio/Kconfig.bd8lb600fs" source "drivers/gpio/Kconfig.brcmstb" source "drivers/gpio/Kconfig.cc13xx_cc26xx" source "drivers/gpio/Kconfig.cc32xx" +source "drivers/gpio/Kconfig.ch32v" source "drivers/gpio/Kconfig.cmsdk_ahb" source "drivers/gpio/Kconfig.creg_gpio" source "drivers/gpio/Kconfig.cy8c95xx" diff --git a/drivers/gpio/Kconfig.ch32v b/drivers/gpio/Kconfig.ch32v new file mode 100644 index 000000000000..ec549fd1ef63 --- /dev/null +++ b/drivers/gpio/Kconfig.ch32v @@ -0,0 +1,10 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_CH56X + bool "WCH CH56x GPIO driver" + default y + depends on DT_HAS_WCH_CH56X_GPIO_ENABLED + select SHARED_INTERRUPTS + help + Enable WCH CH56x GPIO driver. diff --git a/drivers/gpio/gpio_ch56x.c b/drivers/gpio/gpio_ch56x.c new file mode 100644 index 000000000000..d98863abab34 --- /dev/null +++ b/drivers/gpio/gpio_ch56x.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT wch_ch56x_gpio + +#include +#include +#include +#include +#include +#include +#include + +#define GPIO_R32_PAD_DIR(base) (base + 0x00) +#define GPIO_R32_PAD_PIN(base) (base + 0x04) +#define GPIO_R32_PAD_OUT(base) (base + 0x08) +#define GPIO_R32_PAD_CLR(base) (base + 0x0C) +#define GPIO_R32_PAD_PU(base) (base + 0x10) +#define GPIO_R32_PAD_PD(base) (base + 0x14) +#define GPIO_R32_PAD_DRV(base) (base + 0x18) +#define GPIO_R32_PAD_SMT(base) (base + 0x1C) + +struct gpio_ch56x_config { + struct gpio_driver_config common; + void (*irq_config_func)(void); + mem_addr_t base; + const uint32_t *int_pins; + uint32_t int_pins_cnt; +}; + +struct gpio_ch56x_data { + struct gpio_driver_data common; + sys_slist_t cb; +}; + +static int gpio_ch56x_pin_configure(const struct device *port, gpio_pin_t pin, gpio_flags_t flags) +{ + const struct gpio_ch56x_config *cfg = port->config; + uint32_t regval; + + /* Simultaneous pin in/out mode is not supported */ + if ((flags & GPIO_INPUT) && (flags & GPIO_OUTPUT)) { + return -ENOTSUP; + } + + /* Reset */ + { + regval = sys_read32(GPIO_R32_PAD_PU(cfg->base)); + regval &= ~BIT(pin); + sys_write32(regval, GPIO_R32_PAD_PU(cfg->base)); + + regval = sys_read32(GPIO_R32_PAD_PD(cfg->base)); + regval &= ~BIT(pin); + sys_write32(regval, GPIO_R32_PAD_PD(cfg->base)); + + regval = sys_read32(GPIO_R32_PAD_DRV(cfg->base)); + regval &= ~BIT(pin); + sys_write32(regval, GPIO_R32_PAD_DRV(cfg->base)); + + regval = sys_read32(GPIO_R32_PAD_SMT(cfg->base)); + regval &= ~BIT(pin); + sys_write32(regval, GPIO_R32_PAD_SMT(cfg->base)); + } + + if (flags & GPIO_INPUT) { + /* Set input direction */ + { + regval = sys_read32(GPIO_R32_PAD_DIR(cfg->base)); + regval &= ~BIT(pin); + sys_write32(regval, GPIO_R32_PAD_DIR(cfg->base)); + } + + /* Set pulls */ + if (flags & GPIO_PULL_UP) { + regval = sys_read32(GPIO_R32_PAD_PU(cfg->base)); + regval |= BIT(pin); + sys_write32(regval, GPIO_R32_PAD_PU(cfg->base)); + } else if (flags & GPIO_PULL_DOWN) { + regval = sys_read32(GPIO_R32_PAD_PD(cfg->base)); + regval |= BIT(pin); + sys_write32(regval, GPIO_R32_PAD_PD(cfg->base)); + } + + /* Set schmitt trigger */ + if (flags & CH56X_GPIO_SCHMITT_TRIGGER) { + regval = sys_read32(GPIO_R32_PAD_SMT(cfg->base)); + regval |= BIT(pin); + sys_write32(regval, GPIO_R32_PAD_SMT(cfg->base)); + } + } else if (flags & GPIO_OUTPUT) { + /* Set output direction */ + { + regval = sys_read32(GPIO_R32_PAD_DIR(cfg->base)); + regval |= BIT(pin); + sys_write32(regval, GPIO_R32_PAD_DIR(cfg->base)); + } + + /* Set open drain */ + if (flags & GPIO_OPEN_DRAIN) { + regval = sys_read32(GPIO_R32_PAD_PD(cfg->base)); + regval |= BIT(pin); + sys_write32(regval, GPIO_R32_PAD_PD(cfg->base)); + } + + /* Set drive strength */ + if (flags & CH56X_GPIO_DRIVE_STRENGTH_16MA) { + regval = sys_read32(GPIO_R32_PAD_DRV(cfg->base)); + regval |= BIT(pin); + sys_write32(regval, GPIO_R32_PAD_DRV(cfg->base)); + } + + /* Set initial level */ + if (flags & GPIO_OUTPUT_INIT_HIGH) { + regval = sys_read32(GPIO_R32_PAD_OUT(cfg->base)); + regval |= BIT(pin); + sys_write32(regval, GPIO_R32_PAD_OUT(cfg->base)); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + regval = sys_read32(GPIO_R32_PAD_CLR(cfg->base)); + regval |= BIT(pin); + sys_write32(regval, GPIO_R32_PAD_CLR(cfg->base)); + } + } + + return 0; +} + +static int gpio_ch56x_port_get_raw(const struct device *port, gpio_port_value_t *value) +{ + const struct gpio_ch56x_config *cfg = port->config; + + *value = sys_read32(GPIO_R32_PAD_PIN(cfg->base)); + + return 0; +} + +static int gpio_ch56x_port_set_masked_raw(const struct device *port, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + const struct gpio_ch56x_config *cfg = port->config; + uint32_t regval; + + regval = sys_read32(GPIO_R32_PAD_OUT(cfg->base)); + regval &= ~mask; + regval |= value; + sys_write32(regval, GPIO_R32_PAD_OUT(cfg->base)); + + return 0; +} + +static int gpio_ch56x_port_set_bits_raw(const struct device *port, gpio_port_pins_t pins) +{ + const struct gpio_ch56x_config *cfg = port->config; + uint32_t regval; + + regval = sys_read32(GPIO_R32_PAD_OUT(cfg->base)); + regval |= pins; + sys_write32(regval, GPIO_R32_PAD_OUT(cfg->base)); + + return 0; +} + +static int gpio_ch56x_port_clear_bits_raw(const struct device *port, gpio_port_pins_t pins) +{ + const struct gpio_ch56x_config *cfg = port->config; + + sys_write32(pins, GPIO_R32_PAD_CLR(cfg->base)); + + return 0; +} + +static int gpio_ch56x_port_toggle_bits(const struct device *port, gpio_port_pins_t pins) +{ + const struct gpio_ch56x_config *cfg = port->config; + uint32_t regval; + + regval = sys_read32(GPIO_R32_PAD_OUT(cfg->base)); + regval ^= pins; + sys_write32(regval, GPIO_R32_PAD_OUT(cfg->base)); + + return 0; +} + +static int gpio_ch56x_pin_interrupt_configure(const struct device *port, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + const struct gpio_ch56x_config *cfg = port->config; + uint32_t regval; + uint32_t offset = 0; + + if (trig == GPIO_INT_TRIG_BOTH) { + /* Both edge not supported */ + return -ENOTSUP; + } + + for (uint32_t i = 0; i < cfg->int_pins_cnt; i++) { + if (pin == cfg->int_pins[i * 2]) { + offset = cfg->int_pins[i * 2 + 1]; + break; + } + } + + if (offset == 0) { + /* Interrupt not supported on this pin */ + return -ENOTSUP; + } + + /* Disable interrupt first */ + regval = sys_read8(CH32V_SYS_R8_GPIO_INT_ENABLE_REG); + regval &= ~BIT(offset); + sys_write8(regval, CH32V_SYS_R8_GPIO_INT_ENABLE_REG); + + if (mode == GPIO_INT_MODE_DISABLED) { + return 0; + } + + /* Set interrupt mode */ + regval = sys_read8(CH32V_SYS_R8_GPIO_INT_MODE_REG); + if (mode == GPIO_INT_MODE_EDGE) { + regval |= BIT(offset); + } else { + regval &= ~BIT(offset); + } + sys_write8(regval, CH32V_SYS_R8_GPIO_INT_MODE_REG); + + /* Set interrupt trigger */ + regval = sys_read8(CH32V_SYS_R8_GPIO_INT_POLAR_REG); + if (trig == GPIO_INT_TRIG_HIGH) { + regval |= BIT(offset); + } else if (trig == GPIO_INT_TRIG_LOW) { + regval &= ~BIT(offset); + } + sys_write8(regval, CH32V_SYS_R8_GPIO_INT_POLAR_REG); + + /* Enable interrupt */ + regval = sys_read8(CH32V_SYS_R8_GPIO_INT_ENABLE_REG); + regval |= BIT(offset); + sys_write8(regval, CH32V_SYS_R8_GPIO_INT_ENABLE_REG); + + return 0; +} + +static int gpio_ch56x_manage_callback(const struct device *port, struct gpio_callback *cb, bool set) +{ + struct gpio_ch56x_data *data = port->data; + + return gpio_manage_callback(&data->cb, cb, set); +} + +static void gpio_ch56x_isr(const struct device *port) +{ + const struct gpio_ch56x_config *cfg = port->config; + struct gpio_ch56x_data *data = port->data; + uint32_t regval; + uint32_t pin, offset; + uint32_t status = 0, regset = 0; + + regval = sys_read8(CH32V_SYS_R8_GPIO_INT_FLAG_REG); + for (uint32_t i = 0; i < cfg->int_pins_cnt; i++) { + pin = cfg->int_pins[i * 2]; + offset = cfg->int_pins[i * 2 + 1]; + if (BIT(offset) & regval) { + status |= BIT(pin); + regset |= BIT(offset); + } + } + + /* Clear interrupt */ + sys_write8(regset, CH32V_SYS_R8_GPIO_INT_FLAG_REG); + + gpio_fire_callbacks(&data->cb, port, status); +} + +int gpio_ch56x_init(const struct device *port) +{ + const struct gpio_ch56x_config *cfg = port->config; + + cfg->irq_config_func(); + + return 0; +} + +static const struct gpio_driver_api gpio_ch56x_api = { + .pin_configure = gpio_ch56x_pin_configure, + .port_get_raw = gpio_ch56x_port_get_raw, + .port_set_masked_raw = gpio_ch56x_port_set_masked_raw, + .port_set_bits_raw = gpio_ch56x_port_set_bits_raw, + .port_clear_bits_raw = gpio_ch56x_port_clear_bits_raw, + .port_toggle_bits = gpio_ch56x_port_toggle_bits, + .pin_interrupt_configure = gpio_ch56x_pin_interrupt_configure, + .manage_callback = gpio_ch56x_manage_callback, +}; + +#define GPIO_CH56X_INST(n) \ + static struct gpio_ch56x_data gpio_ch56x_data_##n; \ + \ + static void gpio_ch56x_irq_config_func_##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), gpio_ch56x_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } \ + \ + static const uint32_t gpio_ch56x_int_pins_##n[] = DT_INST_PROP(n, interruptible_pins); \ + \ + static const struct gpio_ch56x_config gpio_ch56x_cfg_##n = { \ + .common = {.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n)}, \ + .irq_config_func = gpio_ch56x_irq_config_func_##n, \ + .base = DT_INST_REG_ADDR(n), \ + .int_pins = gpio_ch56x_int_pins_##n, \ + .int_pins_cnt = DT_INST_PROP_LEN(n, interruptible_pins) / 2, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_ch56x_init, NULL, &gpio_ch56x_data_##n, &gpio_ch56x_cfg_##n, \ + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &gpio_ch56x_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_CH56X_INST) diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index e9b7488f05b5..2987070907fb 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -42,6 +42,7 @@ zephyr_library_sources_ifdef(CONFIG_NXP_PINT intc_nxp_pint.c) zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_ICU intc_renesas_ra_icu.c) zephyr_library_sources_ifdef(CONFIG_NXP_IRQSTEER intc_nxp_irqsteer.c) zephyr_library_sources_ifdef(CONFIG_INTC_MTK_ADSP intc_mtk_adsp.c) +zephyr_library_sources_ifdef(CONFIG_CH32V_PFIC intc_ch32v_pfic.c) if(CONFIG_INTEL_VTD_ICTL) zephyr_library_include_directories(${ZEPHYR_BASE}/arch/x86/include) diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index 250309d20833..3641c6ff8f81 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -108,4 +108,6 @@ source "drivers/interrupt_controller/Kconfig.nxp_irqsteer" source "drivers/interrupt_controller/Kconfig.mtk_adsp" +source "drivers/interrupt_controller/Kconfig.ch32v" + endmenu diff --git a/drivers/interrupt_controller/Kconfig.ch32v b/drivers/interrupt_controller/Kconfig.ch32v new file mode 100644 index 000000000000..64dff4978f33 --- /dev/null +++ b/drivers/interrupt_controller/Kconfig.ch32v @@ -0,0 +1,9 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config CH32V_PFIC + bool "WCH CH32V PFIC" + default y + depends on DT_HAS_WCH_CH32V_PFIC_ENABLED + help + Enable WCH CH32V PFIC driver. diff --git a/drivers/interrupt_controller/intc_ch32v_pfic.c b/drivers/interrupt_controller/intc_ch32v_pfic.c new file mode 100644 index 000000000000..9f9ed4bf4358 --- /dev/null +++ b/drivers/interrupt_controller/intc_ch32v_pfic.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT wch_ch32v_pfic + +#include +#include +#include + +#define PFIC_BASE DT_INST_REG_ADDR(0) + +#define PFIC_R32_ISR(n) (PFIC_BASE + 0x000 + 0x4 * n) +#define PFIC_R32_IPR(n) (PFIC_BASE + 0x020 + 0x4 * n) +#define PFIC_R32_ITHRESDR (PFIC_BASE + 0x040) +#define PFIC_R32_VTFBADDRR (PFIC_BASE + 0x044) +#define PFIC_R32_CFGR (PFIC_BASE + 0x048) +#define PFIC_R32_GISR (PFIC_BASE + 0x04C) +#define PFIC_R32_IDCFGR (PFIC_BASE + 0x050) +#define PFIC_R32_VTFADDRR(n) (PFIC_BASE + 0x060 + 0x4 * n) +#define PFIC_R32_IENR(n) (PFIC_BASE + 0x100 + 0x4 * n) +#define PFIC_R32_IRER(n) (PFIC_BASE + 0x180 + 0x4 * n) +#define PFIC_R32_IPSR(n) (PFIC_BASE + 0x200 + 0x4 * n) +#define PFIC_R32_IPRR(n) (PFIC_BASE + 0x280 + 0x4 * n) +#define PFIC_R32_IACTR(n) (PFIC_BASE + 0x300 + 0x4 * n) +#define PFIC_R32_IPRIOR(n) (PFIC_BASE + 0x400 + n) +#define PFIC_R32_SCTLR (PFIC_BASE + 0xD10) + +/* PFIC_R32_ITHRESDR */ +#define ITHRESDR_THRESHOLD(n) ((n & BIT_MASK(4)) << 4) + +#define PFIC_IRQN_GROUP(irqn) (irqn >> 5) +#define PFIC_IRQN_SHIFT(irqn) (irqn & BIT_MASK(5)) + +void ch32v_pfic_enable(unsigned int irq) +{ + sys_write32(BIT(PFIC_IRQN_SHIFT(irq)), PFIC_R32_IENR(PFIC_IRQN_GROUP(irq))); +} + +void ch32v_pfic_disable(unsigned int irq) +{ + uint32_t regval; + + /* Temporarily mask ISRs with priority lower than SYSTICK (1) */ + regval = sys_read32(PFIC_R32_ITHRESDR); + sys_write32(ITHRESDR_THRESHOLD(1), PFIC_R32_ITHRESDR); + + sys_write32(BIT(PFIC_IRQN_SHIFT(irq)), PFIC_R32_IRER(PFIC_IRQN_GROUP(irq))); + + /* Restore the original threshold */ + sys_write32(regval, PFIC_R32_ITHRESDR); +} + +int ch32v_pfic_is_enabled(unsigned int irq) +{ + return sys_read32(PFIC_R32_ISR(PFIC_IRQN_GROUP(irq))) & BIT(PFIC_IRQN_SHIFT(irq)); +} + +void ch32v_pfic_priority_set(unsigned int irq, unsigned int prio, unsigned int flags) +{ + sys_write8(prio, PFIC_R32_IPRIOR(irq)); +} diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 1dce91d59778..eaa1b0320a17 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -38,5 +38,6 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_MCI_IO_MUX pinctrl_mci_io_mux.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_ENE_KB1200 pinctrl_ene_kb1200.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX_SCU pinctrl_imx_scu.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_MAX32 pinctrl_max32.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_CH5XX pinctrl_ch5xx.c) add_subdirectory(renesas) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index b919fa0f169b..a8fa99d6efe9 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -66,6 +66,7 @@ source "drivers/pinctrl/Kconfig.mci_io_mux" source "drivers/pinctrl/Kconfig.ene" source "drivers/pinctrl/Kconfig.zynqmp" source "drivers/pinctrl/Kconfig.max32" +source "drivers/pinctrl/Kconfig.ch32v" rsource "renesas/Kconfig" diff --git a/drivers/pinctrl/Kconfig.ch32v b/drivers/pinctrl/Kconfig.ch32v new file mode 100644 index 000000000000..629afe0938a2 --- /dev/null +++ b/drivers/pinctrl/Kconfig.ch32v @@ -0,0 +1,10 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_CH5XX + bool "WCH CH5xx pin controller" + default y + depends on DT_HAS_WCH_CH5XX_PINCTRL_ENABLED + depends on GPIO + help + Enable WCH CH5xx pin controller. diff --git a/drivers/pinctrl/pinctrl_ch5xx.c b/drivers/pinctrl/pinctrl_ch5xx.c new file mode 100644 index 000000000000..a05ab133e8b5 --- /dev/null +++ b/drivers/pinctrl/pinctrl_ch5xx.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT wch_ch5xx_pinctrl + +#include +#include +#include +#include +#include + +#define GET_GPIO_CONTROLLER(node_id, prop, idx) \ + DEVICE_DT_GET_OR_NULL(DT_PHANDLE_BY_IDX(node_id, prop, idx)), + +const struct device *gpio[] = {DT_INST_FOREACH_PROP_ELEM(0, gpio_controllers, GET_GPIO_CONTROLLER)}; + +static void pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) +{ + uint32_t regval; + + if (pin->port >= ARRAY_SIZE(gpio) || !device_is_ready(gpio[pin->port])) { + return; + } + + if (pin->remap_bit) { + regval = sys_read8(CH32V_SYS_R8_PIN_ALTERNATE_REG); + if (pin->remap_en) { + regval |= BIT(pin->remap_bit); + } else { + regval &= ~BIT(pin->remap_bit); + } + sys_write8(regval, CH32V_SYS_R8_PIN_ALTERNATE_REG); + } + + gpio_pin_configure(gpio[pin->port], pin->pin, pin->flags); +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + ARG_UNUSED(reg); + + for (uint8_t i = 0; i < pin_cnt; i++) { + pinctrl_configure_pin(&pins[i]); + } + + return 0; +} diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 946f00cfddfc..a1e33e8a194f 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -77,6 +77,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_ENE_KB1200 uart_ene_kb1200.c) zephyr_library_sources_ifdef(CONFIG_UART_RZT2M uart_rzt2m.c) zephyr_library_sources_ifdef(CONFIG_UART_RA8_SCI_B uart_renesas_ra8_sci_b.c) zephyr_library_sources_ifdef(CONFIG_UART_SI32_USART uart_si32_usart.c) +zephyr_library_sources_ifdef(CONFIG_UART_CH5XX uart_ch5xx.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c) zephyr_library_sources_ifdef(CONFIG_UART_SCI_RA uart_renesas_ra_sci.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index cb4207d12007..32d4dfb6301b 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -282,4 +282,6 @@ rsource "Kconfig.renesas_ra8" source "drivers/serial/Kconfig.si32" +source "drivers/serial/Kconfig.ch32v" + endif # SERIAL diff --git a/drivers/serial/Kconfig.ch32v b/drivers/serial/Kconfig.ch32v new file mode 100644 index 000000000000..904f87861342 --- /dev/null +++ b/drivers/serial/Kconfig.ch32v @@ -0,0 +1,12 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config UART_CH5XX + bool "WCH CH5xx UART driver" + default y + depends on DT_HAS_WCH_CH5XX_UART_ENABLED + select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT + select PINCTRL + help + Enable WCH CH5xx UART driver. diff --git a/drivers/serial/uart_ch5xx.c b/drivers/serial/uart_ch5xx.c new file mode 100644 index 000000000000..01d89187031a --- /dev/null +++ b/drivers/serial/uart_ch5xx.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT wch_ch5xx_uart + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(uart_ch5xx, CONFIG_UART_LOG_LEVEL); + +#define UART_R8_MCR(base) (base + 0x00) +#define UART_R8_IER(base) (base + 0x01) +#define UART_R8_FCR(base) (base + 0x02) +#define UART_R8_LCR(base) (base + 0x03) +#define UART_R8_IIR(base) (base + 0x04) +#define UART_R8_LSR(base) (base + 0x05) +#define UART_R8_MSR(base) (base + 0x06) +#define UART_R8_RBR(base) (base + 0x08) +#define UART_R8_THR(base) (base + 0x08) +#define UART_R8_RFC(base) (base + 0x0A) +#define UART_R8_TFC(base) (base + 0x0B) +#define UART_R16_DL(base) (base + 0x0C) +#define UART_R8_DIV(base) (base + 0x0E) + +/* UART_R8_MCR */ +#define MCR_DTR BIT(0) +#define MCR_RTS BIT(1) +#define MCR_OUT1 BIT(2) +#define MCR_INT_OE BIT(3) +#define MCR_LOOP BIT(4) +#define MCR_AU_FLOW_EN BIT(5) +#define MCR_TNOW BIT(6) +#define MCR_HALF BIT(7) + +/* UART_R8_IER */ +#define IER_RECV_RDY BIT(0) +#define IER_THR_EMPTY BIT(1) +#define IER_LINE_STAT BIT(2) +#define IER_MODEM_CHG BIT(3) +#define IER_DTR_EN BIT(4) +#define IER_RTS_EN BIT(5) +#define IER_TXD_EN BIT(6) +#define IER_RESET BIT(7) + +/* UART_R8_FCR */ +#define FCR_FIFO_EN BIT(0) +#define FCR_RX_FIFO_CLR BIT(1) +#define FCR_TX_FIFO_CLR BIT(2) +#define FCR_FIFO_TRIG_1 (0 << 6) +#define FCR_FIFO_TRIG_2 (1 << 6) +#define FCR_FIFO_TRIG_4 (2 << 6) +#define FCR_FIFO_TRIG_7 (3 << 6) +#define FCR_FIFO_TRIG_MASK (BIT_MASK(2) << 6) + +/* UART_R8_LCR */ +#define LCR_WORD_SZ_5 (0 << 0) +#define LCR_WORD_SZ_6 (1 << 0) +#define LCR_WORD_SZ_7 (2 << 0) +#define LCR_WORD_SZ_8 (3 << 0) +#define LCR_WORD_SZ_MASK (BIT_MASK(2) << 0) +#define LCR_STOP_BIT BIT(2) +#define LCR_PAR_EN BIT(3) +#define LCR_PAR_MOD_ODD (0 << 4) +#define LCR_PAR_MOD_EVEN (1 << 4) +#define LCR_PAR_MOD_MASK (2 << 4) +#define LCR_PAR_MOD_SPACE (3 << 4) +#define LCR_PAR_MOD_MARK (BIT_MASK(2) << 4) +#define LCR_BREAK_EN BIT(6) + +/* UART_R8_IIR */ +#define IIR_INT_MASK (BIT_MASK(4) << 0) +#define IIR_INT_NOINT (0x1) +#define IIR_INT_ADDR (0xe) +#define IIR_INT_LSR (0x6) +#define IIR_INT_RBR_AVAIL (0x4) +#define IIR_INT_RBR_TIMEOUT (0xc) +#define IIR_INT_THR_EMPTY (0x2) +#define IIR_INT_MSR_CHG (0x0) + +/* UART_R8_LSR */ +#define LSR_DATA_RDY BIT(0) +#define LSR_OVER_ERR BIT(1) +#define LSR_PAR_ERR BIT(2) +#define LSR_FRAME_ERR BIT(3) +#define LSR_BREAK_ERR BIT(4) +#define LSR_TX_FIFO_EMP BIT(5) +#define LSR_TX_ALL_EMP BIT(6) +#define LSR_ERR_RX_FIFO BIT(7) + +#define UART_FIFO_SIZE 8 + +struct uart_ch5xx_config { + void (*irq_config_func)(void); + mem_addr_t base; + const struct pinctrl_dev_config *pcfg; + uint32_t sys_clk_freq; + uint32_t baud_rate; +}; + +struct uart_ch5xx_data { +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t cb; + void *cb_data; +#endif +}; + +static int uart_ch5xx_poll_in(const struct device *dev, unsigned char *p_char) +{ + const struct uart_ch5xx_config *cfg = dev->config; + + /* Wait for RX FIFO available */ + while (sys_read8(UART_R8_RFC(cfg->base)) == 0) { + } + + *p_char = sys_read8(UART_R8_RBR(cfg->base)); + + return 0; +} + +static void uart_ch5xx_poll_out(const struct device *dev, unsigned char out_char) +{ + const struct uart_ch5xx_config *cfg = dev->config; + + /* Wait for TX FIFO available */ + while (sys_read8(UART_R8_TFC(cfg->base)) == UART_FIFO_SIZE) { + } + + sys_write8(out_char, UART_R8_THR(cfg->base)); +} + +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) +static int uart_ch5xx_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) +{ + const struct uart_ch5xx_config *cfg = dev->config; + int sent; + + for (sent = 0; sent < len && sys_read8(UART_R8_TFC(cfg->base)) < UART_FIFO_SIZE; sent++) { + sys_write8(tx_data[sent], UART_R8_THR(cfg->base)); + } + + return sent; +} + +static int uart_ch5xx_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) +{ + const struct uart_ch5xx_config *cfg = dev->config; + int read; + + for (read = 0; read < size && sys_read8(UART_R8_RFC(cfg->base)) > 0; read++) { + rx_data[read] = sys_read8(UART_R8_RBR(cfg->base)); + } + + return read; +} + +static void uart_ch5xx_irq_tx_enable(const struct device *dev) +{ + const struct uart_ch5xx_config *cfg = dev->config; + uint32_t regval; + + regval = sys_read8(UART_R8_IER(cfg->base)); + regval |= IER_THR_EMPTY; + sys_write8(regval, UART_R8_IER(cfg->base)); +} + +static void uart_ch5xx_irq_tx_disable(const struct device *dev) +{ + const struct uart_ch5xx_config *cfg = dev->config; + uint32_t regval; + + regval = sys_read8(UART_R8_IER(cfg->base)); + regval &= ~IER_THR_EMPTY; + sys_write8(regval, UART_R8_IER(cfg->base)); +} + +static int uart_ch5xx_irq_tx_ready(const struct device *dev) +{ + const struct uart_ch5xx_config *cfg = dev->config; + + return sys_read8(UART_R8_TFC(cfg->base)) < UART_FIFO_SIZE; +} + +static void uart_ch5xx_irq_rx_enable(const struct device *dev) +{ + const struct uart_ch5xx_config *cfg = dev->config; + uint32_t regval; + + regval = sys_read8(UART_R8_IER(cfg->base)); + regval |= IER_RECV_RDY; + sys_write8(regval, UART_R8_IER(cfg->base)); +} + +static void uart_ch5xx_irq_rx_disable(const struct device *dev) +{ + const struct uart_ch5xx_config *cfg = dev->config; + uint32_t regval; + + regval = sys_read8(UART_R8_IER(cfg->base)); + regval &= ~IER_RECV_RDY; + sys_write8(regval, UART_R8_IER(cfg->base)); +} + +static int uart_ch5xx_irq_rx_ready(const struct device *dev) +{ + const struct uart_ch5xx_config *cfg = dev->config; + + return sys_read8(UART_R8_RFC(cfg->base)) > 0; +} + +static int uart_ch5xx_irq_is_pending(const struct device *dev) +{ + const struct uart_ch5xx_config *cfg = dev->config; + uint32_t regval; + + regval = sys_read8(UART_R8_IIR(cfg->base)) & IIR_INT_MASK; + + return regval != IIR_INT_NOINT; +} + +static int uart_ch5xx_irq_update(const struct device *dev) +{ + return 1; +} + +static void uart_ch5xx_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, + void *user_data) +{ + struct uart_ch5xx_data *data = dev->data; + + data->cb = cb; + data->cb_data = user_data; +} + +static void uart_ch5xx_isr(const struct device *dev) +{ + const struct uart_ch5xx_config *cfg = dev->config; + struct uart_ch5xx_data *data = dev->data; + uint32_t regval; + + if (data->cb) { + data->cb(dev, data->cb_data); + } + + regval = sys_read8(UART_R8_IIR(cfg->base)); + switch (regval & IIR_INT_MASK) { + case IIR_INT_NOINT: + case IIR_INT_ADDR: + break; + case IIR_INT_LSR: + if (sys_read8(UART_R8_LSR(cfg->base)) & LSR_ERR_RX_FIFO) { + uart_irq_err_enable(dev); + } + break; + case IIR_INT_RBR_AVAIL: + if (sys_read8(UART_R8_LSR(cfg->base)) & LSR_DATA_RDY) { + uart_irq_rx_ready(dev); + } + break; + case IIR_INT_RBR_TIMEOUT: + if (sys_read8(UART_R8_LSR(cfg->base)) & LSR_DATA_RDY) { + uart_irq_rx_ready(dev); + } + break; + case IIR_INT_THR_EMPTY: + uart_irq_tx_ready(dev); + break; + default: + break; + } +} +#endif + +static int uart_ch5xx_init(const struct device *dev) +{ + const struct uart_ch5xx_config *cfg = dev->config; + uint32_t regval; + int ret; + + regval = 10 * cfg->sys_clk_freq * 2 / 16 / cfg->baud_rate; + regval = (regval + 5) / 10; + sys_write8(1, UART_R8_DIV(cfg->base)); + sys_write16(regval, UART_R16_DL(cfg->base)); + + sys_write8(FCR_FIFO_EN | FCR_RX_FIFO_CLR | FCR_TX_FIFO_CLR, UART_R8_FCR(cfg->base)); + + sys_write8(LCR_WORD_SZ_8, UART_R8_LCR(cfg->base)); + + sys_write8(IER_TXD_EN, UART_R8_IER(cfg->base)); + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) + regval = sys_read8(UART_R8_MCR(cfg->base)); + regval |= MCR_INT_OE; + sys_write8(regval, UART_R8_MCR(cfg->base)); + + cfg->irq_config_func(); +#endif + + return 0; +} + +static const struct uart_driver_api uart_ch5xx_api = { + .poll_in = uart_ch5xx_poll_in, + .poll_out = uart_ch5xx_poll_out, +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) + .fifo_fill = uart_ch5xx_fifo_fill, + .fifo_read = uart_ch5xx_fifo_read, + .irq_tx_enable = uart_ch5xx_irq_tx_enable, + .irq_tx_disable = uart_ch5xx_irq_tx_disable, + .irq_tx_ready = uart_ch5xx_irq_tx_ready, + .irq_rx_enable = uart_ch5xx_irq_rx_enable, + .irq_rx_disable = uart_ch5xx_irq_rx_disable, + .irq_rx_ready = uart_ch5xx_irq_rx_ready, + .irq_is_pending = uart_ch5xx_irq_is_pending, + .irq_update = uart_ch5xx_irq_update, + .irq_callback_set = uart_ch5xx_irq_callback_set, +#endif +}; + +#define UART_CH5XX_INST(n) \ + static struct uart_ch5xx_data uart_ch5xx_data_##n; \ + \ + static void uart_ch5xx_irq_config_func_##n(void) \ + { \ + IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, \ + (IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), uart_ch5xx_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n));)) \ + } \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + static const struct uart_ch5xx_config uart_ch5xx_cfg_##n = { \ + .irq_config_func = uart_ch5xx_irq_config_func_##n, \ + .base = DT_INST_REG_ADDR(n), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .sys_clk_freq = DT_INST_PROP_BY_PHANDLE(n, clocks, clock_frequency), \ + .baud_rate = DT_INST_PROP(n, current_speed), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, uart_ch5xx_init, NULL, &uart_ch5xx_data_##n, &uart_ch5xx_cfg_##n, \ + PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, &uart_ch5xx_api); + +DT_INST_FOREACH_STATUS_OKAY(UART_CH5XX_INST) diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index ac5bac6c244a..e407d07fa7a1 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -37,3 +37,4 @@ zephyr_library_sources_ifdef(CONFIG_XLNX_PSTTC_TIMER xlnx_psttc_timer.c) zephyr_library_sources_ifdef(CONFIG_XTENSA_TIMER xtensa_sys_timer.c) zephyr_library_sources_ifdef(CONFIG_SMARTBOND_TIMER smartbond_timer.c) zephyr_library_sources_ifdef(CONFIG_MTK_ADSP_TIMER mtk_adsp_timer.c) +zephyr_library_sources_ifdef(CONFIG_CH32V_V3_SYSTICK ch32v_v3_systick.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 3343f78d79ce..4de53e36b7e0 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -96,6 +96,7 @@ source "drivers/timer/Kconfig.ti_dm_timer" source "drivers/timer/Kconfig.xlnx_psttc" source "drivers/timer/Kconfig.xtensa" source "drivers/timer/Kconfig.mtk_adsp" +source "drivers/timer/Kconfig.ch32v" endmenu diff --git a/drivers/timer/Kconfig.ch32v b/drivers/timer/Kconfig.ch32v new file mode 100644 index 000000000000..b025a7b641c5 --- /dev/null +++ b/drivers/timer/Kconfig.ch32v @@ -0,0 +1,10 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config CH32V_V3_SYSTICK + bool "WCH CH32V V3 SysTick" + default y + depends on DT_HAS_WCH_CH32V_V3_SYSTICK_ENABLED + select TIMER_HAS_64BIT_CYCLE_COUNTER + help + Enable WCH CH32V V3 SysTick driver. diff --git a/drivers/timer/ch32v_v3_systick.c b/drivers/timer/ch32v_v3_systick.c new file mode 100644 index 000000000000..bcb6984fa114 --- /dev/null +++ b/drivers/timer/ch32v_v3_systick.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT wch_ch32v_v3_systick + +#include +#include +#include + +#define CYCLES_PER_TICK (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC) + +#define STK_BASE DT_INST_REG_ADDR(0) + +#define STK_R32_CTLR (STK_BASE + 0x00) +#define STK_R64_CNT (STK_BASE + 0x04) +#define STK_R64_CMPR (STK_BASE + 0x0C) +#define STK_R32_CNTFG (STK_BASE + 0x14) + +/* STK_R32_CTLR */ +#define CTLR_STE BIT(0) +#define CTLR_STIE BIT(1) +#define CTLR_STCLK BIT(2) +#define CTLR_RELOAD BIT(8) + +/* STK_R32_CNTFG */ +#define CNTFG_SWIE BIT(0) +#define CNTFG_CNTIF BIT(1) + +static volatile uint64_t announced_ticks; + +static void sys_clock_isr(const void *arg) +{ + ARG_UNUSED(arg); + + /* Clear interrupt */ + sys_write32(0, STK_R32_CNTFG); + + announced_ticks++; + sys_clock_announce(1); +} + +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ + ARG_UNUSED(ticks); + ARG_UNUSED(idle); +} + +uint32_t sys_clock_elapsed(void) +{ + return 0; +} + +uint32_t sys_clock_cycle_get_32(void) +{ + return (uint32_t)sys_clock_cycle_get_64(); +} + +uint64_t sys_clock_cycle_get_64(void) +{ + return announced_ticks * CYCLES_PER_TICK + + (sys_read64(STK_R64_CMPR) - sys_read64(STK_R64_CNT)); +} + +static int sys_clock_init(void) +{ + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), sys_clock_isr, NULL, 0); + irq_enable(DT_INST_IRQN(0)); + + sys_write64(CYCLES_PER_TICK, STK_R64_CMPR); + sys_write32(CTLR_STE | CTLR_STIE | CTLR_STCLK | CTLR_RELOAD, STK_R32_CTLR); + + return 0; +} + +SYS_INIT(sys_clock_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/dts/bindings/clock/wch,ch56x-clkmux.yaml b/dts/bindings/clock/wch,ch56x-clkmux.yaml new file mode 100644 index 000000000000..28d7b004962d --- /dev/null +++ b/dts/bindings/clock/wch,ch56x-clkmux.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +description: WCH CH56x clock mux controller + +compatible: "wch,ch56x-clkmux" + +include: [clock-controller.yaml, base.yaml] + +properties: + clock-frequency: + type: int + description: | + System clock frequency in Hz. Supported values are: + - DT_FREQ_M(2) + - DT_FREQ_M(15) + - DT_FREQ_M(30) + - DT_FREQ_M(60) + - DT_FREQ_M(80) + - DT_FREQ_M(96) + - DT_FREQ_M(120) + enum: + - 2000000 + - 15000000 + - 30000000 + - 60000000 + - 80000000 + - 96000000 + - 120000000 + + "#clock-cells": + const: 0 diff --git a/dts/bindings/cpu/wch,qingke-v3.yaml b/dts/bindings/cpu/wch,qingke-v3.yaml new file mode 100644 index 000000000000..4db505ea6bb7 --- /dev/null +++ b/dts/bindings/cpu/wch,qingke-v3.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +description: WCH QingKe V3 RISC-V CPU + +compatible: "wch,qingke-v3" + +include: cpu.yaml diff --git a/dts/bindings/gpio/wch,ch56x-gpio.yaml b/dts/bindings/gpio/wch,ch56x-gpio.yaml new file mode 100644 index 000000000000..7319601079c8 --- /dev/null +++ b/dts/bindings/gpio/wch,ch56x-gpio.yaml @@ -0,0 +1,28 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +description: WCH CH56x GPIO + +compatible: "wch,ch56x-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + interruptible-pins: + type: array + description: | + List of pairs for pins that can be used as interrupt. Refer + to the datasheet for offset values. + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/interrupt-controller/wch,ch32v-pfic.yaml b/dts/bindings/interrupt-controller/wch,ch32v-pfic.yaml new file mode 100644 index 000000000000..5f49e71e548e --- /dev/null +++ b/dts/bindings/interrupt-controller/wch,ch32v-pfic.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +description: WCH CH32V PFIC + +compatible: "wch,ch32v-pfic" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#interrupt-cells": + const: 2 + +interrupt-cells: + - irq + - priority diff --git a/dts/bindings/pinctrl/wch,ch5xx-pinctrl.yaml b/dts/bindings/pinctrl/wch,ch5xx-pinctrl.yaml new file mode 100644 index 000000000000..6321e5863914 --- /dev/null +++ b/dts/bindings/pinctrl/wch,ch5xx-pinctrl.yaml @@ -0,0 +1,49 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +description: | + The CH5xx series introduces limited pin multiplexing capabilities, where the + functionality of each pin is prioritized and determined by the enabled + peripherals. When a peripheral is enabled, it connects and locks specific pins + (unlike most MCUs, which allow unconnected pins to remain as regular GPIOs). + + Nevertheless, the pinctrl driver for CH5xx has been implemented to handle the + following tasks: + + * Configuring pin directions, pull-ups/pull-downs, and other pin parameters + for peripherals. + * Enabling the remapping of a subset of supported peripherals from a fixed set + of pins to another. + +compatible: "wch,ch5xx-pinctrl" + +include: base.yaml + +properties: + gpio-controllers: + type: phandles + description: Phandle to GPIO controllers. + required: true + +child-binding: + description: CH5xx pinmux group + + child-binding: + include: + - name: pincfg-node.yaml + property-allowlist: + - bias-pull-up + - bias-pull-down + - drive-push-pull + - drive-open-drain + - input-enable + - output-enable + + properties: + pinmux: + required: true + type: array + + gpio-flags: + type: int + description: Additional flags for the pin. diff --git a/dts/bindings/serial/wch,ch5xx-uart.yaml b/dts/bindings/serial/wch,ch5xx-uart.yaml new file mode 100644 index 000000000000..8849e34c8df5 --- /dev/null +++ b/dts/bindings/serial/wch,ch5xx-uart.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +description: WCH CH5xx UART driver + +compatible: "wch,ch5xx-uart" + +include: [uart-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + clocks: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true diff --git a/dts/bindings/timer/wch,ch32v-v3-systick.yaml b/dts/bindings/timer/wch,ch32v-v3-systick.yaml new file mode 100644 index 000000000000..098740039810 --- /dev/null +++ b/dts/bindings/timer/wch,ch32v-v3-systick.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +description: WCH CH32V V3 SysTick + +compatible: "wch,ch32v-v3-systick" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index b243c8e61162..c6506110d931 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -720,6 +720,7 @@ vot Vision Optical Technology Co., Ltd. vxt VXT Ltd wand Wandbord (Technexion) waveshare Waveshare Electronics +wch Nanjing Qinheng Microelectronics Co., Ltd. wd Western Digital Corp. we Würth Elektronik GmbH. weact WeAct Studio diff --git a/dts/riscv/wch/ch56x/ch565m-pinctrl.dtsi b/dts/riscv/wch/ch56x/ch565m-pinctrl.dtsi new file mode 100644 index 000000000000..4b76b4df75a1 --- /dev/null +++ b/dts/riscv/wch/ch56x/ch565m-pinctrl.dtsi @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/dts/riscv/wch/ch56x/ch565m.dtsi b/dts/riscv/wch/ch56x/ch565m.dtsi new file mode 100644 index 000000000000..eb2625581770 --- /dev/null +++ b/dts/riscv/wch/ch56x/ch565m.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + compatible = "wch,ch565m", "simple-bus"; + }; +}; + +&gpioa { + gpio-reserved-ranges = <7 2>, /* PA 7 - PA 8 */ + <10 3>, /* PA 10 - PA 12 */ + <14 10>; /* PA 14 - PA 23 */ +}; + +&gpiob { + gpio-reserved-ranges = <0 3>, /* PB 0 - PB 2 */ + <5 6>; /* PB 5 - PB 10 */ +}; diff --git a/dts/riscv/wch/ch56x/ch565w-pinctrl.dtsi b/dts/riscv/wch/ch56x/ch565w-pinctrl.dtsi new file mode 100644 index 000000000000..55aeb1dcf025 --- /dev/null +++ b/dts/riscv/wch/ch56x/ch565w-pinctrl.dtsi @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include diff --git a/dts/riscv/wch/ch56x/ch565w.dtsi b/dts/riscv/wch/ch56x/ch565w.dtsi new file mode 100644 index 000000000000..fc9069e54a6b --- /dev/null +++ b/dts/riscv/wch/ch56x/ch565w.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + soc { + compatible = "wch,ch565w", "simple-bus"; + }; +}; diff --git a/dts/riscv/wch/ch56x/ch569w-pinctrl.dtsi b/dts/riscv/wch/ch56x/ch569w-pinctrl.dtsi new file mode 100644 index 000000000000..55aeb1dcf025 --- /dev/null +++ b/dts/riscv/wch/ch56x/ch569w-pinctrl.dtsi @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include diff --git a/dts/riscv/wch/ch56x/ch569w.dtsi b/dts/riscv/wch/ch56x/ch569w.dtsi new file mode 100644 index 000000000000..f947c0bf0b3c --- /dev/null +++ b/dts/riscv/wch/ch56x/ch569w.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + soc { + compatible = "wch,ch569w", "simple-bus"; + }; +}; diff --git a/dts/riscv/wch/ch56x/ch56x-common-pinctrl.dtsi b/dts/riscv/wch/ch56x/ch56x-common-pinctrl.dtsi new file mode 100644 index 000000000000..75f3e9e71cd6 --- /dev/null +++ b/dts/riscv/wch/ch56x/ch56x-common-pinctrl.dtsi @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /omit-if-no-ref/ pwm0_default: pwm0_default { + group1 { + pinmux = ; /* PWM0 */ + output-enable; + drive-push-pull; + }; + }; + + /omit-if-no-ref/ pwm1_default: pwm1_default { + group1 { + pinmux = ; /* PWM1 */ + output-enable; + drive-push-pull; + }; + }; + + /omit-if-no-ref/ tmr0_capture_default: tmr0_capture_default { + group1 { + pinmux = ; /* TMR0 */ + input-enable; + }; + }; + + /omit-if-no-ref/ tmr0_output_default: tmr0_output_default { + group1 { + pinmux = ; /* TMR0 */ + output-enable; + drive-push-pull; + }; + }; + + /omit-if-no-ref/ tmr1_capture_default: tmr1_capture_default { + group1 { + pinmux = ; /* TMR1 */ + input-enable; + }; + }; + + /omit-if-no-ref/ tmr1_output_default: tmr1_output_default { + group1 { + pinmux = ; /* TMR1 */ + output-enable; + drive-push-pull; + }; + }; + + /omit-if-no-ref/ tmr2_capture_default: tmr2_capture_default { + group1 { + pinmux = ; /* TMR2 */ + input-enable; + }; + }; + + /omit-if-no-ref/ tmr2_output_default: tmr2_output_default { + group1 { + pinmux = ; /* TMR2 */ + output-enable; + drive-push-pull; + }; + }; + + /omit-if-no-ref/ tmr2_capture_remap: tmr2_capture_remap { + group1 { + pinmux = ; /* TMR2 */ + input-enable; + }; + }; + + /omit-if-no-ref/ tmr2_output_remap: tmr2_output_remap { + group1 { + pinmux = ; /* TMR2 */ + output-enable; + drive-push-pull; + }; + }; + + /omit-if-no-ref/ uart0_remap: uart0_remap { + group1 { + pinmux = , /* TXD0_ */ + , /* DTR */ + ; /* RTS */ + output-enable; + drive-push-pull; + }; + group2 { + pinmux = , /* RXD0_ */ + , /* DSR */ + , /* RI */ + , /* DCD */ + ; /* CTS */ + input-enable; + }; + }; + + /omit-if-no-ref/ uart2_default: uart2_default { + group1 { + pinmux = ; /* TXD2 */ + output-enable; + drive-push-pull; + }; + group2 { + pinmux = ; /* RXD2 */ + input-enable; + }; + }; + + /omit-if-no-ref/ uart3_default: uart3_default { + group1 { + pinmux = ; /* TXD3 */ + output-enable; + drive-push-pull; + }; + group2 { + pinmux = ; /* RXD3 */ + input-enable; + }; + }; + + /omit-if-no-ref/ spi1_default: spi1_default { + group1 { + pinmux = , /* SCK1 */ + ; /* MOSI1 */ + output-enable; + drive-push-pull; + }; + group2 { + pinmux = ; /* MISO1 */ + input-enable; + }; + }; +}; diff --git a/dts/riscv/wch/ch56x/ch56x-common.dtsi b/dts/riscv/wch/ch56x/ch56x-common.dtsi new file mode 100644 index 000000000000..6c2bd0426fec --- /dev/null +++ b/dts/riscv/wch/ch56x/ch56x-common.dtsi @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +/ { + soc { + flash: flash@0 { + compatible = "soc-nv-flash"; + reg = <0x00000000 DT_SIZE_K(448)>; + }; + + rams: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(16)>; + }; + + ramx: memory@20020000 { + compatible = "mmio-sram"; + reg = <0x20020000 DT_SIZE_K(16)>; + }; + + syscon: system-control@40001000 { + reg = <0x40001000 0x20>; + + pinctrl: pin-alternate { + compatible = "wch,ch5xx-pinctrl"; + gpio-controllers = <&gpioa>, <&gpiob>; + }; + }; + + gpioa: gpio@40001040 { + compatible = "wch,ch56x-gpio"; + reg = <0x40001040 0x20>; + interrupts = <18 4>; + interruptible-pins = <2 0>, <3 1>, <4 2>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <24>; + }; + + gpiob: gpio@40001060 { + compatible = "wch,ch56x-gpio"; + reg = <0x40001060 0x20>; + interrupts = <18 4>; + interruptible-pins = <3 3>, <4 4>, <11 5>, <12 6>, <15 7>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <25>; + }; + + uart0: uart@40003000 { + compatible = "wch,ch5xx-uart"; + reg = <0x40003000 0x400>; + interrupts = <24 10>; + clocks = <&hclk>; + status = "disabled"; + }; + + uart2: uart@40003800 { + compatible = "wch,ch5xx-uart"; + reg = <0x40003800 0x400>; + interrupts = <31 17>; + clocks = <&hclk>; + status = "disabled"; + }; + + uart3: uart@40003c00 { + compatible = "wch,ch5xx-uart"; + reg = <0x40003c00 0x400>; + interrupts = <32 18>; + clocks = <&hclk>; + status = "disabled"; + }; + }; + + clocks { + hclk: clkmux { + compatible = "wch,ch56x-clkmux"; + clock-frequency = ; + #clock-cells = <0>; + }; + }; +}; diff --git a/dts/riscv/wch/ch56x/ch56xw-common-pinctrl.dtsi b/dts/riscv/wch/ch56x/ch56xw-common-pinctrl.dtsi new file mode 100644 index 000000000000..33d6f1fbf580 --- /dev/null +++ b/dts/riscv/wch/ch56x/ch56xw-common-pinctrl.dtsi @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /omit-if-no-ref/ pwm2_default: pwm2_default { + group1 { + pinmux = ; /* PWM2 */ + output-enable; + drive-push-pull; + }; + }; + + /omit-if-no-ref/ pwm3_default: pwm3_default { + group1 { + pinmux = ; /* PWM3 */ + output-enable; + drive-push-pull; + }; + }; + + /omit-if-no-ref/ tmr1_capture_remap: tmr1_capture_remap { + group1 { + pinmux = ; /* TMR1 */ + input-enable; + }; + }; + + /omit-if-no-ref/ tmr1_output_remap: tmr1_output_remap { + group1 { + pinmux = ; /* TMR1 */ + output-enable; + drive-push-pull; + }; + }; + + /omit-if-no-ref/ uart0_default: uart0_default { + group1 { + pinmux = , /* TXD0 */ + , /* DTR */ + ; /* RTS */ + output-enable; + drive-push-pull; + }; + group2 { + pinmux = , /* RXD0 */ + , /* DSR */ + , /* RI */ + , /* DCD */ + ; /* CTS */ + input-enable; + }; + }; + + /omit-if-no-ref/ uart1_default: uart1_default { + group1 { + pinmux = ; /* TXD1 */ + output-enable; + drive-push-pull; + }; + group2 { + pinmux = ; /* RXD1 */ + input-enable; + }; + }; + + /omit-if-no-ref/ spi0_default: spi0_default { + group1 { + pinmux = , /* SCK */ + ; /* MOSI */ + output-enable; + drive-push-pull; + }; + group2 { + pinmux = ; /* MISO */ + input-enable; + }; + }; +}; diff --git a/dts/riscv/wch/ch56x/ch56xw-common.dtsi b/dts/riscv/wch/ch56x/ch56xw-common.dtsi new file mode 100644 index 000000000000..c86604dc4c14 --- /dev/null +++ b/dts/riscv/wch/ch56x/ch56xw-common.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + uart1: uart@40003400 { + compatible = "wch,ch5xx-uart"; + reg = <0x40003400 0x400>; + interrupts = <30 16>; + clocks = <&hclk>; + status = "disabled"; + }; + }; +}; diff --git a/dts/riscv/wch/qingke-v3.dtsi b/dts/riscv/wch/qingke-v3.dtsi new file mode 100644 index 000000000000..966961a18b5e --- /dev/null +++ b/dts/riscv/wch/qingke-v3.dtsi @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "wch,qingke-v3"; + reg = <0>; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&pfic>; + + pfic: pfic@e000e000 { + compatible = "wch,ch32v-pfic"; + reg = <0xe000e000 0x1000>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + systick: systick@e000f000 { + compatible = "wch,ch32v-v3-systick"; + reg = <0xe000f000 0x14>; + interrupts = <12 0>; + }; + }; +}; diff --git a/include/zephyr/arch/riscv/irq.h b/include/zephyr/arch/riscv/irq.h index 8408912716a7..c33a92d7f9a9 100644 --- a/include/zephyr/arch/riscv/irq.h +++ b/include/zephyr/arch/riscv/irq.h @@ -50,6 +50,8 @@ extern "C" { #ifndef _ASMLANGUAGE +#if !defined(CONFIG_RISCV_CUSTOM_INTERRUPT_CONTROLLER) + extern void arch_irq_enable(unsigned int irq); extern void arch_irq_disable(unsigned int irq); extern int arch_irq_is_enabled(unsigned int irq); @@ -62,6 +64,26 @@ extern void z_riscv_irq_priority_set(unsigned int irq, #define z_riscv_irq_priority_set(i, p, f) /* Nothing */ #endif /* CONFIG_RISCV_HAS_PLIC || CONFIG_RISCV_HAS_CLIC */ +#else + +/* + * When a custom interrupt controller is specified, map the architecture + * interrupt control functions to the SoC layer interrupt control functions. + */ + +void z_soc_irq_init(void); +void z_soc_irq_enable(unsigned int irq); +void z_soc_irq_disable(unsigned int irq); +int z_soc_irq_is_enabled(unsigned int irq); +void z_soc_irq_priority_set(unsigned int irq, unsigned int prio, unsigned int flags); + +#define arch_irq_enable(irq) z_soc_irq_enable(irq) +#define arch_irq_disable(irq) z_soc_irq_disable(irq) +#define arch_irq_is_enabled(irq) z_soc_irq_is_enabled(irq) +#define z_riscv_irq_priority_set(irq, prio, flags) z_soc_irq_priority_set(irq, prio, flags) + +#endif /* !CONFIG_RISCV_CUSTOM_INTERRUPT_CONTROLLER */ + #ifdef CONFIG_RISCV_HAS_CLIC extern void z_riscv_irq_vector_set(unsigned int irq); #else diff --git a/include/zephyr/drivers/interrupt_controller/intc_ch32v_pfic.h b/include/zephyr/drivers/interrupt_controller/intc_ch32v_pfic.h new file mode 100644 index 000000000000..d30bea582ba6 --- /dev/null +++ b/include/zephyr/drivers/interrupt_controller/intc_ch32v_pfic.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_CH32V_PFIC_ +#define ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_CH32V_PFIC_ + +void ch32v_pfic_enable(unsigned int irq); +void ch32v_pfic_disable(unsigned int irq); +int ch32v_pfic_is_enabled(unsigned int irq); +void ch32v_pfic_priority_set(unsigned int irq, unsigned int prio, unsigned int flags); + +#endif /* ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_CH32V_PFIC_ */ diff --git a/include/zephyr/dt-bindings/gpio/ch56x-gpio.h b/include/zephyr/dt-bindings/gpio/ch56x-gpio.h new file mode 100644 index 000000000000..0cdb5a19330f --- /dev/null +++ b/include/zephyr/dt-bindings/gpio/ch56x-gpio.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DT_CH56X_GPIO_H_ +#define ZEPHYR_DT_CH56X_GPIO_H_ + +#include + +#define CH56X_GPIO_DRIVE_STRENGTH_16MA BIT(8) +#define CH56X_GPIO_SCHMITT_TRIGGER BIT(9) + +#endif /* ZEPHYR_DT_CH56X_GPIO_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/ch56x-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/ch56x-pinctrl.h new file mode 100644 index 000000000000..a1511a367bcd --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/ch56x-pinctrl.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DT_CH56X_PINCTRL_H_ +#define ZEPHYR_DT_CH56X_PINCTRL_H_ + +#include +#include + +#define CH56X_PINMUX(port, pin) CH5XX_PINMUX(port, pin) + +#define CH56X_PINMUX_REMAP(port, pin, func, remap) \ + CH5XX_PINMUX_REMAP(port, pin, CH56X_PINMUX_REMAP_##func, remap) + +#define CH56X_PINMUX_REMAP_MII 0 +#define CH56X_PINMUX_REMAP_TMR1 1 +#define CH56X_PINMUX_REMAP_TMR2 2 +#define CH56X_PINMUX_REMAP_UART0 4 + +#endif /* ZEPHYR_DT_CH56X_PINCTRL_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/ch5xx-pinctrl-common.h b/include/zephyr/dt-bindings/pinctrl/ch5xx-pinctrl-common.h new file mode 100644 index 000000000000..c80c8cbda8a6 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/ch5xx-pinctrl-common.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DT_CH5XX_PINCTRL_COMMON_H_ +#define ZEPHYR_DT_CH5XX_PINCTRL_COMMON_H_ + +#include + +#define CH5XX_PINMUX_PORT_S (0) +#define CH5XX_PINMUX_PORT_M BIT_MASK(8) + +#define CH5XX_PINMUX_PIN_S (8) +#define CH5XX_PINMUX_PIN_M BIT_MASK(8) + +#define CH5XX_PINMUX_REMAP_BIT_S (16) +#define CH5XX_PINMUX_REMAP_BIT_M BIT_MASK(8) + +#define CH5XX_PINMUX_REMAP_EN_S (24) +#define CH5XX_PINMUX_REMAP_EN_M BIT_MASK(1) + +#define CH5XX_PINMUX(port, pin) \ + ((((port - 'A') & CH5XX_PINMUX_PORT_M) << CH5XX_PINMUX_PORT_S) | \ + ((pin & CH5XX_PINMUX_PIN_M) << CH5XX_PINMUX_PIN_S)) + +#define CH5XX_PINMUX_REMAP(port, pin, bit, en) \ + (CH5XX_PINMUX(port, pin) | \ + ((bit & CH5XX_PINMUX_REMAP_BIT_M) << CH5XX_PINMUX_REMAP_BIT_S) | \ + ((CH5XX_PINMUX_REMAP_EN_##en) << CH5XX_PINMUX_REMAP_EN_S)) + +#define CH5XX_PINMUX_REMAP_EN_DEFAULT (0) +#define CH5XX_PINMUX_REMAP_EN_REMAP (1) + +#endif /* ZEPHYR_DT_CH5XX_PINCTRL_COMMON_H_ */ diff --git a/scripts/west_commands/runners/__init__.py b/scripts/west_commands/runners/__init__.py index 6d5539905e33..6684514f6426 100644 --- a/scripts/west_commands/runners/__init__.py +++ b/scripts/west_commands/runners/__init__.py @@ -59,6 +59,7 @@ def _import_runner_module(runner_name): 'teensy', 'trace32', 'uf2', + 'wchisp', 'xtensa', # Keep this list sorted by runner name; don't add to the end. ] diff --git a/scripts/west_commands/runners/wchisp.py b/scripts/west_commands/runners/wchisp.py new file mode 100644 index 000000000000..6c901e55ee52 --- /dev/null +++ b/scripts/west_commands/runners/wchisp.py @@ -0,0 +1,43 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +'''Runner for flashing WCH devices with WCHISPTool_CMD.''' + +from runners.core import ZephyrBinaryRunner, RunnerCaps + +class WchIspBinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for WCHISPTool_CMD''' + + def __init__(self, cfg, device, cfg_file): + super().__init__(cfg) + self.app_bin = cfg.bin_file + self.device = device + self.cfg_file = cfg_file + + @classmethod + def name(cls): + return 'wchisp' + + @classmethod + def capabilities(cls): + return RunnerCaps(commands={'flash'}) + + @classmethod + def do_add_parser(cls, parser): + parser.add_argument('--device', required=True, + help='port of the USB ISP device') + parser.add_argument('--cfg-file', required=True, + help='configuration file generated by WCHISPTool') + + @classmethod + def do_create(cls, cfg, args): + return WchIspBinaryRunner(cfg, args.device, args.cfg_file) + + def do_run(self, command, **kwargs): + self.check_call([ + 'WCHISPTool_CMD', + '--device', self.device, + '--configure', self.cfg_file, + '--operation', 'program', + '--flash', self.app_bin, + ]) diff --git a/scripts/west_commands/tests/test_imports.py b/scripts/west_commands/tests/test_imports.py index 42fb983586df..1e31e3afa5ca 100644 --- a/scripts/west_commands/tests/test_imports.py +++ b/scripts/west_commands/tests/test_imports.py @@ -49,5 +49,6 @@ def test_runner_imports(): 'trace32', 'teensy', 'uf2', + 'wchisp', 'xtensa')) assert runner_names == expected diff --git a/soc/common/riscv-privileged/CMakeLists.txt b/soc/common/riscv-privileged/CMakeLists.txt index 80be64cf2a97..626ca0b88ff1 100644 --- a/soc/common/riscv-privileged/CMakeLists.txt +++ b/soc/common/riscv-privileged/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_include_directories(.) zephyr_sources( soc_irq.S - soc_common_irq.c vector.S ) + +zephyr_sources_ifndef(CONFIG_RISCV_CUSTOM_INTERRUPT_CONTROLLER soc_common_irq.c) diff --git a/soc/wch/ch32v/CMakeLists.txt b/soc/wch/ch32v/CMakeLists.txt new file mode 100644 index 000000000000..dfa55b9c7b98 --- /dev/null +++ b/soc/wch/ch32v/CMakeLists.txt @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_include_directories(.) + +zephyr_library_sources( + cpu_idle.c + irq.c + soc_common.c +) + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/wch/ch32v/Kconfig b/soc/wch/ch32v/Kconfig new file mode 100644 index 000000000000..83db4bb182c2 --- /dev/null +++ b/soc/wch/ch32v/Kconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_CH32V + select RISCV + select RISCV_PRIVILEGED + select RISCV_CUSTOM_INTERRUPT_CONTROLLER + select INCLUDE_RESET_VECTOR + select ATOMIC_OPERATIONS_C + select ARCH_HAS_CUSTOM_CPU_IDLE + select ARCH_HAS_CUSTOM_CPU_ATOMIC_IDLE + +if SOC_FAMILY_CH32V + +rsource "*/Kconfig" + +endif # SOC_FAMILY_CH32V diff --git a/soc/wch/ch32v/Kconfig.defconfig b/soc/wch/ch32v/Kconfig.defconfig new file mode 100644 index 000000000000..bd22bde3a248 --- /dev/null +++ b/soc/wch/ch32v/Kconfig.defconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_CH32V + +rsource "*/Kconfig.defconfig" + +endif # SOC_FAMILY_CH32V diff --git a/soc/wch/ch32v/Kconfig.soc b/soc/wch/ch32v/Kconfig.soc new file mode 100644 index 000000000000..76cd16585737 --- /dev/null +++ b/soc/wch/ch32v/Kconfig.soc @@ -0,0 +1,10 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_CH32V + bool + +config SOC_FAMILY + default "ch32v" if SOC_FAMILY_CH32V + +rsource "*/Kconfig.soc" diff --git a/soc/wch/ch32v/cpu_idle.c b/soc/wch/ch32v/cpu_idle.c new file mode 100644 index 000000000000..63fda0000ccd --- /dev/null +++ b/soc/wch/ch32v/cpu_idle.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +void arch_cpu_idle(void) +{ + sys_trace_idle(); + irq_unlock(MSTATUS_IEN); +} + +void arch_cpu_atomic_idle(unsigned int key) +{ + sys_trace_idle(); + irq_unlock(key); +} diff --git a/soc/wch/ch32v/irq.c b/soc/wch/ch32v/irq.c new file mode 100644 index 000000000000..30708ccaa917 --- /dev/null +++ b/soc/wch/ch32v/irq.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +void z_soc_irq_enable(unsigned int irq) +{ + ch32v_pfic_enable(irq); +} + +void z_soc_irq_disable(unsigned int irq) +{ + ch32v_pfic_disable(irq); +} + +int z_soc_irq_is_enabled(unsigned int irq) +{ + return ch32v_pfic_is_enabled(irq); +} + +void z_soc_irq_priority_set(unsigned int irq, unsigned int prio, unsigned int flags) +{ + ch32v_pfic_priority_set(irq, prio, flags); +} diff --git a/soc/wch/ch32v/pinctrl_soc_ch5xx.h b/soc/wch/ch32v/pinctrl_soc_ch5xx.h new file mode 100644 index 000000000000..4e4e7c153f80 --- /dev/null +++ b/soc/wch/ch32v/pinctrl_soc_ch5xx.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __CH32V_PINCTRL_SOC_CH5XX_H__ +#define __CH32V_PINCTRL_SOC_CH5XX_H__ + +#include +#include +#include +#include + +struct pinctrl_soc_pin { + uint8_t port; + uint8_t pin; + uint8_t remap_bit; + uint8_t remap_en; + uint32_t flags; +}; + +typedef struct pinctrl_soc_pin pinctrl_soc_pin_t; + +#define CH5XX_PINMUX_GET(pinmux, field) \ + ((pinmux >> CH5XX_PINMUX_##field##_S) & CH5XX_PINMUX_##field##_M) + +#define CH5XX_FLAGS_INPUT(val) COND_CODE_1(val, (GPIO_INPUT), (0)) +#define CH5XX_FLAGS_OUTPUT(val) COND_CODE_1(val, (GPIO_OUTPUT), (0)) +#define CH5XX_FLAGS_PUSH_PULL(val) COND_CODE_1(val, (GPIO_PUSH_PULL), (0)) +#define CH5XX_FLAGS_OPEN_DRAIN(val) COND_CODE_1(val, (GPIO_OPEN_DRAIN), (0)) +#define CH5XX_FLAGS_PULL_UP(val) COND_CODE_1(val, (GPIO_PULL_UP), (0)) +#define CH5XX_FLAGS_PULL_DOWN(val) COND_CODE_1(val, (GPIO_PULL_DOWN), (0)) + +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + { \ + .port = CH5XX_PINMUX_GET(DT_PROP_BY_IDX(node_id, prop, idx), PORT), \ + .pin = CH5XX_PINMUX_GET(DT_PROP_BY_IDX(node_id, prop, idx), PIN), \ + .remap_bit = CH5XX_PINMUX_GET(DT_PROP_BY_IDX(node_id, prop, idx), REMAP_BIT), \ + .remap_en = CH5XX_PINMUX_GET(DT_PROP_BY_IDX(node_id, prop, idx), REMAP_EN), \ + .flags = CH5XX_FLAGS_PULL_UP(DT_PROP(node_id, bias_pull_up)) | \ + CH5XX_FLAGS_PULL_DOWN(DT_PROP(node_id, bias_pull_down)) | \ + CH5XX_FLAGS_PUSH_PULL(DT_PROP(node_id, drive_push_pull)) | \ + CH5XX_FLAGS_OPEN_DRAIN(DT_PROP(node_id, drive_open_drain)) | \ + CH5XX_FLAGS_INPUT(DT_PROP(node_id, input_enable)) | \ + CH5XX_FLAGS_OUTPUT(DT_PROP(node_id, output_enable)) | \ + DT_PROP_OR(node_id, gpio_flags, 0), \ + }, + +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + {DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), DT_FOREACH_PROP_ELEM, pinmux, \ + Z_PINCTRL_STATE_PIN_INIT)} + +#endif /* __CH32V_PINCTRL_SOC_CH5XX_H__ */ diff --git a/soc/wch/ch32v/qingke_v3/CMakeLists.txt b/soc/wch/ch32v/qingke_v3/CMakeLists.txt new file mode 100644 index 000000000000..f79d0b3255d3 --- /dev/null +++ b/soc/wch/ch32v/qingke_v3/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/wch/ch32v/qingke_v3/Kconfig b/soc/wch/ch32v/qingke_v3/Kconfig new file mode 100644 index 000000000000..0d0a2b4b4863 --- /dev/null +++ b/soc/wch/ch32v/qingke_v3/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_CH32V_QINGKE_V3A + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR diff --git a/soc/wch/ch32v/qingke_v3/Kconfig.defconfig b/soc/wch/ch32v/qingke_v3/Kconfig.defconfig new file mode 100644 index 000000000000..23f03f910c96 --- /dev/null +++ b/soc/wch/ch32v/qingke_v3/Kconfig.defconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_CH32V_QINGKE_V3A + +config RISCV_GP + default y + +rsource "Kconfig.defconfig.*" + +endif # SOC_SERIES_CH32V_QINGKE_V3A diff --git a/soc/wch/ch32v/qingke_v3/Kconfig.defconfig.ch56x b/soc/wch/ch32v/qingke_v3/Kconfig.defconfig.ch56x new file mode 100644 index 000000000000..a83681b6df48 --- /dev/null +++ b/soc/wch/ch32v/qingke_v3/Kconfig.defconfig.ch56x @@ -0,0 +1,16 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +if SOC_CH56X + +config NUM_IRQS + int + default 36 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,$(dt_nodelabel_path,hclk),clock-frequency) + +config CLOCK_CONTROL + default y + +endif # SOC_CH56X diff --git a/soc/wch/ch32v/qingke_v3/Kconfig.soc b/soc/wch/ch32v/qingke_v3/Kconfig.soc new file mode 100644 index 000000000000..95732ffa074d --- /dev/null +++ b/soc/wch/ch32v/qingke_v3/Kconfig.soc @@ -0,0 +1,11 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_CH32V_QINGKE_V3A + bool + select SOC_FAMILY_CH32V + +config SOC_SERIES + default "qingke_v3" if SOC_SERIES_CH32V_QINGKE_V3A + +rsource "Kconfig.soc.*" diff --git a/soc/wch/ch32v/qingke_v3/Kconfig.soc.ch56x b/soc/wch/ch32v/qingke_v3/Kconfig.soc.ch56x new file mode 100644 index 000000000000..5e0923c1e9a3 --- /dev/null +++ b/soc/wch/ch32v/qingke_v3/Kconfig.soc.ch56x @@ -0,0 +1,18 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config SOC_CH56X + bool + select SOC_SERIES_CH32V_QINGKE_V3A + +config SOC_CH565 + bool "WCH CH565" + select SOC_CH56X + +config SOC_CH569 + bool "WCH CH569" + select SOC_CH56X + +config SOC + default "ch565" if SOC_CH565 + default "ch569" if SOC_CH569 diff --git a/soc/wch/ch32v/qingke_v3/pinctrl_soc.h b/soc/wch/ch32v/qingke_v3/pinctrl_soc.h new file mode 100644 index 000000000000..22dbad6585d0 --- /dev/null +++ b/soc/wch/ch32v/qingke_v3/pinctrl_soc.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __CH32V_PINCTRL_SOC_H__ +#define __CH32V_PINCTRL_SOC_H__ + +#include "pinctrl_soc_ch5xx.h" + +#endif /* __CH32V_PINCTRL_SOC_H__ */ diff --git a/soc/wch/ch32v/qingke_v3/soc.h b/soc/wch/ch32v/qingke_v3/soc.h new file mode 100644 index 000000000000..4d0d496fb54e --- /dev/null +++ b/soc/wch/ch32v/qingke_v3/soc.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SOC_H__ +#define __SOC_H__ + +#include + +#if defined(CONFIG_SOC_CH56X) +#include "syscon_regs_ch56x.h" +#endif + +#endif /* __SOC_H__ */ diff --git a/soc/wch/ch32v/qingke_v3/syscon_regs_ch56x.h b/soc/wch/ch32v/qingke_v3/syscon_regs_ch56x.h new file mode 100644 index 000000000000..712893eef372 --- /dev/null +++ b/soc/wch/ch32v/qingke_v3/syscon_regs_ch56x.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SOC_CH32V_SYSCON_REGS_CH56X_H__ +#define __SOC_CH32V_SYSCON_REGS_CH56X_H__ + +#define CH32V_SYS_R8_SAFE_ACCESS_SIG_REG (CH32V_SYS_BASE + 0x00) +#define CH32V_SYS_R8_CHIP_ID_REG (CH32V_SYS_BASE + 0x01) +#define CH32V_SYS_R8_SAFE_ACCESS_ID_REG (CH32V_SYS_BASE + 0x02) +#define CH32V_SYS_R8_WDOG_COUNT_REG (CH32V_SYS_BASE + 0x03) +#define CH32V_SYS_R8_GLOB_ROM_CFG_REG (CH32V_SYS_BASE + 0x04) +#define CH32V_SYS_R8_RST_BOOT_STAT_REG (CH32V_SYS_BASE + 0x05) +#define CH32V_SYS_R8_RST_WDOG_CTRL_REG (CH32V_SYS_BASE + 0x06) +#define CH32V_SYS_R8_GLOB_RESET_KEEP_REG (CH32V_SYS_BASE + 0x07) +#define CH32V_SYS_R8_CLK_PLL_DIV_REG (CH32V_SYS_BASE + 0x08) +#define CH32V_SYS_R8_CLK_CFG_CTRL_REG (CH32V_SYS_BASE + 0x0A) +#define CH32V_SYS_R8_CLK_MOD_AUX_REG (CH32V_SYS_BASE + 0x0B) +#define CH32V_SYS_R8_SLP_CLK_OFF_REG(n) (CH32V_SYS_BASE + 0x0C + n) +#define CH32V_SYS_R8_SLP_CLK_OFF_CNT (2) +#define CH32V_SYS_R8_SLP_WAKE_CTRL_REG (CH32V_SYS_BASE + 0x0E) +#define CH32V_SYS_R8_SLP_POWER_CTRL_REG (CH32V_SYS_BASE + 0x0F) +#define CH32V_SYS_R8_PIN_ALTERNATE_REG (CH32V_SYS_BASE + 0x12) +#define CH32V_SYS_R8_GPIO_INT_FLAG_REG (CH32V_SYS_BASE + 0x1C) +#define CH32V_SYS_R8_GPIO_INT_ENABLE_REG (CH32V_SYS_BASE + 0x1D) +#define CH32V_SYS_R8_GPIO_INT_MODE_REG (CH32V_SYS_BASE + 0x1E) +#define CH32V_SYS_R8_GPIO_INT_POLAR_REG (CH32V_SYS_BASE + 0x1F) +#define CH32V_SYS_R16_SERD_ANA_CFG1 (CH32V_SYS_BASE + 0x20) +#define CH32V_SYS_R32_SERD_ANA_CFG2 (CH32V_SYS_BASE + 0x24) + +#endif /* __SOC_CH32V_SYSCON_REGS_CH56X_H__ */ diff --git a/soc/wch/ch32v/soc.yml b/soc/wch/ch32v/soc.yml new file mode 100644 index 000000000000..3a113ec9dd1a --- /dev/null +++ b/soc/wch/ch32v/soc.yml @@ -0,0 +1,7 @@ +family: +- name: ch32v + series: + - name: qingke-v3 + socs: + - name: ch565 + - name: ch569 diff --git a/soc/wch/ch32v/soc_common.c b/soc/wch/ch32v/soc_common.c new file mode 100644 index 000000000000..69bcc15c90e8 --- /dev/null +++ b/soc/wch/ch32v/soc_common.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* CH32V_SYS_R8_SAFE_ACCESS_SIG_REG */ +#define SAFE_ACCESS_SIG_KEY_1 (0x57) +#define SAFE_ACCESS_SIG_KEY_2 (0xA8) + +void ch32v_sys_unlock(void) +{ + sys_write8(SAFE_ACCESS_SIG_KEY_1, CH32V_SYS_R8_SAFE_ACCESS_SIG_REG); + sys_write8(SAFE_ACCESS_SIG_KEY_2, CH32V_SYS_R8_SAFE_ACCESS_SIG_REG); +} + +void ch32v_sys_relock(void) +{ + sys_write8(0x00, CH32V_SYS_R8_SAFE_ACCESS_SIG_REG); +} diff --git a/soc/wch/ch32v/soc_common.h b/soc/wch/ch32v/soc_common.h new file mode 100644 index 000000000000..f5c4147439b7 --- /dev/null +++ b/soc/wch/ch32v/soc_common.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SOC_COMMON_H__ +#define __SOC_COMMON_H__ + +#include + +#define CH32V_SYS_BASE DT_REG_ADDR(DT_NODELABEL(syscon)) + +void ch32v_sys_unlock(void); +void ch32v_sys_relock(void); + +#endif /* __SOC_COMMON_H__ */