From 6179a6fe73f83293dc88f14f4d113ebae886d97d Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Sat, 21 Oct 2023 15:16:48 +0800 Subject: [PATCH 01/14] dts: vendor-prefixes: Add WCH * Website: https://wch-ic.com/ Signed-off-by: Chen Xingyu --- dts/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) 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 From afd3b7c26c8179118c2865d790e41e9e834994eb Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Tue, 7 Nov 2023 11:38:25 +0800 Subject: [PATCH 02/14] [DNM] arch: riscv: Add support for custom interrupt controller NOTE: Duplicated with an existing PR. Leaving this commit here just as a placeholder. Will be rebased soon after that existing PR get merged. ========================================================================== In certain cases, platforms may have their own implemented interrupt controllers (e.g., the PFIC on WCH MCUs) that require the ability to implement the irq_enable/disable functions at the SoC level. Similar support already exists for ARM and ARM64. This commit adds support for RISC-V as well. Signed-off-by: Chen Xingyu # Conflicts: # include/zephyr/arch/riscv/irq.h --- arch/riscv/Kconfig | 10 ++++++++++ include/zephyr/arch/riscv/irq.h | 22 ++++++++++++++++++++++ soc/common/riscv-privileged/CMakeLists.txt | 3 ++- 3 files changed, 34 insertions(+), 1 deletion(-) 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/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/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) From 0cd60e96028b5b240f30a1a8bfe0657596a883f5 Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Fri, 20 Oct 2023 16:26:40 +0800 Subject: [PATCH 03/14] dts/soc: wch: Add WCH QingKe V3 series QingKe V3 is an RV32IMAC core developed by WCH Signed-off-by: Chen Xingyu --- dts/bindings/cpu/wch,qingke-v3.yaml | 8 ++++++++ dts/riscv/wch/qingke-v3.dtsi | 22 ++++++++++++++++++++++ soc/wch/ch32v/CMakeLists.txt | 9 +++++++++ soc/wch/ch32v/Kconfig | 16 ++++++++++++++++ soc/wch/ch32v/Kconfig.defconfig | 8 ++++++++ soc/wch/ch32v/Kconfig.soc | 10 ++++++++++ soc/wch/ch32v/cpu_idle.c | 19 +++++++++++++++++++ soc/wch/ch32v/qingke_v3/CMakeLists.txt | 3 +++ soc/wch/ch32v/qingke_v3/Kconfig | 9 +++++++++ soc/wch/ch32v/qingke_v3/Kconfig.defconfig | 11 +++++++++++ soc/wch/ch32v/qingke_v3/Kconfig.soc | 11 +++++++++++ soc/wch/ch32v/soc.yml | 4 ++++ 12 files changed, 130 insertions(+) create mode 100644 dts/bindings/cpu/wch,qingke-v3.yaml create mode 100644 dts/riscv/wch/qingke-v3.dtsi create mode 100644 soc/wch/ch32v/CMakeLists.txt create mode 100644 soc/wch/ch32v/Kconfig create mode 100644 soc/wch/ch32v/Kconfig.defconfig create mode 100644 soc/wch/ch32v/Kconfig.soc create mode 100644 soc/wch/ch32v/cpu_idle.c create mode 100644 soc/wch/ch32v/qingke_v3/CMakeLists.txt create mode 100644 soc/wch/ch32v/qingke_v3/Kconfig create mode 100644 soc/wch/ch32v/qingke_v3/Kconfig.defconfig create mode 100644 soc/wch/ch32v/qingke_v3/Kconfig.soc create mode 100644 soc/wch/ch32v/soc.yml 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/riscv/wch/qingke-v3.dtsi b/dts/riscv/wch/qingke-v3.dtsi new file mode 100644 index 000000000000..89e269a8d275 --- /dev/null +++ b/dts/riscv/wch/qingke-v3.dtsi @@ -0,0 +1,22 @@ +/* + * 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>; + }; +}; diff --git a/soc/wch/ch32v/CMakeLists.txt b/soc/wch/ch32v/CMakeLists.txt new file mode 100644 index 000000000000..7590ff1f8bc5 --- /dev/null +++ b/soc/wch/ch32v/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources( + cpu_idle.c +) + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/wch/ch32v/Kconfig b/soc/wch/ch32v/Kconfig new file mode 100644 index 000000000000..5e0625454595 --- /dev/null +++ b/soc/wch/ch32v/Kconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_CH32V + select RISCV + select RISCV_PRIVILEGED + 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/qingke_v3/CMakeLists.txt b/soc/wch/ch32v/qingke_v3/CMakeLists.txt new file mode 100644 index 000000000000..187982e82160 --- /dev/null +++ b/soc/wch/ch32v/qingke_v3/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +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.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/soc.yml b/soc/wch/ch32v/soc.yml new file mode 100644 index 000000000000..10731abcd652 --- /dev/null +++ b/soc/wch/ch32v/soc.yml @@ -0,0 +1,4 @@ +family: +- name: ch32v + series: + - name: qingke-v3 From a05583a3fad79a65db38292213006ebe25cf72b1 Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Sat, 21 Oct 2023 15:14:30 +0800 Subject: [PATCH 04/14] dts/soc: wch: ch56x: Add WCH CH569/5 SoC Based on QingKe V3A core, CH569/5 are members of the CH56x series. Signed-off-by: Chen Xingyu --- dts/riscv/wch/ch56x/ch565m.dtsi | 12 ++++++++ dts/riscv/wch/ch56x/ch565w.dtsi | 13 +++++++++ dts/riscv/wch/ch56x/ch569w.dtsi | 13 +++++++++ dts/riscv/wch/ch56x/ch56x-common.dtsi | 28 +++++++++++++++++++ dts/riscv/wch/ch56x/ch56xw-common.dtsi | 6 ++++ .../ch32v/qingke_v3/Kconfig.defconfig.ch56x | 10 +++++++ soc/wch/ch32v/qingke_v3/Kconfig.soc.ch56x | 18 ++++++++++++ soc/wch/ch32v/soc.yml | 3 ++ 8 files changed, 103 insertions(+) create mode 100644 dts/riscv/wch/ch56x/ch565m.dtsi create mode 100644 dts/riscv/wch/ch56x/ch565w.dtsi create mode 100644 dts/riscv/wch/ch56x/ch569w.dtsi create mode 100644 dts/riscv/wch/ch56x/ch56x-common.dtsi create mode 100644 dts/riscv/wch/ch56x/ch56xw-common.dtsi create mode 100644 soc/wch/ch32v/qingke_v3/Kconfig.defconfig.ch56x create mode 100644 soc/wch/ch32v/qingke_v3/Kconfig.soc.ch56x diff --git a/dts/riscv/wch/ch56x/ch565m.dtsi b/dts/riscv/wch/ch56x/ch565m.dtsi new file mode 100644 index 000000000000..06352f4f0f7d --- /dev/null +++ b/dts/riscv/wch/ch56x/ch565m.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + compatible = "wch,ch565m", "simple-bus"; + }; +}; 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.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.dtsi b/dts/riscv/wch/ch56x/ch56x-common.dtsi new file mode 100644 index 000000000000..261515d816db --- /dev/null +++ b/dts/riscv/wch/ch56x/ch56x-common.dtsi @@ -0,0 +1,28 @@ +/* + * 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)>; + }; + }; +}; diff --git a/dts/riscv/wch/ch56x/ch56xw-common.dtsi b/dts/riscv/wch/ch56x/ch56xw-common.dtsi new file mode 100644 index 000000000000..9d6967c1da09 --- /dev/null +++ b/dts/riscv/wch/ch56x/ch56xw-common.dtsi @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2023-2024 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include 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..585cd10cbc56 --- /dev/null +++ b/soc/wch/ch32v/qingke_v3/Kconfig.defconfig.ch56x @@ -0,0 +1,10 @@ +# Copyright (c) 2023-2024 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +if SOC_CH56X + +config NUM_IRQS + int + default 36 + +endif # SOC_CH56X 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/soc.yml b/soc/wch/ch32v/soc.yml index 10731abcd652..3a113ec9dd1a 100644 --- a/soc/wch/ch32v/soc.yml +++ b/soc/wch/ch32v/soc.yml @@ -2,3 +2,6 @@ family: - name: ch32v series: - name: qingke-v3 + socs: + - name: ch565 + - name: ch569 From 6292691c11a9c2344a51edcb12af958a76220056 Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Sat, 21 Oct 2023 22:51:04 +0800 Subject: [PATCH 05/14] drivers: intc: Implement interrupt controller for WCH QingKe CPUs PFIC (Programmable Fast Interrupt Controller) is the interrupt controller implmentation in WCH QingKe series RISC-V MCUs. Signed-off-by: Chen Xingyu # Conflicts: # drivers/interrupt_controller/CMakeLists.txt # drivers/interrupt_controller/Kconfig --- drivers/interrupt_controller/CMakeLists.txt | 1 + drivers/interrupt_controller/Kconfig | 2 + drivers/interrupt_controller/Kconfig.ch32v | 9 +++ .../interrupt_controller/intc_ch32v_pfic.c | 63 +++++++++++++++++++ .../interrupt-controller/wch,ch32v-pfic.yaml | 19 ++++++ dts/riscv/wch/qingke-v3.dtsi | 8 +++ .../interrupt_controller/intc_ch32v_pfic.h | 14 +++++ soc/wch/ch32v/CMakeLists.txt | 1 + soc/wch/ch32v/Kconfig | 1 + soc/wch/ch32v/irq.c | 27 ++++++++ 10 files changed, 145 insertions(+) create mode 100644 drivers/interrupt_controller/Kconfig.ch32v create mode 100644 drivers/interrupt_controller/intc_ch32v_pfic.c create mode 100644 dts/bindings/interrupt-controller/wch,ch32v-pfic.yaml create mode 100644 include/zephyr/drivers/interrupt_controller/intc_ch32v_pfic.h create mode 100644 soc/wch/ch32v/irq.c 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/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/riscv/wch/qingke-v3.dtsi b/dts/riscv/wch/qingke-v3.dtsi index 89e269a8d275..3a59da28b5a8 100644 --- a/dts/riscv/wch/qingke-v3.dtsi +++ b/dts/riscv/wch/qingke-v3.dtsi @@ -18,5 +18,13 @@ 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>; + }; }; }; 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/soc/wch/ch32v/CMakeLists.txt b/soc/wch/ch32v/CMakeLists.txt index 7590ff1f8bc5..716bcae8ba3e 100644 --- a/soc/wch/ch32v/CMakeLists.txt +++ b/soc/wch/ch32v/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_library() zephyr_library_sources( cpu_idle.c + irq.c ) add_subdirectory(${SOC_SERIES}) diff --git a/soc/wch/ch32v/Kconfig b/soc/wch/ch32v/Kconfig index 5e0625454595..83db4bb182c2 100644 --- a/soc/wch/ch32v/Kconfig +++ b/soc/wch/ch32v/Kconfig @@ -4,6 +4,7 @@ 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 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); +} From 129a6088c3795d942a2c4226370076d82fa9a121 Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Sat, 21 Oct 2023 20:36:52 +0800 Subject: [PATCH 06/14] drivers: timer: Add systick driver for WCH QingKe V3 CPUs This driver is shared across QingKe V3A series, including CH32V103, CH569/5 and CH573/1. Signed-off-by: Chen Xingyu --- drivers/timer/CMakeLists.txt | 1 + drivers/timer/Kconfig | 1 + drivers/timer/Kconfig.ch32v | 10 +++ drivers/timer/ch32v_v3_systick.c | 77 ++++++++++++++++++++ dts/bindings/timer/wch,ch32v-v3-systick.yaml | 15 ++++ dts/riscv/wch/qingke-v3.dtsi | 6 ++ 6 files changed, 110 insertions(+) create mode 100644 drivers/timer/Kconfig.ch32v create mode 100644 drivers/timer/ch32v_v3_systick.c create mode 100644 dts/bindings/timer/wch,ch32v-v3-systick.yaml 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/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/riscv/wch/qingke-v3.dtsi b/dts/riscv/wch/qingke-v3.dtsi index 3a59da28b5a8..966961a18b5e 100644 --- a/dts/riscv/wch/qingke-v3.dtsi +++ b/dts/riscv/wch/qingke-v3.dtsi @@ -26,5 +26,11 @@ interrupt-controller; #interrupt-cells = <2>; }; + + systick: systick@e000f000 { + compatible = "wch,ch32v-v3-systick"; + reg = <0xe000f000 0x14>; + interrupts = <12 0>; + }; }; }; From bcc5ea7976702016c5fa47f4e9964a30e891bb3a Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Mon, 30 Oct 2023 14:05:23 +0800 Subject: [PATCH 07/14] dts/soc: wch: ch56x: Add syscon node for WCH CH56x This commit describes the system control block of the CH56x in DTS. This block will be utilized in future drivers for functions such as pin remapping, clock control, and interrupt management. Additionally, macros has been added to facilitate easy access to the block. Signed-off-by: Chen Xingyu --- dts/riscv/wch/ch56x/ch56x-common.dtsi | 4 +++ soc/wch/ch32v/CMakeLists.txt | 3 ++ soc/wch/ch32v/qingke_v3/CMakeLists.txt | 2 ++ soc/wch/ch32v/qingke_v3/soc.h | 15 ++++++++++ soc/wch/ch32v/qingke_v3/syscon_regs_ch56x.h | 32 +++++++++++++++++++++ soc/wch/ch32v/soc_common.c | 22 ++++++++++++++ soc/wch/ch32v/soc_common.h | 16 +++++++++++ 7 files changed, 94 insertions(+) create mode 100644 soc/wch/ch32v/qingke_v3/soc.h create mode 100644 soc/wch/ch32v/qingke_v3/syscon_regs_ch56x.h create mode 100644 soc/wch/ch32v/soc_common.c create mode 100644 soc/wch/ch32v/soc_common.h diff --git a/dts/riscv/wch/ch56x/ch56x-common.dtsi b/dts/riscv/wch/ch56x/ch56x-common.dtsi index 261515d816db..79184c7ecfc9 100644 --- a/dts/riscv/wch/ch56x/ch56x-common.dtsi +++ b/dts/riscv/wch/ch56x/ch56x-common.dtsi @@ -24,5 +24,9 @@ compatible = "mmio-sram"; reg = <0x20020000 DT_SIZE_K(16)>; }; + + syscon: system-control@40001000 { + reg = <0x40001000 0x20>; + }; }; }; diff --git a/soc/wch/ch32v/CMakeLists.txt b/soc/wch/ch32v/CMakeLists.txt index 716bcae8ba3e..dfa55b9c7b98 100644 --- a/soc/wch/ch32v/CMakeLists.txt +++ b/soc/wch/ch32v/CMakeLists.txt @@ -2,9 +2,12 @@ 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/qingke_v3/CMakeLists.txt b/soc/wch/ch32v/qingke_v3/CMakeLists.txt index 187982e82160..f79d0b3255d3 100644 --- a/soc/wch/ch32v/qingke_v3/CMakeLists.txt +++ b/soc/wch/ch32v/qingke_v3/CMakeLists.txt @@ -1,3 +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/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_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__ */ From 2d4afeba201f73ae0b7f822ec051e8bf5c531287 Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Mon, 30 Oct 2023 15:31:01 +0800 Subject: [PATCH 08/14] drivers: clock: Implement system clock mux controller for CH56x The CH56x can be configured to run on a 30MHz external oscillator or a 480MHz PLL generated by the USB PHY. This commit introduces a clock controller that can automatically select one of the two available clock sources and determine the appropriate divisor based on the given frequency. The `CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC` value is also updated with the selected frequency. Signed-off-by: Chen Xingyu # Conflicts: # drivers/clock_control/Kconfig # soc/riscv/riscv-privileged/wch_ch32v/Kconfig.defconfig.ch56x --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.ch32v | 9 ++ .../clock_control_ch56x_clkmux.c | 129 ++++++++++++++++++ dts/bindings/clock/wch,ch56x-clkmux.yaml | 32 +++++ dts/riscv/wch/ch56x/ch56x-common.dtsi | 8 ++ .../ch32v/qingke_v3/Kconfig.defconfig.ch56x | 6 + 7 files changed, 187 insertions(+) create mode 100644 drivers/clock_control/Kconfig.ch32v create mode 100644 drivers/clock_control/clock_control_ch56x_clkmux.c create mode 100644 dts/bindings/clock/wch,ch56x-clkmux.yaml 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/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/riscv/wch/ch56x/ch56x-common.dtsi b/dts/riscv/wch/ch56x/ch56x-common.dtsi index 79184c7ecfc9..8a269b23c2bb 100644 --- a/dts/riscv/wch/ch56x/ch56x-common.dtsi +++ b/dts/riscv/wch/ch56x/ch56x-common.dtsi @@ -29,4 +29,12 @@ reg = <0x40001000 0x20>; }; }; + + clocks { + hclk: clkmux { + compatible = "wch,ch56x-clkmux"; + clock-frequency = ; + #clock-cells = <0>; + }; + }; }; diff --git a/soc/wch/ch32v/qingke_v3/Kconfig.defconfig.ch56x b/soc/wch/ch32v/qingke_v3/Kconfig.defconfig.ch56x index 585cd10cbc56..a83681b6df48 100644 --- a/soc/wch/ch32v/qingke_v3/Kconfig.defconfig.ch56x +++ b/soc/wch/ch32v/qingke_v3/Kconfig.defconfig.ch56x @@ -7,4 +7,10 @@ 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 From 67d516ce94f13cb3f0a41f0e26dd663325376c79 Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Sun, 22 Oct 2023 16:04:14 +0800 Subject: [PATCH 09/14] drivers: gpio: Add GPIO driver for WCH CH56x This commit implements a GPIO driver for CH56x series. The 2 instances of GPIO share a same IRQ line on this chip. So the config `SHARED_IRQ` is selected as well. Signed-off-by: Chen Xingyu --- drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 1 + drivers/gpio/Kconfig.ch32v | 10 + drivers/gpio/gpio_ch56x.c | 318 +++++++++++++++++++ dts/bindings/gpio/wch,ch56x-gpio.yaml | 28 ++ dts/riscv/wch/ch56x/ch565m.dtsi | 11 + dts/riscv/wch/ch56x/ch56x-common.dtsi | 20 ++ include/zephyr/dt-bindings/gpio/ch56x-gpio.h | 14 + 8 files changed, 403 insertions(+) create mode 100644 drivers/gpio/Kconfig.ch32v create mode 100644 drivers/gpio/gpio_ch56x.c create mode 100644 dts/bindings/gpio/wch,ch56x-gpio.yaml create mode 100644 include/zephyr/dt-bindings/gpio/ch56x-gpio.h 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/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/riscv/wch/ch56x/ch565m.dtsi b/dts/riscv/wch/ch56x/ch565m.dtsi index 06352f4f0f7d..eb2625581770 100644 --- a/dts/riscv/wch/ch56x/ch565m.dtsi +++ b/dts/riscv/wch/ch56x/ch565m.dtsi @@ -10,3 +10,14 @@ 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/ch56x-common.dtsi b/dts/riscv/wch/ch56x/ch56x-common.dtsi index 8a269b23c2bb..63dc88951c07 100644 --- a/dts/riscv/wch/ch56x/ch56x-common.dtsi +++ b/dts/riscv/wch/ch56x/ch56x-common.dtsi @@ -28,6 +28,26 @@ syscon: system-control@40001000 { reg = <0x40001000 0x20>; }; + + 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>; + }; }; clocks { 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_ */ From 4d436d3c72dc20d198e6b6550b2e2c2cb73caff2 Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Tue, 24 Oct 2023 12:40:32 +0800 Subject: [PATCH 10/14] drivers: pinctrl: Implement pin controller for WCH CH5xx series This commit introduces a pinctrl driver for the CH5xx series. The limitations of pin multiplexing of WCH CH5xx series are described in the binding configuration. Signed-off-by: Chen Xingyu --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.ch32v | 10 ++ drivers/pinctrl/pinctrl_ch5xx.c | 49 ++++++ dts/bindings/pinctrl/wch,ch5xx-pinctrl.yaml | 49 ++++++ dts/riscv/wch/ch56x/ch565m-pinctrl.dtsi | 6 + dts/riscv/wch/ch56x/ch565w-pinctrl.dtsi | 7 + dts/riscv/wch/ch56x/ch569w-pinctrl.dtsi | 7 + dts/riscv/wch/ch56x/ch56x-common-pinctrl.dtsi | 139 ++++++++++++++++++ dts/riscv/wch/ch56x/ch56x-common.dtsi | 5 + .../wch/ch56x/ch56xw-common-pinctrl.dtsi | 82 +++++++++++ .../dt-bindings/pinctrl/ch56x-pinctrl.h | 22 +++ .../pinctrl/ch5xx-pinctrl-common.h | 35 +++++ soc/wch/ch32v/pinctrl_soc_ch5xx.h | 53 +++++++ soc/wch/ch32v/qingke_v3/pinctrl_soc.h | 11 ++ 15 files changed, 477 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.ch32v create mode 100644 drivers/pinctrl/pinctrl_ch5xx.c create mode 100644 dts/bindings/pinctrl/wch,ch5xx-pinctrl.yaml create mode 100644 dts/riscv/wch/ch56x/ch565m-pinctrl.dtsi create mode 100644 dts/riscv/wch/ch56x/ch565w-pinctrl.dtsi create mode 100644 dts/riscv/wch/ch56x/ch569w-pinctrl.dtsi create mode 100644 dts/riscv/wch/ch56x/ch56x-common-pinctrl.dtsi create mode 100644 dts/riscv/wch/ch56x/ch56xw-common-pinctrl.dtsi create mode 100644 include/zephyr/dt-bindings/pinctrl/ch56x-pinctrl.h create mode 100644 include/zephyr/dt-bindings/pinctrl/ch5xx-pinctrl-common.h create mode 100644 soc/wch/ch32v/pinctrl_soc_ch5xx.h create mode 100644 soc/wch/ch32v/qingke_v3/pinctrl_soc.h 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/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/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/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/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/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 index 63dc88951c07..3a823a97628d 100644 --- a/dts/riscv/wch/ch56x/ch56x-common.dtsi +++ b/dts/riscv/wch/ch56x/ch56x-common.dtsi @@ -27,6 +27,11 @@ syscon: system-control@40001000 { reg = <0x40001000 0x20>; + + pinctrl: pin-alternate { + compatible = "wch,ch5xx-pinctrl"; + gpio-controllers = <&gpioa>, <&gpiob>; + }; }; gpioa: gpio@40001040 { 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/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/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/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__ */ From 128f2021f35f55dac929c469b7574a148f167359 Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Fri, 27 Oct 2023 15:52:53 +0800 Subject: [PATCH 11/14] drivers: serial: Implement UART driver for WCH CH5xx series This commit introduces UART driver for CH5xx series, supporting both polling and interrupt-driven mode. Signed-off-by: Chen Xingyu --- drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 2 + drivers/serial/Kconfig.ch32v | 12 + drivers/serial/uart_ch5xx.c | 354 ++++++++++++++++++++++++ dts/bindings/serial/wch,ch5xx-uart.yaml | 24 ++ dts/riscv/wch/ch56x/ch56x-common.dtsi | 24 ++ dts/riscv/wch/ch56x/ch56xw-common.dtsi | 12 + 7 files changed, 429 insertions(+) create mode 100644 drivers/serial/Kconfig.ch32v create mode 100644 drivers/serial/uart_ch5xx.c create mode 100644 dts/bindings/serial/wch,ch5xx-uart.yaml 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/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/riscv/wch/ch56x/ch56x-common.dtsi b/dts/riscv/wch/ch56x/ch56x-common.dtsi index 3a823a97628d..6c2bd0426fec 100644 --- a/dts/riscv/wch/ch56x/ch56x-common.dtsi +++ b/dts/riscv/wch/ch56x/ch56x-common.dtsi @@ -53,6 +53,30 @@ #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 { diff --git a/dts/riscv/wch/ch56x/ch56xw-common.dtsi b/dts/riscv/wch/ch56x/ch56xw-common.dtsi index 9d6967c1da09..c86604dc4c14 100644 --- a/dts/riscv/wch/ch56x/ch56xw-common.dtsi +++ b/dts/riscv/wch/ch56x/ch56xw-common.dtsi @@ -4,3 +4,15 @@ */ #include + +/ { + soc { + uart1: uart@40003400 { + compatible = "wch,ch5xx-uart"; + reg = <0x40003400 0x400>; + interrupts = <30 16>; + clocks = <&hclk>; + status = "disabled"; + }; + }; +}; From 4ad9fd3a07ada6749841236a9e5af075465ff63a Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Fri, 27 Oct 2023 11:33:31 +0800 Subject: [PATCH 12/14] scripts: runners: Add wrapper for WCHISPTool `WCHISPTool_CMD` is the commandline version of WCHISPTool, which is a USB flashing tool for WCH series MCUs. Signed-off-by: Chen Xingyu --- boards/common/wchisp.board.cmake | 5 +++ scripts/west_commands/runners/__init__.py | 1 + scripts/west_commands/runners/wchisp.py | 43 +++++++++++++++++++++ scripts/west_commands/tests/test_imports.py | 1 + 4 files changed, 50 insertions(+) create mode 100644 boards/common/wchisp.board.cmake create mode 100644 scripts/west_commands/runners/wchisp.py 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/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 From d3c40862c7b067382a57780730a9a1700b0a1282 Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Sun, 22 Oct 2023 01:20:35 +0800 Subject: [PATCH 13/14] boards: wch: Bring up WCH CH56(5/9)W-EVT CH565W-EVT and CH569W-EVT are boards by WCH for the evaluation of CH565W and CH569W chips. Signed-off-by: Chen Xingyu --- boards/wch/ch565w_evt/Kconfig.ch565w_evt | 5 ++ boards/wch/ch565w_evt/board.cmake | 4 ++ boards/wch/ch565w_evt/board.yml | 5 ++ boards/wch/ch565w_evt/ch565w_evt.dts | 54 +++++++++++++++ boards/wch/ch565w_evt/ch565w_evt.yaml | 13 ++++ boards/wch/ch565w_evt/ch565w_evt_defconfig | 7 ++ boards/wch/ch565w_evt/doc/index.rst | 81 ++++++++++++++++++++++ boards/wch/ch569w_evt/Kconfig.ch569w_evt | 5 ++ boards/wch/ch569w_evt/board.cmake | 4 ++ boards/wch/ch569w_evt/board.yml | 5 ++ boards/wch/ch569w_evt/ch569w_evt.dts | 54 +++++++++++++++ boards/wch/ch569w_evt/ch569w_evt.yaml | 13 ++++ boards/wch/ch569w_evt/ch569w_evt_defconfig | 7 ++ boards/wch/ch569w_evt/doc/index.rst | 81 ++++++++++++++++++++++ boards/wch/index.rst | 10 +++ 15 files changed, 348 insertions(+) create mode 100644 boards/wch/ch565w_evt/Kconfig.ch565w_evt create mode 100644 boards/wch/ch565w_evt/board.cmake create mode 100644 boards/wch/ch565w_evt/board.yml create mode 100644 boards/wch/ch565w_evt/ch565w_evt.dts create mode 100644 boards/wch/ch565w_evt/ch565w_evt.yaml create mode 100644 boards/wch/ch565w_evt/ch565w_evt_defconfig create mode 100644 boards/wch/ch565w_evt/doc/index.rst create mode 100644 boards/wch/ch569w_evt/Kconfig.ch569w_evt create mode 100644 boards/wch/ch569w_evt/board.cmake create mode 100644 boards/wch/ch569w_evt/board.yml create mode 100644 boards/wch/ch569w_evt/ch569w_evt.dts create mode 100644 boards/wch/ch569w_evt/ch569w_evt.yaml create mode 100644 boards/wch/ch569w_evt/ch569w_evt_defconfig create mode 100644 boards/wch/ch569w_evt/doc/index.rst create mode 100644 boards/wch/index.rst 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: + + **/* From 7cd499e990fd18304f7f08a25096fb21bf46550f Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Fri, 27 Oct 2023 14:14:17 +0800 Subject: [PATCH 14/14] MAINTAINERS: Add WCH platform and assign myself as maintainer * Add `WCH Platforms` section * Add `xingrz` to maintainers of `WCH Platform` Signed-off-by: Chen Xingyu --- MAINTAINERS.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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: